Skip to main content

Python State Machines for Humans

Project description

state machine for humans

There are two types of developers in this world: those who love state machines and those who will eventually.

I fall in the first camp. I think it is really important to have a declarative way to define the states of an object. That’s why I developed yasm.


pip install yasm

Basic Usage

from collections import deque
import operator
import six
from string import whitespace, digits

from yasm import Event, state_machine
from yasm.utils import dispatch

class Calculator(object):

    operators = {
        '+': operator.add,
        '-': operator.sub,
        '*': operator.mul,
    if six.PY3:
        operators['/'] = operator.truediv
        operators['/'] = operator.div

    def __init__(self):
        self.stack = deque()
        self.result = None

    def reset(self):
        self.result = None

    def calculate(self, string):
        for char in string:
            dispatch(self, Event('parse', input=char))
        return self.result

    def start_building_number(self, state, event, instance):
        digit = event.input

    def build_number(self, state, event, instance):
        digit = event.input
        number = str(self.stack.pop())
        number += digit

    def do_operation(self, state, event, instance):
        operation = event.input
        y = self.stack.pop()
        x = self.stack.pop()
        self.stack.append(self.operators[operation](float(x), float(y)))

    def do_equal(self, state, event, instance):
        number = self.stack.pop()
        self.result = number

def is_digit(state, event, instance):
    return event.input in digits

sm = Calculator.machine
sm.add_states(['initial', 'number', 'result'], initial='initial')

    {'from_state': 'initial', 'to_state': 'number', 'event': 'parse',
     'conditions': [is_digit], 'before': 'start_building_number'},
    {'from_state': 'number', 'to_state': 'number', 'event': 'parse',
     'conditions': [is_digit], 'before': 'build_number'},
    {'from_state': 'number', 'to_state': 'initial', 'event': 'parse',
     'conditions': [lambda state, evt, ins: evt.input in whitespace]},
    {'from_state': 'initial', 'to_state': 'initial', 'event': 'parse',
     'conditions': [lambda state, evt, ins: evt.input in '+-*/'],
     'before': 'do_operation'},
    {'from_state': 'initial', 'to_state': 'result', 'event': 'parse',
     'conditions': [lambda state, evt, ins: evt.input == '='],
     'before': 'do_equal'},

 calc = Calculator()
 for syntax, value in ((' 167 3 2 2 * * * 1 - =', 2003),
                       ('    167 3 2 2 * * * 1 - 2 / =', 1001.5),
                       ('    3   5 6 +  * =', 33),
                       ('        3    4       +     =', 7),
                       ('2 4 / 5 6 - * =', -0.5),):
     result = calc.calculate(syntax)
     assert result == value, (syntax, result, value)

Thank you

to aasm and ruby’s state_machine and jtushman’s jtushman/state_machine and all other state machines that I loved before

Project details

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Filename, size & hash SHA256 hash help File type Python version Upload date
yasm-0.1.0a1-py2.py3-none-any.whl (13.6 kB) Copy SHA256 hash SHA256 Wheel py2.py3 Sep 6, 2018

Supported by

Elastic Elastic Search Pingdom Pingdom Monitoring Google Google BigQuery Sentry Sentry Error logging AWS AWS Cloud computing DataDog DataDog Monitoring Fastly Fastly CDN SignalFx SignalFx Supporter DigiCert DigiCert EV certificate StatusPage StatusPage Status page