Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

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

Metadata

Release files for yasm 0.1.0a1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distribution (wheel)

Table of built distributions (wheels) for yasm 0.1.0a1
File Interpreter ABI Platform
yasm-0.1.0a1-py2.py3-none-any.whl Python 3, Python 2 none any Details

Release files / yasm-0.1.0a1-py2.py3-none-any.whl

Download URL yasm-0.1.0a1-py2.py3-none-any.whl
Size 13.6 kB
Tags Python 2 Python 3
SHA-256 checksum
How to use checksums
268aaee7a0e35da90183687c8393a41cba6d2bccfaecd37905386ede9e81976c
BLAKE2b-256 checksum
How to use checksums
e3a23a9e6b11dad093dcd0232b565b06fefa97e8c40bf7b834bb123dd989dc46
Upload date
Uploaded using Trusted Publishing?
What is 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

Security for yasm 0.1.0a1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page