Source code for statemachine.transition

from copy import deepcopy
from typing import TYPE_CHECKING

from .callbacks import CallbackGroup
from .callbacks import CallbackPriority
from .callbacks import CallbackSpecList
from .events import Events
from .exceptions import InvalidDefinition

if TYPE_CHECKING:
    from .statemachine import State


[docs] class Transition: """A transition holds reference to the source and target state. Args: source (State): The origin state of the transition. target (State): The target state of the transition. event (Optional[Union[str, List[str]]]): List of designators of events that trigger this transition. Can be either a list of strings, or a space-separated string list of event descriptors. internal (bool): Is the transition internal or external? Internal transitions don't execute the state entry/exit actions. Default ``False``. validators (Optional[Union[str, Callable, List[Callable]]]): The validation callbacks to be invoked before the transition is executed. cond (Optional[Union[str, Callable, List[Callable]]]): The condition callbacks to be invoked before the transition is executed that should evaluate to `True`. unless (Optional[Union[str, Callable, List[Callable]]]): The condition callbacks to be invoked if the `cond` is False before the transition is executed. on (Optional[Union[str, Callable, List[Callable]]]): The callbacks to be invoked when the transition is executed. before (Optional[Union[str, Callable, List[Callable]]]): The callbacks to be invoked before the transition is executed. after (Optional[Union[str, Callable, List[Callable]]]): The callbacks to be invoked after the transition is executed. """ def __init__( self, source: "State", target: "State", event=None, internal=False, validators=None, cond=None, unless=None, on=None, before=None, after=None, ): self.source = source self.target = target self.internal = internal if internal and source is not target: raise InvalidDefinition("Internal transitions should be self-transitions.") self._events = Events().add(event) self._specs = CallbackSpecList() self.validators = self._specs.grouper(CallbackGroup.VALIDATOR).add( validators, priority=CallbackPriority.INLINE ) self.before = self._specs.grouper(CallbackGroup.BEFORE).add( before, priority=CallbackPriority.INLINE ) self.on = self._specs.grouper(CallbackGroup.ON).add(on, priority=CallbackPriority.INLINE) self.after = self._specs.grouper(CallbackGroup.AFTER).add( after, priority=CallbackPriority.INLINE ) self.cond = ( self._specs.grouper(CallbackGroup.COND) .add(cond, priority=CallbackPriority.INLINE, expected_value=True) .add(unless, priority=CallbackPriority.INLINE, expected_value=False) ) def __repr__(self): return ( f"{type(self).__name__}({self.source!r}, {self.target!r}, event={self.event!r}, " f"internal={self.internal!r})" ) def __str__(self): return f"transition {self.event!s} from {self.source!s} to {self.target!s}" def _setup(self): before = self.before.add on = self.on.add after = self.after.add before("before_transition", priority=CallbackPriority.GENERIC, is_convention=True) on("on_transition", priority=CallbackPriority.GENERIC, is_convention=True) for event in self._events: same_event_cond = event.is_same_event before( f"before_{event}", priority=CallbackPriority.NAMING, is_convention=True, cond=same_event_cond, ) on( f"on_{event}", priority=CallbackPriority.NAMING, is_convention=True, cond=same_event_cond, ) after( f"after_{event}", priority=CallbackPriority.NAMING, is_convention=True, cond=same_event_cond, ) after( "after_transition", priority=CallbackPriority.AFTER, is_convention=True, ) def match(self, event: str): return self._events.match(event) @property def event(self): return str(self._events) @property def events(self): return self._events def add_event(self, value): self._events.add(value) def _copy_with_args(self, **kwargs): source = kwargs.pop("source", self.source) target = kwargs.pop("target", self.target) event = kwargs.pop("event", self.event) internal = kwargs.pop("internal", self.internal) new_transition = Transition( source=source, target=target, event=event, internal=internal, **kwargs ) for spec in self._specs: new_spec = deepcopy(spec) new_transition._specs.add(new_spec, new_spec.group) return new_transition