xstate-statemachine 0.1.0__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.
- xstate_statemachine/__init__.py +31 -0
- xstate_statemachine/events.py +39 -0
- xstate_statemachine/exceptions.py +43 -0
- xstate_statemachine/factory.py +46 -0
- xstate_statemachine/interpreter.py +1492 -0
- xstate_statemachine/logger.py +21 -0
- xstate_statemachine/machine_logic.py +136 -0
- xstate_statemachine/models.py +694 -0
- xstate_statemachine/plugins.py +181 -0
- xstate_statemachine/resolver.py +118 -0
- xstate_statemachine/task_manager.py +85 -0
- xstate_statemachine-0.1.0.dist-info/LICENSE +21 -0
- xstate_statemachine-0.1.0.dist-info/METADATA +380 -0
- xstate_statemachine-0.1.0.dist-info/RECORD +15 -0
- xstate_statemachine-0.1.0.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# src/xstate_statemachine/__init__.py
|
|
2
|
+
|
|
3
|
+
__version__ = "0.2.0" # Version bump for new features
|
|
4
|
+
|
|
5
|
+
from .factory import create_machine
|
|
6
|
+
from .interpreter import Interpreter
|
|
7
|
+
from .machine_logic import MachineLogic
|
|
8
|
+
from .events import Event
|
|
9
|
+
from .plugins import PluginBase, LoggingInspector
|
|
10
|
+
from .exceptions import (
|
|
11
|
+
XStateMachineError,
|
|
12
|
+
InvalidConfigError,
|
|
13
|
+
StateNotFoundError,
|
|
14
|
+
ImplementationMissingError,
|
|
15
|
+
ActorSpawningError,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
# This is the public API of the library.
|
|
19
|
+
__all__ = [
|
|
20
|
+
"create_machine",
|
|
21
|
+
"Interpreter",
|
|
22
|
+
"MachineLogic",
|
|
23
|
+
"Event",
|
|
24
|
+
"PluginBase",
|
|
25
|
+
"LoggingInspector",
|
|
26
|
+
"XStateMachineError",
|
|
27
|
+
"InvalidConfigError",
|
|
28
|
+
"StateNotFoundError",
|
|
29
|
+
"ImplementationMissingError",
|
|
30
|
+
"ActorSpawningError",
|
|
31
|
+
]
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# src/xstate_statemachine/events.py
|
|
2
|
+
from typing import Any, Dict, Literal, NamedTuple
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
# -----------------------------------------------------------------------------
|
|
6
|
+
# ✉️ Event Definitions
|
|
7
|
+
# -----------------------------------------------------------------------------
|
|
8
|
+
# Standardizing event structures within the machine ensures consistency and
|
|
9
|
+
# clear communication between components.
|
|
10
|
+
# -----------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Event(NamedTuple):
|
|
14
|
+
"""Represents an event sent to the machine."""
|
|
15
|
+
|
|
16
|
+
type: str
|
|
17
|
+
payload: Dict[str, Any] = {}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class DoneEvent(NamedTuple):
|
|
21
|
+
"""
|
|
22
|
+
Represents the completion of an invoked service.
|
|
23
|
+
|
|
24
|
+
The type follows the convention 'done.invoke.<service_id>'.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
type: str
|
|
28
|
+
data: Any
|
|
29
|
+
src: str
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class AfterEvent(NamedTuple):
|
|
33
|
+
"""
|
|
34
|
+
Represents the firing of a delayed transition.
|
|
35
|
+
|
|
36
|
+
The type follows the convention 'after.<delay>.<state_id>'.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
type: str
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# src/xstate_statemachine/exceptions.py
|
|
2
|
+
|
|
3
|
+
# -----------------------------------------------------------------------------
|
|
4
|
+
# 🚨 Custom Exceptions
|
|
5
|
+
# -----------------------------------------------------------------------------
|
|
6
|
+
# Defining specific exceptions improves error handling and makes the library's
|
|
7
|
+
# failure modes clearer to the user.
|
|
8
|
+
# -----------------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class XStateMachineError(Exception):
|
|
12
|
+
"""Base exception for all errors raised by this library."""
|
|
13
|
+
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class InvalidConfigError(XStateMachineError):
|
|
18
|
+
"""Raised when the machine configuration JSON is invalid."""
|
|
19
|
+
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class StateNotFoundError(XStateMachineError):
|
|
24
|
+
"""Raised when a target state cannot be resolved."""
|
|
25
|
+
|
|
26
|
+
def __init__(self, target: str, reference_id: str):
|
|
27
|
+
self.target = target
|
|
28
|
+
self.reference_id = reference_id
|
|
29
|
+
super().__init__(
|
|
30
|
+
f"Could not resolve target state '{target}' from state '{reference_id}'."
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class ImplementationMissingError(XStateMachineError):
|
|
35
|
+
"""Raised when an action, guard, or service implementation is missing."""
|
|
36
|
+
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class ActorSpawningError(XStateMachineError):
|
|
41
|
+
"""Raised when there is an error spawning or communicating with an actor."""
|
|
42
|
+
|
|
43
|
+
pass
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# src/xstate_statemachine/factory.py
|
|
2
|
+
from typing import Any, Dict
|
|
3
|
+
from .models import MachineNode
|
|
4
|
+
from .machine_logic import MachineLogic
|
|
5
|
+
from .exceptions import InvalidConfigError
|
|
6
|
+
from .logger import logger
|
|
7
|
+
|
|
8
|
+
# -----------------------------------------------------------------------------
|
|
9
|
+
# 🏭 Machine Factory
|
|
10
|
+
# -----------------------------------------------------------------------------
|
|
11
|
+
# This module provides a single entry point for creating a state machine
|
|
12
|
+
# instance from its configuration, applying the Factory design pattern.
|
|
13
|
+
# -----------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def create_machine(
|
|
17
|
+
config: Dict[str, Any], logic: MachineLogic = None
|
|
18
|
+
) -> MachineNode:
|
|
19
|
+
"""
|
|
20
|
+
Creates a state machine instance from a JSON-like config and implementation logic.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
config: The state machine's definition.
|
|
24
|
+
logic: An object containing the implementations for all actions, guards, etc.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
The root node of the fully constructed state machine graph.
|
|
28
|
+
|
|
29
|
+
Raises:
|
|
30
|
+
InvalidConfigError: If the configuration is malformed.
|
|
31
|
+
"""
|
|
32
|
+
if logic is None:
|
|
33
|
+
logic = MachineLogic()
|
|
34
|
+
|
|
35
|
+
machine_id = config.get("id")
|
|
36
|
+
logger.info(f"🏭 Creating machine with id: '{machine_id}'")
|
|
37
|
+
if (
|
|
38
|
+
not isinstance(config, dict)
|
|
39
|
+
or "states" not in config
|
|
40
|
+
or not machine_id
|
|
41
|
+
):
|
|
42
|
+
raise InvalidConfigError(
|
|
43
|
+
"Invalid config: must be a dict with 'id' and 'states' keys."
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
return MachineNode(config, logic)
|