Skip to content

Commit 6c55410

Browse files
committed
fix: avoid instantiating StateChart class in diagram extraction
The extract function now uses the class directly (never instantiates it) since all structural metadata (states, transitions, name) is already available on the class thanks to the metaclass. Active-state highlighting is only produced when an instance is passed.
1 parent 8750736 commit 6c55410

1 file changed

Lines changed: 17 additions & 8 deletions

File tree

statemachine/contrib/diagram/extract.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from typing import TYPE_CHECKING
22
from typing import List
3+
from typing import Union
34

45
from .model import DiagramAction
56
from .model import DiagramGraph
@@ -11,6 +12,9 @@
1112
from statemachine.state import State
1213
from statemachine.statemachine import StateChart
1314

15+
# A StateChart class or instance — both expose the same structural metadata.
16+
MachineRef = Union["StateChart", "type[StateChart]"]
17+
1418

1519
def _determine_state_type(state: "State") -> StateType:
1620
from statemachine.state import HistoryState
@@ -27,7 +31,7 @@ def _determine_state_type(state: "State") -> StateType:
2731
return StateType.REGULAR
2832

2933

30-
def _actions_getter(machine: "StateChart"):
34+
def _actions_getter(machine: "MachineRef"):
3135
from statemachine.statemachine import StateChart
3236

3337
if isinstance(machine, StateChart):
@@ -67,7 +71,7 @@ def _extract_state_actions(state: "State", getter) -> List[DiagramAction]:
6771

6872
def _extract_state(
6973
state: "State",
70-
machine: "StateChart",
74+
machine: "MachineRef",
7175
getter,
7276
active_values: set,
7377
) -> DiagramState:
@@ -131,9 +135,14 @@ def _extract_all_transitions(states, getter) -> List[DiagramTransition]:
131135
return result
132136

133137

134-
def extract(machine_or_class: "StateChart | type") -> DiagramGraph:
138+
def extract(machine_or_class: "MachineRef") -> DiagramGraph:
135139
"""Extract a DiagramGraph IR from a state machine instance or class.
136140
141+
Accepts either a class or an instance. The class is **never** instantiated
142+
— all structural metadata (states, transitions, name) is available on the
143+
class itself thanks to the metaclass. Active-state highlighting is only
144+
produced when an *instance* is passed.
145+
137146
Args:
138147
machine_or_class: A StateMachine/StateChart instance or class.
139148
@@ -142,17 +151,17 @@ def extract(machine_or_class: "StateChart | type") -> DiagramGraph:
142151
"""
143152
from statemachine.statemachine import StateChart
144153

145-
is_class = isinstance(machine_or_class, type)
146-
if is_class and issubclass(machine_or_class, StateChart): # type: ignore[arg-type]
147-
machine = machine_or_class() # type: ignore[operator]
148-
elif isinstance(machine_or_class, StateChart):
154+
if isinstance(machine_or_class, StateChart):
155+
machine: "MachineRef" = machine_or_class
156+
elif isinstance(machine_or_class, type) and issubclass(machine_or_class, StateChart):
149157
machine = machine_or_class
150158
else:
151159
raise TypeError(f"Expected a StateChart instance or class, got {type(machine_or_class)}")
152160

153161
getter = _actions_getter(machine)
162+
154163
active_values: set = set()
155-
if not is_class and hasattr(machine, "configuration_values"):
164+
if isinstance(machine, StateChart) and hasattr(machine, "configuration_values"):
156165
active_values = set(machine.configuration_values)
157166

158167
states: List[DiagramState] = []

0 commit comments

Comments
 (0)