* fix: support event declarations inside State.Compound bodies
A nested state class body only understood the assignment form of an event
declaration. The `Event` class and the `@<source>.to(<target>)` decorator both
fell through to the generic callable branch, so the name was bound to a
detached object and the transition it wrapped stayed eventless, firing as soon
as its source state became active.
Handle both forms in the nested class body scanner, which is extracted from
`NestedStateFactory.__new__` into `_collect_nested_members`.
Closes #643
Signed-off-by: Fernando Macedo <[email protected]>
* refactor: read statechart class bodies through one shared reader
The two kinds of statechart class body, a StateChart subclass and a nested
State.Compound / State.Parallel, accept the same declaration forms, but each
had its own copy of the recognition table. That is how #643 happened: the
nested copy never learned about `Event`, so an event declared there silently
became an eventless transition.
Recognition now lives once in `class_body.read`, which dispatches to a reader
supplying only what each side does with a form. The reader interface is a
Protocol, so a form added to one side and forgotten on the other is a type
error rather than a silent gap.
Drop the `error_` prefix expansion the previous commit gave to nested
decorated events: it is not what the top-level path does, and the two must
agree.
Signed-off-by: Fernando Macedo <[email protected]>
* docs: drop the versionchanged note for the compound Event fix
The docs describe the current behavior. The previous behavior was a bug, not a
documented contract, and the release notes already carry the history.
Signed-off-by: Fernando Macedo <[email protected]>
* refactor: declare nested events inline instead of through a shared reader
The reader added a module, a seven-method Protocol under TYPE_CHECKING and two
implementations, to share class body recognition between the statechart
metaclass and NestedStateFactory. The two consumers need different amounts of
it, which showed up as an aliased on_history on one side and an empty on_other
on the other, and all three defects found in review lived in the nested
implementation.
Declare the Event and decorator forms with two branches in the loop that was
already there. The event reaches the machine through the path that already
exists: add_state walks the tree and collects state.transitions.unique_events.
Nothing is placed in the callbacks dict, so the expanded id of an error_ prefix
no longer overwrites the class attribute that add_event had bound correctly.
Two differences from the top level remain, both because a nested body is
evaluated before the owning class exists: an explicit id that differs from the
attribute name does not also bind the attribute name, and a transition-less
Event is dropped.
Signed-off-by: Fernando Macedo <[email protected]>
* fix: keep delay and internal when declaring an explicit Event
Event(dark.to(lit), delay=50) rebuilt the event without its delay, so
BeaconsOfGondor.light.delay was 0 and the event fired immediately instead of
being queued. internal was dropped the same way.
test_delayed_event_on_event_definition built its own BoundEvent(delay=50)
instead of triggering the declared one, so it never exercised the bug.
internal is preserved on the declaration but still has no effect at trigger
time: Event.__get__ does not pass it to BoundEvent and send() does not read it.
Signed-off-by: Fernando Macedo <[email protected]>
* docs: link the nested Event limitations to their issues
The notes stated what does not work without pointing anywhere. #656 covers the
missing attribute binding in a nested body, #655 the internal flag that is
preserved on the declaration but ignored at trigger time.
Signed-off-by: Fernando Macedo <[email protected]>
* docs: drop the compound Event section and the issue links
Declaring an Event inside a nested body was always expected to work, so an
example for it repeats what the section above already shows. Open limitations
are tracked on GitHub, not in the docs.
Signed-off-by: Fernando Macedo <[email protected]>
---------
Signed-off-by: Fernando Macedo <[email protected]>