|
1 | 1 | from typing import TYPE_CHECKING |
2 | 2 | from typing import Any |
3 | 3 | from typing import Dict |
| 4 | +from typing import List |
4 | 5 | from weakref import ref |
5 | 6 |
|
6 | 7 | from .callbacks import CallbackGroup |
|
15 | 16 | from .statemachine import StateMachine |
16 | 17 |
|
17 | 18 |
|
| 19 | +class _TransitionBuilder: |
| 20 | + def __init__(self, state: "State"): |
| 21 | + self._state = state |
| 22 | + |
| 23 | + def itself(self, **kwargs): |
| 24 | + return self.__call__(self._state, **kwargs) |
| 25 | + |
| 26 | + def __call__(self, *states: "State", **kwargs): |
| 27 | + raise NotImplementedError |
| 28 | + |
| 29 | + |
| 30 | +class _ToState(_TransitionBuilder): |
| 31 | + def __call__(self, *states: "State", **kwargs): |
| 32 | + transitions = TransitionList(Transition(self._state, state, **kwargs) for state in states) |
| 33 | + self._state.transitions.add_transitions(transitions) |
| 34 | + return transitions |
| 35 | + |
| 36 | + |
| 37 | +class _FromState(_TransitionBuilder): |
| 38 | + def any(self, **kwargs): |
| 39 | + return self.__call__(AnyState(), **kwargs) |
| 40 | + |
| 41 | + def __call__(self, *states: "State", **kwargs): |
| 42 | + transitions = TransitionList() |
| 43 | + for origin in states: |
| 44 | + transition = Transition(origin, self._state, **kwargs) |
| 45 | + origin.transitions.add_transitions(transition) |
| 46 | + transitions.add_transitions(transition) |
| 47 | + return transitions |
| 48 | + |
| 49 | + |
18 | 50 | class State: |
19 | 51 | """ |
20 | 52 | A State in a :ref:`StateMachine` describes a particular behavior of the machine. |
@@ -136,6 +168,12 @@ def _setup(self): |
136 | 168 | self.exit.add("on_exit_state", priority=CallbackPriority.GENERIC, is_convention=True) |
137 | 169 | self.exit.add(f"on_exit_{self.id}", priority=CallbackPriority.NAMING, is_convention=True) |
138 | 170 |
|
| 171 | + def _on_event_defined(self, event: str, transition: Transition, states: List["State"]): |
| 172 | + """Called by statemachine factory when an event is defined having a transition |
| 173 | + starting from this state. |
| 174 | + """ |
| 175 | + pass |
| 176 | + |
139 | 177 | def __repr__(self): |
140 | 178 | return ( |
141 | 179 | f"{type(self).__name__}({self.name!r}, id={self.id!r}, value={self.value!r}, " |
@@ -172,38 +210,15 @@ def _set_id(self, id: str): |
172 | 210 | if not self.name: |
173 | 211 | self.name = self._id.replace("_", " ").capitalize() |
174 | 212 |
|
175 | | - def _to_(self, *states: "State", **kwargs): |
176 | | - transitions = TransitionList(Transition(self, state, **kwargs) for state in states) |
177 | | - self.transitions.add_transitions(transitions) |
178 | | - return transitions |
179 | | - |
180 | | - def _from_(self, *states: "State", **kwargs): |
181 | | - transitions = TransitionList() |
182 | | - for origin in states: |
183 | | - transition = Transition(origin, self, **kwargs) |
184 | | - origin.transitions.add_transitions(transition) |
185 | | - transitions.add_transitions(transition) |
186 | | - return transitions |
187 | | - |
188 | | - def _get_proxy_method_to_itself(self, method): |
189 | | - def proxy(*states: "State", **kwargs): |
190 | | - return method(*states, **kwargs) |
191 | | - |
192 | | - def proxy_to_itself(**kwargs): |
193 | | - return proxy(self, **kwargs) |
194 | | - |
195 | | - proxy.itself = proxy_to_itself |
196 | | - return proxy |
197 | | - |
198 | 213 | @property |
199 | | - def to(self): |
| 214 | + def to(self) -> _ToState: |
200 | 215 | """Create transitions to the given target states.""" |
201 | | - return self._get_proxy_method_to_itself(self._to_) |
| 216 | + return _ToState(self) |
202 | 217 |
|
203 | 218 | @property |
204 | | - def from_(self): |
| 219 | + def from_(self) -> _FromState: |
205 | 220 | """Create transitions from the given target states (reversed).""" |
206 | | - return self._get_proxy_method_to_itself(self._from_) |
| 221 | + return _FromState(self) |
207 | 222 |
|
208 | 223 | @property |
209 | 224 | def initial(self): |
@@ -269,3 +284,19 @@ def id(self) -> str: |
269 | 284 | @property |
270 | 285 | def is_active(self): |
271 | 286 | return self._machine().current_state == self |
| 287 | + |
| 288 | + |
| 289 | +class AnyState(State): |
| 290 | + """A special state that works as a "ANY" placeholder. |
| 291 | +
|
| 292 | + It is used as the "From" state of a transtion, |
| 293 | + until the state machine class is evaluated. |
| 294 | + """ |
| 295 | + |
| 296 | + def _on_event_defined(self, event: str, transition: Transition, states: List[State]): |
| 297 | + for state in states: |
| 298 | + if state.final: |
| 299 | + continue |
| 300 | + new_transition = transition._copy_with_args(source=state, event=event) |
| 301 | + |
| 302 | + state.transitions.add_transitions(new_transition) |
0 commit comments