State Machine¶
Core FSM class: load config from YAML or dict, process transitions, and run guards and actions.
StateMachine
¶
StateMachine(
states: dict[str, State],
transitions: list[Transition],
meta: dict[str, Any] | None = None,
error_policy: ErrorPolicy | None = None,
)
Config-driven finite state machine definition and factory.
The StateMachine is stateless -- it holds the FSM definition
(states, transitions, guards, actions) but no per-entity state.
Use :meth:create to get a stateful :class:EntitySession.
Config is the single source of truth
- States, transitions, guards, and actions are declared in YAML/dict.
- Python implementations are bound via
@machine.guard("name")and@machine.action("name")decorators.
Source code in src/pystator/machine.py
from_yaml
classmethod
¶
from_yaml(
path: str | Path,
validate: bool = True,
variables: dict[str, str] | None = None,
) -> StateMachine
Create a StateMachine from a YAML configuration file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str | Path
|
Path to the YAML configuration file. |
required |
validate
|
bool
|
If True, validate config against schema. |
True
|
variables
|
dict[str, str] | None
|
Optional variables for |
None
|
Returns:
| Type | Description |
|---|---|
StateMachine
|
Configured StateMachine instance. |
Source code in src/pystator/machine.py
from_dict
classmethod
¶
Create a StateMachine from a configuration dictionary.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
dict[str, Any]
|
Configuration dictionary matching the schema. |
required |
Returns:
| Type | Description |
|---|---|
StateMachine
|
Configured StateMachine instance. |
Source code in src/pystator/machine.py
validate_config
classmethod
¶
Validate a configuration dict (Pydantic schema + semantic rules).
Does not build a machine. Returns a list of error messages, or an empty
list if valid. Equivalent to ConfigValidator().validate(config).
Example
errors = StateMachine.validate_config({"states": [...], "transitions": [...]}) if errors: ... raise SystemExit(errors) machine = StateMachine.from_dict(config)
Source code in src/pystator/machine.py
guard
¶
Decorator to bind a guard implementation to its config name.
Example
@machine.guard("is_valid") ... def is_valid(ctx): ... return ctx.get("valid", False)
Source code in src/pystator/machine.py
action
¶
Decorator to bind an action implementation to its config name.
Example
@machine.action("notify") ... def notify(ctx): ... send_email(ctx["email"], "State changed")
Source code in src/pystator/machine.py
on_enter
¶
Decorator to register a callback when state is entered.
Example
@machine.on_enter("shipped") ... def notify_customer(ctx): ... send_email(ctx["email"], "Your order shipped!")
Source code in src/pystator/machine.py
on_exit
¶
Decorator to register a callback when state is exited.
Example
@machine.on_exit("pending") ... def log_departure(ctx): ... logger.info("Left pending: %s", ctx.get("order_id"))
Source code in src/pystator/machine.py
on_transition
¶
Decorator to register a callback for a specific transition.
Example
@machine.on_transition("pending", "confirmed") ... def celebrate(ctx): ... logger.info("Order confirmed!")
Source code in src/pystator/machine.py
bind_guards
¶
Bind an external guard registry.
Replaces the internal guard registry with the provided one.
Returns:
| Type | Description |
|---|---|
StateMachine
|
Self for method chaining. |
Source code in src/pystator/machine.py
bind_actions
¶
process
¶
process(
current_state: str,
event: str | Event,
context: dict[str, Any] | None = None,
) -> TransitionResult
Process an event and compute the transition result.
Pure computation -- no side effects, no state mutation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
current_state
|
str
|
The current state name. |
required |
event
|
str | Event
|
Event trigger string or Event object. |
required |
context
|
dict[str, Any] | None
|
Optional context dict for guards. |
None
|
Returns:
| Type | Description |
|---|---|
TransitionResult
|
TransitionResult describing the computed transition. |
Source code in src/pystator/machine.py
aprocess
async
¶
aprocess(
current_state: str,
event: str | Event,
context: dict[str, Any] | None = None,
) -> TransitionResult
Async version of :meth:process (supports async guards).
Source code in src/pystator/machine.py
create
¶
create(
*,
entity_id: str | None = None,
context: dict[str, Any] | None = None,
initial_state: str | None = None
) -> EntitySession
Create a stateful instance of this machine.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
entity_id
|
str | None
|
Optional identifier (auto-generated UUID if omitted). |
None
|
context
|
dict[str, Any] | None
|
Initial context dict for the instance. |
None
|
initial_state
|
str | None
|
Override the initial state (defaults to config initial). |
None
|
Returns:
| Type | Description |
|---|---|
EntitySession
|
A new :class: |
Source code in src/pystator/machine.py
orchestrate
¶
orchestrate(
store: Any,
*,
context_validator: Any = None,
scheduler: Any = None,
use_initial_state_when_missing: bool = True,
invoke_adapter: Any = None,
hooks: list[Any] | None = None,
audit_store: Any = None
) -> Any
Create an Orchestrator with this machine's registries.
Convenience factory that eliminates the need to pass guard and action registries separately — they are taken from this machine.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
store
|
Any
|
Sync or async state store. |
required |
context_validator
|
Any
|
Optional pre-transition context validator. |
None
|
scheduler
|
Any
|
Optional scheduler for delayed transitions. |
None
|
use_initial_state_when_missing
|
bool
|
Use initial state for new entities. |
True
|
invoke_adapter
|
Any
|
Optional adapter for invoked services. |
None
|
hooks
|
list[Any] | None
|
Optional list of TransitionHook implementations. |
None
|
audit_store
|
Any
|
Optional AuditStore for transition audit logging. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
Configured |
Any
|
class: |
Source code in src/pystator/machine.py
get_state
¶
Get a state definition by name.
Source code in src/pystator/machine.py
get_initial_state
¶
get_available_transitions
¶
Get all transitions available from a state.
Source code in src/pystator/machine.py
get_available_triggers
¶
Get all trigger names available from a state.
can_transition
¶
Check if a transition is possible (convenience method).
Source code in src/pystator/machine.py
evaluate_destination
¶
evaluate_destination(
current_state: str,
destination_state: str,
context: dict[str, Any] | None = None,
) -> DestinationCheckResult
Check whether destination_state can be reached from current_state.
Uses the same rules as :meth:process: for each transition whose
configured dest equals destination_state (exact string match;
history pseudo-destinations are excluded), runs :meth:process with
that transition's trigger. allowed is True if at least one
such path succeeds and lands on destination_state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
current_state
|
str
|
Current leaf (or active) state name. |
required |
destination_state
|
str
|
Requested target state name (e.g. external status). |
required |
context
|
dict[str, Any] | None
|
Context for guards; same as :meth: |
None
|
Returns:
| Type | Description |
|---|---|
DestinationCheckResult
|
Structured result with per-trigger candidates. If destination_state |
DestinationCheckResult
|
is not a defined state name, returns |
DestinationCheckResult
|
|
Raises:
| Type | Description |
|---|---|
UndefinedStateError
|
If current_state is not defined (same as
:meth: |
Source code in src/pystator/machine.py
511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 | |
can_transition_to
¶
can_transition_to(
current_state: str,
destination_state: str,
context: dict[str, Any] | None = None,
) -> bool
True if destination_state is reachable from current_state now.
Equivalent to evaluate_destination(...).allowed.
Source code in src/pystator/machine.py
validate_state
¶
is_terminal
¶
is_initial
¶
get_state_variables
¶
Get state variable definitions from meta.
Source code in src/pystator/machine.py
validate_context
¶
Validate context against state_variables.
Returns (valid, error_messages).
Source code in src/pystator/machine.py
to_mermaid
¶
Generate Mermaid stateDiagram-v2. See :func:visualization.to_mermaid.
to_dot
¶
to_scxml
¶
get_statistics
¶
Get machine statistics. See :func:visualization.get_statistics.
StateMachineBuilder
¶
Fluent builder for StateMachine from Python code.
Source code in src/pystator/machine.py
add_state
¶
Add a state. type: initial, stable, terminal, error.
Source code in src/pystator/machine.py
add_transition
¶
add_transition(
trigger: str,
source: str | list[str],
dest: str,
**kwargs: Any
) -> StateMachineBuilder
Add a transition.
Source code in src/pystator/machine.py
add_state_variable
¶
add_state_variable(
key: str,
*,
type: str | None = None,
required: bool = False,
default: Any = None,
**kwargs: Any
) -> StateMachineBuilder
Add a state variable (context key) definition.
Source code in src/pystator/machine.py
to_dict
¶
Export to config dict.
Source code in src/pystator/machine.py
from_dict
classmethod
¶
Create builder from config dict (loads state_variables).