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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy