3 from AnaAlgorithm.Logging
import logging
4 logCPAlgCfgSeq = logging.getLogger(
'CPAlgCfgSeq')
6 from functools
import wraps
7 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 """a sequence of ConfigBlock objects
31 This could in principle just be a simple python list, and maybe we
32 change it to that at some point (10 Mar 22). Having it as its own
33 class allows to implement some helper functions.
35 This implements an interface similar to ConfigBlock, but it
36 doesn't derive from it, as ConfigBlock will likely gain
37 functionality in the future that wouldn't work for a sequence (or
38 wouldn't work in the same way).
47 """append a configuration block to the sequence"""
52 """call makeAlgs() on all blocks
54 This will create the actual algorithm configurables based on
55 how the blocks are configured right now.
58 if not block.isUsedForConfig(config):
60 config.setAlgPostfix(block.instanceName())
61 block.makeAlgs (config)
62 config.setAlgPostfix(
'')
67 Apply any properties that were set in the block's
68 'propertyOverrides' option.
71 if not block.isUsedForConfig(config):
73 config.setAlgPostfix(block.instanceName())
74 block.applyConfigOverrides(config)
75 config.setAlgPostfix(
'')
79 Check for blocks with dependencies.
81 If a block required another block that is not present, will
82 throw an error; Otherwise, will move block immediately after
83 required block. If dependency is not required, will move
84 after other block, if it is present.
86 Note: this implementation can only move blocks forward.
88 def moveBlock(blocks):
89 for i, block
in enumerate(blocks):
91 ignore = block.getOptionValue(
'ignoreDependencies')
92 if block.hasDependencies():
94 for dep
in block.getDependencies():
99 lastIdx =
max(index
for index,value
in enumerate(blocks)
if value == dep.blockName)
103 raise ValueError(f
"{dep} block is required"
104 f
" for {block} but was not found.")
107 logCPAlgCfgSeq.info(f
"Moving {block} after {blocks[depIdx]}")
109 blocks.insert(depIdx, blocks.pop(i))
114 for _
in range(MAXTRIES):
119 raise Exception(
"Could not order blocks based on dependencies"
120 f
" in {MAXTRIES} moves.")
124 """do the full configuration on this sequence
126 This sequence needs to be the only sequence, i.e. it needs to
127 contain all the blocks that will be configured, as it will
128 perform all configuration steps at once.
131 if re.compile (
'^[_a-zA-Z0-9]*$').match (block.instanceName())
is None :
132 raise ValueError (f
'invalid block instance name: {block.instanceName()} for {block.factoryName()}')
142 """set the given option on the sequence
144 The name should generally be of the form
145 "groupName.optionName" to identify what group the option
148 For simplicity I also allow a ".optionName" here, which will
149 then set the property in the last group added. That makes it
150 fairly straightforward to add new blocks, set options on them,
151 and then move on to the next blocks. Please note that this
152 mechanism ought to be viewed as strictly as a temporary
153 convenience, and this short cut may go away once better
154 alternatives are available.
156 WARNING: The backend to option handling is slated to be
157 replaced at some point. This particular function may change
158 behavior, interface or be removed/replaced entirely.
160 names = name.split(
'.')
162 optionName = names.pop(-1)
165 groupName = names.pop(0)
if names
else ''
167 raise ValueError(f
'Option name can be either <groupName>.<optionName>'
168 f
' or <optionName> not {name}')
172 groupName = blocks[-1].getOptionValue(
'groupName')
177 if ( block.getOptionValue(
'groupName') == groupName
178 and block.hasOption(optionName) ):
179 block.setOptionValue (optionName, value, **kwargs)
182 raise ValueError(f
'{optionName} not found in blocks with '
183 f
'group name {groupName}')
186 blocks[-1].setOptionValue (optionName, value, **kwargs)
191 Prints options and their values for each config block in a config sequence
194 logCPAlgCfgSeq.info(config.__class__.__name__)
195 config.printOptions(verbose=verbose)
199 """get information on options for last block in sequence"""
201 groupName = self.
_blocks[-1].getOptionValue(
'groupName')
205 for block
in self.
_blocks[:-1]:
206 if block.getOptionValue(
'groupName') == groupName:
211 for name, o
in block.getOptions().
items():
212 val = getattr(block, name)
213 valDefault = o.default
215 valRequired = o.required
216 noneAction = o.noneAction
217 options.append({
'name': name,
'defaultValue': valDefault,
218 'type': valType,
'required': valRequired,
219 'noneAction': noneAction,
'value': val})
224 """Set options for a ConfigBlock"""
226 for opt
in algOptions:
230 logCPAlgCfgSeq.info(f
" {name}: {options[name]}")
233 raise ValueError(f
'{name} is required but not included in config')
235 defaultVal = opt[
'value']
if opt[
'value']
else opt[
'defaultValue']
237 if name !=
'groupName':
238 options[name] = defaultVal
239 logCPAlgCfgSeq.info(f
" {name}: {defaultVal}")
245 Assigns all blocks in configSequence groupName. If no name is
246 provided, the name is set to group_ plus an integer.
248 Blocks with the same groupName can be configured together.
251 groupName = f
"group_{randrange(10**8):08}"
253 block.setOptionValue(
'groupName', groupName)
258 Set the factory name for all blocks in the sequence.
260 This is used to set a common factory name for all blocks, which
261 can be useful for debugging or logging purposes.
267 for index, block
in enumerate(self.
_blocks):
268 block.setFactoryName(f
"{factoryName}[{index}:{block.__class__.__name__}]")
271 """Add another sequence to this one
273 This function is used to add another sequence to this sequence
274 using the '+=' operator.
277 if not isinstance( sequence, ConfigSequence ):
278 raise TypeError(
'The received object is not of type ConfigSequence' )
280 for block
in sequence._blocks :
288 """Create an iterator over all the configurations in this sequence
290 This is to allow for a Python-like iteration over all
291 configuration blocks that are part of the sequence.