A simple, decorator-based, transition-focused Finite State Machine implementation.
Project description
Fineas
A simple, thread-safe, decorator-based, transition-focused Finite State Machine implementation.
Possible Use Cases:
- Configuration management from multiple sources.
- Keeping track of state during complex system startup.
- Tracking state while parsing.
from fineas import state_machine
@state_machine(initial_state='new', store_history=True)
class TestMachine:
def __init__(self):
self.config = None
@state_machine.transition(
source=['new', 'invalid_configuration'],
dest='configured',
error_state='invalid_configuration')
def got_config(self, config):
# validate config
self.config = config
@state_machine.transition(source='configured', dest='scheduled')
def ready(self):
pass
@state_machine.transition(
source='scheduled',
dest='scheduled',
error_state='canceled',
failed_state='retry')
def run(self, fail_transition):
# do work
status = self._do_work()
if not status:
fail_transition()
@state_machine.transition(
source='retry',
dest='run',
error_state='canceled',
failed_state='too_many_failures'
)
def try_again(self, times, fail_transition):
for i in range(times):
if self._do_work():
return
fail_transition()
@state_machine.transition(
source=['retry', 'too_many_failures'],
dest='cancelled'
)
def abandon(self):
pass
@state_machine.transition(
source='too_many_failures',
dest='configured'
)
def reconfigure(self, config):
self.config = config
def _do_work(self):
pass
t = TestMachine()
t.got_config(None)
t.ready()
t.run()
t.try_again(3)
t.abandon()
print(t.history)
print(t.state)
Quickstart
- Decorate a class with
@fineas.state_machine(initial_state='new'). You must pass a value forinitial_state. - Define a method that implements the work required to transition form one or more source states
to a single destination state. Decorate that method with
@fineas.transition(source='new', dest='ready'). - That's it! Each instance of your decorated class is its own state machine. You may check its
current state with its
stateattribute, and, if you've enabledrecord_history, you can access its transition history with itshistoryattribute.
Overview
To turn each instance of a class into a state machine, simply decorate it with
@fineas.state_machine(). You must pass an initial_state value to @fineas.state_machine().
This will be the state every instance of your type starts in. You can also enable recording state
transitions with the record_history flag; this is useful while developing finite state machines.
Every transition in your state machine is represented by a method inside the class you annotated
with @fineas.state_machihe(). To turn a method into a transition, decorate it with
@fineas.transition() and supply one or more source states for the transition, and exactly one
destination state. You can also define a state to transition to if an exception is raised inside
your method (there is also a flag to enable or disable re-raising that exception). If your method
accepts a parameter named fail_transition, its value will be a callable your method can invoke to
cause the transition to fail while still allowing your method to return a value to its caller. You
may also pass a fail_state parameter to the decorator, and when fail_transition is invoked, your
instance will be transitioned to the given state.
When any method annotated with @fineas.transistion() is called, the following steps happen:
- Acquire a lock over the receiving instance.
- Fineas validates that the receiving instance's state is in the sources passed to
@fineas.transition()- If it is not, a TransitionException is raised.
- The decorated method is invoked, passing
fail_transistionif able. - If the decorated method raises an exception:
- If
error_statewas passed, immediately transition to that state. - If
reraise_erroris True, re-raise the exception. - Return.
- If
- If
fail_transitionwas called:- If 'fail_state' was passed, immediately transition to that state.
- If no exception was raised and
fail_transitionwas not called, transition to the destination state and return the value returned by the decorated method.
Requirements
Python 3.6 or higher
wrapt 1.12.x
Release Notes
1.0.1 (12 March, 2021):
- Minor Cleanup
- Move to poetry
- Basic test coverage
- Bump to 1.0.0 due to no issues being found in the last year.
0.1.0 (07 March, 2021):
- Initial Release
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 fineas-1.0.1.tar.gz.
File metadata
- Download URL: fineas-1.0.1.tar.gz
- Upload date:
- Size: 9.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.1.13 CPython/3.10.2 Windows/10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fc323f0eef806fb0c6d2844c529ea24995a0f237ed78ea1af2ac9a6227cbeb56
|
|
| MD5 |
0acb0ddb1e17ec1764993722338e9575
|
|
| BLAKE2b-256 |
547658f403eb4b468dd10f160ca92ea9ac7458017105e53e1f23f46bd851251f
|
File details
Details for the file fineas-1.0.1-py3-none-any.whl.
File metadata
- Download URL: fineas-1.0.1-py3-none-any.whl
- Upload date:
- Size: 8.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/1.1.13 CPython/3.10.2 Windows/10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ebed9f79477e6e4e1f802b24369d881de8413c477033126746a9603cdd669b80
|
|
| MD5 |
562ef34892b6ff89cbdcc180f67e09f5
|
|
| BLAKE2b-256 |
7144bfd499fa9bf240c70465f83d27ab46f07ed349f49ab23e1dd1b4da222444
|