1+ from typing import TYPE_CHECKING
2+ from typing import Any
3+ from typing import Dict
4+ from typing import Tuple
15from uuid import uuid4
26
37from . import registry
711from .graph import visit_connected_states
812from .i18n import _
913from .state import State
14+ from .states import States
1015from .transition import Transition
1116from .transition_list import TransitionList
1217
1318
1419class StateMachineMetaclass (type ):
15- def __init__ (cls , name , bases , attrs ):
20+ def __init__ (cls , name : str , bases : Tuple [ type ] , attrs : Dict [ str , Any ] ):
1621 super ().__init__ (name , bases , attrs )
1722 registry .register (cls )
18- cls ._abstract = True
1923 cls .name = cls .__name__
20- cls .states = []
21- cls ._events = {}
22- cls .states_map = {}
24+ cls .states : States = States ()
25+ cls .states_map : Dict [Any , State ] = {}
26+ """Map of ``state.value`` to the corresponding :ref:`state`."""
27+
28+ cls ._abstract = True
29+ cls ._events : Dict [str , Event ] = {}
30+
2331 cls .add_inherited (bases )
2432 cls .add_from_attributes (attrs )
2533
2634 cls ._set_special_states ()
2735 cls ._check ()
2836
37+ if TYPE_CHECKING :
38+ """Makes mypy happy with dynamic created attributes"""
39+
40+ def __getattr__ (self , attribute : str ) -> Any :
41+ ...
42+
2943 def _set_special_states (cls ):
3044 if not cls .states :
3145 return
@@ -95,13 +109,19 @@ def add_inherited(cls, bases):
95109
96110 def add_from_attributes (cls , attrs ):
97111 for key , value in sorted (attrs .items (), key = lambda pair : pair [0 ]):
112+ if isinstance (value , States ):
113+ cls ._add_states_from_dict (value )
98114 if isinstance (value , State ):
99115 cls .add_state (key , value )
100116 elif isinstance (value , (Transition , TransitionList )):
101117 cls .add_event (key , value )
102118 elif getattr (value , "_callbacks_to_update" , None ):
103119 cls ._add_unbounded_callback (key , value )
104120
121+ def _add_states_from_dict (cls , states ):
122+ for state_id , state in states .items ():
123+ cls .add_state (state_id , state )
124+
105125 def _add_unbounded_callback (cls , attr_name , func ):
106126 if func ._is_event :
107127 # if func is an event, the `attr_name` will be replaced by an event trigger,
@@ -118,6 +138,8 @@ def add_state(cls, id, state: State):
118138 state ._set_id (id )
119139 cls .states .append (state )
120140 cls .states_map [state .value ] = state
141+ if not hasattr (cls , id ):
142+ setattr (cls , id , state )
121143
122144 # also register all events associated directly with transitions
123145 for event in state .transitions .unique_events :
0 commit comments