Objects instantiation¶
The config.get(<object_name>)
method returns a live object from the configuration:
from bliss.config.static import get_config config = get_config() # my_object_name has to be one of config.names_list obj = config.get("my_object_name")
Configuration plugins¶
Every object in the configuration is associated with a configuration plugin. The role of the configuration plugin is to instantiate the object from the YAML mappings. It figures out:
- which class (or controller) needs to be instantiated
- which parameters have to be passed to the constructor
- which objects are finally exported
- one, in case of a single class,
- one or many for a controller
Beacon supports the following plugins:
default
: converts YAML data into a Python dictionary- if an object has no
plugin
information,default
will be used
- if an object has no
bliss
: general-purpose control objectsemotion
: axes, encoders, shutters and motor controllers configurationtemperature
: inputs, outputs, control loops for temperature controllerssession
: to configureSession
objects (sessions, measurement groups)diffractometer
: to configure diffractometers
Configuration plugins are Python files located in bliss.config.plugins
. The
name of the plugin Python module must correspond to the plugin name.
Using bliss
plugin to create an object¶
With this plugin, keywords are:
class
: basically the class of our object.-
package
(optional): what package should be load where the class will be found.- example:
id15.motors.aero
- example:
-
module
(optional): define the package name found under bliss.controllers ifpackage
keyword is not specified.- example:
temperature.oxford800
package loaded would bebliss.controllers.temperature.oxford800
- example:
Note
if package
and module
are not defined, the plugin will use the
class
field. It lowers the name given and loads the module under
bliss.controllers.
Signature of object constructor using this plugin is:
class MyObject: def __init__(self,name,configuration): pass
with:
name
: the given name in the configuration fileconfiguration
: a dictionary like
Simple example¶
name: simple_object class: SimpleObject package: example.simple_object needed_params: "Don't remove" other_params: 10
This file has to be located at example.simple_object
class SimpleObject: # class name specify in yaml def __init__(self,name,configuration): self.name = name assert configuration.get('needed_params') == "Don't remove" # other params is 5 if not specify in yaml file self.other_params = configuration.get('other_params',5)
In case of configuring several object of that kind, yaml may look like:
class: SimpleObject package: example.simple_object object_list: # could be any keyword - name: simple_object1 needed_params: "Don't remove" other_params: 10 - name: simple_object2 needed_params: "Don't remove" other_params: 23.2
Note
class
, package
and module
need to be at the same level in that case.
Writing a configuration plugin¶
Each plugin module has to define a create_objects_from_config_node
function,
that receives:
- the static configuration singleton
- the Node object that corresponds to the object configuration
bliss
plugin example¶
The bliss plugin creates an object from a YAML mapping.
- it relies on the
find_class
utility function, to determine which class needs to be instantiated- it looks for a
class
item in the object configuration, and tries to find the corresponding Python module inbliss.controllers
. The module filename is expected to be the lower-case version of the class name. In case this basic mechanism is not enough to find the class definition module, it is possible to specify it explicitly with themodule:
item. In case the module cannot be found underbliss.controllers
, it is also possible to specify thepackage:
item.
- it looks for a
- it uses the
replace_reference_by_object
helper to replace YAML items starting with the dollar sign ($
) with an instance of the corresponding object from the configuration- the referenced objects are set as attributes of the instance
- the name of the object and the configuration is passed to the class
constructor. Each class depending on the
bliss
plugin has its own rules to interpret the different YAML items: one has to refer to the documentation to know how to configure each object - finally, the created object is returned in a dictionary indexed by the object name
from bliss.config.plugins.utils import find_class, replace_reference_by_object def create_objects_from_config_node(config, cfg_node): item_cfg_node = cfg_node.deep_copy() klass = find_class(item_cfg_node) item_name = item_cfg_node["name"] referenced_objects = dict() replace_reference_by_object(config, item_cfg_node, referenced_objects) o = klass(item_name, item_cfg_node) for name, object in referenced_objects.items(): if hasattr(o, name): continue else: setattr(o, name, object) return {item_name: o}
Note
When grouping similar configuration information in a directory, it is
quite useful to specify the plugin in a __init__.yml
file:
plugin: <plugin_name>
Configuration tool UI panels¶
The other role of configuration plugins is to define a HTML render function for generating graphical configuration panels for the Beacon configuration web application, depending on the kind of object instantiated by the plugin.
Currently, the bliss plugin provides a special User Interface (UI) for P201/CT2 counting card configuration. Similarly the emotion plugin provides a special UI for IcePAP motor controller configuration.