Skip to content

Callback names collide between sibling nested state bodies #653

Description

@fgmacedo

StateMachineMetaclass._unpack_builders_callbacks flattens state._callbacks from every state
into a single dict and setattrs the result on the class. The dict is keyed by the callback
name alone, with no reference to the owning state, so two sibling regions that declare the same
callback name collide and the last one silently wins.

Measured on develop:

log = []

class P(StateChart):
    class par(State.Parallel):
        class r1(State.Compound):
            a1 = State(initial=True)
            b1 = State(final=True)

            @a1.to(b1)
            def go(self):
                log.append("r1")

        class r2(State.Compound):
            a2 = State(initial=True)
            b2 = State(final=True)

            @a2.to(b2)
            def go(self):
                log.append("r2")

sm = P()
sm.send("go")
log  # ['r2'] -- r1's body never runs

Both regions do transition; only r1.go's body is discarded. The same collision already happens
with plain callbacks of the same name in sibling regions, so this is not new, but #645 makes the
decorator form reachable inside a nested body and therefore much easier to hit.

The mangled name needs to be namespaced by the owning state, or the collision detected and
raised as InvalidDefinition. Namespacing falls out naturally from #657,
where the metaclass reads each body with the owning state in hand.

When fixing: revisit docs/actions.md / docs/statecharts.md for anything that implies
sibling regions are independent namespaces, and add an entry to the open release notes.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions