Skip to content
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

may_ function in parallel state does not report correct value #647

Closed
spearsear opened this issue Feb 29, 2024 · 1 comment
Closed

may_ function in parallel state does not report correct value #647

spearsear opened this issue Feb 29, 2024 · 1 comment
Assignees
Labels

Comments

@spearsear
Copy link

spearsear commented Feb 29, 2024

Thank you for taking the time to report a bug! Your support is essential for the maintenance of this project. Please fill out the following fields to ease bug hunting and resolving this issue as soon as possible:

Describe the bug
In parallel state of a hierarchical machine, the may_ function for a trigger returns False, yet it should return True, since the trigger indeed return True

I have a simple statemachine which runs a task for each month in quarter 1 parallelly, then run each month in quarter 2 parallelly. When it reach the parallell state of run_qtr_1, may_ function of any trigger in quater1 should return True, yet it returns False. And I indeed can run the trigger function

from transitions.extensions import HierarchicalMachine
        from transitions.extensions.nesting import NestedState
        class Model:
            def __init__(self):
                pass

            def qtr1_completed(self, event):
                # check embedding_[1-3]_succeeded state has been reached
                return True

            def qtr2_completed(self, event):
                # check embedding_[1-3]_succeeded state has been reached
                return True

        model = Model()
        states = [
            'workflow_started',
            {
                'name': 'running_qtr_1',
                'parallel': [
                    {
                        'name': 'running_jan',
                        'children': [
                            'jan_started', 'jan_succeeded', 'jan_failed'
                        ],
                        'initial': 'jan_started',
                        'transitions': [
                            ['end_success_jan', 'jan_started', 'jan_succeeded'],
                            ['end_failure_jan', 'jan_started', 'jan_failed']
                        ]
                    },
                    {
                        'name': 'running_feb',
                        'children': [
                            'feb_started', 'feb_succeeded', 'feb_failed'
                        ],
                        'initial': 'feb_started',
                        'transitions': [
                            ['end_success_feb', 'feb_started', 'feb_succeeded'],
                            ['end_failure_feb', 'feb_started', 'feb_failed']
                        ]
                    },
                    {
                        'name': 'running_mar',
                        'children': [
                            'mar_started', 'mar_succeeded', 'mar_failed'
                        ],
                        'initial': 'mar_started',
                        'transitions': [
                            ['end_success_mar', 'mar_started', 'mar_succeeded'],
                            ['end_failure_mar', 'mar_started', 'mar_failed']
                        ]
                    },
                ]
            },
            'completed_qtr_1',
            {
                'name': 'running_qtr_2',
                'parallel': [
                    {
                        'name': 'running_apr',
                        'children': [
                            'apr_started', 'apr_succeeded', 'apr_failed'
                        ],
                        'initial': 'apr_started',
                        'transitions': [
                            ['end_success_apr', 'apr_started', 'apr_succeeded'],
                            ['end_failure_apr', 'apr_started', 'apr_failed']
                        ]
                    },
                    {
                        'name': 'running_may',
                        'children': [
                            'may_started', 'may_succeeded', 'may_failed'
                        ],
                        'initial': 'may_started',
                        'transitions': [
                            ['end_success_may', 'may_started', 'may_succeeded'],
                            ['end_failure_may', 'may_started', 'may_failed']
                        ]
                    },
                    {
                        'name': 'running_jun',
                        'children': [
                            'jun_started', 'jun_succeeded', 'jun_failed'
                        ],
                        'initial': 'jun_started',
                        'transitions': [
                            ['end_success_jun', 'jun_started', 'jun_succeeded'],
                            ['end_failure_jun', 'jun_started', 'jun_failed']
                        ]
                    },
                ],
            },
            'completed_qtr_2',
            'workflow_succeeded', 'workflow_failed'
        ]
        transitions = [
                {'trigger': 'next', 'source': 'workflow_started', 'dest': 'running_qtr_1'},
                {'trigger': 'next', 'source': 'running_qtr_1~running_jan~jan_succeeded', 'dest': 'completed_qtr_1',
                 'conditions': 'qtr1_completed'},
                {'trigger': 'next', 'source': 'running_qtr_1~running_feb~feb_succeeded', 'dest': 'completed_qtr_1',
                 'conditions': 'qtr1_completed'},
                {'trigger': 'next', 'source': 'running_qtr_1~running_mar~mar_succeeded', 'dest': 'completed_qtr_1',
                 'conditions': 'qtr1_completed'},
                {'trigger': 'next', 'source': 'completed_qtr_1', 'dest': 'running_qtr_2'},
                {'trigger': 'next', 'source': 'running_qtr_2~running_apr~apr_succeeded', 'dest': 'completed_qtr_2',
                 'conditions': 'qtr2_completed'},
                {'trigger': 'next', 'source': 'running_qtr_2~running_may~may_succeeded', 'dest': 'completed_qtr_2',
                 'conditions': 'qtr2_completed'},
                {'trigger': 'next', 'source': 'running_qtr_2~running_jun~jun_succeeded', 'dest': 'completed_qtr_2',
                 'conditions': 'qtr2_completed'},
                {'trigger': 'next', 'source': 'completed_qtr_2', 'dest': 'workflow_succeeded'},
                {'trigger': 'next',
                 'source': [
                     'running_qtr_1~running_jan~jan_failed',
                     'running_qtr_1~running_feb~feb_failed',
                     'running_qtr_1~running_mar~mar_failed',
                     'running_qtr_2~running_apr~apr_failed',
                     'running_qtr_2~running_may~may_failed',
                     'running_qtr_2~running_jun~jun_failed'
                 ],
                 'dest': 'workflow_failed'
                 },
            ]
        initial_state = 'workflow_started'
        machine = HierarchicalMachine(
            model=model,
            states=states,
            transitions=transitions,
            initial=initial_state
        )
        print(f"current_state is: {machine.model.state}")
        machine.model.next()
        print(f"current_state is: {machine.model.state}")
        # BUG HERE??? may_ function returns False
        print(f"may_end_success_feb: {machine.model.may_end_success_feb()} <<--- BUG HERE???, Should be True")
        # but indeed I can run the trigger
        machine.model.end_success_feb()
        # you see the parallel state has transitioned to "running_qtr_1~running_feb~feb_succeeded" as expected
        print(f"current_state is: {machine.model.state}")

Expected behavior
may_ function for the triggers in parallel states should return True

Additional context
Output of above code:

current_state is: workflow_started
current_state is: ['running_qtr_1~running_jan~jan_started', 'running_qtr_1~running_feb~feb_started', 'running_qtr_1~running_mar~mar_started']
may_end_success_feb: False  <<--- BUG HERE??? Should be True
current_state is ['running_qtr_1~running_jan~jan_started', 'running_qtr_1~running_feb~feb_succeeded', 'running_qtr_1~running_mar~mar_started']
@aleneum
Copy link
Member

aleneum commented May 24, 2024

Hi @spearsear,

I could reproduce the error.
I agree that may_ and the actual transition should come to the same conclusion.
This is an MRE based on your provided example:

from transitions.extensions import HierarchicalMachine
from transitions.extensions.nesting import NestedState

NestedState.separator = "~"

states = [
    'workflow_started',
    {
        'name': 'running_qtr_1',
        'parallel': [
            {
                'name': 'running_jan',
                'children': [
                    'jan_started', 'jan_succeeded'
                ],
                'initial': 'jan_started'
            },
            {
                'name': 'running_feb',
                'children': [
                    'feb_started', 'feb_succeeded'
                ],
                'initial': 'feb_started',
                'transitions': [
                    ['end_success_feb', 'feb_started', 'feb_succeeded'],
                ]
            },
        ]
    },
]
transitions = [
        {'trigger': 'next', 'source': 'workflow_started', 'dest': 'running_qtr_1'}
]
initial_state = 'workflow_started'
machine = HierarchicalMachine(
    states=states,
    transitions=transitions,
    initial=initial_state
)
machine.next()
print(f"current_state is: {machine.state}")
may_res = machine.may_end_success_feb()
res = machine.end_success_feb()
assert may_res == res
print(f"current_state is: {machine.state}")

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants