XWorkflows is a library designed to bring a simple approach to workflows in Python.
It provides:
You can also refer to the django_xworkflows project for integration with Django.
First, install the xworkflows package:
pip install xworkflows
You can now define a Workflow:
class MyWorkflow(xworkflows.Workflow):
states = (
('init', _(u"Initial state")),
('ready', _(u"Ready")),
('active', _(u"Active")),
('done', _(u"Done")),
('cancelled', _(u"Cancelled")),
)
transitions = (
('prepare', 'init', 'ready'),
('activate', 'ready', 'active'),
('complete', 'active', 'done'),
('cancelled', ('ready', 'active'), 'cancelled'),
)
initial_state = 'init'
In order to apply that workflow to an object, you must:
Here is an example:
class MyObject(xworkflows.WorkflowEnabled):
state = MyWorkflow()
With the previous definition, some methods have been magically added to your object definition (have a look at WorkflowEnabledMeta to see how).
There is now one method per transition defined in the workflow:
>>> obj = MyObject()
>>> obj.state
State('init')
>>> obj.prepare()
>>> obj.state
State('ready')
As seen in the example above, calling a transition automatically updates the state of the workflow.
Only transitions compatible with the current state may be called:
>>> obj.state
State('ready')
>>> obj.complete()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
InvalidTransitionError: Transition "complete" isn't available from state "ready"
It is possible to define explicit code for a transition:
class MyObject(xworkflows.WorkflowEnabled):
state = MyWorkflow
@xworkflows.transition()
def activate(self, user):
self.activated_by = user
print "State is %s" % self.state.name
When calling the transition, the custom code is called before updating the state:
>>> obj.state
State('ready')
>>> obj.activate('blah')
State is ready
>>> obj.state
State('active')
>>> obj.activated_by
'blah'
Other functions can be hooked onto transitions, through the before_transition(), after_transition(), transition_check(), on_enter_state() and on_leave_state() decorators:
class MyObject(xworkflows.WorkflowEnabled):
state = MyWorkflow
@xworkflows.before_transition('foobar', 'gobaz')
def hook(self, *args, **kwargs):
pass