Machine definitions (parser, store, builder)¶
Use this pipeline when you want a canonical MachineDefinition (parse once, validate, store in DB) and build a StateMachine only when needed. For a single YAML file in a script, StateMachine.from_yaml() is usually enough.
See the Package structure guide for when to use each layer.
Types and parsing¶
MachineDefinition
dataclass
¶
MachineDefinition(name: str, version: str, config: dict[str, Any], states: list[dict[str, Any]] = list(), transitions: list[dict[str, Any]] = list(), description: str | None = None, strict_mode: bool = True)
A fully parsed and validated FSM machine definition.
Analogous to PyCharter's ContractMetadata — the single canonical representation that flows between parser, store, and builder.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Machine name (lowercase, underscores only). |
version |
str
|
Semantic version string. |
config |
dict[str, Any]
|
Full validated config dict (round-trip safe for persistence). |
states |
list[dict[str, Any]]
|
List of state definition dicts from config. |
transitions |
list[dict[str, Any]]
|
List of transition definition dicts from config. |
description |
str | None
|
Human-readable description. |
strict_mode |
bool
|
Whether the machine enforces strict mode. |
parse_machine
¶
parse_machine(config: dict[str, Any], *, validate: bool = True) -> MachineDefinition
Parse an FSM config dict into a MachineDefinition.
Steps: 1. Resolve submachine references (inline expansion). 2. Optionally validate via ConfigValidator (Pydantic). 3. Extract canonical meta fields (name, version, description, strict_mode). 4. Return a frozen MachineDefinition.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
dict[str, Any]
|
Raw FSM config dict (with meta, states, transitions). |
required |
validate
|
bool
|
If True, run Pydantic schema + semantic validation. |
True
|
Returns:
| Type | Description |
|---|---|
MachineDefinition
|
A validated MachineDefinition. |
Raises:
| Type | Description |
|---|---|
ConfigurationError
|
If validation fails. |
ValueError
|
If required meta fields are missing or invalid. |
Source code in src/pystator/machine_parser/parser.py
parse_machine_file
¶
parse_machine_file(path: str | Path, *, validate: bool = True, variables: dict[str, str] | None = None) -> MachineDefinition
Parse an FSM config from a YAML or JSON file.
Handles YAML/JSON detection, environment variable substitution, submachine resolution, and validation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str | Path
|
Path to .yaml, .yml, or .json file. |
required |
validate
|
bool
|
If True, run Pydantic schema + semantic validation. |
True
|
variables
|
dict[str, str] | None
|
Extra variables for ${VAR} substitution (in addition to env). |
None
|
Returns:
| Type | Description |
|---|---|
MachineDefinition
|
A validated MachineDefinition. |
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If the file does not exist. |
ConfigurationError
|
If parsing or validation fails. |
Source code in src/pystator/machine_parser/parser.py
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | |
Building runtime machines¶
build_machine
¶
build_machine(definition: MachineDefinition, *, guards: GuardRegistry | None = None, actions: ActionRegistry | None = None) -> StateMachine
Build a runtime StateMachine from a MachineDefinition.
Optionally binds guard and action registries so the machine is ready for event processing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
definition
|
MachineDefinition
|
A parsed MachineDefinition. |
required |
guards
|
GuardRegistry | None
|
Optional guard registry to bind. |
None
|
actions
|
ActionRegistry | None
|
Optional action registry to bind. |
None
|
Returns:
| Type | Description |
|---|---|
StateMachine
|
A fully configured StateMachine instance. |
Source code in src/pystator/machine_builder/builder.py
build_machine_from_store
¶
build_machine_from_store(store: MachineStoreClient, name: str, version: str | None = None, *, guards: GuardRegistry | None = None, actions: ActionRegistry | None = None) -> StateMachine
Load a machine definition from a store and build a StateMachine.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
store
|
MachineStoreClient
|
A connected MachineStoreClient. |
required |
name
|
str
|
Machine name to look up. |
required |
version
|
str | None
|
Specific version, or None for latest. |
None
|
guards
|
GuardRegistry | None
|
Optional guard registry to bind. |
None
|
actions
|
ActionRegistry | None
|
Optional action registry to bind. |
None
|
Returns:
| Type | Description |
|---|---|
StateMachine
|
A fully configured StateMachine instance. |
Raises:
| Type | Description |
|---|---|
MachineNotFoundError
|
If the machine is not in the store. |
Source code in src/pystator/machine_builder/builder.py
MachineNotFoundError
¶
Bases: Exception
Raised when a machine definition cannot be found in the store.
Source code in src/pystator/machine_builder/builder.py
Definition stores¶
MachineStoreClient
¶
Bases: ABC
Abstract base for machine definition storage.
All operations are keyed by (machine_name, version). Implementations extend this for specific backends.
Source code in src/pystator/machine_store/client.py
connect
abstractmethod
¶
disconnect
¶
save
abstractmethod
¶
save(definition: MachineDefinition) -> str
Persist a machine definition (upsert by name + version).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
definition
|
MachineDefinition
|
The parsed machine definition to store. |
required |
Returns:
| Type | Description |
|---|---|
str
|
The machine identifier (implementation-defined, e.g. UUID string). |
Source code in src/pystator/machine_store/client.py
get
abstractmethod
¶
get(name: str, version: str | None = None) -> MachineDefinition | None
Retrieve a machine definition by name and optional version.
When version is None, returns the latest version.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Machine name. |
required |
version
|
str | None
|
Specific version, or None for latest. |
None
|
Returns:
| Type | Description |
|---|---|
MachineDefinition | None
|
MachineDefinition if found, None otherwise. |
Source code in src/pystator/machine_store/client.py
list
abstractmethod
¶
list(name: str | None = None) -> list[MachineDefinition]
List machine definitions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str | None
|
If provided, filter to versions of this machine only. |
None
|
Returns:
| Type | Description |
|---|---|
list[MachineDefinition]
|
List of MachineDefinition objects. |
Source code in src/pystator/machine_store/client.py
delete
abstractmethod
¶
Delete a specific machine version.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Machine name. |
required |
version
|
str
|
Version to delete. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
True if deleted, False if not found. |
InMemoryMachineStore
¶
Bases: MachineStoreClient
Dict-backed machine store for tests, notebooks, and embedded use.
Does not require a database. Machines are stored in a dict keyed by (name, version).
Source code in src/pystator/machine_store/in_memory.py
SQLAlchemyMachineStore
¶
Bases: MachineStoreClient
Machine store backed by SQLAlchemy (PostgreSQL or SQLite).
Uses the existing pystator.machines table (MachineModel).
Source code in src/pystator/machine_store/_sqlalchemy.py
SQLAlchemyMachineStore requires SQLAlchemy (included with pystator[api] or pystator[worker]). It is also exported as from pystator.machine_store import SQLAlchemyMachineStore when dependencies are present.
Imports¶
from pystator.machine_parser import MachineDefinition, parse_machine, parse_machine_file
from pystator.machine_builder import build_machine, build_machine_from_store, MachineNotFoundError
from pystator.machine_store import MachineStoreClient, InMemoryMachineStore
# Optional, when SQLAlchemy is installed:
from pystator.machine_store import SQLAlchemyMachineStore
The same symbols are available from the top-level pystator package (from pystator import ...).