transitions icon indicating copy to clipboard operation
transitions copied to clipboard

@initial.setter doesn't change current initial state

Open Henddher opened this issue 2 years ago • 1 comments

Calling machine.initial = 'start' changes self._initial but doesn't change the actual initial state.

Minimal working example

    def test_initial(self):
      import transitions as sm
      machine = sm.Machine()
      assert machine.state == 'initial'
      machine.initial = 'start'
>     assert machine.state == 'start'
E     AssertionError: assert 'initial' == 'start'
E       - start
E       + initial

Expected behavior

I'd say that if the current state is 'initial' and a new initial state is set, then the new initial state should be honored.

Henddher avatar Jun 06 '22 02:06 Henddher

Additional Information

A workaround is to call set_state(...)

 class TestMachineInitial:
   def test_initial(self):
     import transitions as sm
     machine = sm.Machine()
     assert machine.state == 'initial'
     machine.initial = 'start'
     machine.set_state('start')  # <<<<<<<< Workaround
     assert machine.state == 'start'

Henddher avatar Jun 06 '22 02:06 Henddher

Hello @Henddher,

I'd say that if the current state is 'initial' and a new initial state is set, then the new initial state should be honored.

as of now initial is only considered when a model is initialized. When a machine acts as a model this is done during construction. Setting Machine.initial afterwards will not affect already initialized models but new models will be initialized with the new value:

import transitions as sm


class Model:
    pass


 class TestMachineInitial:
     def test_initial(self):
         machine = sm.Machine()
         model = Model()
         assert machine.state == 'initial'
         machine.initial = 'start'
         machine.add_model(model)
         assert model.state == 'start'

transitions could call set_state on all models where model.state == machine.initial when initial is changed but it does not know how the model ended up in this state. Not every initial state must be reserved for initialization only. This could lead to undesired side effects:

from transitions import Machine


class Model:
    pass


states = ["ON", "OFF"]
transitions = [['switch', "ON", "OFF"], ["switch", "OFF", "ON"]]
bulb_1 = Model()
bulb_2 = Model()

machine = Machine(bulb_1, states=states, transitions=transitions, initial="OFF")
assert bulb_1.is_OFF()
bulb_1.switch()
assert bulb_1.is_ON()
bulb_1.switch()
assert bulb_1.is_OFF()
machine.initial = "ON"
machine.add_model(bulb_2)
assert bulb_2.is_ON()
assert bulb_1.is_OFF()  # [1]

I would not expect bulb_1 to be ON at [1].

aleneum avatar Aug 25 '22 09:08 aleneum

Since there hasn't been any feedback in the last 14 days I will close this issue for now. Feel free to comment nevertheless if this issue is still not solved for you. If necessary, I will reopen the issue again.

aleneum avatar Sep 08 '22 08:09 aleneum

Thank you @aleneum!

It makes perfect sense!

Henddher avatar Sep 20 '22 00:09 Henddher