Skip to content

Commit ee0a9ca

Browse files
authored
Merge pull request #33 from ATNoG/bug/branch-initials
Multiple fixes for the graph/state machine generation functionality
2 parents be7b641 + 8aae4a4 commit ee0a9ca

File tree

2 files changed

+121
-107
lines changed

2 files changed

+121
-107
lines changed

serverlessworkflow/sdk/state_machine_generator.py

Lines changed: 114 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def __init__(
4747
"The provided state machine can not be of the HierarchicalMachine type."
4848
)
4949

50-
def source_code(self):
50+
def generate(self):
5151
self.definitions()
5252
self.transitions()
5353

@@ -182,12 +182,16 @@ def parallel_state_details(self):
182182
branches = self.state.branches
183183
if branches:
184184
if self.get_actions:
185+
self.state_machine.get_state(state_name).initial = []
185186
for branch in branches:
186187
if hasattr(branch, "actions") and branch.actions:
187188
branch_name = branch.name
188189
self.state_machine.get_state(state_name).add_substates(
189190
NestedState(branch_name)
190191
)
192+
self.state_machine.get_state(state_name).initial.append(
193+
branch_name
194+
)
191195
branch_state = self.state_machine.get_state(
192196
state_name
193197
).states[branch.name]
@@ -196,12 +200,6 @@ def parallel_state_details(self):
196200
state_name=f"{state_name}.{branch_name}",
197201
actions=branch.actions,
198202
)
199-
self.generate_composite_state(
200-
branch_state,
201-
f"{state_name}.{branch_name}",
202-
branch.actions,
203-
"sequential",
204-
)
205203

206204
def event_based_switch_state_details(self): ...
207205

@@ -242,119 +240,130 @@ def callback_state_details(self):
242240
actions=[action],
243241
)
244242

245-
def generate_composite_state(
243+
def get_subflow_state(
244+
self, machine_state: NestedState, state_name: str, actions: List[Action]
245+
):
246+
added_states = {}
247+
for i, action in enumerate(actions):
248+
if action.subFlowRef:
249+
if isinstance(action.subFlowRef, str):
250+
workflow_id = action.subFlowRef
251+
workflow_version = None
252+
else:
253+
workflow_id = action.subFlowRef.workflowId
254+
workflow_version = action.subFlowRef.version
255+
none_found = True
256+
for sf in self.subflows:
257+
if sf.id == workflow_id and (
258+
(workflow_version and sf.version == workflow_version)
259+
or not workflow_version
260+
):
261+
none_found = False
262+
new_machine = HierarchicalMachine(
263+
model=None, initial=None, auto_transitions=False
264+
)
265+
266+
# Generate the state machine for the subflow
267+
for index, state in enumerate(sf.states):
268+
StateMachineGenerator(
269+
state=state,
270+
state_machine=new_machine,
271+
is_first_state=index == 0,
272+
get_actions=self.get_actions,
273+
subflows=self.subflows,
274+
).generate()
275+
276+
# Convert the new_machine into a NestedState
277+
added_states[i] = self.subflow_state_name(
278+
action=action, subflow=sf
279+
)
280+
nested_state = NestedState(added_states[i])
281+
machine_state.add_substate(nested_state)
282+
self.state_machine_to_nested_state(
283+
state_name=state_name,
284+
state_machine=new_machine,
285+
nested_state=nested_state,
286+
)
287+
288+
if none_found:
289+
warnings.warn(
290+
f"Specified subflow [{workflow_id} {workflow_version if workflow_version else ''}] not found.",
291+
category=UserWarning,
292+
)
293+
return added_states
294+
295+
def generate_actions_info(
246296
self,
247297
machine_state: NestedState,
248298
state_name: str,
249299
actions: List[Dict[str, Any]],
250300
action_mode: str = "sequential",
251301
):
252302
parallel_states = []
253-
254303
if actions:
304+
new_subflows_names = self.get_subflow_state(
305+
machine_state=machine_state, state_name=state_name, actions=actions
306+
)
255307
for i, action in enumerate(actions):
256-
fn_name = (
257-
self.get_function_name(action.functionRef)
258-
if isinstance(action.functionRef, str)
259-
else (
260-
action.functionRef.refName
261-
if isinstance(action.functionRef, FunctionRef)
262-
else None
308+
name = None
309+
if action.functionRef:
310+
name = (
311+
self.get_function_name(action.functionRef)
312+
if isinstance(action.functionRef, str)
313+
else (
314+
action.functionRef.refName
315+
if isinstance(action.functionRef, FunctionRef)
316+
else None
317+
)
263318
)
264-
)
265-
if fn_name:
266-
if fn_name not in machine_state.states.keys():
267-
machine_state.add_substate(NestedState(fn_name))
319+
if name not in machine_state.states.keys():
320+
machine_state.add_substate(NestedState(name))
321+
elif action.subFlowRef:
322+
name = new_subflows_names.get(i)
323+
if name:
268324
if action_mode == "sequential":
269325
if i < len(actions) - 1:
270-
next_fn_name = (
271-
self.get_function_name(actions[i + 1].functionRef)
272-
if isinstance(actions[i + 1].functionRef, str)
273-
else (
274-
actions[i + 1].functionRef.refName
275-
if isinstance(
276-
actions[i + 1].functionRef, FunctionRef
326+
# get next name
327+
next_name = None
328+
if actions[i + 1].functionRef:
329+
next_name = (
330+
self.get_function_name(actions[i + 1].functionRef)
331+
if isinstance(actions[i + 1].functionRef, str)
332+
else (
333+
actions[i + 1].functionRef.refName
334+
if isinstance(
335+
actions[i + 1].functionRef, FunctionRef
336+
)
337+
else None
277338
)
278-
else None
279339
)
280-
)
281-
if (
282-
next_fn_name
283-
not in self.state_machine.get_state(
284-
state_name
285-
).states.keys()
286-
):
287-
machine_state.add_substate(NestedState(next_fn_name))
340+
if (
341+
next_name
342+
not in self.state_machine.get_state(
343+
state_name
344+
).states.keys()
345+
):
346+
machine_state.add_substate(NestedState(next_name))
347+
elif actions[i + 1].subFlowRef:
348+
next_name = new_subflows_names.get(i + 1)
288349
self.state_machine.add_transition(
289350
trigger="",
290-
source=f"{state_name}.{fn_name}",
291-
dest=f"{state_name}.{next_fn_name}",
351+
source=f"{state_name}.{name}",
352+
dest=f"{state_name}.{next_name}",
292353
)
293354
if i == 0:
294-
machine_state.initial = fn_name
355+
machine_state.initial = name
295356
elif action_mode == "parallel":
296-
parallel_states.append(fn_name)
357+
parallel_states.append(name)
297358
if action_mode == "parallel":
298359
machine_state.initial = parallel_states
299360

300-
def generate_actions_info(
301-
self,
302-
machine_state: NestedState,
303-
state_name: str,
304-
actions: List[Action],
305-
action_mode: str = "sequential",
306-
):
307-
if actions:
308-
if self.get_actions:
309-
self.generate_composite_state(
310-
machine_state,
311-
state_name,
312-
actions,
313-
action_mode,
314-
)
315-
for action in actions:
316-
if action.subFlowRef:
317-
if isinstance(action.subFlowRef, str):
318-
workflow_id = action.subFlowRef
319-
workflow_version = None
320-
else:
321-
workflow_id = action.subFlowRef.workflowId
322-
workflow_version = action.subFlowRef.version
323-
none_found = True
324-
for sf in self.subflows:
325-
if sf.id == workflow_id and (
326-
(workflow_version and sf.version == workflow_version)
327-
or not workflow_version
328-
):
329-
none_found = False
330-
new_machine = HierarchicalMachine(
331-
model=None, initial=None, auto_transitions=False
332-
)
333-
334-
# Generate the state machine for the subflow
335-
for index, state in enumerate(sf.states):
336-
StateMachineGenerator(
337-
state=state,
338-
state_machine=new_machine,
339-
is_first_state=index == 0,
340-
get_actions=self.get_actions,
341-
subflows=self.subflows,
342-
).source_code()
343-
344-
# Convert the new_machine into a NestedState
345-
nested_state = NestedState(
346-
action.name
347-
if action.name
348-
else f"{sf.id}/{sf.version.replace(NestedState.separator, '-')}"
349-
)
350-
self.state_machine_to_nested_state(
351-
state_machine=new_machine, nested_state=nested_state
352-
)
353-
if none_found:
354-
warnings.warn(
355-
f"Specified subflow [{workflow_id} {workflow_version if workflow_version else ''}] not found.",
356-
category=UserWarning,
357-
)
361+
def subflow_state_name(self, action: Action, subflow: Workflow):
362+
return (
363+
action.name
364+
if action.name
365+
else f"{subflow.id}/{subflow.version.replace(NestedState.separator, '-')}"
366+
)
358367

359368
def add_all_sub_states(
360369
cls,
@@ -366,12 +375,14 @@ def add_all_sub_states(
366375
for substate in original_state.states.values():
367376
new_state.add_substate(ns := NestedState(substate.name))
368377
cls.add_all_sub_states(substate, ns)
378+
new_state.initial = original_state.initial
369379

370380
def state_machine_to_nested_state(
371-
self, state_machine: HierarchicalMachine, nested_state: NestedState
381+
self,
382+
state_name: str,
383+
state_machine: HierarchicalMachine,
384+
nested_state: NestedState,
372385
) -> NestedState:
373-
self.state_machine.get_state(self.state.name).add_substate(nested_state)
374-
375386
self.add_all_sub_states(state_machine, nested_state)
376387

377388
for trigger, event in state_machine.events.items():
@@ -381,8 +392,8 @@ def state_machine_to_nested_state(
381392
dest = transition.dest
382393
self.state_machine.add_transition(
383394
trigger=trigger,
384-
source=f"{self.state.name}.{nested_state.name}.{source}",
385-
dest=f"{self.state.name}.{nested_state.name}.{dest}",
395+
source=f"{state_name}.{nested_state.name}.{source}",
396+
dest=f"{state_name}.{nested_state.name}.{dest}",
386397
)
387398

388399
def get_function_name(

serverlessworkflow/sdk/state_machine_helper.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,13 @@ def __init__(
3232
)
3333
for index, state in enumerate(workflow.states):
3434
StateMachineGenerator(
35-
state=state, state_machine=self.machine, is_first_state=index == 0, get_actions=self.get_actions, subflows=subflows
36-
).source_code()
37-
38-
35+
state=state,
36+
state_machine=self.machine,
37+
is_first_state=index == 0,
38+
get_actions=self.get_actions,
39+
subflows=subflows,
40+
).generate()
41+
3942
delattr(self.machine, "get_graph")
4043
self.machine.add_model(machine_type.self_literal)
4144

0 commit comments

Comments
 (0)