makeConfigClass

lsst.pex.config.makeConfigClass(ctrl, name=None, base=<class 'lsst.pex.config.config.Config'>, doc=None, module=None, cls=None)

Create a Config class that matches a C++ control object class.

See the wrap decorator as a convenient interface to makeConfigClass.

Parameters:
ctrl : class

C++ control class to wrap.

name : str, optional

Name of the new config class; defaults to the __name__ of the control class with 'Control' replaced with 'Config'.

base : lsst.pex.config.Config-type, optional

Base class for the config class.

doc : str, optional

Docstring for the config class.

module : object, str, int, or None optional

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 the immediate caller of wrap. 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. Defaults to None in which case module is looked up from the module of ctrl.

cls : class

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 also

wrap

Notes

To use makeConfigClass, write a control object in C++ using the LSST_CONTROL_FIELD macro in lsst/pex/config.h (note that it must have sensible default constructor):

// 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) {}
};

You can use LSST_NESTED_CONTROL_FIELD to nest control objects. 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.

Next, in Python:

import lsst.pex.config
import myWrappedLib

InnerConfig = lsst.pex.config.makeConfigClass(myWrappedLib.InnerControl)
FooConfig = lsst.pex.config.makeConfigClass(myWrappedLib.FooControl)

This does the following things:

  • Adds bar, baz, and zot fields to FooConfig.
  • Set FooConfig.Control to FooControl.
  • Adds makeControl and readControl methods to create a FooControl and set the FooConfig from the FooControl, respectively.
  • If FooControl has a validate() member function, a custom validate() method will be added to FooConfig that uses it.

All of the above are done for InnerConfig as well.

Any field that would be injected that would clash with an existing attribute of the class is be silently ignored. This allows you to customize fields and inherit them from wrapped control classes. However, these names are 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.