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.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

yasm-0.1.0a1-py2.py3-none-any.whl (13.6 kB view hashes)

Uploaded Python 2 Python 3

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