9#include <boost/python/register_ptr_to_python.hpp>
10#include <boost/python/class.hpp>
11#include <boost/python/list.hpp>
12#include <boost/python/dict.hpp>
13#include <boost/python/copy_const_reference.hpp>
14#include <boost/python/overloads.hpp>
15#include <boost/python/enum.hpp>
16#include <boost/python/docstring_options.hpp>
19#include <framework/core/Module.h>
20#include <framework/core/ModuleCondition.h>
21#include <framework/core/PyModule.h>
22#include <framework/core/ModuleManager.h>
23#include <framework/core/Path.h>
25#include <framework/logging/Logger.h>
28using namespace boost::python;
33 m_description(
"Not set by the author"),
36 m_hasReturnValue(false),
44 B2FATAL(
"Module type not set for " <<
getName());
51 B2FATAL(
"Trying to change module type from " <<
m_type <<
" is not allowed, the value is assumed to be fixed.");
81 m_conditions.emplace_back(expression, path, afterConditionPath);
87 if_value(
"<1", path, afterConditionPath);
92 if_value(
">=1", path, afterConditionPath);
102 B2FATAL(
"A condition was set for '" <<
getName() <<
"', but the module did not set a return value!");
120 B2FATAL(
"A condition was set for '" <<
getName() <<
"', but the module did not set a return value!");
125 return condition.getPath();
135 if (
m_conditions.empty())
return EAfterConditionPath::c_End;
139 B2FATAL(
"A condition was set for '" <<
getName() <<
"', but the module did not set a return value!");
144 return condition.getAfterConditionPath();
148 return EAfterConditionPath::c_End;
152 std::vector<std::shared_ptr<Path>> allConditionPaths;
154 allConditionPaths.push_back(condition.getPath());
157 return allConditionPaths;
169 std::string allMissing =
"";
170 for (
const auto& s : missing)
171 allMissing += s +
" ";
172 if (!missing.empty())
173 B2ERROR(
"The following required parameters of Module '" <<
getName() <<
"' were not specified: " << allMissing <<
174 "\nPlease add them to your steering file.");
175 return !missing.empty();
182 newModule->m_moduleParamList.setParameters(
getParamList());
195 std::string output =
getName();
198 output += condition.getString();
240 }
catch (std::runtime_error& e) {
241 throw std::runtime_error(
"Cannot set parameter '" + name +
"' for module '"
242 +
m_name +
"': " + e.what());
255 boost::python::list dictKeys = dictionary.keys();
256 int nKey = boost::python::len(dictKeys);
259 for (
int iKey = 0; iKey < nKey; ++iKey) {
260 boost::python::object currKey = dictKeys[iKey];
261 boost::python::extract<std::string> keyProxy(currKey);
263 if (keyProxy.check()) {
264 const boost::python::object& currValue = dictionary[currKey];
267 B2ERROR(
"Setting the module parameters from a python dictionary: invalid key in dictionary!");
286 boost::python::list _getParamInfoListPython(
const Module* m)
288 return *(m->getParamInfoListPython().get());
290 boost::python::list _getAllConditionPathsPython(
const Module* m)
292 boost::python::list allConditionPaths;
293 for (
const auto& conditionPath : m->getAllConditionPaths()) {
294 allConditionPaths.append(boost::python::object(conditionPath));
297 return allConditionPaths;
299 boost::python::list _getAllConditionsPython(
const Module* m)
301 boost::python::list allConditions;
302 for (
const auto& condition : m->getAllConditions()) {
303 allConditions.append(boost::python::object(boost::ref(condition)));
306 return allConditions;
310#if !defined(__GNUG__) || defined(__ICC)
312#pragma GCC diagnostic push
313#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
316BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(if_value_overloads, if_value, 2, 3)
317BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(if_false_overloads, if_false, 1, 2)
318BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(if_true_overloads, if_true, 1, 2)
319#if !defined(__GNUG__) || defined(__ICC)
321#pragma GCC diagnostic pop
328 namespace bp = boost::python;
330 docstring_options options(
true,
true,
false);
334 enum_<Module::EAfterConditionPath>(
"AfterConditionPath",
335 R
"(Determines execution behaviour after a conditional path has been executed:
339 End processing of this path after the conditional path. (this is the default for if_value() etc.)
341.. attribute:: CONTINUE
343 After the conditional path, resume execution after this module.)")
344 .value("END", Module::EAfterConditionPath::c_End)
345 .value(
"CONTINUE", Module::EAfterConditionPath::c_Continue)
349 enum_<Belle2::ModuleCondition::EConditionOperators>(
"ConditionOperator")
358 enum_<Module::EModulePropFlags>(
"ModulePropFlags",
359 R
"(Flags to indicate certain low-level features of modules, see :func:`Module.set_property_flags()`, :func:`Module.has_properties()`. Most useful flags are:
361.. attribute:: PARALLELPROCESSINGCERTIFIED
363 This module can be run in parallel processing mode safely (All I/O must be done through the data store, in particular, the module must not write any files.)
365.. attribute:: HISTOGRAMMANAGER
367 This module is used to manage histograms accumulated by other modules
369.. attribute:: TERMINATEINALLPROCESSES
371 When using parallel processing, call this module's terminate() function in all processes. This will also ensure that there is exactly one process (single-core if no parallel modules found) or at least one input, one main and one output process.
382 class_<Module, PyModule> module(
"Module", R
"(
383Base class for Modules.
385A module is the smallest building block of the framework.
386A typical event processing chain consists of a Path containing
387modules. By inheriting from this base class, various types of
388modules can be created. To use a module, please refer to
389:func:`Path.add_module()`. A list of modules is available by running
390``basf2 -m`` or ``basf2 -m package``, detailed information on parameters is
391given by e.g. ``basf2 -m RootInput``.
393The 'Module Development' section in the manual provides detailed information
394on how to create modules, setting parameters, or using return values/conditions:
395https://confluence.desy.de/display/BI/Software+Basf2manual#Module_Development
400 .def(
"name", &
Module::getName, return_value_policy<copy_const_reference>(),
401 "Returns the name of the module. Can be changed via :func:`set_name() <Module.set_name()>`, use :func:`type() <Module.type()>` for identifying a particular module class.")
402 .def(
"type", &
Module::getType, return_value_policy<copy_const_reference>(),
403 "Returns the type of the module (i.e. class name minus 'Module')")
405Set custom name, e.g. to distinguish multiple modules of the same type.
407>>> path.add_module('EventInfoSetter')
408>>> ro = path.add_module('RootOutput', branchNames=['EventMetaData'])
409>>> ro.set_name('RootOutput_metadata_only')
411[EventInfoSetter -> RootOutput_metadata_only]
415 "Returns the description of this module.")
417 "Returns the package this module belongs to.")
418 .def(
"available_params", &_getParamInfoListPython,
419 "Return list of all module parameters as `ModuleParamInfo` instances")
421 R
"DOCSTRING(Allows to check if the module has the given properties out of `ModulePropFlags` set.
423>>> if module.has_properties(ModulePropFlags.PARALLELPROCESSINGCERTIFIED):
427 properties (int): bitmask of `ModulePropFlags` to check for.
430 "Set module properties in the form of an OR combination of `ModulePropFlags`.");
433 docstring_options subOptions(
true,
false,
false);
436 (bp::arg(
"expression"), bp::arg(
"condition_path"), bp::arg(
"after_condition_path")= Module::EAfterConditionPath::c_End),
437 R
"DOCSTRING(if_value(expression, condition_path, after_condition_path=AfterConditionPath.END)
439Sets a conditional sub path which will be executed after this
440module if the return value set in the module passes the given ``expression``.
442Modules can define a return value (int or bool) using ``setReturnValue()``,
443which can be used in the steering file to split the Path based on this value, for example
445>>> module_with_condition.if_value("<1", another_path)
447In case the return value of the ``module_with_condition`` for a given event is
448less than 1, the execution will be diverted into ``another_path`` for this event.
450You could for example set a special return value if an error occurs, and divert
451the execution into a path containing :b2:mod:`RootOutput` if it is found;
452saving only the data producing/produced by the error.
454After a conditional path has executed, basf2 will by default stop processing
455the path for this event. This behaviour can be changed by setting the
456``after_condition_path`` argument.
459 expression (str): Expression to determine if the conditional path should be executed.
460 This should be one of the comparison operators ``<``, ``>``, ``<=``,
461 ``>=``, ``==``, or ``!=`` followed by a numerical value for the return value
462 condition_path (Path): path to execute in case the expression is fulfilled
463 after_condition_path (AfterConditionPath): What to do once the ``condition_path`` has been executed.
466 (bp::arg(
"condition_path"), bp::arg(
"after_condition_path")= Module::EAfterConditionPath::c_End),
467 R
"DOC(if_false(condition_path, after_condition_path=AfterConditionPath.END)
469Sets a conditional sub path which will be executed after this module if
470the return value of the module evaluates to False. This is equivalent to
471calling `if_value` with ``expression=\"<1\"``)DOC")
473 (bp::arg(
"condition_path"), bp::arg(
"after_condition_path")= Module::EAfterConditionPath::c_End),
474 R
"DOC(if_true(condition_path, after_condition_path=AfterConditionPath.END)
476Sets a conditional sub path which will be executed after this module if
477the return value of the module evaluates to True. It is equivalent to
478calling `if_value` with ``expression=\">=1\"``)DOC");
482 "Return true if a conditional path has been set for this module "
483 "using `if_value`, `if_true` or `if_false`")
484 .def(
"get_all_condition_paths", &_getAllConditionPathsPython,
485 "Return a list of all conditional paths set for this module using "
486 "`if_value`, `if_true` or `if_false`")
487 .def(
"get_all_conditions", &_getAllConditionsPython,
488 "Return a list of all conditional path expressions set for this module using "
489 "`if_value`, `if_true` or `if_false`")
490 .add_property(
"logging", make_function(&
Module::getLogConfig, return_value_policy<reference_existing_object>()),
492 .def(
"return_value", setReturnValueInt, bp::arg(
"value"), \
493 "Set a return value. Can be used by custom modules to set the return value "
494 "used to determine if conditional paths are executed")
496 "Set the log level for this module. Messages below that level will be suppressed\n\n"
497 "Parameters:\n log_level (LogLevel): Minimum level for messages to be displayed")
499 "Set the debug level for this module. Debug messages with a higher level will "
500 "be suppressed. This function has no visible effect if the log level is "
501 "not set to `DEBUG <LogLevel.DEBUG>`\n\n"
502 "Parameters:\n debug_level (int): Maximum debug level for messages to be displayed.")
504 "Set the log level which will cause processing to be aborted. Usually "
505 "processing is only aborted for `FATAL <LogLevel.FATAL>` messages "
506 "but with this function it's possible to set this to a lower value\n\n"
507 "Parameters:\n abort_level (LogLevel): log level which will cause processing to be aborted.")
509 "Set a `LogInfo` configuration object for this module to determine how log messages should be formatted")
512 "This function is called by the processing just once before processing any data "
513 "is processed. Modules can override this method to perform some actions at "
514 "startup once all parameters are set")
516 "This function is called by the processing just before a new run of data "
517 "is processed. Modules can override this method to perform actions which "
520 "This function is called by the processing once for each event."
521 "Modules should override this method to perform actions during event processing")
523 "This function is called by the processing just after a new run of data "
524 "is processed. Modules can override this method to perform actions which "
527 "This function is called by the processing once after all data "
528 "is processed. Modules can override this method to perform some cleanup at "
529 "shutdown. The terminate functions of all modules are called in reverse "
530 "order of the `initialize` calls.")
535 docstring_options param_options(
true,
false,
false);
539This method can be used to set module parameters. There are two ways of
540calling this function:
5421. With two arguments where the first is the name of the parameter and the second is the value.
544 >>> module.param("parameterName", "parameterValue")
5462. Or with just one parameter which is a dictionary mapping multiple parameter names to their values
548 >>> module.param({"parameter1": "value1", "parameter2": True})
553 register_ptr_to_python<ModulePtr>();
561 m_package(
std::move(package))
void setDebugLevel(int debugLevel)
Configure the debug messaging level.
ELogLevel
Definition of the supported log levels.
void setAbortLevel(ELogLevel abortLevel)
Configure the abort level.
void setLogLevel(ELogLevel logLevel)
Configure the log level.
void setLogInfo(ELogLevel logLevel, unsigned int logInfo)
Configure the printed log information for the given level.
Class for logging debug, info and error messages.
void updateModule(const LogConfig *moduleLogConfig=nullptr, const std::string &moduleName="")
Sets the log configuration to the given module log configuration and sets the module name This method...
static LogSystem & Instance()
Static method to get a reference to the LogSystem instance.
@ c_GE
Greater or equal than: ">=".
@ c_SE
Smaller or equal than: "<=".
EAfterConditionPath
Different options for behaviour after a conditional path was executed.
void registerModuleProxy(ModuleProxyBase *moduleProxy)
Registers a module proxy.
std::shared_ptr< Module > registerModule(const std::string &moduleName, std::string sharedLibPath="") noexcept(false)
Creates an instance of a module and registers it to the ModuleManager.
static ModuleManager & Instance()
Exception is thrown if the requested module could not be created by the ModuleManager.
std::shared_ptr< boost::python::list > getParamInfoListPython() const
Returns a python list of all parameters.
std::vector< std::string > getUnsetForcedParams() const
Returns list of unset parameters (if they are required to have a value.
ModuleProxyBase(std::string moduleType, std::string package)
The constructor of the ModuleProxyBase class.
void setLogLevel(int logLevel)
Configure the log level.
std::shared_ptr< boost::python::list > getParamInfoListPython() const
Returns a python list of all parameters.
LogConfig & getLogConfig()
Returns the log system configuration.
void if_value(const std::string &expression, const std::shared_ptr< Path > &path, EAfterConditionPath afterConditionPath=EAfterConditionPath::c_End)
Add a condition to the module.
void setDescription(const std::string &description)
Sets the description of the module.
const ModuleParamList & getParamList() const
Return module param list.
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
const std::string & getName() const
Returns the name of the module.
void if_true(const std::shared_ptr< Path > &path, EAfterConditionPath afterConditionPath=EAfterConditionPath::c_End)
A simplified version to set the condition of the module.
virtual void def_endRun()
This method can receive that the current run ends as a call from the Python side.
std::vector< std::shared_ptr< Path > > getAllConditionPaths() const
Return all condition paths currently set (no matter if the condition is true or not).
int m_returnValue
The return value.
const std::string & getType() const
Returns the type of the module (i.e.
void setReturnValue(int value)
Sets the return value for this module as integer.
@ c_HistogramManager
This module is used to manage histograms accumulated by other modules.
@ c_Input
This module is an input module (reads data).
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
@ c_InternalSerializer
This module is an internal serializer/deserializer for parallel processing.
@ c_Output
This module is an output module (writes data).
@ c_TerminateInAllProcesses
When using parallel processing, call this module's terminate() function in all processes().
void setLogConfig(const LogConfig &logConfig)
Set the log system configuration.
const std::string & getDescription() const
Returns the description of the module.
void setAbortLevel(int abortLevel)
Configure the abort log level.
virtual void def_terminate()
Wrapper method for the virtual function terminate() that has the implementation to be used in a call ...
void setDebugLevel(int debugLevel)
Configure the debug messaging level.
void setParamPython(const std::string &name, const boost::python::object &pyObj)
Implements a method for setting boost::python objects.
virtual void def_initialize()
Wrappers to make the methods without "def_" prefix callable from Python.
unsigned int m_propertyFlags
The properties of the module as bitwise or (with |) of EModulePropFlags.
void if_false(const std::shared_ptr< Path > &path, EAfterConditionPath afterConditionPath=EAfterConditionPath::c_End)
A simplified version to add a condition to the module.
ModuleParamList m_moduleParamList
List storing and managing all parameter of the module.
bool hasCondition() const
Returns true if at least one condition was set for the module.
std::shared_ptr< Path > getConditionPath() const
Returns the path of the last true condition (if there is at least one, else reaturn a null pointer).
std::string m_type
The type of the module, saved as a string.
bool m_hasReturnValue
True, if the return value is set.
virtual void def_beginRun()
Wrapper method for the virtual function beginRun() that has the implementation to be used in a call f...
const std::string & getPackage() const
Returns the package this module is in.
void setName(const std::string &name)
Set the name of the module.
void setType(const std::string &type)
Set the module type.
static void exposePythonAPI()
Exposes methods of the Module class to Python.
LogConfig m_logConfig
The log system configuration of the module.
Module::EAfterConditionPath getAfterConditionPath() const
What to do after the conditional path is finished.
std::vector< ModuleCondition > m_conditions
Module condition, only non-null if set.
std::shared_ptr< PathElement > clone() const override
Create an independent copy of this module.
bool hasProperties(unsigned int propertyFlags) const
Returns true if all specified property flags are available in this module.
std::string m_description
The description of the module.
virtual void def_event()
Wrapper method for the virtual function event() that has the implementation to be used in a call from...
std::string m_name
The name of the module, saved as a string (user-modifiable)
bool evalCondition() const
If at least one condition was set, it is evaluated and true returned if at least one condition return...
void setParamPythonDict(const boost::python::dict &dictionary)
Implements a method for reading the parameter values from a boost::python dictionary.
std::string m_package
Package this module is found in (may be empty).
void setLogInfo(int logLevel, unsigned int logInfo)
Configure the printed log information for the given level.
bool hasUnsetForcedParams() const
Returns true and prints error message if the module has unset parameters which the user has to set in...
std::string getPathString() const override
return the module name.
std::shared_ptr< Path > PathPtr
Defines a pointer to a path object as a boost shared pointer.
void setParamPython(const std::string &name, const PythonObject &pyObj)
Implements a method for setting boost::python objects.
std::shared_ptr< Module > ModulePtr
Defines a pointer to a module object as a boost shared pointer.
Abstract base class for different kinds of events.