# simplestate
**Simplestate** helps developers create and manage finite state machines in the simplest way possible—focusing solely on states and transitions, leaving out complex event systems.
## Features
- Focus on states and transitions.
- Minimalistic and easy to use.
- Supports entering-state handlers for additional functionality.
## Installation
To install simplestate,
use poetry:
```bash
poetry add simplestate
```
use pip:
```bash
pip install simplestate
```
## Usage Example
Here's a basic example of using **simplestate**:
m[`state`] + `action` >> `next_state`
```python
from simplestate import StateMachine
m = StateMachine("loading") # Define the machine with an initial state
m["loading"] + "error" >> "failed" # Transition from loading to failed on "error"
m["loading"] + "ok" >> "success" # Transition from loading to success on "ok"
m["?"] + "back" >> "loading" # Any state transitions to loading on "back"
# Start the machine
m.start() # adjust inital state by this m.start(at_state="ok")
assert m.current == "loading"
# Trigger transitions
m.handle("ok")
assert m.current == "success"
m.handle("back")
assert m.current == "loading"
m.handle("back")
assert m.current == "loading"
# Trigger transitions with context
m.handle("error", error="Something went wrong")
assert m.current == "failed"
```
## Why Simplestate?
The goal of **simplestate** is to keep finite state machines simple and focused. By eliminating complex event systems, you can easily manage states and transitions while keeping the code testable and maintainable.
### Event Handling on State Entry
Simplestate allows event handling when entering a state using `.add_callbacks()`. These callbacks take `previous` and an optional `**input_context`.
```python
# Add handlers for entering states
m.add_callbacks({
"loading": lambda previous: print(f"{previous} >> loading"),
"failed": lambda previous, **input_context: print(f"{previous} >> failed: {input_context['error']}"),
"success": lambda previous: print(f"{previous} >> success"),
})
```
## FAQ
**Q: How can I handle state exit events?**
A: You can use the entering handler for the next state to handle actions when leaving the previous state.
```python
def on_state_x(previous, **input_context):
if previous == "a":
do_this()
elif previous == "b":
do_that()
```
**Q: Can I represent the state machine as a class?**
A: Yes! Think of simplestate as a state manager. You can compose it within your own class for handling side effects:
```python
class TrafficLight:
def __init__(self):
m = StateMachine("red")
m["red"] + "next" >> "green"
m["green"] + "next" >> "yellow"
m["yellow"] + "next" >> "red"
m.start()
self.machine = m
def display(self) -> str:
return self.machine.current
def next(self) -> None:
self.machine.handle("next")
if __name__ == '__main__':
light = TrafficLight()
while True:
state = light.display()
print(state)
# pause for a few seconds
match state:
case "red" | "green":
time.sleep(30)
case "yellow":
time.sleep(5)
# transition
light.next()
```
## Tests
To run the tests:
```bash
poetry install --with test
poetry run pytest
```
## Contribution
Contributions are welcome! Feel free to open an issue or submit a pull request.
1. Install [devcontainer](https://code.visualstudio.com/docs/devcontainers/containers)
2. Open this project in dev container
3. Run `poetry shell`
4. Run `poetry install --with test`
5. Run `poetry run pytest`
## License
This project is licensed under a free, open-source license.
Raw data
{
"_id": null,
"home_page": "https://pypi.org/project/simplestate",
"name": "simplestate",
"maintainer": null,
"docs_url": null,
"requires_python": "<4.0,>=3.10",
"maintainer_email": null,
"keywords": "finite state machine, simplestate",
"author": "panupong-puttarathamrongkul",
"author_email": "54784627+panupong-puttarathamrongkul@users.noreply.github.com",
"download_url": "https://files.pythonhosted.org/packages/d9/2d/01f0b32ad2d7d30dab90431b3cf0026679a8532a6ea46498c3efd2ac8864/simplestate-0.1.5.tar.gz",
"platform": null,
"description": "# simplestate\n\n**Simplestate** helps developers create and manage finite state machines in the simplest way possible\u2014focusing solely on states and transitions, leaving out complex event systems.\n\n## Features\n\n- Focus on states and transitions.\n- Minimalistic and easy to use.\n- Supports entering-state handlers for additional functionality.\n\n## Installation\n\nTo install simplestate, \n\nuse poetry:\n\n```bash\npoetry add simplestate\n```\n\nuse pip:\n```bash\npip install simplestate\n```\n\n## Usage Example\n\nHere's a basic example of using **simplestate**:\n\nm[`state`] + `action` >> `next_state`\n\n```python\nfrom simplestate import StateMachine\n\nm = StateMachine(\"loading\") # Define the machine with an initial state\nm[\"loading\"] + \"error\" >> \"failed\" # Transition from loading to failed on \"error\"\nm[\"loading\"] + \"ok\" >> \"success\" # Transition from loading to success on \"ok\"\nm[\"?\"] + \"back\" >> \"loading\" # Any state transitions to loading on \"back\"\n\n# Start the machine\nm.start() # adjust inital state by this m.start(at_state=\"ok\")\nassert m.current == \"loading\"\n\n# Trigger transitions\nm.handle(\"ok\")\nassert m.current == \"success\"\n\nm.handle(\"back\")\nassert m.current == \"loading\"\n\nm.handle(\"back\")\nassert m.current == \"loading\"\n\n# Trigger transitions with context\nm.handle(\"error\", error=\"Something went wrong\")\nassert m.current == \"failed\"\n```\n\n## Why Simplestate?\n\nThe goal of **simplestate** is to keep finite state machines simple and focused. By eliminating complex event systems, you can easily manage states and transitions while keeping the code testable and maintainable.\n\n### Event Handling on State Entry\n\nSimplestate allows event handling when entering a state using `.add_callbacks()`. These callbacks take `previous` and an optional `**input_context`.\n```python\n# Add handlers for entering states\nm.add_callbacks({\n \"loading\": lambda previous: print(f\"{previous} >> loading\"),\n \"failed\": lambda previous, **input_context: print(f\"{previous} >> failed: {input_context['error']}\"),\n \"success\": lambda previous: print(f\"{previous} >> success\"),\n})\n```\n\n## FAQ\n\n**Q: How can I handle state exit events?** \nA: You can use the entering handler for the next state to handle actions when leaving the previous state.\n\n```python\ndef on_state_x(previous, **input_context):\n if previous == \"a\":\n do_this()\n elif previous == \"b\":\n do_that()\n```\n\n**Q: Can I represent the state machine as a class?** \nA: Yes! Think of simplestate as a state manager. You can compose it within your own class for handling side effects:\n\n```python\nclass TrafficLight:\n def __init__(self):\n m = StateMachine(\"red\")\n m[\"red\"] + \"next\" >> \"green\"\n m[\"green\"] + \"next\" >> \"yellow\"\n m[\"yellow\"] + \"next\" >> \"red\"\n m.start()\n\n self.machine = m\n\n def display(self) -> str:\n return self.machine.current\n\n def next(self) -> None:\n self.machine.handle(\"next\")\n\nif __name__ == '__main__':\n light = TrafficLight()\n\n while True:\n state = light.display()\n print(state)\n\n # pause for a few seconds\n match state:\n case \"red\" | \"green\":\n time.sleep(30)\n case \"yellow\":\n time.sleep(5)\n\n # transition\n light.next()\n```\n\n## Tests\n\nTo run the tests:\n\n```bash\npoetry install --with test\npoetry run pytest\n```\n\n## Contribution\n\nContributions are welcome! Feel free to open an issue or submit a pull request.\n\n1. Install [devcontainer](https://code.visualstudio.com/docs/devcontainers/containers)\n2. Open this project in dev container\n3. Run `poetry shell`\n4. Run `poetry install --with test`\n5. Run `poetry run pytest`\n\n## License\n\nThis project is licensed under a free, open-source license.\n\n",
"bugtrack_url": null,
"license": "Apache-2.0",
"summary": "A simple stupid, declarative finite state machine for Python.",
"version": "0.1.5",
"project_urls": {
"Homepage": "https://pypi.org/project/simplestate",
"Repository": "https://github.com/panupong-develop/simplestate"
},
"split_keywords": [
"finite state machine",
" simplestate"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "513fcb92fa4c159528531fdd74eac0f88453f5fac1f6ccd4cb7799b16da38c83",
"md5": "cf9beb125c55ed04617b4b227d1b0ac5",
"sha256": "bea93fbcaa758588257c79c56a28293ee753512e771971dcf10032d48b4d3993"
},
"downloads": -1,
"filename": "simplestate-0.1.5-py3-none-any.whl",
"has_sig": false,
"md5_digest": "cf9beb125c55ed04617b4b227d1b0ac5",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.10",
"size": 8163,
"upload_time": "2024-08-19T04:38:20",
"upload_time_iso_8601": "2024-08-19T04:38:20.364920Z",
"url": "https://files.pythonhosted.org/packages/51/3f/cb92fa4c159528531fdd74eac0f88453f5fac1f6ccd4cb7799b16da38c83/simplestate-0.1.5-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "d92d01f0b32ad2d7d30dab90431b3cf0026679a8532a6ea46498c3efd2ac8864",
"md5": "8bf8e0257e48c20b4bf087a0663032ae",
"sha256": "c07ee32da4220184d6718c245ef7ad642141741adb1f44282c3d98e494df713e"
},
"downloads": -1,
"filename": "simplestate-0.1.5.tar.gz",
"has_sig": false,
"md5_digest": "8bf8e0257e48c20b4bf087a0663032ae",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.10",
"size": 7202,
"upload_time": "2024-08-19T04:38:21",
"upload_time_iso_8601": "2024-08-19T04:38:21.708341Z",
"url": "https://files.pythonhosted.org/packages/d9/2d/01f0b32ad2d7d30dab90431b3cf0026679a8532a6ea46498c3efd2ac8864/simplestate-0.1.5.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-08-19 04:38:21",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "panupong-develop",
"github_project": "simplestate",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "simplestate"
}