Kabaret extension to create and activate relations at arbitrary locations in the flow
Project description
kabaret.flow_extensions
Flow extensions is a Kabaret extension which allows to extend flow objects with standalone relations (i.e. defined outside of the flow object classes). These relations are named dynamic relations.
Dependencies
This module relies on versions 2.3.0
and later of Kabaret, which provide the feature to override the object manager type needed to enable extensions on objects.
Enabling extensions
The ability of an object to accept extensions relies on its manager, which must be of type DynamicTreeManager
. We can then control extensions using the mecanism provided in Kabaret to override the object manager type (Object._MANAGER_TYPE
) and specify whether it must be used in the object sub-tree (Object._PROPAGATE_MANAGER_TYPE
).
To enable extensions on an object, simply set the manager type of its class to DynamicTreeManager
.
from kabaret.flow import Object
from kabaret.flow_extensions.flow import DynamicTreeManager
class MyExtendableObject(Object):
_MANAGER_TYPE = DynamicTreeManager
In the above example, only MyExtendableObject
instances can be extended. To enable extensions for all children existing in the sub-trees of these instances as well, set the value of the class attribute _PROPAGATE_MANAGER_TYPE
to True
.
class MyExtendableProject(Object):
_MANAGER_TYPE = DynamicTreeManager
_PROPAGATE_MANAGER_TYPE = True
In case the use of extensions must be disabled on an object which exists in a part of the flow where extensions are enabled by default, one can reset its _MANAGER_TYPE
to the default type _Manager
.
class MyRegularObject(Object):
_MANAGER_TYPE = _Manager
class MyExtendableObject(Object):
_MANAGER_TYPE = DynamicTreeManager
_PROPAGATE_MANAGER_TYPE = True
regular_object = flow.Child(MyRegularObject)
...
In the above example, all but the MyRegularObject
child under the MyExtendableObject
will be able to register extensions.
Definition
Factories
Dynamic relations must be defined in factories. A factory is a function which takes an Object
instance as an argument representing an extendable object, and returns either a single relation (_Relation
instance), a list of relations, or None
if no relation has to be registered by the target object.
def relation_factory(parent -> Object) -> [None, _Relation, list]:
...
Declaring a dynamic relation is done similarly as for a regular relation, except that its name must be set explicitly.
def create_dynamic_param(parent):
if parent.oid() == '/my/target/oid':
relation = flow.Param('').ui(label='My dynamic param')
relation.name = 'my_dynamic_param'
return relation
Ordering
Optionally, one might set the relation's index to control its position among the existing ones. The default index of a dynamic relation is 0
, which makes it appear first in the UI. When set to None
, the index is automatically computed so that the relation appears last.
relation.index = 5
Overrides
When multiple relation candidates have the same name, only the one with the highest priority weight is retained. This weight is optional and can be provided by the factory:
def create_relation(parent):
...
return relation, 10
The default value of a relation weight is 0
. When not provided, only the last found relation candidate will be available.
It is also possible to provide a negative weight to prevent a dynamic relation from overriding an existing base relation.
Installers
Installers are functions called by the manager of an object to retrieve its dynamic relations. An installer takes the current session as an argument, and returns a dictionary which maps a list of relation factories with the name of the extension.
Example:
def install_extensions(session):
if session.session_uid().split(':', 1)[0] = 'my_user_name':
return {
"my_extension": [
create_dynamic_param,
...
],
...
}
In order for installers to be accessible to the manager, they must be provided in the environment variable KABARET_FLOW_EXT_INSTALLERS
following the pattern: <module_qualified_name>:<installer_name>[;<module_qualified_name>:<installer_name>...]
.
Known issues
Instanciation of objects referenced by native relations obeys to the principle of lazy evaluation: objects are not instanciated until the relations are accessed. The extension system currently drops this mecanism, in two points:
- child objects referenced by dynamic relations are instanciated as soon as their parent is instanciated.
- child objects themselves are set as attributes of their parent (instead of the generating relations).
The issues listed below stem from this change of behaviour. We propose a workaround for each whenever possible.
-
Infinite extension branch. Given an extendable flow object, all objects in its sub-tree, including children generated by dynamic relations, will also accept extensions unless their manager type is set back to Kabaret's default manager type
_Manager
. It means that as long as factories return relations, an extension object can itself registers dynamic relations, leading to an infinite creation of dynamic relations.Workaround: explicitly set the manager type of the dynamic relation's related types to
_Manager
.class MyExtensionObject(flow.Object): _MANAGER_TYPE = _Manager # prevent extension from registering extensions itself
-
Invalid calls to
ProjectRoot.project()
. When theparent
object is the project instance, any call toObject.root().project()
currently raises anAttributeError
. This is because the project is not instanciated yet at the time the factory is called, hence it is not available as an attribute of theProjectRoot
instance.Workarounds:
- get the project instance (from an object): use an explicit
Parent
relation pointing to the project - check if the
parent
extension target is the project instance (in a factory): exploit the fact that the project oid equals to its name preceded by/
.
if parent.oid() == '/'+parent.name(): ...
- get the project instance (from an object): use an explicit
As a consequence of the second point, nothing prevents from overwriting a child object since it is a regular Python attribute.
Changelog
[1.0.0] - 2024-04-26
Added
issue #1: Manage flow extensions
[0.0.1] - 2024-04-26
Initial commit
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
File details
Details for the file kabaret_flow_extensions-1.0.0.tar.gz
.
File metadata
- Download URL: kabaret_flow_extensions-1.0.0.tar.gz
- Upload date:
- Size: 34.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/5.0.0 CPython/3.12.3
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 8c3de5e792a484f850fb02f15cceb7402f35ff0670f3de2b45c6092b4ff041b8 |
|
MD5 | 3ca068519052fdd6806a521611dd9a66 |
|
BLAKE2b-256 | b1a515f26f33ba5530a6188a90caba8493b86d4010affa4a3c8179574121368c |