_expand_event_id turns error_foo into the string "error_foo error.foo", meaning "one event
with two spellings". But a space-separated id is already a public format meaning "this
transition responds to N distinct events":
green.to(yellow, event=Event("cycle slowdown", name="Will be ignored"))
assert sm.slowdown.name == "Slowdown"
tests/test_events.py::TestExplicitEvent::test_multiple_ids_from_the_same_event_will_be_converted_to_multiple_events
pins that behaviour, and the argument is literally named "Will be ignored".
Two meanings on one carrier, wanting opposite handling. By the time Event.split runs, the
string is just a string and cannot tell them apart, so the fix does not belong there.
Measured on develop, with no Event involved at all:
class Bare(StateChart):
a = State(initial=True)
b = State(final=True)
error_foo = a.to(b)
Bare.events # ['error_foo error.foo'] -- one event with a glued id
Bare.error_foo # TransitionList -- never became an event
sm.error_foo() # TypeError: TransitionList only supports the decorator syntax
sm.send("error.foo") # works
With the Event class the attribute exists but the call is a silent no-op, because it sends an
id that matches no transition:
class T(StateChart):
a = State(initial=True)
b = State(final=True)
error_foo = Event(a.to(b), name="Boom")
T.events # [('error_foo error.foo', 'Boom')]
sm = T(); sm.error_foo()
sm.configuration_values # {'a'} -- nothing happened
So the error_ convention documented in AGENTS.md has only ever worked through send(), never
through the method call form. The transitions themselves are fine: they carry the two correct
ids. What is wrong is the registration, which keeps the glued id as a single event in
cls._events and binds it as the class attribute.
done_state_ and done_invoke_ expand the same way and have the same problem.
The fix is to make _expand_event_id return the ids as a list and have the callers register N
events, instead of smuggling a list inside a string. That also removes the limitation that a
nested Event(a.to(b), name=..., delay=...) with an error_ prefix drops its arguments, which
#645 documents and pins in
tests/test_statechart_compound.py::TestEventClassInsideCompound::test_expanded_id_drops_the_declared_arguments.
When fixing: that test asserts today's behaviour and must be inverted; drop the matching
paragraph from docs/events.md and from the nested-Event section of docs/releases/3.2.2.md,
and add an entry for this fix to the open release notes.
_expand_event_idturnserror_foointo the string"error_foo error.foo", meaning "one eventwith two spellings". But a space-separated id is already a public format meaning "this
transition responds to N distinct events":
tests/test_events.py::TestExplicitEvent::test_multiple_ids_from_the_same_event_will_be_converted_to_multiple_eventspins that behaviour, and the argument is literally named
"Will be ignored".Two meanings on one carrier, wanting opposite handling. By the time
Event.splitruns, thestring is just a string and cannot tell them apart, so the fix does not belong there.
Measured on
develop, with noEventinvolved at all:With the
Eventclass the attribute exists but the call is a silent no-op, because it sends anid that matches no transition:
So the
error_convention documented inAGENTS.mdhas only ever worked throughsend(), neverthrough the method call form. The transitions themselves are fine: they carry the two correct
ids. What is wrong is the registration, which keeps the glued id as a single event in
cls._eventsand binds it as the class attribute.done_state_anddone_invoke_expand the same way and have the same problem.The fix is to make
_expand_event_idreturn the ids as a list and have the callers register Nevents, instead of smuggling a list inside a string. That also removes the limitation that a
nested
Event(a.to(b), name=..., delay=...)with anerror_prefix drops its arguments, which#645 documents and pins in
tests/test_statechart_compound.py::TestEventClassInsideCompound::test_expanded_id_drops_the_declared_arguments.When fixing: that test asserts today's behaviour and must be inverted; drop the matching
paragraph from
docs/events.mdand from the nested-Eventsection ofdocs/releases/3.2.2.md,and add an entry for this fix to the open release notes.