pytransitions / transitions

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

when a error occour in shipment,state trigger again will be exception #486

Closed m986883511 closed 3 years ago

m986883511 commented 3 years ago

image

[2020-11-18 21:38:13,205] test:39 [ERROR] 出现异常,当前步骤为=QNMainActivity,err=State 'Shipment_Shipment_waitSendView' is not a registered state.

yaml:

aleneum commented 3 years ago

Hello @m986883511,

I cannot really tell what's going on based on the info you have provided. Could you provide a minimal and executable code snippets that illustrates your issue?

m986883511 commented 3 years ago
import time
import logging

from transitions.extensions import HierarchicalGraphMachine as Machine

LOG = logging.getLogger()

class MyMatter(object):

    def check_liquid(self):
        raise Exception('check_liquid have a exception')
        print('check ok')

    def show_graph(self):
        self.get_graph().draw('temp', prog='dot', format='svg')
        time.sleep(1)

transitions = [
    {'trigger': 'evaporate', 'source': 'change_liquid', 'dest': 'change_gas'},
    {'trigger': 'again_initial', 'source': 'change_gas', 'dest': 'initial'},
    {'trigger': 'just_change', 'source': 'initial', 'dest': 'change'},
    {'trigger': 'goto_initial', 'source': 'Exception', 'dest': 'initial'}
]
states = ['Exception',
          {'name': 'change', 'initial': 'liquid', 'children': ['gas',{'name': 'liquid', 'on_enter': 'check_liquid'}]}
          ]

class TransitionFsm(object):
    def __init__(self):
        self.model = MyMatter()
        self.machine = Machine(model=self.model, transitions=transitions, states=states,
                               show_conditions=True, show_state_attributes=True)
        self.model.show_graph()

    def run(self):
        while True:
            try:
                now_state = self.model.state
                triggers = self.machine.get_triggers(now_state)
                self.machine.get_triggers()
                triggers = [trigger for trigger in triggers if not trigger.startswith('to_')]
                LOG.debug('available trigger is {}',format(triggers))
                for trigger in triggers:
                    if self.model.trigger(trigger):
                        break
                    else:
                        LOG.warning('not {}, try another'.format(trigger))
                else:
                    raise Exception('can not trigger from {}'.format(now_state))
            except Exception as e:
                LOG.error('raise exceptionm,now state={},err={}'.format(self.model.state, str(e)))
                self.machine.set_state('Exception', self.model)
                LOG.info('reset noe state={}'.format(self.model.state))
                time.sleep(2)
            else:
                LOG.debug('trigger from {} to {} success'.format(now_state, trigger))
                time.sleep(1)

if __name__ == '__main__':
    a = TransitionFsm()
    a.run()
m986883511 commented 3 years ago

image

if a exception in check_liquid,you can see the unknown state error; raise exceptionm,now state=change_liquid,err=check_liquid have a exception raise exceptionm,now state=initial,err=State 'change_change_liquid' is not a registered state. raise exceptionm,now state=initial,err=State 'change_change_liquid' is not a registered state.

m986883511 commented 3 years ago

you can copy my code at:https://github.com/m986883511/my_issues/blob/main/transitions_problem_1.py

m986883511 commented 3 years ago

Hello @m986883511,

I cannot really tell what's going on based on the info you have provided. Could you provide a minimal and executable code snippets that illustrates your issue?

i have provide a minimal code,expect your replay

aleneum commented 3 years ago

i have provide a minimal code

your code was executable. thanks for that. There was room for improvement considering 'minimal' though. I could boil it down to this:

from transitions.extensions import HierarchicalMachine as Machine

class MyMatter(object):

    def check_liquid(self):
        raise RuntimeError('check_liquid have a exception')
        print('check ok')

transitions = [
    {'trigger': 'just_change', 'source': 'initial', 'dest': 'change'},
    {'trigger': 'goto_initial', 'source': 'Exception', 'dest': 'initial'}
]

states = ['Exception',
          {'name': 'change', 'initial': 'liquid', 'children': ['gas', {'name': 'liquid', 'on_enter': 'check_liquid'}]}]

if __name__ == '__main__':
    model = MyMatter()
    machine = Machine(model=model, transitions=transitions, states=states)
    try:
        model.just_change()
    except RuntimeError:
        machine.set_state('Exception', model)
    model.goto_initial()
    try:
        model.just_change()
    except RuntimeError:
        pass

I'd also appreciate if you take the time to format your comments and code blocks. This would make it easier for me to copy it and for future readers to comprehend your contributions. Nevertheless thank you for bringing this bug to my attention! Let me know if c275526 solves your issue. If not, I will reopen the issue