3from AnalysisAlgorithmsConfig.ConfigBlock
import ConfigBlock
4from AnaAlgorithm.Logging
import logging
5logCPAlgCfgSeq = logging.getLogger(
'CPAlgCfgSeq')
7from functools
import wraps
8from random
import randrange
13 Decorates a configSequence or function with 'seq' as a
16 Sets groupName to the name of the decorated funtion or
17 calss plus and integer for each ConfigBlock in the configSequence.
19 Blocks with the same groupName can be configured together.
22 def wrapper(**kwargs):
24 groupName = f
"{func.__name__}_{randrange(10**8):08}"
25 for block
in kwargs[
'seq']:
26 block.setOptionValue(
'groupName', groupName)
30 """a sequence of ConfigBlock objects
32 This could in principle just be a simple python list, and maybe we
33 change it to that at some point (10 Mar 22). Having it as its own
34 class allows to implement some helper functions.
36 This implements an interface similar to ConfigBlock, but it
37 doesn't derive from it, as ConfigBlock will likely gain
38 functionality in the future that wouldn't work for a sequence (or
39 wouldn't work in the same way).
48 """append a configuration block to the sequence"""
53 """call makeAlgs() on all blocks
55 This will create the actual algorithm configurables based on
56 how the blocks are configured right now.
59 if not block.isUsedForConfig(config):
61 config.setAlgPostfix(block.instanceName())
62 block.checkExpertSettings (config)
63 block.makeAlgs (config)
64 config.setAlgPostfix(
'')
65 ConfigBlock.instance_counts.clear()
70 Apply any properties that were set in the block's
71 'propertyOverrides' option.
74 if not block.isUsedForConfig(config):
76 config.setAlgPostfix(block.instanceName())
77 block.applyConfigOverrides(config)
78 config.setAlgPostfix(
'')
82 Check for blocks with dependencies.
84 If a block required another block that is not present, will
85 throw an error; Otherwise, will move block immediately after
86 required block. If dependency is not required, will move
87 after other block, if it is present.
89 Note: this implementation can only move blocks forward.
91 def moveBlock(blocks):
92 for i, block
in enumerate(blocks):
94 ignore = block.getOptionValue(
'ignoreDependencies')
95 if block.hasDependencies():
97 for dep
in block.getDependencies():
102 lastIdx =
max(index
for index,value
in enumerate(blocks)
if value == dep.blockName)
106 raise ValueError(f
"{dep} block is required"
107 f
" for {block} but was not found.")
110 logCPAlgCfgSeq.info(f
"Moving {block} after {blocks[depIdx]}")
112 blocks.insert(depIdx, blocks.pop(i))
117 for _
in range(MAXTRIES):
122 raise Exception(
"Could not order blocks based on dependencies"
123 f
" in {MAXTRIES} moves.")
127 """do the full configuration on this sequence
129 This sequence needs to be the only sequence, i.e. it needs to
130 contain all the blocks that will be configured, as it will
131 perform all configuration steps at once.
134 if re.compile (
'^[_a-zA-Z0-9]*$').match (block.instanceName())
is None :
135 raise ValueError (f
'invalid block instance name: {block.instanceName()} for {block.factoryName()}')
140 config.renameFinalContainers()
144 """set the given option on the sequence
146 The name should generally be of the form
147 "groupName.optionName" to identify what group the option
150 For simplicity I also allow a ".optionName" here, which will
151 then set the property in the last group added. That makes it
152 fairly straightforward to add new blocks, set options on them,
153 and then move on to the next blocks. Please note that this
154 mechanism ought to be viewed as strictly as a temporary
155 convenience, and this short cut may go away once better
156 alternatives are available.
158 WARNING: The backend to option handling is slated to be
159 replaced at some point. This particular function may change
160 behavior, interface or be removed/replaced entirely.
162 names = name.split(
'.')
164 optionName = names.pop(-1)
167 groupName = names.pop(0)
if names
else ''
169 raise ValueError(f
'Option name can be either <groupName>.<optionName>'
170 f
' or <optionName> not {name}')
174 groupName = blocks[-1].getOptionValue(
'groupName')
179 if ( block.getOptionValue(
'groupName') == groupName
180 and block.hasOption(optionName) ):
181 block.setOptionValue (optionName, value, **kwargs)
184 raise ValueError(f
'{optionName} not found in blocks with '
185 f
'group name {groupName}')
188 blocks[-1].setOptionValue (optionName, value, **kwargs)
193 Prints options and their values for each config block in a config sequence
196 logCPAlgCfgSeq.info(config.__class__.__name__)
197 config.printOptions(verbose=verbose)
201 """get information on options for last block in sequence"""
203 groupName = self.
_blocks[-1].getOptionValue(
'groupName')
207 for block
in self.
_blocks[:-1]:
208 if block.getOptionValue(
'groupName') == groupName:
213 for name, o
in block.getOptions().items():
214 val = getattr(block, name)
215 valDefault = o.default
217 valRequired = o.required
218 noneAction = o.noneAction
219 options.append({
'name': name,
'defaultValue': valDefault,
220 'type': valType,
'required': valRequired,
221 'noneAction': noneAction,
'value': val})
226 """Set options for a ConfigBlock"""
228 for opt
in algOptions:
232 logCPAlgCfgSeq.debug(f
" {name}: {options[name]}")
235 raise ValueError(f
'{name} is required but not included in config')
237 defaultVal = opt[
'value']
if opt[
'value']
else opt[
'defaultValue']
239 if name !=
'groupName':
240 options[name] = defaultVal
241 logCPAlgCfgSeq.debug(f
" {name}: {defaultVal}")
248 Assigns all blocks in configSequence groupName. If no name is
249 provided, the name is set to group_ plus an integer.
251 Blocks with the same groupName can be configured together.
254 groupName = f
"group_{randrange(10**8):08}"
256 block.setOptionValue(
'groupName', groupName)
261 Set the factory name for all blocks in the sequence.
263 This is used to set a common factory name for all blocks, which
264 can be useful for debugging or logging purposes.
270 for index, block
in enumerate(self.
_blocks):
271 block.setFactoryName(f
"{factoryName}[{index}:{block.__class__.__name__}]")
274 """Add another sequence to this one
276 This function is used to add another sequence to this sequence
277 using the '+=' operator.
280 if not isinstance( sequence, ConfigSequence ):
281 raise TypeError(
'The received object is not of type ConfigSequence' )
283 for block
in sequence._blocks :
291 """Create an iterator over all the configurations in this sequence
293 This is to allow for a Python-like iteration over all
294 configuration blocks that are part of the sequence.
groupBlocks(self, groupName='')
setOptionValue(self, name, value, **kwargs)
__iadd__(self, sequence, index=None)
fullConfigure(self, config)
setFactoryName(self, factoryName)
setOptions(self, options)
printOptions(self, verbose=False)
applyConfigOverrides(self, config)