python-statemachine 3.2.1__py3-none-any.whl → 3.2.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_statemachine-3.2.1.dist-info → python_statemachine-3.2.2.dist-info}/METADATA +7 -6
- {python_statemachine-3.2.1.dist-info → python_statemachine-3.2.2.dist-info}/RECORD +28 -27
- {python_statemachine-3.2.1.dist-info → python_statemachine-3.2.2.dist-info}/WHEEL +1 -1
- statemachine/__init__.py +1 -1
- statemachine/callbacks.py +11 -0
- statemachine/contrib/diagram/__init__.py +15 -6
- statemachine/contrib/diagram/formatter.py +4 -2
- statemachine/contrib/diagram/graphviz.py +66 -0
- statemachine/contrib/diagram/sphinx_ext.py +28 -7
- statemachine/dispatcher.py +3 -2
- statemachine/engines/async_.py +209 -177
- statemachine/engines/base.py +245 -244
- statemachine/engines/sync.py +224 -108
- statemachine/event.py +29 -10
- statemachine/event_data.py +19 -3
- statemachine/events.py +5 -2
- statemachine/factory.py +126 -29
- statemachine/io/actions.py +4 -2
- statemachine/io/schemas/statechart.schema.json +8 -1
- statemachine/locale/en/LC_MESSAGES/statemachine.po +58 -17
- statemachine/locale/hi_IN/LC_MESSAGES/statemachine.po +66 -17
- statemachine/locale/pt_BR/LC_MESSAGES/statemachine.po +66 -17
- statemachine/locale/zh_CN/LC_MESSAGES/statemachine.po +60 -17
- statemachine/registry.py +6 -1
- statemachine/spec_parser.py +95 -19
- statemachine/state.py +45 -6
- statemachine/statemachine.py +42 -19
- {python_statemachine-3.2.1.dist-info → python_statemachine-3.2.2.dist-info}/licenses/LICENSE +0 -0
statemachine/statemachine.py
CHANGED
|
@@ -5,6 +5,7 @@ from typing import TYPE_CHECKING
|
|
|
5
5
|
from typing import Any
|
|
6
6
|
from typing import Generic
|
|
7
7
|
from typing import TypeVar
|
|
8
|
+
from typing import cast
|
|
8
9
|
|
|
9
10
|
from statemachine.orderedset import OrderedSet
|
|
10
11
|
|
|
@@ -146,7 +147,7 @@ class StateChart(Generic[TModel], metaclass=StateMachineMetaclass):
|
|
|
146
147
|
listeners: "list[object] | None" = None,
|
|
147
148
|
**kwargs: Any,
|
|
148
149
|
):
|
|
149
|
-
self.model: TModel = model if model is not None else Model()
|
|
150
|
+
self.model: TModel = model if model is not None else cast(TModel, Model())
|
|
150
151
|
"""The external model object that holds domain state, or an internal
|
|
151
152
|
:class:`Model` instance when none is provided. See :ref:`domain models`."""
|
|
152
153
|
|
|
@@ -207,7 +208,7 @@ class StateChart(Generic[TModel], metaclass=StateMachineMetaclass):
|
|
|
207
208
|
instance_states: dict[Any, Any] = {}
|
|
208
209
|
events = self.__class__._events
|
|
209
210
|
for state in self.states_map.values():
|
|
210
|
-
ist = InstanceState(state, self)
|
|
211
|
+
ist = InstanceState(state, self, instance_states)
|
|
211
212
|
instance_states[state.value] = ist
|
|
212
213
|
if state.id not in events:
|
|
213
214
|
vars(self)[state.id] = ist
|
|
@@ -225,7 +226,11 @@ class StateChart(Generic[TModel], metaclass=StateMachineMetaclass):
|
|
|
225
226
|
return run_async_from_sync(result)
|
|
226
227
|
|
|
227
228
|
def _processing_loop(self, caller_future: "Any | None" = None) -> Any:
|
|
228
|
-
result
|
|
229
|
+
# Only the async engine gives an event a future, for its caller to await the result by.
|
|
230
|
+
if isinstance(self._engine, AsyncEngine):
|
|
231
|
+
result = self._engine.processing_loop(caller_future)
|
|
232
|
+
else:
|
|
233
|
+
result = self._engine.processing_loop()
|
|
229
234
|
if not isawaitable(result):
|
|
230
235
|
return result
|
|
231
236
|
return run_async_from_sync(result)
|
|
@@ -259,7 +264,7 @@ class StateChart(Generic[TModel], metaclass=StateMachineMetaclass):
|
|
|
259
264
|
|
|
260
265
|
def __setstate__(self, state: dict[str, Any]) -> None:
|
|
261
266
|
listeners = state.pop("_listeners")
|
|
262
|
-
self.
|
|
267
|
+
vars(self).update(state)
|
|
263
268
|
self._callbacks = CallbacksRegistry()
|
|
264
269
|
self._config = self._build_configuration()
|
|
265
270
|
self._listeners = {}
|
|
@@ -273,11 +278,11 @@ class StateChart(Generic[TModel], metaclass=StateMachineMetaclass):
|
|
|
273
278
|
self._engine.start()
|
|
274
279
|
|
|
275
280
|
def _get_initial_configuration(self):
|
|
276
|
-
initial_state_values =
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
+
initial_state_values = self.start_configuration_values
|
|
282
|
+
if not initial_state_values:
|
|
283
|
+
# Only a machine with no states has no initial state, and none can be created.
|
|
284
|
+
assert self.initial_state is not None
|
|
285
|
+
initial_state_values = [self.initial_state.value]
|
|
281
286
|
try:
|
|
282
287
|
return [self.states_map[value] for value in initial_state_values]
|
|
283
288
|
except KeyError as err:
|
|
@@ -362,7 +367,7 @@ class StateChart(Generic[TModel], metaclass=StateMachineMetaclass):
|
|
|
362
367
|
return f'<div class="statemachine">{self._repr_svg_()}</div>'
|
|
363
368
|
|
|
364
369
|
def _repr_svg_(self):
|
|
365
|
-
return self
|
|
370
|
+
return format(self, "svg")
|
|
366
371
|
|
|
367
372
|
def _graph(self):
|
|
368
373
|
from .contrib.diagram import DotGraphMachine
|
|
@@ -460,18 +465,23 @@ class StateChart(Generic[TModel], metaclass=StateMachineMetaclass):
|
|
|
460
465
|
self,
|
|
461
466
|
event: str,
|
|
462
467
|
*args,
|
|
463
|
-
delay: float =
|
|
468
|
+
delay: "float | None" = None,
|
|
464
469
|
send_id: "str | None" = None,
|
|
465
|
-
internal: bool =
|
|
470
|
+
internal: "bool | None" = None,
|
|
466
471
|
**kwargs,
|
|
467
472
|
) -> Any:
|
|
468
473
|
"""Send an :ref:`Event` to the state machine.
|
|
469
474
|
|
|
470
475
|
:param event: The trigger for the state machine, specified as an event id string.
|
|
471
476
|
:param args: Additional positional arguments to pass to the event.
|
|
472
|
-
:param delay: A time delay in milliseconds to process the event.
|
|
477
|
+
:param delay: A time delay in milliseconds to process the event. Defaults to the
|
|
478
|
+
event's declaration, or 0. An explicit ``0`` overrides a declared delay.
|
|
473
479
|
:param send_id: An identifier for the event, used with ``cancel_event()`` to cancel
|
|
474
480
|
delayed events.
|
|
481
|
+
:param internal: Put the event on the internal queue, so it runs within the current
|
|
482
|
+
macrostep. Defaults to the event's declaration. Honored from a callback; sent from
|
|
483
|
+
outside a step, the event goes to the external queue and its result is returned.
|
|
484
|
+
Cannot be combined with ``delay``.
|
|
475
485
|
:param kwargs: Additional keyword arguments to pass to the event.
|
|
476
486
|
|
|
477
487
|
.. seealso::
|
|
@@ -480,9 +490,10 @@ class StateChart(Generic[TModel], metaclass=StateMachineMetaclass):
|
|
|
480
490
|
"""
|
|
481
491
|
know_event = getattr(self, event, None)
|
|
482
492
|
event_name = know_event.name if know_event else event
|
|
483
|
-
delay
|
|
484
|
-
delay
|
|
485
|
-
|
|
493
|
+
if delay is None:
|
|
494
|
+
delay = cast(float, know_event.delay if know_event else 0)
|
|
495
|
+
if internal is None:
|
|
496
|
+
internal = bool(know_event and know_event.internal)
|
|
486
497
|
event_instance = BoundEvent(
|
|
487
498
|
id=event, name=event_name, delay=delay, internal=internal, _sm=self
|
|
488
499
|
)
|
|
@@ -492,13 +503,22 @@ class StateChart(Generic[TModel], metaclass=StateMachineMetaclass):
|
|
|
492
503
|
return run_async_from_sync(result)
|
|
493
504
|
|
|
494
505
|
def raise_(
|
|
495
|
-
self,
|
|
506
|
+
self,
|
|
507
|
+
event: str,
|
|
508
|
+
*args,
|
|
509
|
+
delay: "float | None" = None,
|
|
510
|
+
send_id: "str | None" = None,
|
|
511
|
+
**kwargs,
|
|
496
512
|
) -> Any:
|
|
497
513
|
"""Send an :ref:`Event` to the state machine in the internal event queue.
|
|
498
514
|
|
|
499
515
|
Events on the internal queue are processed immediately within the current
|
|
500
516
|
macrostep, before any pending external events. This is equivalent to calling
|
|
501
|
-
``send(..., internal=True)
|
|
517
|
+
``send(..., internal=True)``: called from outside a callback, there is no macrostep
|
|
518
|
+
to join, so the event goes to the external queue and its result is returned. A
|
|
519
|
+
``delay`` other than 0, given or declared on the event, is an
|
|
520
|
+
:class:`~statemachine.exceptions.InvalidDefinition`; pass ``delay=0`` to override a
|
|
521
|
+
declared one.
|
|
502
522
|
|
|
503
523
|
.. seealso::
|
|
504
524
|
|
|
@@ -507,7 +527,10 @@ class StateChart(Generic[TModel], metaclass=StateMachineMetaclass):
|
|
|
507
527
|
return self.send(event, *args, delay=delay, send_id=send_id, internal=True, **kwargs)
|
|
508
528
|
|
|
509
529
|
def cancel_event(self, send_id: str):
|
|
510
|
-
"""Cancel all the delayed events with the given ``send_id``.
|
|
530
|
+
"""Cancel all the delayed events with the given ``send_id``.
|
|
531
|
+
|
|
532
|
+
A caller awaiting one of them gets ``None``.
|
|
533
|
+
"""
|
|
511
534
|
self._engine.cancel_event(send_id)
|
|
512
535
|
|
|
513
536
|
@property
|
{python_statemachine-3.2.1.dist-info → python_statemachine-3.2.2.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|