Utility to turn your class into a state machine
Project description
Fusion StateMachine
Many thanks to the original creator of this wonderful library, Fusion StateMachine intended for the development of applications for real-time event lighting via DMX, the starting point is a fork from the simple-state-machine library
It is a python library with which you can
decorate your class to make it a state machine.
Installation
pip install simple-state-machine
State Machine
A state machine which has a finite set of states is called a finite state machine. The one which doesn't have finite states is called a non-finite state machine.
A finite state machine is a mathematical concept in which the machine has a state and uses transitions to move from one state to another. Finite state machines can be of 2 types - deterministic and non-deterministic
A deterministic finite state machine produces the same result after given transitions, hence we can "determine" and so the name. In a non-deterministic finite state machine, for some state and input symbol, the next state may be nothing or one or two or more possible states.
This library provides a deterministic finite state machine.
Basic Usage
from state_machine.machine import machine, transition
@machine(states=["earth", "space"])
class Rocket(object):
def __init__(self):
self.moving = False
# Mandatory to define this method
def load_state(self):
return "space" if self.moving else "earth"
@transition(sources=["earth"], destination="space")
def launch(self):
self.moving = True
rocket = Rocket()
# assert m.current_state == "earth"
rocket.launch()
# assert m.current_state == "space"
rocket.launch()
# InvalidMoveError: Current state - space is not in source states - earth
Note
A data member current_state is added to your class' object. You may use its value to assert in decisions or in your tests.
What if my function has 2(or more) possible transitions?
It is quite common to have functions which have 2 or more possible transitions.
For eg. You are collecting a payment for an order. If the payment is valid, you want to complete the payment, else you want to fail it.
from state_machine.machine import machine, transition
@machine(states=["INIT", "PAYMENT_IN_PROGRESS", "PAYMENT_COMPLETE", "PAYMENT_FAILED"])
class Order:
def __init__(self):
self.payment = ""
def load_state(self):
if not self.payment:
return "INIT"
if self.payment == "SUCCESS":
return "PAYMENT_COMPLETE"
if self.payment == "FAILED":
return "PAYMENT_FAILED"
return "PAYMENT_IN_PROGRESS"
@transition(sources=["INIT"], destination="PAYMENT_IN_PROGRESS")
def create_payment_request(self):
self.payment = "IN_PROGRESS"
def collect_payment(self, payment):
assert self.load_state() == "PAYMENT_IN_PROGRESS"
if payment == "SUCCESS":
self.payment_success()
elif payment == "FAILED":
self.payment_failed()
@transition(sources=["PAYMENT_IN_PROGRESS"], destination="PAYMENT_COMPLETE")
def payment_success(self):
self.payment = "SUCCESS"
@transition(sources=["PAYMENT_IN_PROGRESS"], destination="PAYMENT_FAILED")
def payment_failed(self):
self.payment = "FAILED"
order1 = Order()
# assert order.current_state == "INIT"
order1.create_payment_request()
# assert order.current_state == "PAYMENT_IN_PROGRESS"
order1.collect_payment("SUCCESS")
# assert order.current_state == "PAYMENT_COMPLETE"
order2 = Order()
# assert order.current_state == "INIT"
order2.create_payment_request()
# assert order.current_state == "PAYMENT_IN_PROGRESS"
order2.collect_payment("FAILED")
# assert order.current_state == "PAYMENT_FAILED"
Note
Decision is not a concept in deterministic FSMs, hence we won't be supporting it. This means you will have to assert the current state for a decision accordingly.
Error Handling
The library raises the following errors.
LoaderNotFound- If your class doesn't implement a load_state method.LoaderException- If the load_state method threw an exception.MachineNotFound- If you used a transition decorator on a method whose class is not machine decorated.InvalidStateError- This is raised when the state machine encounters an unknown state. The state machine raises this error in 2 situations. One, when load_state returns an invalid state. And, when you pass invalid source or destination in a transition.InvalidMoveError- It is raised when you enter a transition with a non-source state.UnintendedOperationError- The state machine calls load_state function after each transition to ensure that the state has been updated to the destination. If a transition doesn't update the state of the machine to destination, this error is raised. For eg-
@transition(source=["earth"], destination="sky")
def launch(self):
pass # the function didn't do anything.
Developer's Guide
Setup
We use pipenv to manage python packages. To setup your dev environment, locate yourself in the project directory and execute
pipenv install --dev
pipenv shell
Testing mode
make tests
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 Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fusion_state_machine-0.1.4.tar.gz.
File metadata
- Download URL: fusion_state_machine-0.1.4.tar.gz
- Upload date:
- Size: 6.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.0.1 CPython/3.12.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
329f20f7d9c94547f3242910795543b4664b5673d6aea98f555fac0bc0561949
|
|
| MD5 |
7549c188b2c151f4f31fa0815c8de5e2
|
|
| BLAKE2b-256 |
b44ec5d314eecbfdb1e6d30a5bdb2a1c4c77d06327d30282b4db7bd36d4ff099
|
Provenance
The following attestation bundles were made for fusion_state_machine-0.1.4.tar.gz:
Publisher:
python-publish.yml on Jisus17/Fusion-State-Machine
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fusion_state_machine-0.1.4.tar.gz -
Subject digest:
329f20f7d9c94547f3242910795543b4664b5673d6aea98f555fac0bc0561949 - Sigstore transparency entry: 157382436
- Sigstore integration time:
-
Permalink:
Jisus17/Fusion-State-Machine@204e3e05939a974fee3495b99f80d36224fec76f -
Branch / Tag:
refs/tags/v0.1.4 - Owner: https://github.com/Jisus17
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@204e3e05939a974fee3495b99f80d36224fec76f -
Trigger Event:
release
-
Statement type:
File details
Details for the file Fusion_State_Machine-0.1.4-py3-none-any.whl.
File metadata
- Download URL: Fusion_State_Machine-0.1.4-py3-none-any.whl
- Upload date:
- Size: 6.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.0.1 CPython/3.12.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
10942bfea1c844da895cf353f84a5f0d23b48b9bb78984073982a44e581dd701
|
|
| MD5 |
a2ff25b5bf34ef74f95e7657dff972da
|
|
| BLAKE2b-256 |
913bff1d9e75d5cf89c5f9a1ab6fc6f481d2b218654f34e0fe2a5274fda47f5e
|
Provenance
The following attestation bundles were made for Fusion_State_Machine-0.1.4-py3-none-any.whl:
Publisher:
python-publish.yml on Jisus17/Fusion-State-Machine
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fusion_state_machine-0.1.4-py3-none-any.whl -
Subject digest:
10942bfea1c844da895cf353f84a5f0d23b48b9bb78984073982a44e581dd701 - Sigstore transparency entry: 157382437
- Sigstore integration time:
-
Permalink:
Jisus17/Fusion-State-Machine@204e3e05939a974fee3495b99f80d36224fec76f -
Branch / Tag:
refs/tags/v0.1.4 - Owner: https://github.com/Jisus17
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@204e3e05939a974fee3495b99f80d36224fec76f -
Trigger Event:
release
-
Statement type: