from transitions import Machine
class TradingSystem:
def __init__(self):
self.machine = Machine(model=self, states=['RUNNING'], initial='RUNNING')
def check_running(self) -> None:
if self.is_RUNNING():
print("System is running")
system = TradingSystem()
system.check_running()
mypy transitions_mypy.py
gives the error:
transitions_mypy.py:9: error: "TradingSystem" has no attribute "is_RUNNING" [attr-defined]
This can be avoided by bypassing mypy, for example adding # type: ignore[attr-defined]
at the end of line 9.
But what is the proper way? Is it better to avoid bypassing mypy? Perhaps by manually defining the attribute?
The answer @Mark proposed won't work since transitions does not override already existing model attributes because that would be unexpected (mis)behaviour (as @Mark pointed out). If you enable logging, transitions will also tell you that:
import logging
logging.basicConfig(level=logging.DEBUG)
The output should contain:
WARNING:transitions.core:Model already contains an attribute 'is_RUNNING'. Skip binding.
In the past, I suggested to inherit from Machine
and override Machine._checked_assignment
to workaround that safeguard. However, @james-hirschorn's approach using attrs which was posted in the transitions issue tracker is a better solution in my oppinion:
from typing import Callable
from attrs import define, field
from transitions import Machine
@define(slots=False)
class TradingSystem:
is_RUNNING: Callable[[], bool] = field(init=False)
stop: Callable[[], None] = field(init=False)
def __attrs_post_init__(self):
self.machine = Machine(model=self, states=['RUNNING', 'STOPPED'], initial='RUNNING')
self.machine.add_transition(trigger='stop', source='RUNNING', dest='STOPPED')
def check_running(self) -> None:
if self.is_RUNNING():
print("System is running")
def stop_system(self) -> None:
self.stop()
print("System stopped")
# Example usage
system = TradingSystem()
system.check_running()
system.stop_system()
This produces some overhead since you have to define triggers and convenience methods twice. Furthermore, type information are also incomplete because transitions will also add is_STOPPED
and auto transitions like to_STOPPED/RUNNING
or 'peek' transition methods such as may_stop
to TradingSystem
during runtime.
Improving transitions typing support is currently an open issue.