The Plugin System¶
PyRolL is mainly built on the plugin system pluggy, which is also used in well known projects like pytest and pytask. Many core functionalities are also implemented as plugins. The PyRolL Core project only implements a minimal set of model approaches, look into the various official and unofficial plugins available for more.
Unlike the other mentioned projects, PyRolL has not only one plugin system, but several. Many main classes of PyRolL hold class attributes used to maintain plugins on that class, these are in detail:
Attribute |
Description |
---|---|
|
A |
|
A wrapper around a |
|
A wrapper around a |
This is implemented using the pyroll.plugin_host.PluginHost
class and the pyroll.plugin_host.PluginHostMeta
metaclass.
- class PluginHostMeta(name, bases, dct)¶
Metaclass that provides plugin functionality to a class.
Not for direct uses but through
PluginHost
base class.- hookimpl: HookimplMarker¶
A wrapper around a
pluggy.HookimplMarker
instance for defining new hook implementations.
- hookspec: HookspecMarker¶
A wrapper around a
pluggy.HookspecMarker
instance for defining new hook specifications. Supports only a subset of the original arguments.
- plugin_manager: PluginManager¶
A
pluggy.PluginManager
instance used to maintain the plugins on this class.
- root_hooks: Set[str]¶
Set of hooks to call in every solution iteration.
- class PluginHost(hook_args: Dict[str, Any])¶
A base class providing plugin functionality using the
PluginHostMeta
metaclass.The
get_from_hook()
method is also callable through the attribute syntax (.
notation), where the key equals the attributes name.- Parameters
hook_args – keyword arguments to pass to hook calls
- __getattr__(key: str)¶
Call a hook through attribute syntax if there is no explicit attribute with that name by use of
get_from_hook()
.
- delete_hook_result_attributes()¶
Deletes the attributes created by
get_from_hook()
calls, except those present inroot_hooks
.
- get_from_hook(key: str)¶
Explicitly tries to get a value from a hook specified on this class. Returns and caches the result of the hook call as attribute. Use clear_hook_results() to clear the cache. Hook calls done by this function are not cleared, only those by attribute syntax.
If the plugin manager does not know a hook of name key, the function dispatches to eventual base classes.
- Parameters
key (str) – the hook name to call
- Raises
AttributeError – if the hook call resulted in None
AttributeError – if the hook name is not known to this class, nor to base classes
ValueError – if the hook call resulted in an infinite value
- get_root_hook_results()¶
Call necessary root hooks of this instance and return an array of their results.
- hook_args¶
Keyword arguments to pass to hook calls.
- hook_result_attributes: Set[str]¶
Set remembering all hooks that were called on this class, used by
delete_hook_result_attributes()
.
The hookspec
markers of all classes derived from Unit
(RollPass
and Transport
) and Profile
are preconfigured
as firstresult
. That means, that the first hook
implementation, that returns not None
is used as only result of the hook call. This offers the possibility of
implementing many specialized versions of a hook and fall back to general ones if no special one applies.
Almost every attribute on the mentioned classes can be represented by a hook. This is achieved by
overriding __getattr__
, so that if no attribute with a desired name is present on an object, the framework searches
for a hook of equal name. If there is no such hook, or the hook call results in None
, an error is raised. Therefore,
it is easy to specify new hooks, just use the hookspec
marker on a dummy function and add it to the plugin_manager
by use of plugin_manager.add_hookspecs()
. It is common in writing plugins for PyRolL to specify hooks for all
intermediate and result values on profiles and units you want to calculate, and then to provide at least one general
implementation of them. Afterwards you can proceed providing more specialized implementations in the same plugin
package, or maybe also in another one if you need more flexibility in loading different implementations.
The classes Reporter
and Exporter
are also maintaining a plugin system, to allow plugins to
contribute their own results to the output. But those hooks are
not firstresult
per default and specifying new hooks is
not as easy as with units and profiles.
Details affecting only the distinct classes are described in their documentation.
For examples on specifying and implementing hooks, please read the pluggy documentation and look into the source code of PyRolL.