Registry / workflow / automat

automat

JSON →
library25.4.16pypypi✓ verified 25d ago

Automat provides a declarative, self-service API for defining finite-state machines directly within your Python classes. It helps manage complex state transitions and actions in a structured, testable way. The current version is 25.4.16, and it maintains a relatively stable release cadence with minor updates and bug fixes.

pip install automat
INSTALL
IMPORT
SIG · AUTOMAT
A
automat
workflowpythonv25.4.16
Install
1.5s avg
Import
68ms
Disk
16MB
Pass rate
10/ 10
Env Coverage10 / 10
glibc
3.93.13
musl
3.93.13
Install & Compatibility
Where this runs
tested against v25.4.16 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
py 3.103.95 runs
installs and imports cleanly · install 0.0s · import 0.074s · 18.2MB
glibc
py 3.103.95 runs
installs and imports cleanly · install 1.5s · import 0.062s · 19MB
16MB installed
● package 16MB
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

MethodicalMachine
from automat import MethodicalMachine

This quickstart demonstrates how to define a simple state machine for a door with 'closed' and 'open' states, and 'open_door'/'close_door' inputs. It also shows how to associate outputs (actions) with state transitions and how to initialize and interact with the machine.

from automat import MethodicalMachine class Door(object): _machine = MethodicalMachine() @_machine.state() def closed(self): "The door is closed." @_machine.state() def open(self): "The door is open." @_machine.input() def open_door(self): "Open the door." @_machine.input() def close_door(self): "Close the door." @_machine.output() def _actuallyOpen(self): print("The door opens.") @_machine.output() def _actuallyClose(self): print("The door closes.") closed.upon(open_door, enter=open, outputs=[_actuallyOpen]) open.upon(close_door, enter=closed, outputs=[_actuallyClose]) def __init__(self): # Crucial: Initialize the machine with an initial state self._machine.initial(self, self.closed) # Example usage: d = Door() print(f"Initial state: {d._machine.current_state(d)._name}") d.open_door() print(f"After open_door: {d._machine.current_state(d)._name}") d.close_door() print(f"After close_door: {d._machine.current_state(d)._name}")
Debug
Known issues
gotchaFailing to call `_machine.initial(self, self.initial_state)` in your class's `__init__` method will result in an uninitialized state machine, preventing any transitions.
fix
Always ensure your class's `__init__` explicitly calls `self._machine.initial(self, self.your_initial_state)` to set the starting state.
affects: All versions
gotchaWhen defining transitions with `state.upon(input, ...)` if `enter` is omitted, the machine will remain in the *current* state by default. This can be unexpected if you intended a state change.
fix
Always explicitly specify the `enter` argument in `state.upon` if you intend for the machine to transition to a new state. If you mean to stay in the current state, `enter=self.current_state` (or omitting `enter`) is correct.
affects: All versions
gotchaOutput methods (decorated with `@_machine.output()`) are instance methods and receive `self` as their first argument. They are called in the context of the instance, allowing them to access and modify instance attributes.
fix
Design your output methods to accept `self` and use it to interact with the object's internal state or perform side effects directly related to the object.
affects: All versions
gotchaAutomat discourages directly modifying the machine's state outside of defined inputs and transitions. Attempting to do so breaks the FSM's contract and can lead to unpredictable behavior.
fix
Always drive state changes through the defined `@_machine.input()` methods. If you need to expose internal state, do so via read-only properties or specific queries, not direct manipulation.
affects: All versions
Errors
Common errors & fixes
ModuleNotFoundError: No module named 'automat'
The 'automat' package is not installed in the Python environment.
fix
Install the package using pip: 'pip install automat'.
ImportError: cannot import name 'MethodicalMachine' from 'automat'
The 'MethodicalMachine' class is not found in the 'automat' module, possibly due to an incorrect import statement or version mismatch.
fix
Ensure you are using the correct import statement: 'from automat import MethodicalMachine'.
AttributeError: module 'automat' has no attribute 'MethodicalMachine'
The 'MethodicalMachine' attribute does not exist in the 'automat' module, likely due to an outdated version or incorrect installation.
fix
Verify the installed version of 'automat' and update if necessary: 'pip install --upgrade automat'.
automat.errors.NoTransition: Cannot transition <current_state_name> with input <input_method_name>
The state machine received an input (via an `@machine.input()` decorated method) for which there is no defined transition from its current state.
fix
You must define a valid transition for the given input from the current state using `@current_state.upon(input_method, enter=next_state_method, outputs=[output_method1, ...])` or ensure the input is called only when a transition is expected.
TypeError: 'NoneType' object is not callable (or similar errors when handling output values)
By default, if multiple output methods are triggered by a transition, `automat` collects their return values into a list. If an output method does not explicitly return a value, it implicitly returns `None`, which will be part of this list. Developers might incorrectly assume a single return value or fail to handle the `None` if an output doesn't produce one.
fix
Explicitly define how output values are collected using the `collector` argument in `@state.upon()`, or ensure your code correctly handles a list of return values, including potential `None`s, from the input call. Example for `collector`: `@state.upon(some_input, enter=next_state, outputs=[some_output], collector=lambda results: results[0] if results else None)`.
Upgrade
Version history
25.4.16latest on PyPI · released Apr 16, 2025
Audit
Dependencies

No dependency data recorded yet.

Agent activity
45 hits · last 30 days
node
42
OpenAI (training)
1
Resources