-
-
Notifications
You must be signed in to change notification settings - Fork 85
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Event "Union" does not execute transition actions #453
Comments
I have experimented a bit more. When I define the event like this:
the function on_stop() or on_shutdown() is also not called, when I call the event like in the example above. |
Hi @ostetzer , how are you? Thanks for getting in touch. Sorry about the misleading behavior. This theme is a huge opportunity to improve the docs. This is indeed the expected behavior... To make it clear, I've created a graph representation of the example state machine you provided: >>> test_machine._graph().write_png("test_FSM.png") So, what's going on?Note that on this graph, you have the transitions represented as the edges (arcs) that connect the states, and the events as labels attached to these edges. Note that the transition is created using the pattern When we assign the transition list to a variable at the class level, we're defining an And by declaring Given that you're binding actions by naming convention, by definition:
The key here is that using this naming convention pattern, the action is associated with the event name, not with the transition. The action name matters and must match the pattern of the event. Why the actions How to accomplish the expected behaviourYou can explicitly bind the action to the transition itself, using params, like class test_FSM(StateMachine):
init = State(initial=True)
standby = State()
running = State()
off = State(final=True)
start = init.to(standby)
run = standby.to(running)
stop = running.to(standby, on="on_stop")
shutdown = standby.to(off, on="on_shutdown")
shutdown_cycle = stop | shutdown
def __init__(self):
super().__init__()
def on_start(self):
print("initialize to standby")
def on_run(self):
print("changed to running")
def on_stop(self):
print("stopping")
def on_shutdown(self):
print("shutting down") So if you go with this alternative, I suggest changing the action name to another thing not similar to the naming convention, just to make explicitly that you're binding an action to the transition itself. Like this: class test_FSM(StateMachine):
init = State(initial=True)
standby = State()
running = State()
off = State(final=True)
start = init.to(standby)
run = standby.to(running)
stop = running.to(standby, on="_on_stop")
shutdown = standby.to(off, on="_on_shutdown")
shutdown_cycle = stop | shutdown
def __init__(self):
super().__init__()
def on_start(self):
print("initialize to standby")
def on_run(self):
print("changed to running")
def _on_stop(self):
print("stopping")
def _on_shutdown(self):
print("shutting down")
The last possibility is to explicitly bind the action to a transitions list using decorators, again, with this binding the name of the action method does not matter. class test_FSM(StateMachine):
init = State(initial=True)
standby = State()
running = State()
off = State(final=True)
start = init.to(standby)
run = standby.to(running)
stop = running.to(standby)
shutdown = standby.to(off)
shutdown_cycle = stop | shutdown
def __init__(self):
super().__init__()
def on_start(self):
print("initialize to standby")
def on_run(self):
print("changed to running")
@stop.on
def _on_stop(self):
print("stopping")
@shutdown.on
def _on_shutdown(self):
print("shutting down") ExtraJust to make a point on how things work internally, the Example that also works as you expect: class test_FSM(StateMachine):
init = State(initial=True)
standby = State()
running = State()
off = State(final=True)
init.to(standby, event="start")
standby.to(running, event="run")
running.to(standby, event=["stop", "shutdown_cycle"], on="_on_stop")
standby.to(off, event=["shutdown", "shutdown_cycle"], on="_on_shutdown")
def __init__(self):
super().__init__()
def on_start(self):
print("initialize to standby")
def on_run(self):
print("changed to running")
def _on_stop(self):
print("stopping")
def _on_shutdown(self):
print("shutting down") What do you think about this alternative syntax? :) Please let me know if I have clarified the behavior, or if you have any other questions. |
Thank you so much for this detailed answer with even different options. Yes, please add this to the documentation asI hope it might help others too. I like the decorator version and will implement this. Thanks a lot! :-) |
You're very welcome! I'm glad the options were helpful. I'll definitely document this for others too. Best! |
Description
Describe what you were trying to get done.
As in the traffic light example, I combined several transitions int a "cycle" with a union. e.g.
shutdown_cycle = stop | shutdown
My expectation is, that when I call that "union" event, then the appropriate transition (based on curernt state) is executed.
Tell us what happened, what went wrong, and what you expected to happen.
When I tried that, the state change did happen, but the actions of a the transitions are not executed.
In the example, I call the shutdown-cycle twice from state running and i expect the transitions stop and shutdown to be executed.
However, the functions on_stop() and on_shutdown() are not called/executed when i call shutdown_cycle()
What I Did
I created a minimum example to demonstrate my findings. IS my expectations wrong?
Minimum example:
output:
The text was updated successfully, but these errors were encountered: