0
# Extensions and Specialized Machines
1
2
The transitions library provides numerous extensions that add specialized functionality to the core state machine. These extensions can be used individually or combined through the MachineFactory to create machines with multiple capabilities.
3
4
## Capabilities
5
6
### Machine Factory
7
8
Convenience factory for retrieving pre-configured machine classes with specific capabilities.
9
10
```python { .api }
11
class MachineFactory:
12
@staticmethod
13
def get_predefined(graph=False, nested=False, locked=False, asyncio=False):
14
"""
15
Retrieve machine classes by required functionality.
16
17
Parameters:
18
- graph: Include diagram generation support
19
- nested: Include hierarchical state support
20
- locked: Include thread safety
21
- asyncio: Include async/await support (Python 3+ only)
22
23
Returns:
24
Machine class with requested capabilities
25
"""
26
```
27
28
### Graph Machine (Diagram Generation)
29
30
Machine extension that adds support for generating state machine diagrams using various backends.
31
32
```python { .api }
33
class GraphMachine(Machine):
34
"""
35
Machine extension with graph support for diagram generation.
36
Inherits all Machine functionality plus diagram capabilities.
37
"""
38
39
def get_graph(self, **kwargs):
40
"""
41
Generate a graph representation of the state machine.
42
43
Returns:
44
Graph object that can be rendered to various formats
45
"""
46
```
47
48
Available graph backends:
49
- **Graphviz**: `transitions.extensions.diagrams_graphviz.Graph`
50
- **PyGraphviz**: `transitions.extensions.diagrams_pygraphviz.Graph`
51
- **Mermaid**: `transitions.extensions.diagrams_mermaid.Graph`
52
53
### Hierarchical Machine (Nested States)
54
55
Machine extension that supports hierarchical/nested state machines with parent-child state relationships.
56
57
```python { .api }
58
class HierarchicalMachine(Machine):
59
"""
60
Machine extension for hierarchical/nested state machines.
61
Supports nested states with entry/exit semantics and state inheritance.
62
"""
63
```
64
65
#### Hierarchical Components
66
67
```python { .api }
68
class NestedState(State):
69
"""State extension for hierarchical machines with nesting support."""
70
71
class NestedTransition(Transition):
72
"""Transition extension for hierarchical machines."""
73
74
class NestedEvent(Event):
75
"""Event extension for nested states (NOT compatible with simple Machine instances)."""
76
77
class NestedEventData(EventData):
78
"""EventData extension for nested state machines."""
79
```
80
81
#### Utility Functions
82
83
```python { .api }
84
def resolve_order(state_tree):
85
"""
86
Convert a model state tree into a list of state paths for correct processing order.
87
88
Parameters:
89
- state_tree: Nested state structure
90
91
Returns:
92
list: Ordered list of state paths
93
"""
94
```
95
96
### Locked Machine (Thread Safety)
97
98
Machine extension that provides thread-safe operations through context management and locking.
99
100
```python { .api }
101
class LockedMachine(Machine):
102
"""
103
Machine class which manages contexts for thread safety.
104
Uses threading.RLock to ensure atomic state transitions.
105
"""
106
```
107
108
#### Locking Components
109
110
```python { .api }
111
class PicklableLock:
112
"""A wrapper for threading.Lock which discards state during pickling."""
113
114
class IdentManager:
115
"""Manages thread identity to detect if current thread already has lock."""
116
117
class LockedEvent(Event):
118
"""Event type which uses parent's machine context map when triggered."""
119
```
120
121
### Async Machine (Asynchronous Operations)
122
123
Machine extension with async/await support for asynchronous callback processing (Python 3+ only).
124
125
```python { .api }
126
class AsyncMachine(Machine):
127
"""
128
Machine extension with async/await support.
129
Enables asynchronous callback execution and event processing.
130
"""
131
132
async def dispatch(self, trigger, *args, **kwargs):
133
"""
134
Asynchronously trigger an event on all models.
135
136
Parameters:
137
- trigger: Name of the trigger method
138
- args: Positional arguments
139
- kwargs: Keyword arguments
140
141
Returns:
142
bool: True if at least one transition was successful
143
"""
144
```
145
146
#### Async Components
147
148
```python { .api }
149
class AsyncState(State):
150
"""State extension for asynchronous state machines."""
151
152
class AsyncTransition(Transition):
153
"""Transition extension for async callback support."""
154
155
class AsyncEvent(Event):
156
"""Event extension for async callback support."""
157
158
class AsyncEventData(EventData):
159
"""EventData extension for async machines."""
160
161
class AsyncCondition:
162
"""Condition extension for async callback support."""
163
164
class AsyncTimeout(AsyncState):
165
"""AsyncState extension with timeout functionality."""
166
```
167
168
### Hierarchical Async Machine
169
170
Combined hierarchical and async functionality.
171
172
```python { .api }
173
class HierarchicalAsyncMachine(HierarchicalMachine, AsyncMachine):
174
"""Combination of HierarchicalMachine and AsyncMachine."""
175
```
176
177
#### Combined Components
178
179
```python { .api }
180
class NestedAsyncState(NestedState, AsyncState):
181
"""Combination of NestedState and AsyncState."""
182
183
class NestedAsyncTransition(AsyncTransition, NestedTransition):
184
"""Combination of AsyncTransition and NestedTransition."""
185
186
class NestedAsyncEvent(NestedEvent):
187
"""Combination of NestedEvent for async processing."""
188
```
189
190
### Markup Machine (Dictionary Configuration)
191
192
Machine extension that can be configured using dictionaries/markup instead of direct parameter passing.
193
194
```python { .api }
195
class MarkupMachine(Machine):
196
"""Machine extension that can be configured with dictionaries/markup."""
197
198
class HierarchicalMarkupMachine(MarkupMachine, HierarchicalMachine):
199
"""Combination of MarkupMachine and HierarchicalMachine."""
200
```
201
202
### State Extensions
203
204
Enhanced state classes with additional features.
205
206
```python { .api }
207
class Tags(State):
208
"""State extension that allows tags to be assigned to states."""
209
210
class Error(State):
211
"""State extension for error handling with automatic error clearing."""
212
213
class Timeout(State):
214
"""State extension with timeout functionality."""
215
216
class Volatile(State):
217
"""State extension that is automatically cleared after execution."""
218
219
class Retry(State):
220
"""State extension with retry functionality."""
221
222
class VolatileObject:
223
"""Utility class for volatile state management."""
224
```
225
226
#### State Feature Combination
227
228
```python { .api }
229
def add_state_features(*args):
230
"""
231
Convenience function to combine multiple state features.
232
233
Parameters:
234
- args: State feature classes to combine
235
236
Returns:
237
Combined state class
238
"""
239
```
240
241
### Pre-configured Machine Classes
242
243
Ready-to-use machine classes with common feature combinations.
244
245
```python { .api }
246
class LockedHierarchicalMachine(LockedMachine, HierarchicalMachine):
247
"""A threadsafe hierarchical machine."""
248
249
class LockedGraphMachine(LockedMachine, GraphMachine):
250
"""A threadsafe machine with graph support."""
251
252
class LockedHierarchicalGraphMachine(LockedHierarchicalMachine, GraphMachine):
253
"""A threadsafe hierarchical machine with graph support."""
254
255
class AsyncGraphMachine(AsyncMachine, GraphMachine):
256
"""A machine that supports asynchronous event/callback processing with Graphviz support."""
257
258
class HierarchicalAsyncGraphMachine(HierarchicalAsyncMachine, GraphMachine):
259
"""A hierarchical machine that supports asynchronous event/callback processing with Graphviz support."""
260
```
261
262
## Usage Examples
263
264
### Using MachineFactory
265
266
```python
267
from transitions.extensions import MachineFactory
268
269
# Get a machine with multiple capabilities
270
MachineClass = MachineFactory.get_predefined(graph=True, nested=True, locked=True)
271
machine = MachineClass(model=my_model, states=states, transitions=transitions)
272
```
273
274
### Graph Machine Example
275
276
```python
277
from transitions.extensions import GraphMachine
278
279
class Robot:
280
pass
281
282
states = ['idle', 'working', 'maintenance']
283
transitions = [
284
{'trigger': 'start', 'source': 'idle', 'dest': 'working'},
285
{'trigger': 'break_down', 'source': 'working', 'dest': 'maintenance'},
286
{'trigger': 'repair', 'source': 'maintenance', 'dest': 'idle'}
287
]
288
289
robot = Robot()
290
machine = GraphMachine(model=robot, states=states, transitions=transitions, initial='idle')
291
292
# Generate a diagram
293
graph = machine.get_graph()
294
# graph.draw('robot_states.png', prog='dot') # Requires graphviz
295
```
296
297
### Hierarchical Machine Example
298
299
```python
300
from transitions.extensions import HierarchicalMachine
301
302
class Player:
303
pass
304
305
states = [
306
{'name': 'alive', 'children': ['healthy', 'injured']},
307
'dead'
308
]
309
310
transitions = [
311
{'trigger': 'take_damage', 'source': 'alive_healthy', 'dest': 'alive_injured'},
312
{'trigger': 'heal', 'source': 'alive_injured', 'dest': 'alive_healthy'},
313
{'trigger': 'die', 'source': 'alive', 'dest': 'dead'},
314
{'trigger': 'resurrect', 'source': 'dead', 'dest': 'alive_healthy'}
315
]
316
317
player = Player()
318
machine = HierarchicalMachine(
319
model=player,
320
states=states,
321
transitions=transitions,
322
initial='alive_healthy'
323
)
324
325
print(player.state) # 'alive_healthy'
326
player.take_damage()
327
print(player.state) # 'alive_injured'
328
```
329
330
### Async Machine Example
331
332
```python
333
import asyncio
334
from transitions.extensions import AsyncMachine
335
336
class AsyncRobot:
337
async def on_enter_working(self):
338
print("Starting work...")
339
await asyncio.sleep(1) # Simulate work
340
print("Work completed!")
341
342
states = ['idle', 'working']
343
transitions = [
344
{'trigger': 'start_work', 'source': 'idle', 'dest': 'working'},
345
{'trigger': 'finish_work', 'source': 'working', 'dest': 'idle'}
346
]
347
348
async def main():
349
robot = AsyncRobot()
350
machine = AsyncMachine(model=robot, states=states, transitions=transitions, initial='idle')
351
352
await robot.start_work() # Asynchronously transitions to working state
353
354
# asyncio.run(main())
355
```
356
357
### Locked Machine Example
358
359
```python
360
import threading
361
from transitions.extensions import LockedMachine
362
363
class SharedResource:
364
def __init__(self):
365
self.data = 0
366
367
states = ['idle', 'processing', 'complete']
368
transitions = [
369
{'trigger': 'start', 'source': 'idle', 'dest': 'processing'},
370
{'trigger': 'finish', 'source': 'processing', 'dest': 'complete'},
371
{'trigger': 'reset', 'source': 'complete', 'dest': 'idle'}
372
]
373
374
resource = SharedResource()
375
machine = LockedMachine(model=resource, states=states, transitions=transitions, initial='idle')
376
377
# Safe to use from multiple threads
378
def worker():
379
resource.start()
380
# Process data...
381
resource.finish()
382
383
# Multiple threads can safely interact with the state machine
384
threads = [threading.Thread(target=worker) for _ in range(5)]
385
for t in threads:
386
t.start()
387
```