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> 
   28 using 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();
 
  139     B2FATAL(
"A condition was set for '" << 
getName() << 
"', but the module did not set a return value!");
 
  144       return condition.getAfterConditionPath();
 
  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" 
  316 BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(if_value_overloads, if_value, 2, 3)
 
  317 BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(if_false_overloads, if_false, 1, 2)
 
  318 BOOST_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.)") 
  349   enum_<Belle2::ModuleCondition::EConditionOperators>(
"ConditionOperator")
 
  350   .value(
">", Belle2::ModuleCondition::EConditionOperators::c_GT)
 
  351   .value(
"<", Belle2::ModuleCondition::EConditionOperators::c_ST)
 
  352   .value(
">=", Belle2::ModuleCondition::EConditionOperators::c_GE)
 
  353   .value(
"<=", Belle2::ModuleCondition::EConditionOperators::c_SE)
 
  354   .value(
"==", Belle2::ModuleCondition::EConditionOperators::c_EQ)
 
  355   .value(
"!=", Belle2::ModuleCondition::EConditionOperators::c_NE)
 
  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. 
  373   .value("INPUT", Module::EModulePropFlags::c_Input)
 
  374   .value(
"OUTPUT", Module::EModulePropFlags::c_Output)
 
  375   .value(
"PARALLELPROCESSINGCERTIFIED", Module::EModulePropFlags::c_ParallelProcessingCertified)
 
  376   .value(
"HISTOGRAMMANAGER", Module::EModulePropFlags::c_HistogramManager)
 
  377   .value(
"INTERNALSERIALIZER", Module::EModulePropFlags::c_InternalSerializer)
 
  378   .value(
"TERMINATEINALLPROCESSES", Module::EModulePropFlags::c_TerminateInAllProcesses)
 
  382   class_<Module, PyModule> module(
"Module", R
"( 
  383 Base class for Modules. 
  385 A module is the smallest building block of the framework. 
  386 A typical event processing chain consists of a Path containing 
  387 modules. By inheriting from this base class, various types of 
  388 modules 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 
  391 given by e.g. ``basf2 -m RootInput``. 
  393 The 'Module Development' section in the manual provides detailed information 
  394 on how to create modules, setting parameters, or using return values/conditions: 
  395 https://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')")
 
  405 Set 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); 
 
  437          R
"DOCSTRING(if_value(expression, condition_path, after_condition_path=AfterConditionPath.END) 
  439 Sets a conditional sub path which will be executed after this 
  440 module if the return value set in the module passes the given ``expression``. 
  442 Modules can define a return value (int or bool) using ``setReturnValue()``, 
  443 which 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) 
  447 In case the return value of the ``module_with_condition`` for a given event is 
  448 less than 1, the execution will be diverted into ``another_path`` for this event. 
  450 You could for example set a special return value if an error occurs, and divert 
  451 the execution into a path containing :b2:mod:`RootOutput` if it is found; 
  452 saving only the data producing/produced by the error. 
  454 After a conditional path has executed, basf2 will by default stop processing 
  455 the 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. 
  467          R
"DOC(if_false(condition_path, after_condition_path=AfterConditionPath.END) 
  469 Sets a conditional sub path which will be executed after this module if 
  470 the return value of the module evaluates to False. This is equivalent to 
  471 calling `if_value` with ``expression=\"<1\"``)DOC") 
  474          R
"DOC(if_true(condition_path, after_condition_path=AfterConditionPath.END) 
  476 Sets a conditional sub path which will be executed after this module if 
  477 the return value of the module evaluates to True. It is equivalent to 
  478 calling `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); 
 
  539 This method can be used to set module parameters. There are two ways of 
  540 calling this function: 
  542 1. With two arguments where the first is the name of the parameter and the second is the value. 
  544    >>> module.param("parameterName", "parameterValue") 
  546 2. 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.
EAfterConditionPath
Different options for behaviour after a conditional path was executed.
@ c_End
End current event after the conditional path.
@ c_Continue
After the conditional path, resume execution after this module.
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.
const std::string & getDescription() const
Returns the description of the module.
void if_value(const std::string &expression, const std::shared_ptr< Path > &path, EAfterConditionPath afterConditionPath=EAfterConditionPath::c_End)
Add a condition to the module.
const ModuleParamList & getParamList() const
Return module param list.
void setDescription(const std::string &description)
Sets the description of the module.
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
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.
void setLogConfig(const LogConfig &logConfig)
Set the log system configuration.
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.
const std::string & getName() const
Returns the name of the module.
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...
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)
const std::string & getPackage() const
Returns the package this module is in.
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.
LogConfig & getLogConfig()
Returns the log system configuration.
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.