Skip to content

Package structure: core vs optional

PyStator is split into a core FSM library and optional layers (REST API, DB, UI, schedulers). You can use the core alone; add extras when you need them.

Three-layer machine definitions (parse → store → build)

Besides loading a machine in one step with StateMachine.from_yaml() / from_dict(), the library exposes a three-layer pipeline (similar in spirit to PyCharter-style separation):

Layer Package Role
Parser pystator.machine_parser Parse YAML/JSON (or dict) → MachineDefinition (parse_machine, parse_machine_file).
Store pystator.machine_store Persist and load definitions (MachineStoreClient, InMemoryMachineStore, SQLAlchemyMachineStore when SQLAlchemy is installed).
Builder pystator.machine_builder MachineDefinition or store → runtime StateMachine (build_machine, build_machine_from_store).

Use this when you need versioned definitions in a database, CI validation without constructing a full machine, or sharing the same canonical definition between API, worker, and scripts. For a single file in a script, StateMachine.from_yaml() remains the shortest path.

Facades (optional namespaces that re-export implementation modules):

  • pystator.coreStateMachine, EntitySession, Event, core value types, TransitionContext, parse_stored_state, parallel helpers.
  • pystator.behavior — guards, actions, checks, effects, sinks, builtins.
  • pystator.observability — hooks, lint, visualization.

You can import from pystator (barrel exports) or from these subpackages for clearer layering.

Core (always installed)

The core is the state machine library. Everything you need to define and run FSMs lives here.

Area Modules / components Purpose
Machine & instance StateMachine, StateMachineBuilder, EntitySession Load FSM from YAML/dict or build in code; process() / send().
Events & types Event, State, Transition, TransitionResult, GuardSpec, ActionSpec, CheckSpec, etc. Events and immutable FSM value types.
Guards & actions GuardRegistry, GuardEvaluator, ActionRegistry, ActionExecutor Register and run guards and actions by name.
Declarative checks.evaluate_check, effects.apply_effect YAML check: guards and set / timestamp / … effects without Python.
Config config.loader, config.models, config.converter, config.validator Load/validate YAML or dict and convert to internal types.
Stores StateStore, AsyncStateStore, InMemoryStateStore, PostgresStateStore, RedisStateStore, … Persistence adapters (some require optional deps).
Orchestrator Orchestrator Sandwich loop: load state by entity ID → process → persist → run actions (optional scheduler).
Hooks TransitionObserver, LoggingHook, MetricsCollector, StructuredLoggingHook Observability and metrics.
Sinks pystator.sinks Event/metric sinks for actions and tooling.
Lint pystator.lint.lint Static warnings over FSM config.
Builtins pystator.builtins Optional pre-registered guard/action packs.
Visualization to_mermaid, to_dot, etc. Generate diagrams from FSM config.
Errors FSMError, ConfigurationError, InvalidTransitionError, etc. Exception hierarchy.

Internal implementation details (not part of the public API) live in modules prefixed with _: _types, _engine, _hierarchy, _parallel. You typically use the public classes and functions only.

Install: pip install pystator (core is always present).


Optional (extras)

These components build on the core and are optional. Install them only if you need REST API, DB persistence, web UI, or specific schedulers.

Extra Install What it adds
API pip install pystator[api] REST API (pystator api), DB/migrations (Alembic/SQLAlchemy), PostgreSQL and MongoDB drivers, Pydantic validation, inline expr: guards (simpleeval), and the local docs site (pystator docs serve, MkDocs).
Worker pip install pystator[worker] SQLAlchemy/Alembic + Redis/Celery + PostgreSQL driver for pystator worker, worker_events, and submit_event(). Requires PYSTATOR_DATABASE_URL at runtime. See Worker.
UI pip install pystator[ui] (often with [api]) Static/UI dev server; pystator ui serve / pystator ui dev.
All (runtime) pip install pystator[all] api + worker + ui in one install (no dev-only tools).
Schedulers Core code in package; Redis/Celery via [worker] / env AsyncioScheduler, RedisScheduler, CeleryScheduler for after: transitions with the Orchestrator.
Dev pip install pystator[dev] api + worker + ui plus pytest, ruff, mypy, notebooks, etc.

Directory layout in the source tree (under src/pystator/):

  • Machine pipeline: machine_parser/, machine_store/, machine_builder/ — definition lifecycle separate from runtime execution.
  • Core runtime: machine.py, instance.py, event.py, errors.py, orchestrator.py, config/, stores/, _types.py, _engine.py, _hierarchy.py, _parallel.py, state_parsing.py.
  • Behavior: guards.py, actions.py, checks.py, effects.py, builtins.py, sinks.py, context.py, invoke.py.
  • Observability: hooks.py, lint.py, visualization.py.
  • Facades: core/, behavior/, observability/ — thin __init__.py re-exports.
  • Discovery: discovery/ — inferred FSMs, classification, candidate stores (see Discovery).
  • Optional: api/ (REST API), worker/ (event-processing service, worker_events, submit_event), db/ (migrations, models), ui/ (frontend), scheduler/ (scheduler adapters; present in base install; extra deps for Redis/Celery).

When to use what

  • Only core: Define FSMs in YAML, use StateMachine.from_yaml() / from_dict() and either machine.process() (stateless) or machine.create()EntitySession.send() (stateful in memory). Alternatively, parse_machine_filebuild_machine when working from MachineDefinition. Add a StateStore and Orchestrator when you need persistence by entity ID.
  • Core + API: Run pystator api to expose validate/process and optional machine CRUD over HTTP. Requires pystator[api].
  • Core + Worker: pip install pystator[worker], run pystator worker, enqueue with submit_event(). Requires a database (pystator db upgrade). See Worker.
  • Core + schedulers: Use an Orchestrator with AsyncioScheduler, RedisScheduler, or CeleryScheduler for delayed transitions. Scheduler code is in the base package; Redis/Celery may need extra dependencies.

See Concepts for the three ways to run a machine (EntitySession, stateless process, Orchestrator).