pytransitions / transitions

A lightweight, object-oriented finite state machine implementation in Python with many extensions
MIT License
5.67k stars 529 forks source link

AttributeError: 'state' does not exist #625

Closed atk-portcast closed 11 months ago

atk-portcast commented 1 year ago

Describe the bug I am trying to access the state of the machine. But it's giving me AttributeError: 'state' does not exist on <Machine@4372162448>.

Minimal working example Example to reproduce the error (added a screenshot and code below).

Screenshot

image

Code

from transitions import Machine, State

class MyObject: pass

my_obj = MyObject()
states = ["red", "yellow", "green"]
machine = Machine(my_obj, states, initial="red")
print(machine.state)

Expected behavior I expected the machine.state to provide me with the current state of the machine i.e. initial state: red. The same is shown in the documentation: https://github.com/pytransitions/transitions#checking-state

Additional context Library version used: 0.9.0 System: Mac M1 Python version: 3.11.3

tomtitherington commented 1 year ago

In order to access the state of the machine, you have two options (as per the docs that you linked).

The problem in your case, is that you are trying to access the "state" attribute on the machine instance and not the underlying model instance. i.e. You need to use my_obj.state and not machine.state to get the desired behaviour you are looking for.

aleneum commented 1 year ago

Hello @atk-portcast,

@tomtitherington has already mentioned it. transitions decorates the model passed to a machine with convenience functions such as auto transitions ("to"), event trigger (e.g. "melt"), state checks ("is") and so on. With transitions, models are the stateful objects, not machines. However, machines can act as a model which actually is the default case when no model is passed. One machine can manage multiple models, including itself.

from transitions import Machine

class Model:
     pass

# machine acts as a model
machine = Machine(states=["A", "B"], initial="A") 
assert machine.state == "A"
assert machine.is_A()
assert machine.to_B()
assert not machine.is_A()

# model explicitly passed 
model = Model()
machine = Machine(model, states=["A", "B"], initial="A")
# machine.state ! raises Exception
# machine.to_B() ! raises Exception
assert model.state == "A"
assert model.to_B()
machine.add_model(machine, initial="B")  # add machine as a second model
assert model.state == machine.state.  # now machine has been decorated as well
aleneum commented 11 months ago

Closing this since there has been no feedback for over 2 weeks. Feel free to comment if the issue still persists. I will reopen the issue if necessary.