2 from AthenaConfiguration.ComponentFactory
import CompFactory
5 AthSequencer = CompFactory.AthSequencer
7 def parAND(name, subs=[], invert=False):
8 """parallel AND sequencer"""
14 Members = subs.copy() )
16 def parOR(name, subs=[], invert=False):
17 """parallel OR sequencer
18 This is the default sequencer and lets the DataFlow govern the execution entirely.
25 Members = subs.copy() )
27 def seqAND(name, subs=[], invert=False):
28 """sequential AND sequencer"""
34 Members = subs.copy() )
36 def seqOR(name, subs=[], invert=False):
37 """sequential OR sequencer
38 Used when a barrier needs to be set by all subs reached irrespective of the decision
45 Members = subs.copy() )
49 """Return sequence children (empty if comp is not a sequence)"""
52 except AttributeError:
57 """ Enforce rules for sequence graph - identical items can not be added to itself (even indirectly) """
59 def __noSubSequenceOfName( s, n, seen = set() ):
64 raise RuntimeError(f
"Sequence {c.getName()} contains itself")
67 raise RuntimeError(f
"Sequence {n} contains sub-sequence of the same name")
68 __noSubSequenceOfName( c, c.getName(), seen )
69 __noSubSequenceOfName( c, n, seen )
71 __noSubSequenceOfName( seq, seq.getName() )
75 return isinstance(obj, AthSequencer)
79 """ Traverse sequences tree to find a sequence of a given name. The first one is returned. """
80 if start.getName() == nameToLookFor:
84 if c.getName() == nameToLookFor:
93 """ find sequence that owns the sequence nameTooLookFor"""
95 if c.getName() == nameToLookFor:
105 """ Traverse sequences tree to find the first algorithm satisfying given predicate. The first encountered is returned.
107 Depth of the search can be controlled by the depth parameter.
108 Typical use is to limit search to the startSequence with depth parameter set to 1
124 """ Traverse sequences tree to find the algorithm of given name. The first encountered is returned.
126 The name() method is used to obtain the algorithm name, that one has to match to the request.
133 Returns flat listof of all algorithm instances in this, and in sub-sequences
140 if nameToLookFor
is None or child.getName() == nameToLookFor:
141 algorithms.append(child)
147 Finds all algorithms in sequence and groups them by name
149 Resulting dict has a following structure
150 {"Alg1Name":[(Alg1Instance, parentSequenceA, indexInSequenceA),(Alg1Instance, parentSequenceB, indexInSequenceB)],
151 "Alg2Name":(Alg2Instance, parentSequence, indexInThisSequence),
154 algorithms = collections.defaultdict(list)
156 if child.getName() == sequence.getName():
157 raise RuntimeError(f
"Recursively-nested sequence: {child.getName()} contains itself")
160 for algName
in childAlgs:
161 algorithms[algName] += childAlgs[algName]
163 if namesToLookFor
is None or child.getName()
in namesToLookFor:
164 algorithms[child.getName()].
append( (child, sequence, idx) )
169 """ Converts tree like structure of sequences into dictionary
170 keyed by top/start sequence name containing lists of of algorithms & sequences."""
172 def __inner( seq, collector ):
174 collector[seq.getName()].
append( c )
176 __inner( c, collector )
178 from collections
import defaultdict,OrderedDict
179 c = defaultdict(list)
181 return OrderedDict(c)
185 """Iterator of sequences and their algorithms from (and including) the `start`
186 sequence object. Do start from a sequence name use findSubSequence."""
191 yield from __inner(c)
193 yield from __inner(start)
201 import AthenaPython.PyAthena
as PyAthena
204 top.Members += [
parOR(
"nest1")]
206 top.Members += [nest2]
208 nest2.Members += [
parOR(
"deep_nest1")]
209 nest2.Members += [
parOR(
"deep_nest2")]
218 self.assertIsNotNone( f,
"Can not find sequence at start" )
219 self.assertEqual( f.getName(),
"top",
"Wrong sequence" )
222 self.assertIsNotNone( nest2,
"Can not find sub sequence" )
223 self.assertEqual( nest2.getName(),
"nest2",
"Sub sequence incorrect" )
228 self.assertIsNotNone( d,
"Deep searching for sub seqeunce fails" )
229 self.assertEqual( d.getName(),
"deep_nest2",
"Wrong sub sequence in deep search" )
234 self.assertIsNone( d,
"Algorithm confused as a sequence" )
238 self.assertIsNone( inexistent,
"ERROR, found sub sequence that does not relay exist" )
242 self.assertIsNone( inexistent,
"ERROR, found owner of inexistent sequence " )
246 self.assertEqual( owner.getName(),
"nest2",
"Wrong owner %s" % owner.getName() )
249 self.assertEqual( owner.getName(),
"nest2",
"Wrong owner %s" % owner.getName() )
252 self.assertEqual( owner.getName(),
"nest2",
"Wrong owner %s" % owner.getName() )
255 self.assertEqual( owner.getName() ,
"top",
"Wrong owner %s" % owner.getName() )
260 self.assertEqual( result, [
'top',
'nest1',
'nest2',
'deep_nest1',
'deep_nest2',
261 'SomeAlg1',
'SomeAlg2',
'SomeAlg3',
'SomeAlg0'] )
266 self.assertEqual( result, [
'nest2',
'deep_nest1',
'deep_nest2',
267 'SomeAlg1',
'SomeAlg2',
'SomeAlg3'] )
271 result = [seq.getName()
for seq
in iterSequences( deep_nest2 )]
272 self.assertEqual( result, [
'deep_nest2'] )
277 self.assertEqual( result, [
'SomeAlg1'] )
281 self.assertIsNotNone( a1,
"Can't find algorithm present in sequence" )
284 self.assertIsNotNone( a1,
"Can't find nested algorithm " )
289 self.assertIsNone( a1,
"Finding algorithm that is in the upper sequence" )
292 self.assertIsNone( a1,
"Finding algorithm that is does not exist" )
295 self.assertIsNotNone( a1,
"Could not find algorithm within the required nesting depth == 1" )
298 self.assertIsNone( a1,
"Could find algorithm even if it is deep in sequences structure" )
301 self.assertIsNotNone( a1,
"Could not find algorithm within the required nesting depth == 2" )
304 self.assertIsNotNone( a1
is None,
"Could find algorithm even if it is deep in sequences structure" )
309 global isComponentAccumulatorCfg
310 isComponentAccumulatorCfg =
lambda :
True
313 nest1 =
parOR(
"nest1")
315 top.Members += [nest1, nest2]
317 deep_nest1 =
seqAND(
"deep_nest1")
318 nest1.Members += [deep_nest1]
320 nest2.Members += [nest1]
322 deep_nest1.Members += [nest1]
323 self.assertRaises( RuntimeError, checkSequenceConsistency, top )