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.

Transition - validate against model/machine

See original GitHub issue
  • Python State Machine version: 0.7.1
  • Python version: 3.6.
  • Operating System: macOS 10.14.6

Description

Hi!

I’m trying to figure out how to include the machine’s model or even the machine itself into validation parameters - let me illustrate it by an example.

Assume we have this machine with a single “run” transition and a class representing a runner. Of course running requires some energy, so a side effect of it is, naturally, a decrease in energy:

from statemachine import StateMachine, State

class RunningMachine(StateMachine):
    start = State('start', initial=True)
    end = State('end')

    run = start.to(end)

    def on_run(self):
        self.model.energy -= 10

class Runner:
    def __init__(self, energy):
        self.energy = energy
        self.state = 'start'

runner = Runner(15)
RunningMachine(runner).run()
print(runner.energy)  # 5
print(runner.state)  # end

So far so good! Now what I’d like to do is to make sure that Runner has enough energy to run in the first place, so I add a validation like this:

def has_enough_energy(runner):
    assert runner.energy >= 10

class RunningMachine:
    ...
    run = start.to(end)
    run.validators = [has_enough_energy]

The problem is that in order to use it I now have to pass a Runner instance as an argument for transition, otherwise it won’t make it to the validation function:

class RunningMachine:
    ...
    def on_run(self, runner):
        runner.energy -= 10

machine = RunningMachine(runner)
machine.run(runner)  # wait a second, don't you have reference to the 'runner' already?

It can get even worse since the runner I pass into it might in fact be a different runner! Which of course leads to an inconsistency:

fresh_runner = Runner(10)
tired_runner = Runner(0)

machine = RunningMachine(tired_runner)
machine.run(fresh_runner)  # oops...

print(fresh_runner.energy)  # 0
print(fresh_runner.state)  # start
print(tired_runner.state)  # end 

What I Did

Well there’s not much I can do about it but make sure to pass the same Runner instance to the transition itself. It doesn’t come handy and raises some issues I’ve outlined above so it all comes down to the following questions:

  • Am I missing something / doing something wrong? I.e. is there a (better) way to include the model/machine into the validation process?
  • If there’s none, validators functionality could probably be improved by allowing str arguments, e.g.:
class RunningMachine:
    run = a.to(b)
    
    def can_run(self):
        assert self.runner.energy >= 10
    run.validators = ['can_run']    

or by allowing class method (this would require some checks so that transition would know if it should pass model to the validator in order to not break compatibility):

class RunningMachine:
    def can_run(self):
        assert self.model.energy >= 10
    
    @start.to(end, validators=can_run)
    def run(self):
        self.model.energy -= 10

Of course I’d be happy to create a PR implementing either of these approaches - or any other if that would make more sense to you.

Thanks!

Issue Analytics

  • State:open
  • Created 4 years ago
  • Comments:8 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
arseniy-panfilovcommented, Feb 18, 2020

Hi @claverru! Thanks for your continued attempts to solve my issue! 😃 apparently I’m not that good when it comes to highlighting the important stuff hehe; anyway, let me elaborate one more time.

My main and only issue is adding validators to transitions. Even if I convert my StateMachine into Runner (which I’d like to avoid - I prefer my models being simple), it doesn’t solve validation issue since validators as they are right now do not have access to model nor state machine itself. Instead, they only have access to the same arguments you pass into transition.

E.g. In this example

def on_run(self, foo):
    pass

if you add a validator to the on_run transition, your validator will only receive foo argument and that’s it. Therefore, if you want to validate against StateMachine’s model, you have to pass this model as an argument to the transition, which might potentially break data consistency (see my previous examples).

1reaction
fgmacedocommented, Jan 23, 2020

Hi @arseniy-panfilov , nice snippet! It really shows that something is missing. We can’t keep up with this validators API.

Let me share what I’m thinking about.

I’m reading about statecharts since SCXML (Statechart XML), is a W3C standard and it defines a lot of the semantics and specifies how to deal with certain edge cases. A statechart is essentially a state machine that allows any state to include more machines, in a hierarchical fashion. This is already a feature request at https://github.com/fgmacedo/python-statemachine/issues/246.

With that in mind, my goal to this library may turn to be as much as possible compatible with statecharts but using a different syntax. A pythonic interface to statecharts.

So, related with your issue, we should implement ‘guard’.

Read more comments on GitHub >

github_iconTop Results From Across the Web

pytransitions/transitions - GitHub
This is done to allow multiple machines to work on the same model with individual ... If you need to know which transitions...
Read more >
Validation before persistance on state_machine gem
I'd like to stop the state machine from transitioning into :orange in the first place. The core problem is that in my controller...
Read more >
Model Validation | Kaggle
In this lesson, you will learn to use model validation to measure the quality of your model. Measuring model quality is the key...
Read more >
How to validate the transition by the number of attachments on ...
Hi,. I'm trying to validate the number of attachments in a transition. You can get temporary attachments through form token or id temporary...
Read more >
System enforces the state transition (through com.snc ...
state_model.StateTransitionValidator) and does not allow transition of state through Business Rule / Script if it does not validate against existing model. 592 ...
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