Skip to main content

Lightweight, decorator-based implementation of a Finite State Machine

Project description

Finite State Machine Banner

Finite State Machine

Latest Release Supports Python 3.6+ License: MIT Code Style: Black

Build Status codecov

Lightweight, decorator-based Python implementation of a Finite State Machine.

Table of Contents

Installation

pip install finite-state-machine

Usage

Subclass StateMachine and set the state instance variable:

from finite_state_machine import StateMachine, transition

class LightSwitch(StateMachine):
    def __init__(self):
        self.state = "off"
        super().__init__()

The transition decorator can be used to specify valid state transitions with an optional parameter for conditions. States can be of type: string, int, bool, Enum, or IntEnum. Can specify a single sate or a list of states for the source parameter; can only specify a single state as the target target. All condition functions need to return True for the transition to occur, else a ConditionsNotMet exception will be raised. Condition functions require the same positional position and keyword arguments present in the transition function.

    @transition(source="off", target="on", conditions=[light_is_off])
    def turn_on(self):
        # specify side effects

def light_is_off(machine):
    return machine.state == "off"

Can also specify an on_error parameter to handle situations where the transition function raises an exception:

    @transition(source="off", target="on", on_error="failed")
    def turn_on(self):
        raise ValueError

Example

from finite_state_machine import StateMachine, transition

class Turnstile(StateMachine):
    initial_state = "close"

    def __init__(self):
        self.state = self.initial_state
        super().__init__()

    @transition(source=["close", "open"], target="open")
    def insert_coin(self):
        pass

    @transition(source="open", target="close")
    def pass_thru(self):
        pass

REPL

In [2]: turnstile = Turnstile()

In [3]: turnstile.state
Out[3]: 'close'

In [4]: turnstile.insert_coin()

In [5]: turnstile.state
Out[5]: 'open'

In [6]: turnstile.insert_coin()

In [7]: turnstile.state
Out[7]: 'open'

In [8]: turnstile.pass_thru()

In [9]: turnstile.state
Out[9]: 'close'

In [10]: turnstile.pass_thru()
---------------------------------------------------------------------------
InvalidStartState                         Traceback (most recent call last)
<ipython-input-10-6abc6f4be1cd> in <module>
----> 1 turnstile.pass_thru()

~/state_machine.py in _wrapper(*args, **kwargs)
     32
     33             if self.state not in source:
---> 34                 raise InvalidStartState
     35
     36             for condition in conditions:

InvalidStartState:

The examples folder contains additional workflows.

State Diagram

State Machine workflows can be visualized using a state diagram.

finite-state-machine generates diagrams using Mermaid Markdown syntax, which can be viewed using the Mermaid Live Editor.

Use the fsm_draw_state_diagram command and point to State Machine workflow class that inheritences from StateMachine.

# class parameter is required
$ fsm_draw_state_diagram --class examples.turnstile:Turnstile

# initial_state parameter is optional
$ fsm_draw_state_diagram --class examples.turnstile:Turnstile --initial_state close

Contributing

  1. Clone repo
  2. Create a virtual environment
  3. pip install -r requirements_dev.txt
  4. Install pre-commit
  5. Set up pre-commit hooks in repo: pre-commit install

To install a package locally for development, run:

flit install [--symlink] [--python path/to/python]

Running Tests

pytest

Inspiration

This project is inspired by django-fsm. I wanted a decorator-based state machine without having to use Django.

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

finite-state-machine-0.5.0.tar.gz (2.4 MB view details)

Uploaded Source

Built Distribution

finite_state_machine-0.5.0-py3-none-any.whl (7.1 kB view details)

Uploaded Python 3

File details

Details for the file finite-state-machine-0.5.0.tar.gz.

File metadata

  • Download URL: finite-state-machine-0.5.0.tar.gz
  • Upload date:
  • Size: 2.4 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: python-requests/2.23.0

File hashes

Hashes for finite-state-machine-0.5.0.tar.gz
Algorithm Hash digest
SHA256 ac08e609315e1c8ee1b374ddfb275820efb1cf8ea0a58c47699dfc8bee36f8a1
MD5 338ef280808fab9f7ad9090cfdf267dd
BLAKE2b-256 c982cdf07d9673999c8c03c0e8405d8be57b6b8efb36c57fe45db8164c51eff7

See more details on using hashes here.

File details

Details for the file finite_state_machine-0.5.0-py3-none-any.whl.

File metadata

File hashes

Hashes for finite_state_machine-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9ad1e513e672f3ffda2ef06cb0504c9e1621ea7b13ab9d3ceefa77f88c12399c
MD5 cc4f5f7c9de475799adad04187ba794a
BLAKE2b-256 bc4457f4908755d25aa8400ec773c0a7f43178a9cc2daa7a1f7dcdb753edb7ab

See more details on using hashes here.

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