Skip to content

validators in a dict/JSON transition definition is silently dropped #628

@csentis

Description

@csentis

validators in a dict/JSON transition definition is silently dropped

Summary

create_machine_class_from_definition (the statemachine.io dict adapter) threads cond, unless, on, before, and after from each transition definition into Transition(...), but not validators. As a result, a validators entry in a dict- or JSON-defined machine is silently ignored — it never reaches the Transition, so it never runs at send().

Separately, the TransitionDict TypedDict declares validators: bool, which is the wrong type — it should be the same callback-spec union as cond/unless (str | ActionProtocol | Sequence[...]).

This matters because, per the docs, validators are the intended channel for explicit transition rejection with a reason (raise to abort), distinct from cond/unless (silent disallow). Users building machines from dict/JSON definitions currently have no way to attach that channel.

Reproduction

from statemachine.io import create_machine_class_from_definition

class Rejected(Exception):
    pass

def reject(*args, **kwargs):
    raise Rejected("not allowed")

SM = create_machine_class_from_definition(
    "M",
    states={
        "s1": {"initial": True, "on": {"go": [{"target": "s2", "validators": reject}]}},
        "s2": {"final": True},
    },
)
sm = SM()
sm.send("go")          # expected: raises Rejected; actual: succeeds, lands in s2
assert sm.current_state.id == "s1"

Expected

The validators callbacks supplied in the definition are materialized onto the Transition (which already accepts validators= in its constructor) and run at send(), exactly like cond/unless/on/before/after.

Environment

  • python-statemachine main (also reproduces on 3.1.2)
  • The fix is a one-line addition to transition_kwargs plus a TypedDict type correction.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions