detect loops while building the workflow, not after: faster, better
parent
71a9ba321f
commit
fb6a69c40e
|
@ -11,7 +11,7 @@ class Workflow:
|
||||||
firstStep = None
|
firstStep = None
|
||||||
for label in actions:
|
for label in actions:
|
||||||
if not label in seen:
|
if not label in seen:
|
||||||
(entryPoint, seen, newDangling) = self._initChain(actions, label, seen)
|
(entryPoint, seen, newDangling) = self._initChain(actions, label, seen, (label,))
|
||||||
if firstStep is None:
|
if firstStep is None:
|
||||||
firstStep = entryPoint
|
firstStep = entryPoint
|
||||||
elif len(dangling) > 0:
|
elif len(dangling) > 0:
|
||||||
|
@ -19,11 +19,8 @@ class Workflow:
|
||||||
setter(entryPoint)
|
setter(entryPoint)
|
||||||
dangling = newDangling
|
dangling = newDangling
|
||||||
self.firstStep = firstStep
|
self.firstStep = firstStep
|
||||||
loop = self._checkForLoops()
|
|
||||||
if loop:
|
|
||||||
raise RecursionError("Loop found in actions: %s\n" % loop)
|
|
||||||
|
|
||||||
def _initChain(self, actions, label, seen):
|
def _initChain(self, actions, label, seen, wholeChain):
|
||||||
dangling = []
|
dangling = []
|
||||||
previousSetter = None
|
previousSetter = None
|
||||||
firstStep = None
|
firstStep = None
|
||||||
|
@ -38,12 +35,16 @@ class Workflow:
|
||||||
obj.setStepName(label + '[' + str(stepNum) + ']')
|
obj.setStepName(label + '[' + str(stepNum) + ']')
|
||||||
if mod.thenRun:
|
if mod.thenRun:
|
||||||
(seen, dangling) = \
|
(seen, dangling) = \
|
||||||
self._branchToChain(obj.setNextStep, mod.thenRun, actions, seen, dangling)
|
self._branchToChain(
|
||||||
|
obj.setNextStep, mod.thenRun, wholeChain,
|
||||||
|
actions, seen, dangling)
|
||||||
isThenCalled = True
|
isThenCalled = True
|
||||||
if mod.isFilter:
|
if mod.isFilter:
|
||||||
if mod.elseRun:
|
if mod.elseRun:
|
||||||
(seen, dangling) = \
|
(seen, dangling) = \
|
||||||
self._branchToChain(obj.setAltStep, mod.elseRun, actions, seen, dangling)
|
self._branchToChain(
|
||||||
|
obj.setAltStep, mod.elseRun, wholeChain,
|
||||||
|
actions, seen, dangling)
|
||||||
else:
|
else:
|
||||||
dangling.append(obj.setAltStep)
|
dangling.append(obj.setAltStep)
|
||||||
isPreviousDangling = mod.isFilter and not isThenCalled
|
isPreviousDangling = mod.isFilter and not isThenCalled
|
||||||
|
@ -57,35 +58,16 @@ class Workflow:
|
||||||
seen[label] = firstStep if len(dangling) == 0 else None
|
seen[label] = firstStep if len(dangling) == 0 else None
|
||||||
return (firstStep, seen, dangling)
|
return (firstStep, seen, dangling)
|
||||||
|
|
||||||
def _branchToChain(self, parentSetter, branchName, actions, seen, dangling):
|
def _branchToChain(self, parentSetter, branchName, wholeChain, actions, seen, dangling):
|
||||||
if branchName in seen and seen[branchName]:
|
if branchName in wholeChain:
|
||||||
|
raise RecursionError("Loop found in actions: %s\n" % str(wholeChain + (branchName,)))
|
||||||
|
elif branchName in seen and seen[branchName] is not None:
|
||||||
parentSetter(seen[branchName])
|
parentSetter(seen[branchName])
|
||||||
elif branchName in actions:
|
elif branchName in actions:
|
||||||
(entryPoint, seen, newDangling) = \
|
(entryPoint, seen, newDangling) = \
|
||||||
self._initChain(actions, branchName, seen)
|
self._initChain(actions, branchName, seen, wholeChain + (branchName,))
|
||||||
parentSetter(entryPoint)
|
parentSetter(entryPoint)
|
||||||
dangling.extend(newDangling)
|
dangling.extend(newDangling)
|
||||||
else:
|
else:
|
||||||
raise ValueError("Action chain not found: %s\n" % branchName)
|
raise ValueError("Action chain not found: %s\n" % branchName)
|
||||||
return (seen, dangling)
|
return (seen, dangling)
|
||||||
|
|
||||||
def _checkForLoops(self):
|
|
||||||
if self.firstStep is None:
|
|
||||||
return None
|
|
||||||
branches = [(self.firstStep, [], [])]
|
|
||||||
while True:
|
|
||||||
node, branchIds, branch = branches.pop()
|
|
||||||
idNode = id(node)
|
|
||||||
if idNode in branchIds:
|
|
||||||
return branch if self._withDebug else True
|
|
||||||
branchIds.append(idNode)
|
|
||||||
if self._withDebug:
|
|
||||||
branch.append(node.stepName)
|
|
||||||
if isinstance(node, base.Filter) and node.altStep:
|
|
||||||
altBranch = list(branch)
|
|
||||||
altBranchIds = list(branchIds)
|
|
||||||
branches.append((node.altStep, altBranchIds, altBranch))
|
|
||||||
if node.nextStep:
|
|
||||||
branches.append((node.nextStep, branchIds, branch))
|
|
||||||
if len(branches) == 0:
|
|
||||||
return None
|
|
||||||
|
|
Loading…
Reference in New Issue