1
1
from typing import Any , Dict , List , Optional , Union
2
2
from serverlessworkflow .sdk .action import Action
3
- from serverlessworkflow .sdk .callback_state import CallbackState
4
3
from serverlessworkflow .sdk .function_ref import FunctionRef
5
- from serverlessworkflow .sdk .sleep_state import SleepState
4
+ from serverlessworkflow .sdk .state_machine_extensions import (
5
+ CustomGraphMachine ,
6
+ CustomHierarchicalGraphMachine ,
7
+ CustomHierarchicalMachine ,
8
+ )
6
9
from serverlessworkflow .sdk .transition import Transition
7
10
from serverlessworkflow .sdk .workflow import (
8
11
State ,
12
+ EventState ,
13
+ SleepState ,
14
+ CallbackState ,
9
15
DataBasedSwitchState ,
16
+ InjectState ,
10
17
EventBasedSwitchState ,
11
18
ParallelState ,
12
19
OperationState ,
@@ -27,7 +34,7 @@ class StateMachineGenerator:
27
34
def __init__ (
28
35
self ,
29
36
state : State ,
30
- state_machine : Union [HierarchicalMachine , GraphMachine ],
37
+ state_machine : Union [CustomHierarchicalMachine , CustomGraphMachine ],
31
38
subflows : List [Workflow ] = [],
32
39
is_first_state = False ,
33
40
get_actions = False ,
@@ -38,13 +45,20 @@ def __init__(
38
45
self .get_actions = get_actions
39
46
self .subflows = subflows
40
47
41
- if self .get_actions and not isinstance (self .state_machine , HierarchicalMachine ):
48
+ if (
49
+ self .get_actions
50
+ and not isinstance (self .state_machine , CustomHierarchicalMachine )
51
+ and not isinstance (self .state_machine , CustomHierarchicalGraphMachine )
52
+ ):
42
53
raise AttributeError (
43
- "The provided state machine must be of the HierarchicalMachine type ."
54
+ "The provided state machine must be of the CustomHierarchicalMachine or CustomHierarchicalGraphMachine types ."
44
55
)
45
- if not self .get_actions and isinstance (self .state_machine , HierarchicalMachine ):
56
+ if not self .get_actions and (
57
+ isinstance (self .state_machine , CustomHierarchicalMachine )
58
+ or isinstance (self .state_machine , CustomHierarchicalGraphMachine )
59
+ ):
46
60
raise AttributeError (
47
- "The provided state machine can not be of the HierarchicalMachine type ."
61
+ "The provided state machine can not be of the CustomHierarchicalMachine or CustomHierarchicalGraphMachine types ."
48
62
)
49
63
50
64
def generate (self ):
@@ -65,12 +79,7 @@ def transitions(self):
65
79
66
80
def start_transition (self ):
67
81
if self .is_first_state :
68
- state_name = self .state .name
69
- if state_name not in self .state_machine .states .keys ():
70
- self .state_machine .add_states (state_name )
71
- self .state_machine ._initial = state_name
72
- else :
73
- self .state_machine ._initial = state_name
82
+ self .state_machine ._initial = self .state .name
74
83
75
84
def data_conditions_transitions (self ):
76
85
if isinstance (self .state , DataBasedSwitchState ):
@@ -153,7 +162,7 @@ def definitions(self):
153
162
if state_type == "sleep" :
154
163
self .sleep_state_details ()
155
164
elif state_type == "event" :
156
- pass
165
+ self . event_state_details ()
157
166
elif state_type == "operation" :
158
167
self .operation_state_details ()
159
168
elif state_type == "parallel" :
@@ -166,7 +175,7 @@ def definitions(self):
166
175
else :
167
176
raise Exception (f"Unexpected switch type;\n state value= { self .state } " )
168
177
elif state_type == "inject" :
169
- pass
178
+ self . inject_state_details ()
170
179
elif state_type == "foreach" :
171
180
self .foreach_state_details ()
172
181
elif state_type == "callback" :
@@ -178,10 +187,10 @@ def definitions(self):
178
187
179
188
def parallel_state_details (self ):
180
189
if isinstance (self .state , ParallelState ):
181
- if self .state .name not in self . state_machine . states . keys ():
182
- self .state_machine .add_states ( self . state . name )
183
- if self .is_first_state :
184
- self .state_machine ._initial = self . state . name
190
+ state_name = self .state .name
191
+ if state_name not in self .state_machine .states . keys ():
192
+ self .state_machine . add_states ( state_name )
193
+ self .state_machine .get_state ( state_name ). tags = [ "parallel_state" ]
185
194
186
195
state_name = self .state .name
187
196
branches = self .state .branches
@@ -192,42 +201,82 @@ def parallel_state_details(self):
192
201
if hasattr (branch , "actions" ) and branch .actions :
193
202
branch_name = branch .name
194
203
self .state_machine .get_state (state_name ).add_substates (
195
- NestedState (branch_name )
204
+ branch_state := self .state_machine .state_cls (
205
+ branch_name
206
+ )
196
207
)
197
208
self .state_machine .get_state (state_name ).initial .append (
198
209
branch_name
199
210
)
200
- branch_state = self .state_machine .get_state (
201
- state_name
202
- ).states [branch .name ]
211
+ branch_state .tags = ["branch" ]
203
212
self .generate_actions_info (
204
213
machine_state = branch_state ,
205
214
state_name = f"{ state_name } .{ branch_name } " ,
206
215
actions = branch .actions ,
207
216
)
208
217
209
- def event_based_switch_state_details (self ): ...
218
+ def event_based_switch_state_details (self ):
219
+ if isinstance (self .state , EventBasedSwitchState ):
220
+ state_name = self .state .name
221
+ if state_name not in self .state_machine .states .keys ():
222
+ self .state_machine .add_states (state_name )
223
+ self .state_machine .get_state (state_name ).tags = [
224
+ "event_based_switch_state" ,
225
+ "switch_state" ,
226
+ ]
210
227
211
- def data_based_switch_state_details (self ): ...
228
+ def data_based_switch_state_details (self ):
229
+ if isinstance (self .state , DataBasedSwitchState ):
230
+ state_name = self .state .name
231
+ if state_name not in self .state_machine .states .keys ():
232
+ self .state_machine .add_states (state_name )
233
+ self .state_machine .get_state (state_name ).tags = [
234
+ "data_based_switch_state" ,
235
+ "switch_state" ,
236
+ ]
212
237
213
- def operation_state_details (self ):
214
- if self .state .name not in self .state_machine .states .keys ():
215
- self .state_machine .add_states (self .state .name )
216
- if self .is_first_state :
217
- self .state_machine ._initial = self .state .name
238
+ def inject_state_details (self ):
239
+ if isinstance (self .state , InjectState ):
240
+ state_name = self .state .name
241
+ if state_name not in self .state_machine .states .keys ():
242
+ self .state_machine .add_states (state_name )
243
+ self .state_machine .get_state (state_name ).tags = ["inject_state" ]
218
244
245
+ def operation_state_details (self ):
219
246
if isinstance (self .state , OperationState ):
247
+ state_name = self .state .name
248
+ if state_name not in self .state_machine .states .keys ():
249
+ self .state_machine .add_states (state_name )
250
+ (machine_state := self .state_machine .get_state (state_name )).tags = [
251
+ "operation_state"
252
+ ]
220
253
self .generate_actions_info (
221
- machine_state = self . state_machine . get_state ( self . state . name ) ,
254
+ machine_state = machine_state ,
222
255
state_name = self .state .name ,
223
256
actions = self .state .actions ,
224
257
action_mode = self .state .actionMode ,
225
258
)
226
259
227
- def sleep_state_details (self ): ...
260
+ def sleep_state_details (self ):
261
+ if isinstance (self .state , SleepState ):
262
+ state_name = self .state .name
263
+ if state_name not in self .state_machine .states .keys ():
264
+ self .state_machine .add_states (state_name )
265
+ self .state_machine .get_state (state_name ).tags = ["sleep_state" ]
266
+
267
+ def event_state_details (self ):
268
+ if isinstance (self .state , EventState ):
269
+ state_name = self .state .name
270
+ if state_name not in self .state_machine .states .keys ():
271
+ self .state_machine .add_states (state_name )
272
+ self .state_machine .get_state (state_name ).tags = ["event_state" ]
228
273
229
274
def foreach_state_details (self ):
230
275
if isinstance (self .state , ForEachState ):
276
+ state_name = self .state .name
277
+ if state_name not in self .state_machine .states .keys ():
278
+ self .state_machine .add_states (state_name )
279
+ self .state_machine .get_state (state_name ).tags = ["foreach_state" ]
231
280
self .generate_actions_info (
232
281
machine_state = self .state_machine .get_state (self .state .name ),
233
282
state_name = self .state .name ,
@@ -237,6 +286,10 @@ def foreach_state_details(self):
237
286
238
287
def callback_state_details (self ):
239
288
if isinstance (self .state , CallbackState ):
289
+ state_name = self .state .name
290
+ if state_name not in self .state_machine .states .keys ():
291
+ self .state_machine .add_states (state_name )
292
+ self .state_machine .get_state (state_name ).tags = ["callback_state" ]
240
293
action = self .state .action
241
294
if action and action .functionRef :
242
295
self .generate_actions_info (
@@ -264,7 +317,7 @@ def get_subflow_state(
264
317
or not workflow_version
265
318
):
266
319
none_found = False
267
- new_machine = HierarchicalMachine (
320
+ new_machine = CustomHierarchicalMachine (
268
321
model = None , initial = None , auto_transitions = False
269
322
)
270
323
@@ -282,7 +335,8 @@ def get_subflow_state(
282
335
added_states [i ] = self .subflow_state_name (
283
336
action = action , subflow = sf
284
337
)
285
- nested_state = NestedState (added_states [i ])
338
+ nested_state = self .state_machine .state_cls (added_states [i ])
339
+ nested_state .tags = ["subflow" ]
286
340
machine_state .add_substate (nested_state )
287
341
self .state_machine_to_nested_state (
288
342
state_name = state_name ,
@@ -301,7 +355,7 @@ def generate_actions_info(
301
355
self ,
302
356
machine_state : NestedState ,
303
357
state_name : str ,
304
- actions : List [Dict [str , Any ]],
358
+ actions : List [Dict [str , Action ]],
305
359
action_mode : str = "sequential" ,
306
360
):
307
361
parallel_states = []
@@ -322,9 +376,19 @@ def generate_actions_info(
322
376
)
323
377
)
324
378
if name not in machine_state .states .keys ():
325
- machine_state .add_substate (NestedState (name ))
379
+ machine_state .add_substate (
380
+ ns := self .state_machine .state_cls (name )
381
+ )
382
+ ns .tags = ["function" ]
326
383
elif action .subFlowRef :
327
384
name = new_subflows_names .get (i )
385
+ elif action .eventRef :
386
+ name = f"{ action .eventRef .triggerEventRef } /{ action .eventRef .resultEventRef } "
387
+ if name not in machine_state .states .keys ():
388
+ machine_state .add_substate (
389
+ ns := self .state_machine .state_cls (name )
390
+ )
391
+ ns .tags = ["event" ]
328
392
if name :
329
393
if action_mode == "sequential" :
330
394
if i < len (actions ) - 1 :
@@ -348,9 +412,24 @@ def generate_actions_info(
348
412
state_name
349
413
).states .keys ()
350
414
):
351
- machine_state .add_substate (NestedState (next_name ))
415
+ machine_state .add_substate (
416
+ ns := self .state_machine .state_cls (next_name )
417
+ )
418
+ ns .tags = ["function" ]
352
419
elif actions [i + 1 ].subFlowRef :
353
420
next_name = new_subflows_names .get (i + 1 )
421
+ elif actions [i + 1 ].eventRef :
422
+ next_name = f"{ action .eventRef .triggerEventRef } /{ action .eventRef .resultEventRef } "
423
+ if (
424
+ next_name
425
+ not in self .state_machine .get_state (
426
+ state_name
427
+ ).states .keys ()
428
+ ):
429
+ machine_state .add_substate (
430
+ ns := self .state_machine .state_cls (name )
431
+ )
432
+ ns .tags = ["event" ]
354
433
self .state_machine .add_transition (
355
434
trigger = "" ,
356
435
source = f"{ state_name } .{ name } " ,
@@ -371,21 +450,22 @@ def subflow_state_name(self, action: Action, subflow: Workflow):
371
450
)
372
451
373
452
def add_all_sub_states (
374
- cls ,
375
- original_state : Union [NestedState , HierarchicalMachine ],
453
+ self ,
454
+ original_state : Union [NestedState , CustomHierarchicalMachine ],
376
455
new_state : NestedState ,
377
456
):
378
457
if len (original_state .states ) == 0 :
379
458
return
380
459
for substate in original_state .states .values ():
381
- new_state .add_substate (ns := NestedState (substate .name ))
382
- cls .add_all_sub_states (substate , ns )
460
+ new_state .add_substate (ns := self .state_machine .state_cls (substate .name ))
461
+ ns .tags = substate .tags
462
+ self .add_all_sub_states (substate , ns )
383
463
new_state .initial = original_state .initial
384
464
385
465
def state_machine_to_nested_state (
386
466
self ,
387
467
state_name : str ,
388
- state_machine : HierarchicalMachine ,
468
+ state_machine : CustomHierarchicalMachine ,
389
469
nested_state : NestedState ,
390
470
) -> NestedState :
391
471
self .add_all_sub_states (state_machine , nested_state )
0 commit comments