1
1
from typing import Any , Dict , List , Optional , Union
2
+ from serverlessworkflow .sdk .action import Action
2
3
from serverlessworkflow .sdk .callback_state import CallbackState
3
4
from serverlessworkflow .sdk .function_ref import FunctionRef
4
5
from serverlessworkflow .sdk .sleep_state import SleepState
10
11
ParallelState ,
11
12
OperationState ,
12
13
ForEachState ,
14
+ Workflow ,
13
15
)
14
16
from serverlessworkflow .sdk .transition_data_condition import TransitionDataCondition
15
17
from serverlessworkflow .sdk .end_data_condition import EndDataCondition
@@ -25,13 +27,15 @@ def __init__(
25
27
self ,
26
28
state : State ,
27
29
state_machine : Union [HierarchicalMachine , GraphMachine ],
30
+ subflows : List [Workflow ] = [],
28
31
is_first_state = False ,
29
32
get_actions = False ,
30
33
):
31
34
self .state = state
32
35
self .is_first_state = is_first_state
33
36
self .state_machine = state_machine
34
37
self .get_actions = get_actions
38
+ self .subflows = subflows
35
39
36
40
if self .get_actions and not isinstance (self .state_machine , HierarchicalMachine ):
37
41
raise AttributeError (
@@ -314,6 +318,11 @@ def data_based_switch_state_details(self) -> str:
314
318
315
319
def operation_state_details (self ) -> Optional [str ]:
316
320
descriptions = []
321
+ if self .state .name not in self .state_machine .states .keys ():
322
+ self .state_machine .add_states (self .state .name )
323
+ if self .is_first_state :
324
+ self .state_machine ._initial = self .state .name
325
+
317
326
if isinstance (self .state , OperationState ):
318
327
action_mode = self .state .actionMode
319
328
if action_mode :
@@ -324,26 +333,11 @@ def operation_state_details(self) -> Optional[str]:
324
333
action_mode ,
325
334
)
326
335
)
327
- actions = self .state .actions
328
- if actions :
329
- descriptions .append (
330
- self .state_description (
331
- self .state_key_diagram (self .state .name ),
332
- "Num. of actions" ,
333
- str (len (actions )),
334
- )
336
+ descriptions .extend (
337
+ self .generate_actions_info (
338
+ actions = self .state .actions , action_mode = self .state .actionMode
335
339
)
336
- if self .get_actions :
337
- descriptions .append (
338
- f"state { self .state_key_diagram (self .state .name )} {{\n "
339
- f"{ self .generate_composite_state (self .state_machine .get_state (self .state .name ), self .state .name , actions , action_mode )} \n "
340
- f"}}\n "
341
- )
342
-
343
- if self .state .name not in self .state_machine .states .keys ():
344
- self .state_machine .add_states (self .state .name )
345
- if self .is_first_state :
346
- self .state_machine ._initial = self .state .name
340
+ )
347
341
348
342
return "\n " .join (descriptions ) if descriptions else None
349
343
@@ -368,15 +362,12 @@ def foreach_state_details(self) -> Optional[str]:
368
362
input_collection ,
369
363
)
370
364
)
371
- actions = self .state .actions
372
- if actions :
373
- descriptions .append (
374
- self .state_description (
375
- self .state_key_diagram (self .state .name ),
376
- "Num. of actions" ,
377
- str (len (actions )),
378
- )
365
+ descriptions .extend (
366
+ self .generate_actions_info (
367
+ actions = self .state .actions , action_mode = self .state .mode
379
368
)
369
+ )
370
+
380
371
return "\n " .join (descriptions ) if descriptions else None
381
372
382
373
def callback_state_details (self ) -> Optional [str ]:
@@ -398,12 +389,7 @@ def callback_state_details(self) -> Optional[str]:
398
389
)
399
390
)
400
391
401
- if self .get_actions :
402
- descriptions .append (
403
- f"state { self .state_key_diagram (self .state .name )} {{\n "
404
- f"{ self .generate_composite_state (self .state_machine .get_state (self .state .name ), self .state .name , [action ], 'sequential' )} \n "
405
- f"}}\n "
406
- )
392
+ self .generate_actions_info (actions = [action ], singular_action = True )
407
393
event_ref = self .state .eventRef
408
394
if event_ref :
409
395
descriptions .append (
@@ -438,7 +424,7 @@ def generate_composite_state(
438
424
machine_state : NestedState ,
439
425
state_name : str ,
440
426
actions : List [Dict [str , Any ]],
441
- action_mode : str ,
427
+ action_mode : str = "sequential" ,
442
428
) -> str :
443
429
transitions = ""
444
430
parallel_states = []
@@ -502,6 +488,91 @@ def generate_composite_state(
502
488
503
489
return transitions
504
490
491
+ def generate_actions_info (
492
+ self ,
493
+ actions : List [Action ],
494
+ action_mode : str = "sequential" ,
495
+ singular_action = False ,
496
+ ):
497
+ descriptions = []
498
+ if actions :
499
+ if not singular_action :
500
+ descriptions .append (
501
+ self .state_description (
502
+ self .state_key_diagram (self .state .name ),
503
+ "Num. of actions" ,
504
+ str (len (actions )),
505
+ )
506
+ )
507
+ if self .get_actions :
508
+ descriptions .append (
509
+ f"state { self .state_key_diagram (self .state .name )} {{\n "
510
+ f"{ self .generate_composite_state (self .state_machine .get_state (self .state .name ), self .state .name , actions , action_mode )} \n "
511
+ f"}}\n "
512
+ )
513
+ for action in actions :
514
+ if action .subFlowRef :
515
+ if isinstance (action .subFlowRef , str ):
516
+ workflow_id = action .subFlowRef
517
+ workflow_version = None
518
+ else :
519
+ workflow_id = action .subFlowRef .workflowId
520
+ workflow_version = action .subFlowRef .version
521
+ for sf in self .subflows :
522
+ if (
523
+ sf .id == workflow_id
524
+ ): # and (workflow_version and sf.version == workflow_version or not workflow_version):
525
+ new_machine = HierarchicalMachine (
526
+ model = None , initial = None , auto_transitions = False
527
+ )
528
+
529
+ # Generate the state machine for the subflow
530
+ for index , state in enumerate (sf .states ):
531
+ StateMachineGenerator (
532
+ state = state ,
533
+ state_machine = new_machine ,
534
+ is_first_state = index == 0 ,
535
+ get_actions = self .get_actions ,
536
+ subflows = self .subflows
537
+ ).source_code ()
538
+
539
+ # Convert the new_machine into a NestedState
540
+ nested_state = NestedState (
541
+ action .name if action .name else f"{ sf .id } /{ sf .version .replace (NestedState .separator , '-' )} "
542
+ )
543
+ self .state_machine_to_nested_state (state_machine = new_machine , nested_state = nested_state )
544
+ # else:
545
+ # raise Warning("No correct subflow provided")
546
+
547
+ return descriptions
548
+
549
+ def add_all_sub_states (cls , original_state : Union [NestedState , HierarchicalMachine ], new_state : NestedState ):
550
+ if len (original_state .states ) == 0 :
551
+ return
552
+ for substate in original_state .states .values ():
553
+ new_state .add_substate (ns := NestedState (substate .name ))
554
+ cls .add_all_sub_states (substate , ns )
555
+
556
+ def state_machine_to_nested_state (
557
+ self , state_machine : HierarchicalMachine , nested_state : NestedState
558
+ ) -> NestedState :
559
+ self .state_machine .get_state (
560
+ self .state .name
561
+ ).add_substate (nested_state )
562
+
563
+ self .add_all_sub_states (state_machine , nested_state )
564
+
565
+ for trigger , event in state_machine .events .items ():
566
+ for transition_l in event .transitions .values ():
567
+ for transition in transition_l :
568
+ source = transition .source
569
+ dest = transition .dest
570
+ self .state_machine .add_transition (
571
+ trigger = trigger ,
572
+ source = f"{ self .state .name } .{ nested_state .name } .{ source } " ,
573
+ dest = f"{ self .state .name } .{ nested_state .name } .{ dest } " ,
574
+ )
575
+
505
576
def get_function_name (
506
577
self , fn_ref : Union [Dict [str , Any ], str , None ]
507
578
) -> Optional [str ]:
0 commit comments