question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

`get_triggers` doesn't check conditions

See original GitHub issue

Machine.get_triggers doesn’t check conditions, and so returns triggers that can’t actually be called.

Generally, there is no mechanism to check upon a transition’s conditions before actually trying to apply it.

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:9 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
lortiz-nativocommented, Sep 14, 2021

This thread is a little old now but I found the solution that @aleneum gave to be very helpful for my use case and I wanted to point out a small problem i ran into. The can_trigger function will return triggers that are not valid if they share the same name as valid triggers from a different source state. These should not be taken into account since we know what our current state is.

I think these transitions will reveal the error. If our model is in state “B” can_trigger will still return go_A even though the successful transition does not apply because it requires us to be in state “C”.

transitions = [
    dict(trigger='go_A', source='B', dest='A', conditions=['fails']),
    dict(trigger='go_A', source='C', dest='A', conditions=['success']),
]

I think this should fix it

def _can_trigger(self, model, *args, **kwargs):
    # We can omit the first two arguments state and event since they are only needed for
    # actual state transitions. We do have to pass the machine (self) and the model as well as
    # args and kwargs meant for the callbacks.
    e = EventData(None, None, self, model, args, kwargs)

    return [
        trigger_name
        for trigger_name in self.get_triggers(model.state)
        if any(
            all(c.check(e) for c in t.conditions)
            for t in self.events[trigger_name].transitions[model.state]
        )
    ]
1reaction
aleneumcommented, Sep 11, 2017

Hi @benselme,

EventData is a collection of data relevant for the transition which you can create on the fly as you can see in the following example. PeekMachine is based on your initial idea (thanks for that) and adds a can_trigger method to each model for convenience.

from transitions import Machine, EventData
from functools import partial


class Model(object):

    def fails(self, condition=False):
        return False

    def success(self, condition=False):
        return True

    # condition is passed by EventData
    def depends_on(self, condition=False):
        return condition

    def is_state_B(self, condition=False):
        return self.state == 'B'


class PeekMachine(Machine):

    def _can_trigger(self, model, *args, **kwargs):
        # We can omit the first two arguments state and event since they are only needed for 
        # actual state transitions. We do have to pass the machine (self) and the model as well as 
        # args and kwargs meant for the callbacks.
        e = EventData(None, None, self, model, args, kwargs)

        return [trigger_name for trigger_name in self.get_triggers(model.state)
                if any(all(c.check(e) for c in t.conditions)
                       for ts in self.events[trigger_name].transitions.values()
                       for t in ts)]

    # override Machine.add_model to assign 'can_trigger' to the model
    def add_model(self, model, initial=None):
        super(PeekMachine, self).add_model(model, initial)
        setattr(model, 'can_trigger', partial(self._can_trigger, model))


states = ['A', 'B', 'C', 'D']
transitions = [
    dict(trigger='go_A', source='*', dest='A', conditions=['depends_on']),  # only available when condition=True is passed
    dict(trigger='go_B', source='*', dest='B', conditions=['success']),  # always available
    dict(trigger='go_C', source='*', dest='C', conditions=['fails']),  # never available
    dict(trigger='go_D', source='*', dest='D', conditions=['is_state_B']),  # only available in state B
    dict(trigger='reset', source='D', dest='A', conditions=['success', 'depends_on']), # only available in state D when condition=True is passed
    dict(trigger='forwards', source='A', dest='D', conditions=['success', 'fails']),  # never available
]

model = Model()
machine = PeekMachine(model, states=states, transitions=transitions, initial='A', auto_transitions=False)
assert model.can_trigger() == ['go_B']
assert model.can_trigger(condition=True) == ['go_A', 'go_B']
model.go_B(condition=True)
assert model.can_trigger() == ['go_B', 'go_D']
model.go_D()
assert model.can_trigger() == ['go_B']
assert model.can_trigger(condition=True) == ['go_A', 'go_B', 'reset']
Read more comments on GitHub >

github_iconTop Results From Across the Web

mysql - Trigger can't work properly when check condition
The problem is in product_stock table, INSERT query doesn't work when product record not exist, but update query work does properly when product ......
Read more >
Workflow Automation - How to get Triggers Conditions to combine ...
I currently have an automation set up across all our pipelines so that anytime a project stage is changed to 'confirmed' , the...
Read more >
Triggers - AWS Glue - AWS Documentation
... An array of Condition objects. A list of the conditions that determine when the trigger will fire. ... GetTriggers action (Python: get_triggers)....
Read more >
Trigger Conditions doesn't work - Power Platform Community
This example works with versioning (make sure that this is enabled on your list). In this example we will check if the value...
Read more >
Java API: Condition Class Reference - Kanzi documentation
Check function for condition. void, close (). Close the object, and release native resources. Trigger · getTrigger (). Returns the pointer to a...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found