Belle II Software light-2607-kasei
Configuration.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9#include <framework/database/Configuration.h>
10#include <framework/logging/Logger.h>
11#include <framework/dataobjects/FileMetaData.h>
12#include <framework/database/Downloader.h>
13#include <framework/database/Database.h>
14#include <framework/utilities/Utils.h>
15#include <boost/python.hpp>
16#include <framework/core/PyObjConvUtils.h>
17#include <framework/core/PyObjROOTUtils.h>
18#include <boost/algorithm/string.hpp>
19
20#include <set>
21#include <regex>
22
23// Current default globaltag when generating events.
24#define CURRENT_DEFAULT_TAG "main_2026-06-06"
25
26namespace py = boost::python;
27
28namespace {
34 std::vector<std::string> extractStringList(const py::object& obj)
35 {
36 std::vector<std::string> result;
37 Belle2::PyObjConvUtils::iteratePythonObject(obj, [&result](const boost::python::object & item) {
38 py::object str(py::handle<>(PyObject_Str(item.ptr()))); // convert to string
39 // boost::python::extract<std::string> triggers a false-positive
40 // -Wmaybe-uninitialized in GCC.
41#if defined(__GNUC__) && !defined(__clang__)
42#pragma GCC diagnostic push
43#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
44#endif
45 py::extract<std::string> extract(str); // and extract
46 result.emplace_back(extract()); // and push back
47#if defined(__GNUC__) && !defined(__clang__)
48#pragma GCC diagnostic pop
49#endif
50 return true;
51 });
52 // done, return
53 return result;
54 }
55}
56
57namespace Belle2::Conditions {
58 boost::python::list& CppOrPyList::ensurePy()
59 {
60 // convert to python list ...
61 if (m_value.index() == 0) {
62 boost::python::list tmp;
63 for (const auto& e : std::get<0>(m_value)) { tmp.append(e); }
64 m_value.emplace<boost::python::list>(std::move(tmp));
65 }
66 return std::get<1>(m_value);
67 }
68
69 std::vector<std::string>& CppOrPyList::ensureCpp()
70 {
71 // or convert to std::vector ...
72 if (m_value.index() == 1) {
73 std::vector<std::string> tmp = extractStringList(std::get<1>(m_value));
74 m_value.emplace<std::vector<std::string>>(std::move(tmp));
75 }
76 return std::get<0>(m_value);
77 }
78
79 void CppOrPyList::append(const std::string& element)
80 {
81 std::visit(Utils::VisitOverload{
82 [&element](std::vector<std::string>& list) {list.emplace_back(element);},
83 [&element](boost::python::list & list) {list.append(element);}
84 }, m_value);
85 }
86
87 void CppOrPyList::prepend(const std::string& element)
88 {
89 std::visit(Utils::VisitOverload{
90 [&element](std::vector<std::string>& list) {list.emplace(list.begin(), element);},
91 [&element](boost::python::list & list) {list.insert(0, element);}
92 }, m_value);
93 }
94
95 void CppOrPyList::shallowCopy(const boost::python::object& source)
96 {
97 ensurePy().slice(boost::python::_, boost::python::_) = source;
98 }
99
101 {
102 static Configuration instance;
103 return instance;
104 }
105
107 {
108 // Backwards compatibility with the existing BELLE2_CONDB_GLOBALTAG
109 // environment variable: If it is set disable replay
110 if (EnvironmentVariables::isSet("BELLE2_CONDB_GLOBALTAG")) {
111 fillFromEnv(m_globalTags, "BELLE2_CONDB_GLOBALTAG", "");
113 }
114 const std::string serverList = EnvironmentVariables::get("BELLE2_CONDB_SERVERLIST", "");
115 // The list of the metadata providers we are going to query:
116 const std::string metatadaProviders = serverList + " " + // First, the list of servers provided via env. variable
117 m_defaultLocalMetadataProviderPath + "/database.sqlite" + " " + // Then the default local provider (CVMFS)
118 m_defaultLegacyRemoteMetadataProviderServer + " " + // Then the Java-based legacy central provider
119 m_defaultHSFRemoteMetadataProviderServer; // Finally the HSF central provider
120 fillFromEnv(m_metadataProviders, "BELLE2_CONDB_METADATA", metatadaProviders);
122 }
123
125 {
128 }
129 *this = Configuration();
130 }
131
132 std::vector<std::string> Configuration::getDefaultGlobalTags()
133 {
134 // currently the default globaltag can be overwritten by environment variable
135 // so keep that
136 return EnvironmentVariables::getOrCreateList("BELLE2_CONDB_GLOBALTAG", CURRENT_DEFAULT_TAG);
137 }
138
140 {
141 // same as above but as a python tuple ...
142 py::list list;
143 fillFromEnv(list, "BELLE2_CONDB_GLOBALTAG", CURRENT_DEFAULT_TAG);
144 return py::tuple(list);
145 }
146
147 void Configuration::setInputMetadata(const std::vector<FileMetaData>& inputMetadata)
148 {
150 m_inputMetadata = inputMetadata;
151 // make sure the list of globaltags to be used is created but empty
152 m_inputGlobaltags.emplace();
153 // now check for compatibility: make sure all metadata have the same globaltag
154 // setting. Unless we don't have metadata ...
155 if (inputMetadata.empty()) return;
156
157 std::optional<std::string> inputGlobaltags;
158 for (const auto& metadata : inputMetadata) {
159 if (!inputGlobaltags) {
160 inputGlobaltags = metadata.getDatabaseGlobalTag();
161 } else {
162 if (inputGlobaltags != metadata.getDatabaseGlobalTag()) {
163 B2WARNING("Input files metadata contain incompatible globaltag settings, globaltag replay not possible");
164 // no need to set anything
165 return;
166 }
167 }
168 }
169 // if it's still set and empty we have an empty input list ... warn specifically.
170 if (inputGlobaltags and inputGlobaltags->empty()) {
171 B2WARNING("Input files metadata all have empty globaltag setting, globaltag replay not possible");
172 return;
173 }
174 // set the list of globaltags from the string containing the globaltags
175 boost::split(*m_inputGlobaltags, *inputGlobaltags, boost::is_any_of(","));
176
177 // HACK: So, we successfully set the input globaltags from the input file,
178 // however we also decided that we want to add new payloads for
179 // boost, invariant mass, beam spot, collision axis in CMS.
180 // So if the release is older than when these features were introduced
181 // or if files were produced before specific date, extra GTs are appended.
182 // The appended GTs contain only the possible missing info and are added
183 // with lowest priority.
184 // If the files actually had all payloads these legacy payloads will never
185 // be used as they have lowest priority.
186 // Otherwise this should enable running over old files.
187 //
188 // TODO: Once we're sure all files being used contain all payloads remove this.
189
190 std::optional<std::string> relMin, dateMin;
191
192 for (const auto& metadata : inputMetadata) {
193 // get oldest release
194 std::string rel = metadata.getRelease().substr(0, 10);
195 if (std::regex_match(rel, std::regex("release-[0-9][0-9]"))) {
196 if (!relMin) relMin = rel;
197 relMin = min(*relMin, rel);
198 }
199
200 // get oldest production date
201 std::string date = metadata.getDate().substr(0, 10);
202 if (std::regex_match(date, std::regex("[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]"))) {
203 if (!dateMin) dateMin = date;
204 dateMin = min(*dateMin, date);
205 }
206 }
207
208 // add IP GT if rel older than rel04 or for old files
209 if ((relMin && relMin < "release-04") ||
210 (!relMin && (!dateMin || dateMin < "2019-12-31"))) {
211 B2DEBUG(30, "Enabling legacy IP information globaltag in tag replay");
212 m_inputGlobaltags->emplace_back("Legacy_IP_Information");
213 }
214
215 // add CollisionAxisCMS GT if rel older than rel08 or for old files
216 if ((relMin && relMin < "release-08") ||
217 (!relMin && (!dateMin || dateMin < "2023-08-31"))) {
218 B2DEBUG(30, "Enabling legacy CollsionAxisCMS globaltag in tag replay");
219 m_inputGlobaltags->emplace_back("Legacy_CollisionAxisCMS");
220 }
221 // END TODO/HACK
222 }
223
224 std::vector<std::string> Configuration::getBaseTags() const
225 {
226 // return the list of base tags to be used: Either the default tag
227 // or the list of globaltags from the input files
228 if (not m_inputGlobaltags) return getDefaultGlobalTags();
229 return *m_inputGlobaltags;
230 }
231
232 std::vector<std::string> Configuration::getFinalListOfTags()
233 {
234 if (m_overrideEnabled) {
235 B2INFO("Global tag override is in effect: input globaltags and default globaltag will be ignored");
236 return m_globalTags.ensureCpp();
237 }
238
239 auto baseList = getBaseTags();
240 if (m_callback) {
241 // Create a dictionary of keyword arguments for the callback
242 py::dict arguments;
243 // we want a python list of the base tags
244 {
245 py::list baseListPy;
246 for (const auto& tag : baseList) baseListPy.append(tag);
247 arguments["base_tags"] = baseListPy;
248 }
249 // and set the user tags from our list.
250 arguments["user_tags"] = m_globalTags.ensurePy();
251 // and prepare list of metadata. It's None when no replay has been
252 // requested which should mean that we generate events
253 arguments["metadata"] = py::object();
254 // otherwise it's a list of file metadata instances
255 if (m_inputGlobaltags) {
256 py::list metaDataList;
257 for (const auto& m : m_inputMetadata) metaDataList.append(createROOTObjectPyCopy(m));
258 arguments["metadata"] = metaDataList;
259 }
260 // arguments ready, call callback function, python will handle the exceptions
261 py::object retval = (*m_callback)(*py::tuple(), **arguments);
262 // If the return value is not None it should be an iterable
263 // containing the final tag list
264 if (retval != py::object()) {
265 return extractStringList(retval);
266 }
267 // callback returned None so fall back to default
268 }
269 // Default tag replay ... bail if list of globaltags is empty
270 if (baseList.empty()) {
271 if (m_inputGlobaltags) {
272 B2FATAL(R"(No baseline globaltags available.
273 The input files you selected don't have compatible globaltags or an empty
274 globaltag setting. As such globaltag configuration cannot be determined
275 automatically.
276
277 If you really sure that it is a good idea to process these files together
278 you have to manually override the list of globaltags:
279
280 >>> basf2.conditions.override_globaltags()
281)");
282 }else{
283 B2FATAL(R"(No default globaltags available.
284 There is no default globaltag available for processing. This usually means
285 you set the environment variable BELLE2_CONDB_GLOBALTAG to an empty value.
286
287 As this is unlikely to work for even the most basic functionality this is not
288 directly supported anymore. If you really want to disable any access to the
289 conditions database please configure this explicitly
290
291 >>> basf2.conditions.metadata_providers = []
292 >>> basf2.conditions.override_globaltags([])
293)");
294 }
295 }
296 // We have base tags and possibly user tags, so return both
297 std::vector finalList = m_globalTags.ensureCpp();
298 for (const auto& tag : baseList) { finalList.emplace_back(tag); }
299 return finalList;
300 }
301
302 namespace {
304 boost::python::dict expertSettings(const boost::python::tuple& args, boost::python::dict kwargs)
305 {
306 if (py::len(args) != 1) {
307 // keyword only function: raise typerror on non-keyword arguments
308 PyErr_SetString(PyExc_TypeError, ("expert_settings() takes one positional argument but " +
309 std::to_string(len(args)) + " were given").c_str());
310 py::throw_error_already_set();
311 }
312 Configuration& self = py::extract<Configuration&>(args[0]);
313
314 py::dict result;
315 // We want to check for a list of names if they exist in the input keyword
316 // arguments. If so, set the new value. In any case, add to output
317 // dictionary. Simplest way: create a variadic lambda with references to the
318 // dictionary and arguments for name, getter and setter.
319 auto checkValue = [&kwargs, &result](const std::string & name, auto setter, auto getter) {
320 using value_type = decltype(getter());
321 if (kwargs.has_key(name)) {
322 value_type value{};
323 py::object object = kwargs[name];
324 try {
325 value = PyObjConvUtils::convertPythonObject(object, value);
326 } catch (std::runtime_error&) {
327 std::stringstream error;
328 error << "Cannot convert argument '" << name << "' to " << PyObjConvUtils::Type<value_type>::name();
329 PyErr_SetString(PyExc_TypeError, error.str().c_str());
330 py::throw_error_already_set();
331 }
332 setter(value);
333 // remove key from kwargs so we can easily check for ones we don't understand later
334 py::delitem(kwargs, py::object(name));
335 }
336 result[name] = PyObjConvUtils::convertToPythonObject(getter());
337 };
338 auto& downloader = Downloader::getDefaultInstance();
339 // That was all the heavy lifting, now just declare all known options :D
340 // I would love to indent this a bit better but astyle has different opinions
341 checkValue("save_payloads",
342 [&self](const std::string & path) { self.setNewPayloadLocation(path);},
343 [&self]() {return self.getNewPayloadLocation();});
344 checkValue("download_cache_location",
345 [&self](const std::string & path) { self.setDownloadCacheDirectory(path);},
346 [&self]() {return self.getDownloadCacheDirectory();});
347 checkValue("download_lock_timeout",
348 [&self](size_t timeout) { self.setDownloadLockTimeout(timeout);},
349 [&self]() { return self.getDownloadLockTimeout();});
350 checkValue("usable_globaltag_states",
351 [&self](const auto & states) { self.setUsableTagStates(states); },
352 [&self]() { return self.getUsableTagStates(); });
353 checkValue("connection_timeout",
354 [&downloader](unsigned int timeout) {downloader.setConnectionTimeout(timeout);},
355 [&downloader]() { return downloader.getConnectionTimeout();});
356 checkValue("stalled_timeout",
357 [&downloader](unsigned int timeout) {downloader.setStalledTimeout(timeout);},
358 [&downloader]() { return downloader.getStalledTimeout();});
359 checkValue("max_retries",
360 [&downloader](unsigned int retries) {downloader.setMaxRetries(retries);},
361 [&downloader]() { return downloader.getMaxRetries();});
362 checkValue("backoff_factor",
363 [&downloader](unsigned int factor) { downloader.setBackoffFactor(factor);},
364 [&downloader]() { return downloader.getBackoffFactor();});
365 // And lastly check if there is something in the kwargs we don't understand ...
366 if (py::len(kwargs) > 0) {
367 std::string message = "Unrecognized keyword arguments: ";
368 auto keys = kwargs.keys();
369 // boost::python::extract<std::string> triggers a false-positive
370 // -Wmaybe-uninitialized in GCC; silence it around the extraction.
371#if defined(__GNUC__) && !defined(__clang__)
372#pragma GCC diagnostic push
373#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
374#endif
375 for (int i = 0; i < len(keys); ++i) {
376 if (i > 0) message += ", ";
377 message += py::extract<std::string>(keys[i]);
378 }
379#if defined(__GNUC__) && !defined(__clang__)
380#pragma GCC diagnostic pop
381#endif
382 PyErr_SetString(PyExc_TypeError, message.c_str());
383 py::throw_error_already_set();
384 }
385 return result;
386 }
387 }
388
389 void Configuration::overrideGlobalTagsPy(const boost::python::list& globalTags)
390 {
391 setGlobalTagsPy(globalTags);
392 m_overrideEnabled = true;
393 }
394
396 {
397 //don't show c++ signature in python doc to keep it simple
398 py::docstring_options options(true, false, false);
399
400 void (Configuration::*overrideGTFlag)() = &Configuration::overrideGlobalTags;
401 void (Configuration::*overrideGTList)(const py::list&) = &Configuration::overrideGlobalTagsPy;
402 py::object expert = raw_function(expertSettings);
403 py::class_<Configuration>("ConditionsConfiguration", R"DOC(
404This class contains all configurations for the conditions database service
405
406* which globaltags to use
407* where to look for payload information
408* where to find the actual payload files
409* which temporary testing payloads to use
410
411But for most users the only thing they should need to care about is to set the
412list of additional `globaltags` to use.
413)DOC")
414 .add_property("override_enabled", &Configuration::overrideEnabled, R"DOC(
415Indicator whether or not the override of globaltags is enabled. If true then
416globaltags present in input files will be ignored and only the ones given in
417`globaltags` will be considered.
418)DOC")
419 .def("reset", &Configuration::reset, R"DOC(reset()
420
421Reset the conditions database configuration to its original state.
422)DOC")
423 .add_property("default_globaltags", &Configuration::getDefaultGlobalTagsPy, R"DOC(
424A tuple containing the default globaltags to be used if events are generated without an input file.
425)DOC")
426 .add_property("globaltags", &Configuration::getGlobalTagsPy, &Configuration::setGlobalTagsPy, R"DOC(
427List of globaltags to be used. These globaltags will be the ones with highest
428priority but by default the globaltags used to create the input files or the
429default globaltag will also be used.
430
431The priority of the globaltags in this list is highest first. So the first in
432the list will be checked first and all other globaltags will only be checked for
433payloads not found so far.
434
435Warning:
436 By default this list contains the globaltags to be used **in addition** to
437 the ones from the input file or the default one if no input file is present.
438 If this is not desirable you need to call `override_globaltags()` to disable
439 any addition or modification of this list.
440)DOC")
441 .def("append_globaltag", &Configuration::appendGlobalTag, py::args("name"), R"DOC(append_globaltag(name)
442
443Append a globaltag to the end of the `globaltags` list. That means it will be
444the lowest priority of all tags in the list.
445)DOC")
446 .def("prepend_globaltag", &Configuration::prependGlobalTag, py::args("name"), R"DOC(prepend_globaltag(name)
447
448Add a globaltag to the beginning of the `globaltags` list. That means it will be
449the highest priority of all tags in the list.
450)DOC")
451 .def("override_globaltags", overrideGTFlag)
452 .def("override_globaltags", overrideGTList, py::args("globaltags"), R"DOC(override_globaltags(list=None)
453
454Enable globaltag override. This disables all modification of the globaltag list at the beginning of processing:
455
456* the default globaltag or the input file globaltags will be ignored.
457* any callback set with `set_globaltag_callback` will be ignored.
458* the list of `globaltags` will be used exactly as it is.
459
460Parameters:
461 list (list(str) or None) if given this list will replace the current content of `globaltags`
462
463Warning:
464 it's still possible to modify `globaltags` after this call.
465)DOC")
466 .def("disable_globaltag_replay", &Configuration::disableGlobalTagReplay, R"DOC(disable_globaltag_replay()
467
468Disable global tag replay and revert to the old behavior that the default
469globaltag will be used if no other globaltags are specified.
470
471This is a shortcut to just calling
472
473 >>> conditions.override_globaltags()
474 >>> conditions.globaltags += list(conditions.default_globaltags)
475
476)DOC")
477 .def("append_testing_payloads", &Configuration::appendTestingPayloadLocation, py::args("filename"), R"DOC(append_testing_payloads(filename)
478
479Append a text file containing local test payloads to the end of the list of
480`testing_payloads`. This will mean they will have lower priority than payloads
481in previously defined text files but still higher priority than globaltags.
482
483Parameters:
484 filename (str): file containing a local definition of payloads and their
485 intervals of validity for testing
486
487Warning:
488 This functionality is strictly for testing purposes. Using local payloads
489 leads to results which cannot be reproduced by anyone else and thus cannot
490 be published.
491)DOC")
492 .def("prepend_testing_payloads", &Configuration::prependTestingPayloadLocation, py::args("filename"), R"DOC(prepend_testing_payloads(filename)
493
494Insert a text file containing local test payloads in the beginning of the list
495of `testing_payloads`. This will mean they will have higher priority than payloads in
496previously defined text files as well as higher priority than globaltags.
497
498Parameters:
499 filename (str): file containing a local definition of payloads and their
500 intervals of validity for testing
501
502Warning:
503 This functionality is strictly for testing purposes. Using local payloads
504 leads to results which cannot be reproduced by anyone else and thus cannot
505 be published.
506)DOC")
508List of text files to look for local testing payloads. Each entry should be a
509text file containing local payloads and their intervals of validity to be used
510for testing.
511
512Payloads found in these files and valid for the current run will have a higher
513priority than any of the `globaltags`. If a valid payload is present in multiple
514files the first one in the list will have higher priority.
515
516Warning:
517 This functionality is strictly for testing purposes. Using local payloads
518 leads to results which cannot be reproduced by anyone else and thus cannot
519 be published.
520)DOC")
521 .add_property("metadata_providers", &Configuration::getMetadataProvidersPy, &Configuration::setMetadataProvidersPy, R"DOC(
522List of metadata providers to use when looking for payload metadata. There are currently two supported providers:
523
5241. Central metadata provider to look for payloads in the central conditions database.
525 This provider is used for any entry in this list which starts with ``http(s)://``.
526 The URL should point to the top level of the REST api endpoints on the server
527
5282. Local metadata provider to look for payloads in a local SQLite snapshot taken
529 from the central server. This provider will be assumed for any entry in this
530 list not starting with a protocol specifier or if the protocol is given as ``file://``
531
532This list should rarely need to be changed. The only exception is for users who
533want to be able to use the software without internet connection after they
534downloaded a snapshot of the necessary globaltags with ``b2conditionsdb download``
535to point to this location.
536)DOC")
537 .add_property("default_metadata_provider_server", &Configuration::getDefaultRemoteMetadataProviderServer, R"DOC(
538URL of the default central metadata provider to look for payloads in the
539conditions database.
540)DOC")
541 .add_property("default_hsf_metadata_provider_server", &Configuration::getDefaultHSFRemoteMetadataProviderServer, R"DOC(
542URL of the default HSF central metadata provider to look for payloads in the
543conditions database.
544)DOC")
545 .add_property("payload_locations", &Configuration::getPayloadLocationsPy, &Configuration::setPayloadLocationsPy, R"DOC(
546List of payload locations to search for payloads which have been found by any of
547the configured `metadata_providers`. This can be a local directory or a
548``http(s)://`` url pointing to the payload directory on a server.
549
550For remote locations starting with ``http(s)://`` we assume that the layout of
551the payloads on the server is the same as on the main payload server:
552The combination of given location and the relative url in the payload metadata
553field ``payloadUrl`` should point to the correct payload on the server.
554
555For local directories, two layouts are supported and will be auto detected:
556
557flat
558 All payloads are in the same directory without any substructure with the name
559 ``dbstore_{name}_rev_{revision}.root``
560hashed
561 All payloads are stored in subdirectories in the form ``AB/{name}_r{revision}.root``
562 where ``A`` and ``B`` are the first two characters of the md5 checksum of the
563 payload file.
564
565Example:
566 Given ``payload_locations = ["payload_dir/", "http://server.com/payloads"]``
567 the framework would look for a payload with name ``BeamParameters`` in revision
568 ``45`` (and checksum ``a34ce5...``) in the following places
569
570
571 1. ``payload_dir/a3/BeamParameters_r45.root``
572 2. ``payload_dir/dbstore_BeamParameters_rev_45.root``
573 3. ``http://server.com/payloads/dbstore/BeamParameters/dbstore_BeamParameters_rev_45.root``
574 given the usual pattern of the ``payloadUrl`` metadata. But this could be
575 changed on the central servers so mirrors should not depend on this convention
576 but copy the actual structure of the central server.
577
578If the payload cannot be found in any of the given locations the framework will
579always attempt to download it directly from the central server and put it in a
580local cache directory.
581)DOC")
582 .def("expert_settings", expert, R"DOC(expert_settings(**kwargs)
583
584Set some additional settings for the conditions database.
585
586You can supply any combination of keyword-only arguments defined below. The
587function will return a dictionary containing all current settings.
588
589 >>> conditions.expert_settings(connection_timeout=5, max_retries=1)
590 {'save_payloads': 'localdb/database.txt',
591 'download_cache_location': '',
592 'download_lock_timeout': 120,
593 'usable_globaltag_states': {'PUBLISHED', 'RUNNING', 'TESTING', 'VALIDATED'},
594 'connection_timeout': 5,
595 'stalled_timeout': 60,
596 'max_retries': 1,
597 'backoff_factor': 5}
598
599Warning:
600 Modification of these parameters should not be needed, in rare
601 circumstances this could be used to optimize access for many jobs at once
602 but should only be set by experts.
603
604Parameters:
605 save_payloads (str): Where to store new payloads created during processing.
606 This should be a filename to contain the payload information and the payload
607 files will be placed in the same directory as the file.
608 download_cache_location (str): Where to store payloads which have been downloaded
609 from the central server. This could be a user defined directory, otherwise
610 empty string defaults to ``$TMPDIR/basf2-conditions`` where ``$TMPDIR`` is the
611 temporary directories defined in the system. Newly downloaded payloads will
612 be stored in this directory in a hashed structure, see `payload_locations`
613 download_lock_timeout (int): How many seconds to wait for a write lock when
614 concurrently downloading the same payload between different processes.
615 If locking fails the payload will be downloaded to a temporary file
616 separately for each process.
617 usable_globaltag_states (set(str)): Names of globaltag states accepted for
618 processing. This can be changed to make sure that only fully published
619 globaltags are used or to enable running on an open tag. It is not possible
620 to allow usage of 'INVALID' tags, those will always be rejected.
621 connection_timeout (int): timeout in seconds before connection should be
622 aborted. 0 sets the timeout to the default (300s)
623 stalled_timeout (int): timeout in seconds before a download should be
624 aborted if the speed stays below 10 KB/s, 0 disables this timeout
625 max_retries (int): maximum amount of retries if the server responded with
626 an HTTP response of 500 or more. 0 disables retrying
627 backoff_factor (int): backoff factor for retries in seconds. Retries are
628 performed using something similar to binary backoff: For retry :math:`n`
629 and a ``backoff_factor`` :math:`f` we wait for a random time chosen
630 uniformly from the interval :math:`[1, (2^{n} - 1) \times f]` in
631 seconds.
632)DOC")
633 .def("set_globaltag_callback", &Configuration::setGlobaltagCallbackPy, R"DOC(set_globaltag_callback(function)
634
635Set a callback function to be called just before processing.
636
637This callback can be used to further customize the globaltags to be used during
638processing. It will be called after the input files have been opened and checked
639with three keyword arguments:
640
641base_tags
642 The globaltags determined from either the input files or, if no input files
643 are present, the default globaltags
644
645user_tags
646 The globaltags provided by the user
647
648metadata
649 If there are not input files (e.g. generating events) this argument is None.
650 Otherwise it is a list of all the ``FileMetaData`` instances from all input files.
651 This list can be empty if there is no metadata associated with the input files.
652
653From this information the callback function should then compose the final list
654of globaltags to be used for processing and return this list. If ``None`` is
655returned the default behavior is applied as if there were no callback function.
656If anything else is returned the processing is aborted.
657
658If no callback function is specified the default behavior is equivalent to ::
659
660 def callback(base_tags, user_tags, metadata):
661 if not base_tags:
662 basf2.B2FATAL("No baseline globaltags available. Please use override")
663
664 return user_tags + base_tags
665
666If `override_enabled` is ``True`` then the callback function will not be called.
667
668Warning:
669 If a callback is set it is responsible to select the correct list of globaltags
670 and also make sure that all files are compatible. No further checks will be
671 done by the framework but any list of globaltags which is returned will be used
672 exactly as it is.
673
674 If the list of ``base_tags`` is empty that usually means that the input files
675 had different globaltag settings but it is the responsibility of the callback
676 to then verify if the list of globaltags is usable or not.
677
678 If the callback function determines that no working set of globaltags can be
679 determined then it should abort processing using a FATAL error or an exception
680)DOC")
681 ;
682
683 py::scope().attr("conditions") = py::ptr(&Configuration::getInstance());
684 }
685} // Belle2::Conditions namespace
std::string getDefaultHSFRemoteMetadataProviderServer()
Get the default server URL for the HSF central metadata provider.
static std::vector< std::string > getDefaultGlobalTags()
Get the std::vector of default globaltags.
bool m_overrideEnabled
is the globaltag override enabled?
CppOrPyList m_globalTags
the list with all user globaltags
void prependGlobalTag(const std::string &globalTag)
prepend a globaltag
std::string m_defaultHSFRemoteMetadataProviderServer
default server URL for the HSF remote metadata provider
void appendGlobalTag(const std::string &globalTag)
Append a globaltag.
Configuration()
Initialize default values.
void ensureEditable() const
Check whether the configuration object can be edited or if the database has been initialized already.
void setGlobaltagCallbackPy(const boost::python::object &obj)
Set a callback function from python which will be called when processing starts and should return the...
void disableGlobalTagReplay()
Disable global tag replay.
boost::python::list getGlobalTagsPy()
Get the list of user globaltags as python version.
void setMetadataProvidersPy(const boost::python::list &list)
Set the list of metadata providers in python.
boost::python::list getTestingPayloadLocationsPy()
Get the list of text files containing test payloads in python.
std::string m_defaultLocalMetadataProviderPath
default local path for the local metadata provider
std::vector< std::string > getFinalListOfTags()
Get the final list of globaltags to be used for processing.
boost::python::tuple getDefaultGlobalTagsPy() const
Get the tuple of default globaltags as python version.
static void fillFromEnv(T &target, const std::string &envName, const std::string &defaultValue)
Fill a target object from a list of environment variables.
std::vector< FileMetaData > m_inputMetadata
the file metadata of all input files if globaltag replay is requested by input module
static Configuration & getInstance()
Get a reference to the instance which will be used when the Database is initialized.
void setPayloadLocationsPy(const boost::python::list &list)
Set the list of payload locations in python.
CppOrPyList m_metadataProviders
the list with all the metadata providers
void setInputMetadata(const std::vector< FileMetaData > &inputMetadata)
To be called by input modules with the list of all input FileMetaData.
boost::python::list getMetadataProvidersPy()
Get the list of metadata providers in python.
void overrideGlobalTags()
Enable globaltag override: If this is called once than overrideEnabled() will return true and getFina...
std::vector< std::string > getBaseTags() const
Get the base globaltags to be used in addition to user globaltags.
std::string m_defaultLegacyRemoteMetadataProviderServer
default server URL for the (legacy) remote metadata provider
void setTestingPayloadLocationsPy(const boost::python::list &list)
Set the list of text files containing test payloads in python.
static void exposePythonAPI()
expose this class to python
std::optional< std::vector< std::string > > m_inputGlobaltags
the list of globaltags from all the input files to be used in addition to the user globaltags
void prependTestingPayloadLocation(const std::string &filename)
Prepend a local text file with testing payloads to the list.
boost::python::list getPayloadLocationsPy()
Get the list og payload locations in python.
CppOrPyList m_payloadLocations
the list with all the payload locations
void overrideGlobalTagsPy(const boost::python::list &globalTags)
Enable globaltag override and set the list of user globaltags in one go.
void reset()
Reset to default values.
std::string getDefaultRemoteMetadataProviderServer()
Get the default server URL for the remote metadata provider.
void setGlobalTagsPy(const boost::python::list &globalTags)
Set the list of globaltags from python.
bool overrideEnabled() const
Check if override is enabled by previous calls to overrideGlobalTags()
std::optional< boost::python::object > m_callback
the callback function to determine the final final list of globaltags
void appendTestingPayloadLocation(const std::string &filename)
Add a local text file with testing payloads.
bool m_databaseInitialized
bool indicating whether the database has been initialized, in which case any changes to the configura...
void prepend(const std::string &element)
Prepend an element to whatever representation we currently have.
void shallowCopy(const boost::python::object &source)
shallow copy all elements of the source object into the python representation.
void append(const std::string &element)
Append an element to whatever representation we currently have.
boost::python::list & ensurePy()
Return the python list version.
std::vector< std::string > & ensureCpp()
Return the C++ vector version.
std::variant< std::vector< std::string >, boost::python::list > m_value
Store either a std::vector or a python list of strings.
static Downloader & getDefaultInstance()
Return the default instance.
static std::string get(const std::string &name, const std::string &fallback="")
Get the value of an environment variable or the given fallback value if the variable is not set.
static bool isSet(const std::string &name)
Check if a value is set in the database.
boost::python::object createROOTObjectPyCopy(const T &instance)
Create a python wrapped copy from a class instance which has a ROOT dictionary.
static Database & Instance()
Instance of a singleton Database.
Definition Database.cc:42
static std::vector< std::string > getOrCreateList(const std::string &name, const std::string &fallback, const std::string &separators=" \t\n\r")
Get a list of values from an environment variable or the given fallback string if the variable is not...
static void reset(bool keepConfig=false)
Reset the database instance.
Definition Database.cc:50
boost::python::object convertToPythonObject(const Scalar &value)
------------— From C++ TO Python Converter ---------------------—
bool iteratePythonObject(const boost::python::object &pyObject, Functor function)
Helper function to loop over a python object that implements the iterator concept and call a functor ...
Scalar convertPythonObject(const boost::python::object &pyObject, Scalar)
Convert from Python to given type.
static std::string name()
type name.
Helper struct for the C++17 std::visit overload pattern to allow simple use of variants.
Definition Utils.h:25