This document presents the various classes and components of XWorkflows.
Note
All objects defined in the base module should be considered internal API and subject to change without notice.
Public API consists of the public methods and attributes of the following objects:
The xworkflows module exposes a few specific exceptions:
This is the base for all exceptions from the xworkflows module.
This error is raised whenever a transition call fails, either due to state validation or pre-transition checks.
This exception is raised when trying to perform a transition from an incompatible state.
This exception will be raised when the check parameter of the transition() decorator returns a non-True value.
States may be represented with different objects:
Intended for use as a WorkflowEnabled attribute, this wraps a State with knowledge about the related Workflow.
Its __hash__ is computed from the related name. It compares equal to:
Returns: | A list of Transition with this State as source |
---|
Special property-like object (technically a data descriptor), this class controls access to the current State of a WorkflowEnabled object.
It performs the following actions:
The name of the attribute wrapped by this StateProperty.
A Workflow definition is slightly different from the resulting class.
A few class-level declarations will be converted into advanced objects:
A Workflow definition must inherit from the Workflow class, or use the base.WorkflowMeta metaclass for proper setup.
The list of states should be defined as a list of two-tuples of (name, title):
class MyWorkflow(xworkflows.Workflow):
states = (
('initial', "Initial"),
('middle', "Intermediary"),
('final', "Final - all is said and done."),
)
This is converted into a StateList object.
This class acts as a mixed dictionary/object container of states.
It replaces the states list from the Workflow definition.
Allows retrieving a State from its name, as an attribute of the StateList:
MyWorkflow.states.initial == MyWorkflow.states['initial']
Iterates over the states, in the order they were defined
At a Workflow level, transition are defined in a list of three-tuples:
class MyWorkflow(xworkflows.Workflow):
transitions = (
('advance', 'initial', 'middle'),
('end', ['initial', 'middle'], 'final'),
)
This is converted into a TransitionList object.
This acts as a mixed dictionary/object container of transitions.
It replaces the transitions list from the Workflow definition.
Allows retrieving a Transition from its name or from an instance, in a dict-like manner
Allows retrieving a Transition from its name, as an attribute of the TransitionList:
MyWorkflow.transitions.accept == MyWorkflow.transitions['accept']
Iterates over the transitions, in the order they were defined
Tests whether a Transition instance or its name belong to the Workflow
Retrieve the list of Transition available from the given State.
Container for a transition.
The name of the Transition; should be a valid Python identifier
A list of source states for this Transition
The target State for this Transition
A Workflow should inherit from the Workflow base class, or use the WorkflowMeta metaclass (that builds the states, transitions, initial_state attributes).
This class holds the definition of a workflow.
A TransitionList of all Transition for this Workflow
Parameters: |
|
---|
This method allows logging all transitions performed by objects using a given workflow.
The default implementation logs to the logging module, in the base logger.
The class to use when creating ImplementationWrapper for a WorkflowEnabled using this Workflow.
Defaults to ImplementationWrapper.
This metaclass will simply convert the states, transitions and initial_state class attributes into the related StateList, TransitionList and State objects.
During this process, some sanity checks are performed:
In order to use a Workflow, related objects should inherit from the WorkflowEnabled class.
This class will handle all specific setup related to using workflows:
Adds a workflow to the attributes dict of the future class.
Parameters: |
|
---|
Note
This method is also an extension point for custom XWorkflow-related libraries.
Find all workflow definitions in a class attributes dict.
Parameters: | attrs (dict) – Attribute dict of the future class |
---|---|
Returns: | A dict mapping a field name to a StateField describing parameters for the workflow |
Note
This method is also an extension point for custom XWorkflow-related libraries.
This class-level attribute holds a dict mapping an attribute to the related Workflow.
Note
This is a private attribute, and may change at any time in the future.
This class-level attribute holds a dict mapping an attribute to the related implementations.
Note
This is a private attribute, and may change at any time in the future.
This metaclass handles the parsing of WorkflowEnabled and related magic.
Most of the work is handled by ImplementationList, with one instance handling each Workflow attached to the WorkflowEnabled object.
A bare WorkflowEnabled subclass definition will be automatically modified to include “noop” implementations for all transitions from related workflows.
In order to customize this behaviour, one should use the transition() decorator on methods that should be called when performing transitions.
Decorates a method and uses it for a given Transition.
Parameters: |
|
---|
Actual class holding all values defined by the transition() decorator.
The decorated function, wrapped with a few checks and calls.
Hooks are declared through a _HookDeclaration decorator, which attaches a specific xworkflows_hook attribute to the decorated method. Methods with such attribute will be collected into Hook objects containing all useful fields.
Ensures that the given function has a xworkflows_hook attributes, and returns it.
The xworkflows_hook is a dict mapping each hook kind to a list of (field, hook) pairs:
function.xworkflows_hook = {
HOOK_BEFORE: [('state', <Hook: ...>), ('', <Hook: ...>)],
HOOK_AFTER: [],
...
}
Note
Although the xworkflows_hook is considered a private API, it may become an official extension point in future releases.
Base class for hook declaration decorators.
It accepts an (optional) list of transition/state names, and priority / field as keyword arguments:
@_HookDeclaration('foo', 'bar')
@_HookDeclaration(priority=42)
@_HookDeclaration('foo', field='state1')
@_HookDeclaration(priority=42, field='state1')
def hook(self):
pass
List of transition or state names the hook applies to
Type : | str list |
---|
The priority of the hook
Type : | int |
---|
The name of the StateWrapper field whose transitions the hook applies to
Type : | str |
---|
Create a Hook for the given callable
Create a Hook for the function, and store it in the function’s xworkflows_hook attribute.
Marks a method as a pre-transition hook. The hook will be called just before changing a WorkflowEnabled object state, with the same *args and **kwargs as the actual implementation.
Marks a method as a transition check hook.
The hook will be called when using is_available() and before running the implementation, without any args, and should return a boolean indicating whether the transition may proceed.
Marks a method as a post-transition hook
The hook will be called immediately after the state update, with:
Marks a method as a pre-transition hook to call when the object leaves one of the given states.
The hook will be called with the same arguments as a before_transition() hook.
Marks a method as a post-transition hook to call just after changing the state to one of the given states.
The hook will be called with the same arguments as a after_transition() hook.
The kind of before_transition() hooks
The kind of transition_check() hooks
The kind of after_transition() hooks
The kind of on_leave_state() hooks
The kind of on_enter_state() hooks
Describes a hook, including its kind, priority and the list of transitions it applies to.
One of HOOK_BEFORE, HOOK_AFTER, HOOK_CHECK, HOOK_ON_ENTER or HOOK_ON_LEAVE; the kind of hook.
The priority of the hook, as an integer defaulting to 0. Hooks with higher priority will be executed first; hooks with the same priority will be sorted according to the function name.
Type : | int |
---|
The actual hook function to call. Arguments passed to that function depend on the hook’s kind.
Type : | callable |
---|
Name of states or transitions this hook applies to; will be ('*',) if the hook applies to all states/transitions.
Type : | str tuple |
---|
Check whether the hook applies to the given Transition and optional source State.
If from_state is None, the test means “could the hook apply to the given transition, in at least one source state”.
If from_state is not None, the test means “does the hook apply to the given transition for this specific source state”.
Returns: | bool |
---|
Call the hook
Two hooks are “equal” if they wrap the same function, have the same kind, priority and names.
Hooks are ordered by descending priority and ascending decorated function name.
Once WorkflowEnabledMeta has updated the WorkflowEnabled subclass, all transitions – initially defined and automatically added – are replaced with a base.ImplementationProperty instance.
This class holds all objects required to instantiate a ImplementationWrapper whenever the attribute is accessed on an instance.
Internally, it acts as a ‘non-data descriptor’, close to property().
This method overrides the getattr() behavior:
This class handles applying a Transition to a WorkflowEnabled object.
The WorkflowEnabled object to modify when calling this wrapper.
The name of the field modified by this ImplementationProperty (a string)
Type : | str |
---|
The Transition performed by this object.
Type : | Transition |
---|
The Workflow to which this ImplementationProperty relates.
Type : | Workflow |
---|
The actual method to call when performing the transition. For undefined implementations, uses noop().
Type : | callable |
---|
All hooks that may be applied when performing the related transition.
Type : | dict mapping a hook kind to a list of Hook |
---|
Actually a property, retrieve the current state from the instance.
Type : | StateWrapper |
---|
This method allows the TransitionWrapper to act as a function, performing the whole range of checks and hooks before and after calling the actual implementation.
Determines whether the wrapped transition implementation can be called. In details:
Return type: | bool |
---|
The ‘do-nothing’ function called as default implementation of transitions.
Warning
This documents private APIs. Use at your own risk.
Building the list of ImplementationProperty for a given WorkflowEnabled, and generating the missing ones, is a complex job.
This class performs a few low-level operations on a WorkflowEnabled class:
The name of the attribute (from attr = SomeWorkflow() definition) currently handled.
Type : | str |
---|
The Workflow this ImplementationList refers to
Dict mapping a transition name to the related ImplementationProperty
Type : | dict (str => ImplementationProperty) |
---|
Dict mapping the name of a transition to the attribute holding its ImplementationProperty:
@transition('foo')
def bar(self):
pass
will translate into:
self.implementations == {'foo': <ImplementationProperty for 'foo' on 'state': <function bar at 0xdeadbeed>>}
self.transitions_at == {'foo': 'bar'}
Set of name of implementations which were remapped within the workflow.
Loads implementations defined in a parent ImplementationList.
Parameters: | parent_implems (ImplementationList) – The ImplementationList from a parent |
---|
Retrieves definition of custom (non-automatic) implementations from the current list.
Yields : | (trname, attr, implem): Tuples containing the transition name, the name of the attribute its implementation is stored at, and that implementation (a ImplementationProperty). |
---|
Whether a given attribute value should be collected in the current list.
Checks that it is a TransitionWrapper, for a Transition of the current Workflow, and relates to the current state_field.
Collects all TransitionWrapper from an attribute dict if they verify should_collect().
Raises : | ValueError If two TransitionWrapper for a same Transition are defined in the attributes. |
---|
Registers noop() ImplementationProperty for all Transition that weren’t collected in the collect() step.
Walks the class attributes and collects hooks from those with a xworkflows_hook attribute (through register_function_hooks())
Retrieves hook definitions from the given function, and registers them on the related ImplementationProperty.
Checks whether the implem ImplementationProperty is a valid override for the other ImplementationProperty.
Rules are:
Adds all ImplementationProperty from implementations to the given attributes dict, unless _may_override() prevents the operation.
Parameters: | attrs (dict) – Mapping holding attribute declarations from a class definition |
---|
Performs the following actions, in order: