Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: fgmacedo/python-statemachine
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: main
Choose a base ref
...
head repository: fgmacedo/python-statemachine
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: develop
Choose a head ref
Checking mergeability… Don’t worry, you can still create the pull request.
  • 20 commits
  • 350 files changed
  • 2 contributors

Commits on Feb 13, 2026

  1. Configuration menu
    Copy the full SHA
    2689398 View commit details
    Browse the repository at this point in the history
  2. Configuration menu
    Copy the full SHA
    d062de9 View commit details
    Browse the repository at this point in the history

Commits on Feb 14, 2026

  1. 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.
    fgmacedo authored Feb 14, 2026
    Configuration menu
    Copy the full SHA
    08dd542 View commit details
    Browse the repository at this point in the history
  2. 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.
    fgmacedo committed Feb 14, 2026
    Configuration menu
    Copy the full SHA
    a07c8a4 View commit details
    Browse the repository at this point in the history
  3. 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.
    fgmacedo committed Feb 14, 2026
    Configuration menu
    Copy the full SHA
    4d029e7 View commit details
    Browse the repository at this point in the history

Commits on Feb 15, 2026

  1. 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)
    fgmacedo committed Feb 15, 2026
    Configuration menu
    Copy the full SHA
    68a59a8 View commit details
    Browse the repository at this point in the history
  2. 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.
    fgmacedo committed Feb 15, 2026
    Configuration menu
    Copy the full SHA
    fde13d9 View commit details
    Browse the repository at this point in the history
  3. 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).
    fgmacedo authored Feb 15, 2026
    Configuration menu
    Copy the full SHA
    4654aba View commit details
    Browse the repository at this point in the history
  4. 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
    fgmacedo authored Feb 15, 2026
    Configuration menu
    Copy the full SHA
    c6445c8 View commit details
    Browse the repository at this point in the history
  5. 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
    fgmacedo authored Feb 15, 2026
    Configuration menu
    Copy the full SHA
    a214e04 View commit details
    Browse the repository at this point in the history
  6. 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
    fgmacedo authored Feb 15, 2026
    Configuration menu
    Copy the full SHA
    8117a5e View commit details
    Browse the repository at this point in the history

Commits on Feb 17, 2026

  1. refactor!: remove strict_states, add validate_trap_states and `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`.
    fgmacedo authored Feb 17, 2026
    Configuration menu
    Copy the full SHA
    7faf7fa View commit details
    Browse the repository at this point in the history

Commits on Feb 18, 2026

  1. 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
    fgmacedo authored Feb 18, 2026
    Configuration menu
    Copy the full SHA
    3b5ef35 View commit details
    Browse the repository at this point in the history

Commits on Feb 19, 2026

  1. 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.
    fgmacedo authored Feb 19, 2026
    Configuration menu
    Copy the full SHA
    f1cbfbb View commit details
    Browse the repository at this point in the history
  2. 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)`.
    fgmacedo authored Feb 19, 2026
    Configuration menu
    Copy the full SHA
    6f2b617 View commit details
    Browse the repository at this point in the history
  3. Configuration menu
    Copy the full SHA
    4a554f9 View commit details
    Browse the repository at this point in the history
  4. chore: bump version to 3.0.0

    fgmacedo committed Feb 19, 2026
    Configuration menu
    Copy the full SHA
    dd6f3c9 View commit details
    Browse the repository at this point in the history
  5. 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.
    fgmacedo authored Feb 19, 2026
    Configuration menu
    Copy the full SHA
    4d49dab View commit details
    Browse the repository at this point in the history
  6. 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.
    fgmacedo committed Feb 19, 2026
    Configuration menu
    Copy the full SHA
    e9a9339 View commit details
    Browse the repository at this point in the history
  7. 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
    fgmacedo committed Feb 19, 2026
    Configuration menu
    Copy the full SHA
    a6e57a6 View commit details
    Browse the repository at this point in the history
Loading