3 from AnaAlgorithm.Logging
import logging
4 logCPAlgCfgSeq = logging.getLogger(
'CPAlgCfgSeq')
6 from AnalysisAlgorithmsConfig.ConfigAccumulator
import DataType
7 from functools
import wraps
8 from random
import randrange
12 Decorates a configSequence or function with 'seq' as a
15 Sets groupName to the name of the decorated funtion or
16 calss plus and integer for each ConfigBlock in the configSequence.
18 Blocks with the same groupName can be configured together.
21 def wrapper(**kwargs):
23 groupName = f
"{func.__name__}_{randrange(10**8):08}"
24 for block
in kwargs[
'seq']:
25 block.setOptionValue(
'groupName', groupName)
29 """check whether the sample being run passes a"""
30 """possible DSID filter on the block"""
31 if len(filterList) == 0:
33 for dsid_filter
in filterList:
35 if any(char
in dsid_filter
for char
in "^$*+?.()|[]{}\\"):
36 pattern = re.compile(dsid_filter)
37 if pattern.match(
str(config.dsid())):
41 if str(dsid_filter) ==
str(config.dsid()):
46 """a sequence of ConfigBlock objects
48 This could in principle just be a simple python list, and maybe we
49 change it to that at some point (10 Mar 22). Having it as its own
50 class allows to implement some helper functions.
52 This implements an interface similar to ConfigBlock, but it
53 doesn't derive from it, as ConfigBlock will likely gain
54 functionality in the future that wouldn't work for a sequence (or
55 wouldn't work in the same way).
64 """append a configuration block to the sequence"""
69 """call makeAlgs() on all blocks
71 This will create the actual algorithm configurables based on
72 how the blocks are configured right now.
75 if block.skipOnData
and config.dataType()
is DataType.Data:
77 if block.skipOnMC
and config.dataType()
is not DataType.Data:
81 block.makeAlgs (config)
85 Check for blocks with dependencies.
87 If a block required another block that is not present, will
88 throw an error; Otherwise, will move block immediately after
89 required block. If dependency is not required, will move
90 after other block, if it is present.
92 Note: this implementation can only move blocks forward.
94 def moveBlock(blocks):
95 for i, block
in enumerate(blocks):
97 ignore = block.getOptionValue(
'ignoreDependencies')
98 if block.hasDependencies():
100 for dep
in block.getDependencies():
105 lastIdx =
max(index
for index,value
in enumerate(blocks)
if value == dep.blockName)
109 raise ValueError(f
"{dep} block is required"
110 f
" for {block} but was not found.")
113 logCPAlgCfgSeq.info(f
"Moving {block} after {blocks[depIdx]}")
115 blocks.insert(depIdx, blocks.pop(i))
120 for _
in range(MAXTRIES):
125 raise Exception(
"Could not order blocks based on dependencies"
126 f
" in {MAXTRIES} moves.")
130 """do the full configuration on this sequence
132 This sequence needs to be the only sequence, i.e. it needs to
133 contain all the blocks that will be configured, as it will
134 perform all configuration steps at once.
143 """set the given option on the sequence
145 The name should generally be of the form
146 "groupName.optionName" to identify what group the option
149 For simplicity I also allow a ".optionName" here, which will
150 then set the property in the last group added. That makes it
151 fairly straightforward to add new blocks, set options on them,
152 and then move on to the next blocks. Please note that this
153 mechanism ought to be viewed as strictly as a temporary
154 convenience, and this short cut may go away once better
155 alternatives are available.
157 WARNING: The backend to option handling is slated to be
158 replaced at some point. This particular function may change
159 behavior, interface or be removed/replaced entirely.
161 names = name.split(
'.')
163 optionName = names.pop(-1)
166 groupName = names.pop(0)
if names
else ''
168 raise ValueError(f
'Option name can be either <groupName>.<optionName>'
169 f
' or <optionName> not {name}')
173 groupName = blocks[-1].getOptionValue(
'groupName')
178 if ( block.getOptionValue(
'groupName') == groupName
179 and block.hasOption(optionName) ):
180 block.setOptionValue (optionName, value, **kwargs)
183 raise ValueError(f
'{optionName} not found in blocks with '
184 f
'group name {groupName}')
187 blocks[-1].setOptionValue (optionName, value, **kwargs)
192 Prints options and their values for each config block in a config sequence
195 logCPAlgCfgSeq.info(config.__class__.__name__)
196 config.printOptions(verbose=verbose)
200 """get information on options for last block in sequence"""
202 groupName = self.
_blocks[-1].getOptionValue(
'groupName')
206 for block
in self.
_blocks[:-1]:
207 if block.getOptionValue(
'groupName') == groupName:
212 for name, o
in block.getOptions().
items():
213 val = getattr(block, name)
214 valDefault = o.default
216 valRequired = o.required
217 noneAction = o.noneAction
218 options.append({
'name': name,
'defaultValue': valDefault,
219 'type': valType,
'required': valRequired,
220 'noneAction': noneAction,
'value': val})
225 """Set options for a ConfigBlock"""
227 for opt
in algOptions:
231 logCPAlgCfgSeq.info(f
" {name}: {options[name]}")
234 raise ValueError(f
'{name} is required but not included in config')
236 defaultVal = opt[
'defaultValue']
238 if name !=
'groupName':
239 options[name] = defaultVal
240 logCPAlgCfgSeq.info(f
" {name}: {defaultVal}")
246 Assigns all blocks in configSequence groupName. If no name is
247 provided, the name is set to group_ plus an integer.
249 Blocks with the same groupName can be configured together.
252 groupName = f
"group_{randrange(10**8):08}"
254 block.setOptionValue(
'groupName', groupName)
258 """Add another sequence to this one
260 This function is used to add another sequence to this sequence
261 using the '+=' operator.
264 if not isinstance( sequence, ConfigSequence ):
265 raise TypeError(
'The received object is not of type ConfigSequence' )
267 for block
in sequence._blocks :
275 """Create an iterator over all the configurations in this sequence
277 This is to allow for a Python-like iteration over all
278 configuration blocks that are part of the sequence.