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.
Install
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
@state_machine('calculator')
class Calculator(object):
operators = {
'+': operator.add,
'-': operator.sub,
'*': operator.mul,
}
if six.PY3:
operators['/'] = operator.truediv
else:
operators['/'] = operator.div
def __init__(self):
self.stack = deque()
self.result = None
def reset(self):
self.stack.clear()
self.result = None
self.machine.reinit_instance(self)
def calculate(self, string):
self.reset()
for char in string:
dispatch(self, Event('parse', input=char))
return self.result
def start_building_number(self, state, event, instance):
digit = event.input
self.stack.append(int(digit))
def build_number(self, state, event, instance):
digit = event.input
number = str(self.stack.pop())
number += digit
self.stack.append(int(number))
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')
sm.add_transitions([
{'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)
calc.reset()
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
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 Distributions
No source distribution files available for this release.See tutorial on generating distribution archives.
Built Distribution
File details
Details for the file yasm-0.1.0a1-py2.py3-none-any.whl
.
File metadata
- Download URL: yasm-0.1.0a1-py2.py3-none-any.whl
- Upload date:
- Size: 13.6 kB
- Tags: Python 2, Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/1.11.0 pkginfo/1.4.2 requests/2.19.1 setuptools/20.7.0 requests-toolbelt/0.8.0 tqdm/4.24.0 CPython/2.7.12
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 268aaee7a0e35da90183687c8393a41cba6d2bccfaecd37905386ede9e81976c |
|
MD5 | 8d61c33752e5f9844fda039ba9098437 |
|
BLAKE2b-256 | e3a23a9e6b11dad093dcd0232b565b06fefa97e8c40bf7b834bb123dd989dc46 |