state machine for python classes
Project description
.. figure:: https://travis-ci.org/gemerden/statessvg?branch=master
:alt: Travis
Travis
statemachine
============
Easy to use state machine to manage the state of python objects.
Introduction
------------
This state machine implementation is developed with the following goals
in mind:
- Easy to use API, for configuration of the state machine and
triggering state transitions,
- Usable for any (almost, I'm sure) python class with a finite number
of states,
- Fully featured, including nested states, conditional transitions,
shorthand notations, many ways to configure callbacks,
- Simple state machines do not require advanced knowledge; complexity
of configuration scales with complexity of requirements,
- One state machine instance can manage the state of many stateful
objects; the objects only store their current state string,
- Reasonably fast.
Code Example
------------
Here is a simple statemachine to give some idea of what the
configuration looks like.
.. code:: python
class LightSwitch(StatefulObject):
machine = state_machine(
states=[
{"name": "on"},
{"name": "off"},
],
transitions=[
{"old_state": "off", "new_state": "on", "triggers": ["flick"]},
{"old_state": "on", "new_state": "off", "triggers": ["flick"]},
],
)
lightswitch = LightSwitch(initial="off")
lightswitch.flick()
Limitations
-----------
The state machine module has been tested with python 2.7, if requested I
will definitely consider python 3 support, depending on time
constraints.
Documentation
-------------
To learn more check the extensive
`tutorial <https://github.com/gemerden/statemachine/blob/master/statemachine/docs/tutorial.md>`__.
Concepts
--------
The following basic state machine concepts are used
- *state*: state of an stateful object; objects can be in one state at
the time,
- *transition*: transition of the object from one state to another
resulting,
- *state machine*: system that manages the states of objects according
to predefined states and transitions,
- *trigger*: method called on an object that can result in a state
transition,
- *callbacks*: functions called on state transitions by the state
machine,
- *condition*: conditions for a specific state transition to take
place.
Features
--------
The module has the following basic and some more advanced features:
- trigger state transitions by setting trigger name in machine
configuration:
- same trigger can be set for different transitions,
- trigger method can pass arguments to callbacks like ``on_exit``
and ``on_entry``,
- conditions (also callbacks) can be set on states and transitions:
- if a transition is triggered, but the condition is not met, the
transition does not take place
- switched transitions can be used to go from one state to another
depending on conditions
- trigger can be used for conditional (switched) transition,
- to do this, create multiple trasnitions from the same state to
different states and give them different conditions
- state transitions can be started by explicitly setting the state
(obj.state = "some\_state"):
- if a condition is set and not met on the transition an exception
is raised, because the callbacks would not be called,
- if the callbacks function require extra arguments (apart from the
state managed object), this method will fail
- a number of callbacks can be installed for each state and transition,
with obj the state managed object and **args, **\ \*kwargs the
arguments passed via the trigger to the callback, in calling order:
- StateMachine.prepare(self, obj. **args, **\ \*kwargs),
- StateMachine.before\_any\_exit(self, obj. **args, **\ \*kwargs),
- State.on\_exit(self, obj. **args, **\ \*kwargs),
- Transition.on\_transfer(self, obj. **args, **\ \*kwargs), # after
this the state is changed on the object
- State.on\_entry(self, obj. **args, **\ \*kwargs),
- StateMachine.after\_any\_entry(self, obj. **args, **\ \*kwargs)
- note that if a condition is present and not met, none of these
functions are called, apart from prepare
- callbacks can be methods on the class of which the state is managed
by the machine:
- This is the case when the calback is configured as a string (e.g.
"on\_entry": "do\_callback"),
- wildcards and listed states can be used to define multiple
transitions at once:
- e.g. transition {"old\_state": "\*", "new\_state": ["A", "B"]}
would create transitions from all states to both state A and B
- nested states can be used to better organize states and transitions,
states can be nested to any depth,
- context managers can be used to create a context for all callbacks,
- custom exceptions:
- MachineError: raised in case of a misconfiguration of the state
machine,
- TransitionError: raised in case of e.g. an attempt to trigger a
non-existing transition,
Rules (for the mathematically minded)
-------------------------------------
The state machine in the module has the following rules for setting up
states and transitions:
- notation:
- A, B, C : states of a state managed object (called 'object' from
now)
- A(B, C) : state A with nested states B, C, with \* indicating that
B is the default initial state
- A.B : sub-state B of A; A.B is called a state path
- : transition between state A and state B
- : transition from A to B or C, depending on condition functions
(there is no 'and')
- : shorthand for transitions and
- : shorthand for all transitions from A to states in the same
machine
- an object cannot just be in state A if A has substates; given state
A(B, C), the object can be in A.B or A.C, not in A
- allowed transitions, given states A, B, C(E, F) and D(G, H):
- : basic transition, configured as {"old\_state": "A",
"new\_state": "B"}
- : transition from a state to itself
- <C.E, A>: transition from a specific sub-state of C to A
- : transition from any sub-state of C to specific state D.G
- : transition from A to C.E, E being the initial state of C because
it was explicitly set or because it is the first state in E
- <C.F, D.H>: transitioning from one sub-state in a state to another
sub-state in another state. Note that this would call (if present)
on\_exit on F and C and on\_entry on D and H in that order.
- non-allowed transitions:
- <C.E, C.F>: inner transitions cannot be defined on the top level;
define in state C
- adding switched transitions, given transition :
- B and C must have conditions attached in the transition, these
condition will be run though in order
- D does not need to have a condition attached meaning it will
always be the next state if the conditions on the transition to B
and C fail
Authors
-------
Lars van Gemerden (rational-it) - initial code and documentation.
License
-------
This project is licensed under the license in LICENSE.txt.
:alt: Travis
Travis
statemachine
============
Easy to use state machine to manage the state of python objects.
Introduction
------------
This state machine implementation is developed with the following goals
in mind:
- Easy to use API, for configuration of the state machine and
triggering state transitions,
- Usable for any (almost, I'm sure) python class with a finite number
of states,
- Fully featured, including nested states, conditional transitions,
shorthand notations, many ways to configure callbacks,
- Simple state machines do not require advanced knowledge; complexity
of configuration scales with complexity of requirements,
- One state machine instance can manage the state of many stateful
objects; the objects only store their current state string,
- Reasonably fast.
Code Example
------------
Here is a simple statemachine to give some idea of what the
configuration looks like.
.. code:: python
class LightSwitch(StatefulObject):
machine = state_machine(
states=[
{"name": "on"},
{"name": "off"},
],
transitions=[
{"old_state": "off", "new_state": "on", "triggers": ["flick"]},
{"old_state": "on", "new_state": "off", "triggers": ["flick"]},
],
)
lightswitch = LightSwitch(initial="off")
lightswitch.flick()
Limitations
-----------
The state machine module has been tested with python 2.7, if requested I
will definitely consider python 3 support, depending on time
constraints.
Documentation
-------------
To learn more check the extensive
`tutorial <https://github.com/gemerden/statemachine/blob/master/statemachine/docs/tutorial.md>`__.
Concepts
--------
The following basic state machine concepts are used
- *state*: state of an stateful object; objects can be in one state at
the time,
- *transition*: transition of the object from one state to another
resulting,
- *state machine*: system that manages the states of objects according
to predefined states and transitions,
- *trigger*: method called on an object that can result in a state
transition,
- *callbacks*: functions called on state transitions by the state
machine,
- *condition*: conditions for a specific state transition to take
place.
Features
--------
The module has the following basic and some more advanced features:
- trigger state transitions by setting trigger name in machine
configuration:
- same trigger can be set for different transitions,
- trigger method can pass arguments to callbacks like ``on_exit``
and ``on_entry``,
- conditions (also callbacks) can be set on states and transitions:
- if a transition is triggered, but the condition is not met, the
transition does not take place
- switched transitions can be used to go from one state to another
depending on conditions
- trigger can be used for conditional (switched) transition,
- to do this, create multiple trasnitions from the same state to
different states and give them different conditions
- state transitions can be started by explicitly setting the state
(obj.state = "some\_state"):
- if a condition is set and not met on the transition an exception
is raised, because the callbacks would not be called,
- if the callbacks function require extra arguments (apart from the
state managed object), this method will fail
- a number of callbacks can be installed for each state and transition,
with obj the state managed object and **args, **\ \*kwargs the
arguments passed via the trigger to the callback, in calling order:
- StateMachine.prepare(self, obj. **args, **\ \*kwargs),
- StateMachine.before\_any\_exit(self, obj. **args, **\ \*kwargs),
- State.on\_exit(self, obj. **args, **\ \*kwargs),
- Transition.on\_transfer(self, obj. **args, **\ \*kwargs), # after
this the state is changed on the object
- State.on\_entry(self, obj. **args, **\ \*kwargs),
- StateMachine.after\_any\_entry(self, obj. **args, **\ \*kwargs)
- note that if a condition is present and not met, none of these
functions are called, apart from prepare
- callbacks can be methods on the class of which the state is managed
by the machine:
- This is the case when the calback is configured as a string (e.g.
"on\_entry": "do\_callback"),
- wildcards and listed states can be used to define multiple
transitions at once:
- e.g. transition {"old\_state": "\*", "new\_state": ["A", "B"]}
would create transitions from all states to both state A and B
- nested states can be used to better organize states and transitions,
states can be nested to any depth,
- context managers can be used to create a context for all callbacks,
- custom exceptions:
- MachineError: raised in case of a misconfiguration of the state
machine,
- TransitionError: raised in case of e.g. an attempt to trigger a
non-existing transition,
Rules (for the mathematically minded)
-------------------------------------
The state machine in the module has the following rules for setting up
states and transitions:
- notation:
- A, B, C : states of a state managed object (called 'object' from
now)
- A(B, C) : state A with nested states B, C, with \* indicating that
B is the default initial state
- A.B : sub-state B of A; A.B is called a state path
- : transition between state A and state B
- : transition from A to B or C, depending on condition functions
(there is no 'and')
- : shorthand for transitions and
- : shorthand for all transitions from A to states in the same
machine
- an object cannot just be in state A if A has substates; given state
A(B, C), the object can be in A.B or A.C, not in A
- allowed transitions, given states A, B, C(E, F) and D(G, H):
- : basic transition, configured as {"old\_state": "A",
"new\_state": "B"}
- : transition from a state to itself
- <C.E, A>: transition from a specific sub-state of C to A
- : transition from any sub-state of C to specific state D.G
- : transition from A to C.E, E being the initial state of C because
it was explicitly set or because it is the first state in E
- <C.F, D.H>: transitioning from one sub-state in a state to another
sub-state in another state. Note that this would call (if present)
on\_exit on F and C and on\_entry on D and H in that order.
- non-allowed transitions:
- <C.E, C.F>: inner transitions cannot be defined on the top level;
define in state C
- adding switched transitions, given transition :
- B and C must have conditions attached in the transition, these
condition will be run though in order
- D does not need to have a condition attached meaning it will
always be the next state if the conditions on the transition to B
and C fail
Authors
-------
Lars van Gemerden (rational-it) - initial code and documentation.
License
-------
This project is licensed under the license in LICENSE.txt.
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
states-0.1.5.zip
(17.1 kB
view hashes)
Built Distribution
states-0.1.5-py2-none-any.whl
(16.4 kB
view hashes)