ATLAS Offline Software
Loading...
Searching...
No Matches
python.ConfigText.TextConfig Class Reference
Inheritance diagram for python.ConfigText.TextConfig:
Collaboration diagram for python.ConfigText.TextConfig:

Public Member Functions

 __init__ (self, yamlPath=None, *, config=None, addDefaultBlocks=True)
 setConfig (self, config)
 preprocessConfig (self, config, algs)
 cleanupPlaceholders (self, config)
 loadConfig (self, yamlPath=None, *, configDict=None)
 printConfig (self, sort=False, jsonFormat=False)
 saveYaml (self, filePath='config.yaml', default_flow_style=False, **kwargs)
 addBlock (self, name, **kwargs)
 setOptions (self, **kwargs)
 configure (self)

Protected Member Functions

 _addNewConfigBlocks (self, modulePath, functionName, algName, defaults=None, pos=None, superBlocks=None)
 _configureAlg (self, block, blockConfig, configSeq=None, containerName=None, extraOptions=None)

Protected Attributes

dict _config = {}
 _last = None
 _algs

Private Attributes

bool __loadedYaml = False

Detailed Description

Definition at line 39 of file ConfigText.py.

Constructor & Destructor Documentation

◆ __init__()

python.ConfigText.TextConfig.__init__ ( self,
yamlPath = None,
* ,
config = None,
addDefaultBlocks = True )

Definition at line 40 of file ConfigText.py.

40 def __init__(self, yamlPath=None, *, config=None, addDefaultBlocks=True):
41 super().__init__(addDefaultBlocks=False)
42
43 if yamlPath and config:
44 raise ValueError("Cannot specify both yamlPath and config. Use one or the other.")
45
46 # Block to add new blocks to this object
47 self.addAlgConfigBlock(algName="AddConfigBlocks", alg=self._addNewConfigBlocks,
48 defaults={'self': self})
49 # add default blocks
50 if addDefaultBlocks:
51 self.addDefaultAlgs()
52 # load yaml
53 self._config = {}
54 # do not allow for loading multiple yaml files
55 self.__loadedYaml = False
56 if yamlPath is not None or config is not None:
57 self.loadConfig(yamlPath, configDict=config)
58 # last is used for setOptionValue when using addBlock
59 self._last = None
60
61

Member Function Documentation

◆ _addNewConfigBlocks()

python.ConfigText.TextConfig._addNewConfigBlocks ( self,
modulePath,
functionName,
algName,
defaults = None,
pos = None,
superBlocks = None )
protected
Load <functionName> from <modulePath>

Definition at line 241 of file ConfigText.py.

242 algName, defaults=None, pos=None, superBlocks=None):
243 """
244 Load <functionName> from <modulePath>
245 """
246 try:
247 module = importlib.import_module(modulePath)
248 fxn = getattr(module, functionName)
249 except ModuleNotFoundError as e:
250 raise ModuleNotFoundError(f"{e}\nFailed to load {functionName} from {modulePath}")
251 else:
252 sys.modules[functionName] = fxn
253 # add new algorithm to available algorithms
254 self.addAlgConfigBlock(algName=algName, alg=fxn,
255 defaults=defaults,
256 superBlocks=superBlocks,
257 pos=pos)
258 return
259
260

◆ _configureAlg()

python.ConfigText.TextConfig._configureAlg ( self,
block,
blockConfig,
configSeq = None,
containerName = None,
extraOptions = None )
protected

Definition at line 261 of file ConfigText.py.

262 extraOptions=None):
263 # 'AddConfigBlocks' blocks can be passed as either a list or a dictionary.
264 # Dictionaries are allowed so that when merging YAML files duplicate entries get automatically removed.
265 # This turns the dictionary into a list for downstream use.
266 if block.algName == "AddConfigBlocks" and isinstance(blockConfig, dict):
267 blockConfig = [options | {'algName': algName} for algName, options in blockConfig.items()]
268
269 elif not isinstance(blockConfig, list):
270 blockConfig = [blockConfig]
271
272 for options in blockConfig:
273 # Special case: propogate containerName down to subAlgs
274 if 'containerName' in options:
275 containerName = options['containerName']
276 elif containerName is not None and 'containerName' not in options:
277 options['containerName'] = containerName
278 # will check which options are associated alg and not options
279 logCPAlgTextCfg.debug(f"Configuring {block.algName}")
280 seq, funcOpts = block.makeConfig(options)
281 if not seq._blocks:
282 continue
283 algOpts = seq.setOptions(options)
284 # If containerName was not set explicitly, we can now retrieve
285 # its default value
286 if containerName is None:
287 for opt in algOpts:
288 if 'name' in opt and opt['name'] == 'containerName':
289 containerName = opt.get('value', None)
290 break # Exit the loop as we've found the key
291
292 if configSeq is not None:
293 configSeq += seq
294
295 # propagate special extra options to subalgs
296 if extraOptions is None:
297 extraOptionsList = ["skipOnData", "skipOnMC", "onlyForDSIDs"]
298 for i in algOpts:
299 if i['name'] in extraOptionsList and i['defaultValue'] != i['value']:
300 if extraOptions is None:
301 extraOptions = {}
302 extraOptions[i['name']] = i['value']
303 else:
304 algOpts = seq.setOptions(extraOptions.copy())
305
306 # check to see if there are unused parameters
307 algOpts = [i['name'] for i in algOpts]
308 expectedOptions = set(funcOpts)
309 expectedOptions |= set(algOpts)
310 expectedOptions |= set(block.subAlgs)
311
312 difference = set(options.keys()) - expectedOptions
313 difference.discard('__placeholder__')
314 if difference:
315 difference = "\n".join(difference)
316 raise ValueError(f"There are options set that are not used for "
317 f"{block.algName}:\n{difference}\n"
318 "Please check your configuration.")
319
320 # check for sub-blocks and call this function recursively
321 for alg in self._order.get(block.algName, []):
322 if alg in options:
323 subAlg = block.subAlgs[alg]
324 self._configureAlg(subAlg, options[alg], configSeq, containerName, extraOptions)
325 return configSeq
326
327
STL class.
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition hcg.cxx:130

◆ addBlock()

python.ConfigText.TextConfig.addBlock ( self,
name,
** kwargs )
Create entry into dictionary representing the text configuration

Definition at line 178 of file ConfigText.py.

178 def addBlock(self, name, **kwargs):
179 """
180 Create entry into dictionary representing the text configuration
181 """
182 def setEntry(name, config, opts):
183 if '.' not in name:
184 if name not in config:
185 config[name] = opts
186 elif isinstance(config[name], list):
187 config[name].append(opts)
188 else:
189 config[name] = [config[name], opts]
190 # set last added block for setOptionValue
191 self._last = opts
192 else:
193 name, rest = name[:name.index('.')], name[name.index('.') + 1:]
194 config = config[name]
195 if isinstance(config, list):
196 config = config[-1]
197 setEntry(rest, config, opts)
198 return
199 setEntry(name, self._config, dict(kwargs))
200 return
201
202

◆ cleanupPlaceholders()

python.ConfigText.TextConfig.cleanupPlaceholders ( self,
config )
Remove placeholder markers after initialization.

Definition at line 94 of file ConfigText.py.

94 def cleanupPlaceholders(self, config):
95 """
96 Remove placeholder markers after initialization.
97 """
98 if not isinstance(config, dict):
99 return
100 if "__placeholder__" in config:
101 del config["__placeholder__"]
102 for key, value in config.items():
103 self.cleanupPlaceholders(value)
104

◆ configure()

python.ConfigText.TextConfig.configure ( self)
Process YAML configuration file and confgure added algorithms.

Definition at line 214 of file ConfigText.py.

214 def configure(self):
215 """Process YAML configuration file and confgure added algorithms."""
216 # make sure all blocks in yaml file are added (otherwise they would be ignored)
217 for blockName in self._config:
218 if blockName not in self._order[self.ROOTNAME]:
219 if not blockName:
220 blockName = list(self._config[blockName].keys())[0]
221 raise ValueError(f"Unkown block {blockName} in yaml file")
222
223 # configure blocks
224 configSeq = ConfigSequence()
225 for blockName in self._order[self.ROOTNAME]:
226 if blockName == "AddConfigBlocks":
227 continue
228
229 assert blockName in self._algs
230
231 # order only applies to root blocks
232 if blockName in self._config:
233 blockConfig = self._config[blockName]
234 alg = self._algs[blockName]
235 self._configureAlg(alg, blockConfig, configSeq)
236 else:
237 continue
238 return configSeq
239
240
bool configure(asg::AnaToolHandle< ITrigGlobalEfficiencyCorrectionTool > &tool, ToolHandleArray< IAsgElectronEfficiencyCorrectionTool > &electronEffToolsHandles, ToolHandleArray< IAsgElectronEfficiencyCorrectionTool > &electronSFToolsHandles, ToolHandleArray< CP::IMuonTriggerScaleFactors > &muonToolsHandles, ToolHandleArray< IAsgPhotonEfficiencyCorrectionTool > &photonEffToolsHandles, ToolHandleArray< IAsgPhotonEfficiencyCorrectionTool > &photonSFToolsHandles, const std::string &triggers, const std::map< std::string, std::string > &legsPerTool, unsigned long nToys, bool debug)

◆ loadConfig()

python.ConfigText.TextConfig.loadConfig ( self,
yamlPath = None,
* ,
configDict = None )
read a YAML file. Will combine with any config blocks added using python

Definition at line 105 of file ConfigText.py.

105 def loadConfig(self, yamlPath=None, *, configDict=None):
106 """
107 read a YAML file. Will combine with any config blocks added using python
108 """
109 if self.__loadedYaml or isinstance(yamlPath, list):
110 raise NotImplementedError("Mering multiple yaml files is not implemented.")
111 self.__loadedYaml = True
112
113 def merge(config, algs, path=''):
114 """Add to config block-by-block"""
115 if not isinstance(config, list):
116 config = [config]
117 # loop over list of blocks with same block name
118 for blocks in config:
119 # deal with case where empty dict is config
120 if blocks == {} and path:
121 self.addBlock(path)
122 return
123 # remove any subBlocks from block config
124 subBlocks = {}
125 for blockName in algs:
126 if blockName in blocks:
127 subBlocks[blockName] = blocks.pop(blockName)
128 # anything left should be a block and it's configuration
129 if blocks:
130 self.addBlock(path, **blocks)
131 # add in any subBlocks
132 for subName, subBlock in subBlocks.items():
133 newPath = f'{path}.{subName}' if path else subName
134 merge(subBlock, algs[subName].subAlgs, newPath)
135 return
136
137 logCPAlgTextCfg.debug(f'loading {yamlPath}')
138 if configDict is not None:
139 # if configDict is provided, use it directly
140 config = configDict
141 else:
142 config = readYaml(yamlPath)
143 # check if blocks are defined in yaml file
144 if "AddConfigBlocks" in config:
145 self._configureAlg(self._algs["AddConfigBlocks"], config["AddConfigBlocks"])
146
147 # Preprocess the configuration dictionary (see !76767)
148 self.preprocessConfig(config, self._algs)
149
150 merge(config, self._algs)
151
152 # Cleanup placeholders (see !76767)
153 self.cleanupPlaceholders(config)
154
155 return
156
157
Definition merge.py:1

◆ preprocessConfig()

python.ConfigText.TextConfig.preprocessConfig ( self,
config,
algs )
Preprocess the configuration dictionary.
Ensure blocks with only sub-blocks are initialized with an empty dictionary.

Definition at line 70 of file ConfigText.py.

70 def preprocessConfig(self, config, algs):
71 """
72 Preprocess the configuration dictionary.
73 Ensure blocks with only sub-blocks are initialized with an empty dictionary.
74 """
75 def processNode(node, algs):
76 if not isinstance(node, dict):
77 return # Base case: not a dictionary
78 for blockName, blockContent in list(node.items()):
79 # If the block name is recognized in algs
80 if blockName in algs:
81 # If the block only defines sub-blocks, initialize it
82 if isinstance(blockContent, dict) and not any(
83 key in algs[blockName].options for key in blockContent
84 ):
85 # Ensure parent block is initialized as an empty dictionary
86 node[blockName] = {'__placeholder__': True, **blockContent}
87 # Recurse into sub-blocks
88 processNode(node[blockName], algs[blockName].subAlgs)
89
90 # Start processing from the root of the configuration
91 processNode(config, algs)
92

◆ printConfig()

python.ConfigText.TextConfig.printConfig ( self,
sort = False,
jsonFormat = False )
Print YAML configuration file.

Definition at line 158 of file ConfigText.py.

158 def printConfig(self, sort=False, jsonFormat=False):
159 """Print YAML configuration file."""
160 if self._config is None:
161 raise ValueError("No configuration has been loaded.")
162 printYaml(self._config, sort, jsonFormat)
163 return
164
165

◆ saveYaml()

python.ConfigText.TextConfig.saveYaml ( self,
filePath = 'config.yaml',
default_flow_style = False,
** kwargs )
Convert dictionary representation to yaml and save

Definition at line 166 of file ConfigText.py.

167 **kwargs):
168 """
169 Convert dictionary representation to yaml and save
170 """
171 logCPAlgTextCfg.info(f"Saving configuration to {filePath}")
172 config = self._config
173 with open(filePath, 'w') as outfile:
174 yaml.dump(config, outfile, default_flow_style=False, **kwargs)
175 return
176
177

◆ setConfig()

python.ConfigText.TextConfig.setConfig ( self,
config )
Print YAML configuration file.

Definition at line 62 of file ConfigText.py.

62 def setConfig(self, config):
63 """Print YAML configuration file."""
64 if self._config:
65 raise ValueError("Configuration has already been loaded.")
66 self._config = config
67 return
68

◆ setOptions()

python.ConfigText.TextConfig.setOptions ( self,
** kwargs )
Set option(s) for the lsat block that was added. If an option
was added previously, will update value

Definition at line 203 of file ConfigText.py.

203 def setOptions(self, **kwargs):
204 """
205 Set option(s) for the lsat block that was added. If an option
206 was added previously, will update value
207 """
208 if self._last is None:
209 raise TypeError("Cannot set options before adding a block")
210 # points to dict with opts for last added block
211 self._last.update(**kwargs)
212
213

Member Data Documentation

◆ __loadedYaml

bool python.ConfigText.TextConfig.__loadedYaml = False
private

Definition at line 55 of file ConfigText.py.

◆ _algs

python.ConfigText.TextConfig._algs
protected

Definition at line 148 of file ConfigText.py.

◆ _config

python.ConfigText.TextConfig._config = {}
protected

Definition at line 53 of file ConfigText.py.

◆ _last

python.ConfigText.TextConfig._last = None
protected

Definition at line 59 of file ConfigText.py.


The documentation for this class was generated from the following file: