Python package for co-routine base state machines.
Project description
FiniteStateMachine - A finite state machine class using coroutines
FiniteStateMachine is a class representing a finite state machine. Each state is represented by an instance of the
State class. Each state also has a state handler function defined for it. The handler function is a co-routine that
excepts an event and performs an action based on it.
To define the state machine:
1) define the states (e.g. STATE_A = State('STATE_A'))
2) define the state handler functions. See below for the structure of a state handling function.
3) create an instance of the state machine (e.g. fsm = Fsm())
4) add states to the state machine, including exactly one state marked as the initial state. Each state also takes
a sequence of states that it can be transitioned from (from_states).
5) call the start function on the FSM (e.g. fsm.start())
For each event you will need to call the dispatch_event function (e.g. fsm.dispatch_event()) to route the event
to the co-routine. An event can be anything you want (e.g. a tuple with event_id and arguments). The main loops
generally looks like:
try:
while True:
event = get_next_event()
fsm.dispatch_event(event)
except ExpectedExit as e:
pass
The basic structure of a state handler is:
def state_handler_<state name>(fsm):
# Enter the main loop for the co-routine
while True:
event = yield
if event == 'EVENT_1':
# Transition to another state
fsm.transition_to(STATE_X)
elif event == 'EVENT_2':
# Do some processing but stay in this state
print('Got EVENT_2')
elif event == 'TERMINATING_EVENT':
raise FsmExit
else:
print('Unrecognized event (%s)' % event)
A simple example of this is shown in the turnstile_test.py test case.
For convenience this can be wrapped with a @state_handler decorator. The decorator takes care of the co-routine
boiler plate and hands the handler function an fsm and event. This would look like:
@pystate.state_handler
def state_locked_handler(event, fsm):
if event == 'EVENT_1':
# Transition to another state
fsm.transition_to(STATE_X)
elif event == 'EVENT_2':
# Do some processing but stay in this state
print('Got EVENT_2')
elif event == 'TERMINATING_EVENT':
raise FsmExit
else:
print('Unrecognized event (%s)' % event)
There are two ways to handle a state that needs to keep persistant data. You can create a callable clas (i.e. define
the __call__ dunder method to call as the state handler.) This allows you to use the state_handler decorator around
the __call__ method. Alternatively, you can set the state data above the while loop if you define the co-routine by
hand, however, this precludes using the decorator. See the callable_test.py test case for an example.
Author: Len Wanger
Last Updated: 7/7/2016
FiniteStateMachine is a class representing a finite state machine. Each state is represented by an instance of the
State class. Each state also has a state handler function defined for it. The handler function is a co-routine that
excepts an event and performs an action based on it.
To define the state machine:
1) define the states (e.g. STATE_A = State('STATE_A'))
2) define the state handler functions. See below for the structure of a state handling function.
3) create an instance of the state machine (e.g. fsm = Fsm())
4) add states to the state machine, including exactly one state marked as the initial state. Each state also takes
a sequence of states that it can be transitioned from (from_states).
5) call the start function on the FSM (e.g. fsm.start())
For each event you will need to call the dispatch_event function (e.g. fsm.dispatch_event()) to route the event
to the co-routine. An event can be anything you want (e.g. a tuple with event_id and arguments). The main loops
generally looks like:
try:
while True:
event = get_next_event()
fsm.dispatch_event(event)
except ExpectedExit as e:
pass
The basic structure of a state handler is:
def state_handler_<state name>(fsm):
# Enter the main loop for the co-routine
while True:
event = yield
if event == 'EVENT_1':
# Transition to another state
fsm.transition_to(STATE_X)
elif event == 'EVENT_2':
# Do some processing but stay in this state
print('Got EVENT_2')
elif event == 'TERMINATING_EVENT':
raise FsmExit
else:
print('Unrecognized event (%s)' % event)
A simple example of this is shown in the turnstile_test.py test case.
For convenience this can be wrapped with a @state_handler decorator. The decorator takes care of the co-routine
boiler plate and hands the handler function an fsm and event. This would look like:
@pystate.state_handler
def state_locked_handler(event, fsm):
if event == 'EVENT_1':
# Transition to another state
fsm.transition_to(STATE_X)
elif event == 'EVENT_2':
# Do some processing but stay in this state
print('Got EVENT_2')
elif event == 'TERMINATING_EVENT':
raise FsmExit
else:
print('Unrecognized event (%s)' % event)
There are two ways to handle a state that needs to keep persistant data. You can create a callable clas (i.e. define
the __call__ dunder method to call as the state handler.) This allows you to use the state_handler decorator around
the __call__ method. Alternatively, you can set the state data above the while loop if you define the co-routine by
hand, however, this precludes using the decorator. See the callable_test.py test case for an example.
Author: Len Wanger
Last Updated: 7/7/2016
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
pystate-0.0.1.zip
(7.6 kB
view hashes)