11from typing import TYPE_CHECKING
22from typing import List
3+ from typing import Union
34
45from .model import DiagramAction
56from .model import DiagramGraph
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
1519def _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
6872def _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