Skip to main content

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

Project details


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)

Uploaded Source

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page