pytransitions / transitions

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

Attaching a model with multiple states to multiple machines #453

Closed Yishu1997 closed 3 years ago

Yishu1997 commented 3 years ago

As mentioned in the documentation we can attach multiple machine to a model with multiple states using different model_attribute values.

I am implementing it similar to the way mentioned in the documentation

class Matter():
    pass

lump = Matter()

states = ['solid','liquid','gas']
transitions = [
    { 'trigger': 'melt', 'source': 'solid', 'dest': 'liquid'},
    { 'trigger': 'evaporate', 'source': 'liquid', 'dest': 'gas'}
]

matter_machine = Machine(lump, states=states, transitions=transitions, initial='solid', model_attribute='state')
shipment_machine = Machine(lump, states=states, transitions=transitions, initial='liquid', model_attribute='shipping_state')

lump.melt()
lump.evaporate()
print(lump.state)
>>> gas
print(lump.shipping_state)
>>> liquid

How shall I access the Machine which has the model_attribute='shipping_state' that is shipment_machine, as all the transitions get carried out only on the first machine that is the matter_machine as it is initialized first. I am not able to perform any transition on the shipment_machine.

badiku commented 3 years ago
matter_machine.model.evaporate()
shipment_machine.model.to_liquid()

this is a bad example, why add different machines with same set of states or transitions? can shipment melt or evaporate?

import logging
logging.getLogger('transitions').setLevel(logging.INFO)

after logging setup you'd see many WARNINGs like these:

WARNING:transitions.core:Model already contains an attribute 'trigger'. Skip binding. WARNING:transitions.core:Model already contains an attribute 'to_solid'. Skip binding. WARNING:transitions.core:Model already contains an attribute 'to_liquid'. Skip binding. WARNING:transitions.core:Model already contains an attribute 'to_gas'. Skip binding. WARNING:transitions.core:Model already contains an attribute 'melt'. Skip binding. WARNING:transitions.core:Model already contains an attribute 'evaporate'. Skip binding. WARNING:transitions.core:Model already contains an attribute 'is_solid'. Skip binding. WARNING:transitions.core:Model already contains an attribute 'is_liquid'. Skip binding. WARNING:transitions.core:Model already contains an attribute 'is_gas'. Skip binding.

badiku commented 3 years ago

even when adding different machines with different states and transitions:

import logging
logging.getLogger('transitions').setLevel(logging.INFO)

from transitions import Machine

class Matter():
    pass

lump = Matter()

states = ['solid','liquid','gas']
transitions = [
    { 'trigger': 'melt', 'source': 'solid', 'dest': 'liquid'},
    { 'trigger': 'evaporate', 'source': 'liquid', 'dest': 'gas'}
]

states2 = ['solid2','liquid2','gas2']
transitions2 = [
    { 'trigger': 'melt2', 'source': 'solid2', 'dest': 'liquid2'},
    { 'trigger': 'evaporate2', 'source': 'liquid2', 'dest': 'gas2'}
]

matter_machine1 = Machine(lump, states=states, transitions=transitions, initial='solid', model_attribute='state')
matter_machine2 = Machine(lump, states=states2, transitions=transitions2, initial='solid2', model_attribute='state2')

lump.melt()
lump.melt2()

can not avoid this trigger error:

WARNING:transitions.core:Model already contains an attribute 'trigger'. Skip binding.

maybe add another parameter ? :

m = Machine(...,  , model_trigger='trigger2') 
Yishu1997 commented 3 years ago

even when adding different machines with different states and transitions:

import logging
logging.getLogger('transitions').setLevel(logging.INFO)

from transitions import Machine

class Matter():
    pass

lump = Matter()

states = ['solid','liquid','gas']
transitions = [
    { 'trigger': 'melt', 'source': 'solid', 'dest': 'liquid'},
    { 'trigger': 'evaporate', 'source': 'liquid', 'dest': 'gas'}
]

states2 = ['solid2','liquid2','gas2']
transitions2 = [
    { 'trigger': 'melt2', 'source': 'solid2', 'dest': 'liquid2'},
    { 'trigger': 'evaporate2', 'source': 'liquid2', 'dest': 'gas2'}
]

matter_machine1 = Machine(lump, states=states, transitions=transitions, initial='solid', model_attribute='state')
matter_machine2 = Machine(lump, states=states2, transitions=transitions2, initial='solid2', model_attribute='state2')

lump.melt()
lump.melt2()

can not avoid this trigger error:

WARNING:transitions.core:Model already contains an attribute 'trigger'. Skip binding.

maybe add another parameter ? :

m = Machine(...,  , model_trigger='trigger2') 

Thanks for your input @badiku

Even after adding another parameter such as

matter_machine2 = Machine(lump, states=states2, transitions=transitions2, initial='solid2', model_attribute='state2', ignore_invalid_triggers=True)

I still get the warning

WARNING:transitions.core:Model already contains an attribute 'trigger'. Skip binding.

Also I would like to inform you that what I intend to do is to have a sub-machine for the matter_machine. That is for example say for a given model I have a machine named Car, I wish to have a sub-machine Driver for it. Can you help me with that? And is it the right way what i'm trying to do above for having a sub-machine.

Also, let me know what is more preferable, to have the same model or a different model in this scenario.

aleneum commented 3 years ago

Hi @Yishu1997,

I'd like to answer your question about how to use transitions on SO where you already posted this.

Also I would like to inform you that what I intend to do is to have a sub-machine for the matter_machine. That is for example say for a given model I have a machine named Car, I wish to have a sub-machine Driver for it.

could you add this passage to your SO post? Otherwise my answer might look a bit off.

Yishu1997 commented 3 years ago

Hi @aleneum ,

Sure I will add this paragraph on my SO post.

Looking forward to your answer on SO.

Thanks

aleneum commented 3 years ago

If my answer on SO solves your issue, please mark it appropriately. If not, let's solve missing bits via comments on the post. I will close this issue since it does not represent a feature request or bug report. Feel free to comment. If a bug report/feature request arises, I will reopen the issue.