# Statomata
[](https://pypi.python.org/pypi/statomata)
[](https://pypi.python.org/pypi/statomata)
[](https://mypy.readthedocs.io/en/stable/getting_started.html#strict-mode-and-configuration)
[](https://codecov.io/gh/zerlok/statomata)
[](https://pypistats.org/packages/statomata)
[](https://github.com/zerlok/statomata/stargazers)
**Statomata** is a strictly typed, flexible library for building and running finite state machines (FSMs) and automata
in Python. It provides core automata implementations out of the box and lets you define custom states and state
management logic.
## Features
- 🧠 **State Interface & Context:** Follow the state machine OOP pattern with clear, isolated state definitions.
- ⚡ **Built-in Automata:** feel free to use one of the predefined automata classes from SDK (sync / async; unary /
iterable)
- 🏗 **Custom Automata Support:** Build your own automata with custom state management logic. You can choose declarative
style or built custom automata using provided interfaces.
- ✅ **Strict Typing:** Designed for type safety and clarity with full type hints.
## Installation
```bash
pip install statomata
```
## Quick Start
Use high-level declarative style:
```python
from statomata.declarative import DeclarativeStateMachine, State
class OpenCloseExample(DeclarativeStateMachine):
closed = State(initial=True)
opened = State()
@closed.to(opened)
def open(self) -> str:
return "Opened"
@opened.to(closed)
def close(self) -> str:
return "Closed"
```
Run the state machine:
```python
from contextlib import suppress
from statomata.exception import InvalidStateError
sm = OpenCloseExample()
print(sm.open()) # Output: Opened
print(sm.close()) # Output: Closed
with suppress(InvalidStateError):
sm.close()
```
Or you can use low-level style:
```python
from statomata.abc import State, Context
from statomata.exception import InvalidStateError
class OpenState(State[str, str]):
def handle(self, income: str, context: Context[State[str, str]]) -> str:
if income != "close":
raise InvalidStateError(self, message="already opened")
context.set_state(ClosedState())
return "Closed"
class ClosedState(State[str, str]):
def handle(self, income: str, context: Context[State[str, str]]) -> str:
if income != "open":
raise InvalidStateError(self, message="already closed")
context.set_state(OpenState())
return "Opened"
```
Run the state machine:
```python
from contextlib import suppress
from statomata.exception import InvalidStateError
from statomata.sdk import create_unary_sm
sm = create_unary_sm(ClosedState())
print(sm.run("open")) # Output: Opened
print(sm.run("close")) # Output: Closed
with suppress(InvalidStateError):
sm.run("close")
```
## Examples
* order control
* [low level](examples/state_machines/order_control_low_level.py)
* [high level](examples/state_machines/order_control.py)
* [positive number store](examples/state_machines/positive_number_store.py)
* [traffic light](examples/state_machines/traffic_light_low_level.py)
* [transition cases](examples/state_machines/transition_cases.py)
* [outcome cases](examples/state_machines/outcome_cases.py)
* [anyio cases](examples/state_machines/anyio_cases.py)
Raw data
{
"_id": null,
"home_page": null,
"name": "statomata",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.9",
"maintainer_email": null,
"keywords": "python, automata, fsm, asyncio, finite-state-machine, fsm-library",
"author": "zerlok",
"author_email": "danil.troshnev@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/43/75/b1538fc24fa63a0027cc394860f8af5600e6752d28724353680f6303449b/statomata-0.3.2.tar.gz",
"platform": null,
"description": "# Statomata\n\n[](https://pypi.python.org/pypi/statomata)\n[](https://pypi.python.org/pypi/statomata)\n[](https://mypy.readthedocs.io/en/stable/getting_started.html#strict-mode-and-configuration)\n[](https://codecov.io/gh/zerlok/statomata)\n[](https://pypistats.org/packages/statomata)\n[](https://github.com/zerlok/statomata/stargazers)\n\n**Statomata** is a strictly typed, flexible library for building and running finite state machines (FSMs) and automata\nin Python. It provides core automata implementations out of the box and lets you define custom states and state\nmanagement logic.\n\n## Features\n\n- \ud83e\udde0 **State Interface & Context:** Follow the state machine OOP pattern with clear, isolated state definitions.\n- \u26a1 **Built-in Automata:** feel free to use one of the predefined automata classes from SDK (sync / async; unary /\n iterable)\n- \ud83c\udfd7 **Custom Automata Support:** Build your own automata with custom state management logic. You can choose declarative\n style or built custom automata using provided interfaces.\n- \u2705 **Strict Typing:** Designed for type safety and clarity with full type hints.\n\n## Installation\n\n```bash\npip install statomata\n```\n\n## Quick Start\n\nUse high-level declarative style:\n\n```python\nfrom statomata.declarative import DeclarativeStateMachine, State\n\n\nclass OpenCloseExample(DeclarativeStateMachine):\n closed = State(initial=True)\n opened = State()\n\n @closed.to(opened)\n def open(self) -> str:\n return \"Opened\"\n\n @opened.to(closed)\n def close(self) -> str:\n return \"Closed\"\n```\n\nRun the state machine:\n\n```python\nfrom contextlib import suppress\nfrom statomata.exception import InvalidStateError\n\nsm = OpenCloseExample()\n\nprint(sm.open()) # Output: Opened\nprint(sm.close()) # Output: Closed\n\nwith suppress(InvalidStateError):\n sm.close()\n```\n\nOr you can use low-level style:\n\n```python\nfrom statomata.abc import State, Context\nfrom statomata.exception import InvalidStateError\n\n\nclass OpenState(State[str, str]):\n def handle(self, income: str, context: Context[State[str, str]]) -> str:\n if income != \"close\":\n raise InvalidStateError(self, message=\"already opened\")\n\n context.set_state(ClosedState())\n return \"Closed\"\n\n\nclass ClosedState(State[str, str]):\n def handle(self, income: str, context: Context[State[str, str]]) -> str:\n if income != \"open\":\n raise InvalidStateError(self, message=\"already closed\")\n\n context.set_state(OpenState())\n return \"Opened\"\n```\n\nRun the state machine:\n\n```python\nfrom contextlib import suppress\n\nfrom statomata.exception import InvalidStateError\nfrom statomata.sdk import create_unary_sm\n\nsm = create_unary_sm(ClosedState())\n\nprint(sm.run(\"open\")) # Output: Opened\nprint(sm.run(\"close\")) # Output: Closed\n\nwith suppress(InvalidStateError):\n sm.run(\"close\")\n```\n\n## Examples\n\n* order control\n * [low level](examples/state_machines/order_control_low_level.py)\n * [high level](examples/state_machines/order_control.py)\n* [positive number store](examples/state_machines/positive_number_store.py)\n* [traffic light](examples/state_machines/traffic_light_low_level.py)\n* [transition cases](examples/state_machines/transition_cases.py)\n* [outcome cases](examples/state_machines/outcome_cases.py)\n* [anyio cases](examples/state_machines/anyio_cases.py)\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "a strictly typed, flexible library for building and running state machines in Python",
"version": "0.3.2",
"project_urls": {
"Homepage": "https://github.com/zerlok/statomata",
"Issues": "https://github.com/zerlok/statomata/issues"
},
"split_keywords": [
"python",
" automata",
" fsm",
" asyncio",
" finite-state-machine",
" fsm-library"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "e378ba6ea0750d74c2ab9ec19fb5afd6016bcf3f4fa8d41bd2e45bb2df3b771c",
"md5": "0ff16a7d33f43265121f2856376b66ef",
"sha256": "b5b7e5fce3317d5dd5439485623e88b8377a1d38d12bae302197895c2f39c081"
},
"downloads": -1,
"filename": "statomata-0.3.2-py3-none-any.whl",
"has_sig": false,
"md5_digest": "0ff16a7d33f43265121f2856376b66ef",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.9",
"size": 23085,
"upload_time": "2025-08-02T17:28:55",
"upload_time_iso_8601": "2025-08-02T17:28:55.363112Z",
"url": "https://files.pythonhosted.org/packages/e3/78/ba6ea0750d74c2ab9ec19fb5afd6016bcf3f4fa8d41bd2e45bb2df3b771c/statomata-0.3.2-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "4375b1538fc24fa63a0027cc394860f8af5600e6752d28724353680f6303449b",
"md5": "8a4d09ec2af5953ad34a94a13d37d1a7",
"sha256": "b2a2cfeed20ff1d8b4d3c016a7b3ff889c6e66e724f0de4ffa2d24c50a7467b2"
},
"downloads": -1,
"filename": "statomata-0.3.2.tar.gz",
"has_sig": false,
"md5_digest": "8a4d09ec2af5953ad34a94a13d37d1a7",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.9",
"size": 18313,
"upload_time": "2025-08-02T17:28:56",
"upload_time_iso_8601": "2025-08-02T17:28:56.935444Z",
"url": "https://files.pythonhosted.org/packages/43/75/b1538fc24fa63a0027cc394860f8af5600e6752d28724353680f6303449b/statomata-0.3.2.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-02 17:28:56",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "zerlok",
"github_project": "statomata",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "statomata"
}