LSSTApplications
18.1.0
LSSTDataManagementBasePackage
|
The lsst::pex::config package provides for configurations for the LSST Data Management System.
Configurations are hierarchical trees of parameters used to control the execution of code. They should not be confused with input data. lsst::pex::config configurations ( Config objects) are validatable, documentable, and recordable. The configuration parameters are stored in attributes (member variables) of type Field in the Config object. Their values can be recorded for provenance purposes. The history of their changes during program execution is also tracked, and can be recorded and examined for provenance and debugging purposes.
The package is implemented in Python. Python code is used both in defining the available Fields and in setting or modifying their values. This provides great flexibility and introspection while still being approachable to non-programmers who need to modify configuration settings.
Defining a configuration subclass::
Here is a sample configuration override file to be used with the partial IsrTaskConfig
above. Note that all field names are prefixed with "config" and that overrides should never be used to set already-existing default values::
Typical usage::
lsst::pex::config arose from a desire to have a configuration object holding key-value pairs that also allows for (arbitrarily simple or complex) validation of configuration values.
To configure code using lsst::pex::config, a developer subclasses the Config class. The subclass definition specifies the available Fields, their default values (if any), and their validation, if necessary.
Configs are hierarchical (see ConfigField), so calling code can embed the configuration definitions of called code.
Configurations are not input data. They should not be used in place of function or method arguments, nor are they intended to replace ordinary dictionary data structures. A good rule of thumb is that if a particular parameter does not have a useful default, it is probably an input rather than a configuration parameter. Another rule of thumb is that configuration parameters should generally not be set in algorithmic code, only in initialization or user interface code.
A Config subclass is instantiated to create a configuration object. If any default Field values need to be overridden, they can be set by assignment to the object's Field attributes (e.g. config.param1 = 3.14
), often in a parent Config.setDefaults() method, or by loading from an external file. The code then uses the configuration values by accessing the object's Field attributes (e.g., x = config.param1
).
The Config object can also be frozen; attempting to change the field values of a frozen object will raise an exception. This is useful to expose bugs that change configuration values after none should happen.
Finally, the contents of Config objects may easily be dumped, for provenance or debugging purposes.
See wiki:PolicyEnhancement and wiki:Winter2012/PolicyRedesign.
All Configs are (direct or indirect) subclasses of the Python class lsst.pex.config.Config. Configs may inherit from other Configs, in which case all of the Fields of the parent class are present in the subclass.
Each Field is required to have a doc string that describes the contents of the field. Doc strings can be verbose and should give users of the Config a good understanding of what the Field
is and how it will be interpreted and used. A doc string should also be provided for the class as a whole. The doc strings for the class and its Fields may be inspected using "help(MyConfig)" or with the pydoc command.
Attributes of the configuration object must be subclasses of Field. A number of these are predefined: Field, RangeField, ChoiceField, ListField, ConfigField, ConfigChoiceField, RegistryField and ConfigurableField.
Example of RangeField::
Example of ListField and Config inheritance::
Examples of ChoiceField and ConfigField and the use of Config.setDefaults() and Config.validate() methods::
Example of a RegistryField created from a Registry object and use of both the Registry.register()
method and the registerConfigurable
decorator::
Iterating through a Config yields the names of the Fields it contains. The standard dictionary-like keys(), items(), iterkeys(), iteritems(), and itervalues() methods are also supported.
Config.history contains the history of all changes to the Config's fields. Each Field also has a history. The formatHistory(fieldName) method displays the history of a given Field in a more human-readable format.
help(configObject) can be used to inspect the Config's doc strings as well as those of its Fields.
C++ control objects defined using the LSST_CONTROL_FIELD macro in lsst/pex/config.h can be wrapped using SWIG and the functions in lsst.pex.config.wrap, creating an equivalent Python Config. The Config will automatically create and set values in the C++ object, will provide access to the doc strings from C++, and will even call the C++ class's validate()
method, if one exists. This helps to minimize duplication of code. In C++:
Note that only bool, int, double, and std::string fields, along with std::list and std::vector containers of those types, are fully supported.
Nested control objects are not supported.
After using SWIG, the preferred way to create the Config is via the wrap decorator::
The Policy and PolicyDictionary classes in the lsst::pex::policy package provided many of the features of lsst::pex::config in C++ and, via SWIG wrapping, Python. lsst::pex::config was developed to provide additional features and remove some shortcomings. lsst::pex::policy is being replaced with lsst::pex::config in the LSST DMS codebase; to aid the transition a utility function is provided to convert a Config to a Policy.
Config uses a metaclass to record the Field attributes within each Config object in an internal dictionary. The storage and history for the fields is also maintained in the Config, not the Field itself. This allows Fields to be inherited without difficulty.