-
-
Notifications
You must be signed in to change notification settings - Fork 104
Comparing changes
Open a pull request
base repository: fgmacedo/python-statemachine
base: main
head repository: fgmacedo/python-statemachine
compare: develop
- 20 commits
- 350 files changed
- 2 contributors
Commits on Feb 13, 2026
-
Configuration menu - View commit details
-
Copy full SHA for 2689398 - Browse repository at this point
Copy the full SHA 2689398View commit details -
Configuration menu - View commit details
-
Copy full SHA for d062de9 - Browse repository at this point
Copy the full SHA d062de9View commit details
Commits on Feb 14, 2026
-
feat: StateChart (support for compound / parallel / historical states…
… including SCXML notation) (#501) This PR introduces comprehensive SCXML support to the library, including the full processing model, hierarchical/parallel/history states, internal and multi-target transitions, delayed events (send/cancel), and donedata. It achieves sync/async engine parity, implements spec-compliant error handling (error.execution, error.communication) with proper isolation and safety guards, and significantly improves W3C SCXML test conformance. The change also includes major architectural refactors across the parser, engines, and state model, enhanced diagram generation for compound/parallel/history states, and expanded test coverage to ~100%, with Python ≥3.9 compatibility. Overall, this PR elevates the project to a fully functional, spec-aligned SCXML implementation with stronger reliability and internal design.
Configuration menu - View commit details
-
Copy full SHA for 08dd542 - Browse repository at this point
Copy the full SHA 08dd542View commit details -
docs: rewrite README for v3 with StateChart as primary API
Showcase the full range of statechart capabilities: compound states, parallel regions, history pseudo-states, eventless transitions, guards, error handling, and async support — all using the new StateChart class.
Configuration menu - View commit details
-
Copy full SHA for a07c8a4 - Browse repository at this point
Copy the full SHA a07c8a4View commit details -
docs: add v3 upgrade guide and migrate documentation to StateChart API
Add comprehensive upgrade guide from 2.x to 3.0 covering all breaking changes with before/after examples. Update all documentation to use StateChart as the primary API with non-deprecated methods/properties, replacing StateMachine, current_state, and add_observer references.
Configuration menu - View commit details
-
Copy full SHA for 4d029e7 - Browse repository at this point
Copy the full SHA 4d029e7View commit details
Commits on Feb 15, 2026
-
feat: migrate examples to StateChart, fix delayed events, document is…
…_terminated Migrate all 14 gallery examples from StateMachine to StateChart, setting behavioral flags where needed to preserve existing semantics (allow_event_without_transition, enable_self_transition_entries, error_on_execution). Add 4 new v3 feature examples: - statechart_eventless_machine: eventless transitions (Ring Corruption) - statechart_delayed_machine: compound/parallel states, delayed events, internal events, cancel_event (Beacons of Gondor) - statechart_error_handling_machine: error.execution handling - statechart_in_condition_machine: In() guard with parallel states Fix bugs in delayed event handling: - Rename send()/raise_() parameter from event_id to send_id to match BoundEvent.put() and cancel_event() signatures (cancel_event was silently broken because send_id was always None) - Change continue→break in sync/async engine Phase 3 loop when encountering delayed events, allowing internal events and eventless transitions to be processed while waiting Document is_terminated property: - Add docstring to the property itself - Add "Checking if the machine has terminated" section in docs/states.md - Add migration entry in upgrade guide for current_state.final → is_terminated - Update send_id references in docs (statecharts.md, release notes, upgrade guide)
Configuration menu - View commit details
-
Copy full SHA for 68a59a8 - Browse repository at this point
Copy the full SHA 68a59a8View commit details -
docs: document processing model, raise_(), cleanup/finalize pattern
- Expand docs/processing_model.md with macrostep/microstep definitions, event queues (internal vs external), processing loop diagram, and continuous machine examples (raise_() chaining, eventless self-loops). - Add "Cleanup / finalize pattern" section to docs/statecharts.md showing that after_<event>() acts as a natural finalize with error_on_execution. - Document raise_() vs send() in docs/transitions.md with "External vs internal events" section and fix triggering-events Sphinx anchor. - Improve raise_() docstring in statemachine.py with corrected cross-ref. - Add statechart_cleanup_machine.py sphinx-gallery example demonstrating both success and failure paths with automatic error recovery. - Update AGENTS.md with processing model, error handling, eventless transitions, and callback conventions.
Configuration menu - View commit details
-
Copy full SHA for fde13d9 - Browse repository at this point
Copy the full SHA fde13d9View commit details -
feat: add weighted (probabilistic) transitions (#564)
* feat: add weighted (probabilistic) transitions contrib module Add `weighted_transitions()` utility that enables probabilistic transition selection based on relative weights. Works entirely through the existing `cond` guard system with zero engine changes. API: weighted_transitions(source, (target, weight), ..., seed=N) to(target, weight, cond=..., on=..., ...) # for transition kwargs Inspired by PR #539 (@bcorfman).
Configuration menu - View commit details
-
Copy full SHA for 4654aba - Browse repository at this point
Copy the full SHA 4654abaView commit details -
refactor!: modernize codebase for v3 — remove deprecated APIs, migrat…
…e tests to StateChart (#565) * feat!: remove add_observer() and short registry names (deprecated since v2.x) - Remove `add_observer()` method (deprecated v2.3.2, use `add_listener()`) - Remove short name registration in registry (deprecated v0.8, use fully qualified names) - Update release notes and upgrade guide accordingly * feat!: change States.from_enum default to use_enum_instance=True Fulfills the deprecation promise from v2.3.3. The enum instance is now used as the state value by default. Pass use_enum_instance=False to get the previous behavior of using the raw enum value. * test: add dedicated backward-compat tests for StateMachine (v2 API) Cover all four flag defaults, TransitionNotAllowed behavior (sync and async), error_on_execution=False propagation, self-transition entries, current_state deprecated property, and basic smoke tests. * refactor(tests): migrate conftest fixtures from StateMachine to StateChart - Switch all 7 inline fixture classes to StateChart - Add error_on_execution=False to validator fixture (test expects direct propagation) - Remove classic_traffic_light_machine_allow_event subclass (redundant with StateChart default) - Remove TransitionNotAllowed tests from test_statemachine.py (covered by compat tests) * refactor(tests): migrate main test files from StateMachine to StateChart - test_statemachine.py: all classes → StateChart, current_state → is_active - test_copy.py: all classes → StateChart, current_state → is_active - test_async.py: all classes → StateChart with explicit flags where needed (allow_event_without_transition=False, error_on_execution=False) * refactor(tests): migrate remaining test files from StateMachine to StateChart Migrate 18 test files to use StateChart as base class. For tests that depend on StateMachine-specific behavior (TransitionNotAllowed, error propagation), explicit flags are added (allow_event_without_transition=False, error_on_execution=False). * refactor(tests): migrate testcases, Django and SCXML tests to StateChart * docs: update source doctests to use StateChart as primary API * docs: update release notes and upgrade guide for v3 breaking changes
Configuration menu - View commit details
-
Copy full SHA for c6445c8 - Browse repository at this point
Copy the full SHA c6445c8View commit details -
feat: add pyright support, Generic[TModel], remove __getattr__ catch-…
…all (#566) * feat: add pyright support, Generic[TModel] for typed models, remove __getattr__ catch-all - Add pyright as dev dependency + pre-commit hook, configured with basic type checking targeting Python 3.9 - Make StateChart generic over TModel so `sm.model` gets proper type inference and IDE autocompletion when a model class is provided - Remove TYPE_CHECKING `__getattr__` stubs from both StateChart and StateMachineMetaclass — type checkers now detect misspelled attributes and unresolved references on subclasses - Add explicit type declarations for metaclass-set attributes (name, id, states, states_map, initial_state, final_states) with docstrings - Add return type annotations throughout (send, raise_, enabled_events, activate_initial_state, Event.__call__, run_async_from_sync, etc.) - Fix all 38 baseline pyright errors with proper types, assertions for weakref derefs, and targeted type: ignore for genuinely dynamic APIs (pydot, partial attributes, conditional function definitions) - Update tests/examples to use configuration_values for enum-based state checks instead of relying on dynamic attribute access - Document typed models in docs/models.md and docs/releases/3.0.0.md Closes #515
Configuration menu - View commit details
-
Copy full SHA for a214e04 - Browse repository at this point
Copy the full SHA a214e04View commit details -
feat: future-based result routing for async concurrent events (#567)
* feat: add future-based result routing for async concurrent events (#509) When multiple coroutines send events concurrently, only the lock holder processes events. Previously, non-lock-holding callers returned None, losing both results and exceptions. Now each external event gets an asyncio.Future attached in AsyncEngine.put(). The processing loop resolves/rejects each future with the microstep result. Callers that couldn't acquire the lock await their future instead of returning None. Uses contextvars.ContextVar to distinguish reentrant calls (from within callbacks, including asyncio.gather child tasks) from concurrent external calls — reentrant calls don't get futures to avoid deadlocks. * test: add regression test for issue #509 example * refactor: move reject_futures to EventQueue, fix test latency and doctest - Move future rejection logic from AsyncEngine into EventQueue.reject_futures() to respect encapsulation (avoids reaching into PriorityQueue internals) - Reduce asyncio.sleep in test_issue509 from 0.1s to 0.01s - Convert plain python block in docs/async.md to a testable doctest * test: cover EventQueue.reject_futures with future=None items
Configuration menu - View commit details
-
Copy full SHA for 8117a5e - Browse repository at this point
Copy the full SHA 8117a5eView commit details
Commits on Feb 17, 2026
-
refactor!: remove
strict_states, addvalidate_trap_statesand `va……lidate_final_reachability` (#568) Replace the `strict_states` class parameter (introduced in v2.2.0) with two independent class-level attributes that default to `True`: - `validate_trap_states`: non-final states must have outgoing transitions - `validate_final_reachability`: when final states exist, all non-final states must have a path to at least one final state This fulfils the v2.2.0 promise that `strict_states=True` would become the default in the next major release. The warning-based behavior is removed — violations now always raise `InvalidDefinition`. BREAKING CHANGE: `strict_states=True/False` no longer accepted. Use `validate_trap_states = False` / `validate_final_reachability = False` to opt out, or (recommended) mark terminal states as `final=True`.
Configuration menu - View commit details
-
Copy full SHA for 7faf7fa - Browse repository at this point
Copy the full SHA 7faf7faView commit details
Commits on Feb 18, 2026
-
feat: class-level listener declarations with setup() protocol (#570)
* feat: class-level listener declarations with setup() protocol Allow listeners to be declared at class definition time via a `listeners` attribute on StateChart/StateMachine. The list accepts callables (classes, partial, lambdas) as per-instance factories and pre-built instances as shared listeners. - Metaclass collects `_class_listeners` from attrs and MRO - `listeners_inherit = False` to replace instead of extend parent listeners - `setup(sm, **kwargs)` protocol for runtime dependency injection - `active_listeners` public property to inspect attached listeners - Serialization correctly preserves all listeners through pickle/copy
Configuration menu - View commit details
-
Copy full SHA for 3b5ef35 - Browse repository at this point
Copy the full SHA 3b5ef35View commit details
Commits on Feb 19, 2026
-
feat: invoke callback group — spawn external work from states (#571)
* feat: invoke callback group — spawn external work from states Add invoke as a first-class callback group (CallbackGroup.INVOKE), following SCXML <invoke> semantics. States can spawn background work (API calls, file I/O, child state machines) on entry and cancel it on exit. - New CallbackGroup.INVOKE with convention naming (on_invoke_<state>), decorator (@state.invoke), and inline callables - IInvoke protocol for advanced handlers with InvokeContext (cancellation, send events to parent, machine reference) - StateChartInvoker adapter for child state machine invocation - invoke_group() for running multiple callables concurrently and waiting for all results as a single done.invoke event - InvokeManager lifecycle management integrated into both sync and async engines (sync: daemon threads, async: thread executor wrapped in asyncio.Task) - done_invoke_<state> factory prefix maps to done.invoke.<state> event family - visitor pattern (visit/async_visit) on CallbacksExecutor and CallbacksRegistry - __contains__ on CallbacksRegistry to avoid direct _registry access - Full test suite and documentation with practical file I/O examples - Plain callables receive kwargs via SignatureAdapter dependency injection - IInvoke handlers receive kwargs via ctx.kwargs This allows patterns like sm.send("start", file_name="config.json") where the invoke handler reads file_name as a parameter.Configuration menu - View commit details
-
Copy full SHA for f1cbfbb - Browse repository at this point
Copy the full SHA f1cbfbbView commit details -
feat: propagate constructor kwargs to initial state callbacks (#572)
Forward **kwargs from StateChart.__init__() through the engine's initial event (TriggerData), making them available to on_enter_<initial_state>, invoke handlers, and other initial-entry callbacks via dependency injection. This enables self-contained machines to receive context at creation time, e.g. `MyMachine(url="...", config=config)`.
Configuration menu - View commit details
-
Copy full SHA for 6f2b617 - Browse repository at this point
Copy the full SHA 6f2b617View commit details -
Configuration menu - View commit details
-
Copy full SHA for 4a554f9 - Browse repository at this point
Copy the full SHA 4a554f9View commit details -
Configuration menu - View commit details
-
Copy full SHA for dd6f3c9 - Browse repository at this point
Copy the full SHA dd6f3c9View commit details -
fix: make disconnected states validation hierarchy-aware (#573)
The `visit_connected_states` BFS now traverses the state hierarchy: entering a compound/parallel state implicitly enters its initial children, and being in a child implies being in all ancestor states. This removes the need for `validate_disconnected_states = False` in virtually all parallel, compound, and history state examples — the flag was only needed because the validator didn't understand hierarchical entry semantics.
Configuration menu - View commit details
-
Copy full SHA for 4d49dab - Browse repository at this point
Copy the full SHA 4d49dabView commit details -
fix(tests): make threading tests deterministic
Replace time-based loops and sleep-waits with iteration counts and thread.join(), eliminating flaky failures on slow CI runners.
Configuration menu - View commit details
-
Copy full SHA for e9a9339 - Browse repository at this point
Copy the full SHA e9a9339View commit details -
refactor(tests): replace .fail.md xfail mechanism with in-code sets
The file-based .fail.md mechanism had issues: each .scxml generates two tests (sync + async) but the xfail mark was shared, and --upd-fail caused loops when one engine passed but the other failed. Replace with XFAIL_BOTH/XFAIL_SYNC_ONLY/XFAIL_ASYNC_ONLY sets in conftest.py. - Remove 46 .fail.md files (30 mandatory + 16 optional) - Remove --upd-fail CLI option and FailedMark class - Remove unused DebugListener and helper dataclasses - Support per-engine xfail marks via sync/async set split
Configuration menu - View commit details
-
Copy full SHA for a6e57a6 - Browse repository at this point
Copy the full SHA a6e57a6View commit details
This comparison is taking too long to generate.
Unfortunately it looks like we can’t render this comparison for you right now. It might be too big, or there might be something weird with your repository.
You can try running this command locally to see the comparison on your machine:
git diff main...develop