A function that creates a Python config class that matches a C++ control object class.
@param ctrl C++ control class to wrap.
@param name Name of the new config class; defaults to the __name__ of the control
class with 'Control' replaced with 'Config'.
@param base Base class for the config class.
@param doc Docstring for the config class.
@param module Either a module object, a string specifying the name of the module, or an
integer specifying how far back in the stack to look for the module to use:
0 is pex.config.wrap, 1 is the immediate caller, etc. This will be used to
set __module__ for the new config class, and the class will also be added
to the module. Ignored if None or if cls is not None, but note that the default
is to use the callers' module.
@param cls An existing config class to use instead of creating a new one; name, base
doc, and module will be ignored if this is not None.
See the 'wrap' decorator as a way to use makeConfigClass that may be more convenient.
To use makeConfigClass, in C++, write a control object, using the LSST_CONTROL_FIELD macro in
lsst/pex/config.h (note that it must have sensible default constructor):
@code
// myHeader.h
struct InnerControl {
LSST_CONTROL_FIELD(wim, std::string, "documentation for field 'wim'");
};
struct FooControl {
LSST_CONTROL_FIELD(bar, int, "documentation for field 'bar'");
LSST_CONTROL_FIELD(baz, double, "documentation for field 'baz'");
LSST_NESTED_CONTROL_FIELD(zot, myWrappedLib, InnerControl, "documentation for field 'zot'");
FooControl() : bar(0), baz(0.0) {}
};
@endcode
You can use LSST_NESTED_CONTROL_FIELD to nest control objects. Now, wrap those control objects as
you would any other C++ class, but make sure you include lsst/pex/config.h before including the header
file where the control object class is defined:
Now, in Python, do this:
@code
import myWrappedLib
import lsst.pex.config
InnerConfig = lsst.pex.config.makeConfigClass(myWrappedLib.InnerControl)
FooConfig = lsst.pex.config.makeConfigClass(myWrappedLib.FooControl)
@endcode
This will add fully-fledged "bar", "baz", and "zot" fields to FooConfig, set
FooConfig.Control = FooControl, and inject makeControl and readControl
methods to create a FooControl and set the FooConfig from the FooControl,
respectively. In addition, if FooControl has a validate() member function,
a custom validate() method will be added to FooConfig that uses it. And,
of course, all of the above will be done for InnerControl/InnerConfig too.
Any field that would be injected that would clash with an existing attribute of the
class will be silently ignored; this allows the user to customize fields and
inherit them from wrapped control classes. However, these names will still be
processed when converting between config and control classes, so they should generally
be present as base class fields or other instance attributes or descriptors.
While LSST_CONTROL_FIELD will work for any C++ type, automatic Config generation
only supports bool, int, std::int64_t, double, and std::string fields, along
with std::list and std::vectors of those types.
Definition at line 50 of file wrap.py.