ATLAS Offline Software
Loading...
Searching...
No Matches
python.ConfigText Namespace Reference

Classes

class  TextConfig
class  TextConfigWarning

Functions

 readYaml (yamlPath)
 printYaml (d, sort=False, jsonFormat=False)
 makeSequence (configPath, *, flags=None, algSeq=None, noSystematics=None, dataType=None, geometry=None, autoconfigFromFlags=None, isPhyslite=None, noPhysliteBroken=False)
 combineConfigFiles (local, config_path, fragment_key="include")
 _load_fragment (pathlib.Path fragment_path)
 _find_fragment (fragment_path, config_path)
 _merge_dicts (local, fragment)

Variables

 logCPAlgTextCfg = logging.getLogger('CPAlgTextCfg')

Function Documentation

◆ _find_fragment()

python.ConfigText._find_fragment ( fragment_path,
config_path )
protected

Definition at line 459 of file ConfigText.py.

459def _find_fragment(fragment_path, config_path):
460 paths_to_check = [
461 fragment_path,
462 config_path / fragment_path,
463 *[x / fragment_path for x in os.environ["DATAPATH"].split(":")]
464 ]
465 for path in paths_to_check:
466 if path.exists():
467 return path
468
469 raise FileNotFoundError(fragment_path)
470
471
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:177

◆ _load_fragment()

python.ConfigText._load_fragment ( pathlib.Path fragment_path)
protected
Load a YAML or JSON fragment

This function is superfluous as of the yaml 1.2 spec (which
has not been implemented in ATLAS Yaml dependencies).
Once https://github.com/yaml/pyyaml/issues/173 is resolved
pyyaml will support yaml 1.2, which is compatable with json. 
Until then yaml and json behave differently in some scientific
notation edge cases.

Definition at line 442 of file ConfigText.py.

442def _load_fragment(fragment_path: pathlib.Path):
443 """Load a YAML or JSON fragment
444
445 This function is superfluous as of the yaml 1.2 spec (which
446 has not been implemented in ATLAS Yaml dependencies).
447 Once https://github.com/yaml/pyyaml/issues/173 is resolved
448 pyyaml will support yaml 1.2, which is compatable with json.
449 Until then yaml and json behave differently in some scientific
450 notation edge cases.
451 """
452
453 with open(fragment_path, 'r') as fragment_file:
454 if fragment_path.suffix.lower() == '.json':
455 return json.load(fragment_file)
456 else:
457 return yaml.safe_load(fragment_file)
458

◆ _merge_dicts()

python.ConfigText._merge_dicts ( local,
fragment )
protected

Definition at line 472 of file ConfigText.py.

472def _merge_dicts(local, fragment):
473 # In the list case append the fragment to the local list
474 if isinstance(local, list):
475 local += fragment
476 return
477 # In the dict case, append only missing values to local: the local
478 # values take precedence over the fragment ones.
479 if isinstance(local, dict):
480 for key, value in fragment.items():
481 if key in local:
482 _merge_dicts(local[key], value)
483 else:
484 local[key] = value
485 return

◆ combineConfigFiles()

python.ConfigText.combineConfigFiles ( local,
config_path,
fragment_key = "include" )
Recursively combine configuration fragments into `local`.

- Looks for `fragment_key` at any dict node.
- If value is a string/path: merge that fragment.
- If value is a list: merge all fragments in order.
  For conflicts between fragments, the **earlier** file in the list wins. 
  Local keys still override the merged fragments.

Returns True if any merging happened below this node.

Definition at line 373 of file ConfigText.py.

373def combineConfigFiles(local, config_path, fragment_key="include"):
374 """
375 Recursively combine configuration fragments into `local`.
376
377 - Looks for `fragment_key` at any dict node.
378 - If value is a string/path: merge that fragment.
379 - If value is a list: merge all fragments in order.
380 For conflicts between fragments, the **earlier** file in the list wins.
381 Local keys still override the merged fragments.
382
383 Returns True if any merging happened below this node.
384 """
385 combined = False
386
387 # If this isn't an iterable there's nothing to combine
388 if isinstance(local, dict):
389 to_combine = local.values()
390 elif isinstance(local, list):
391 to_combine = local
392 else:
393 return combined
394
395 # Recurse first so that nested nodes are resolved
396 for sub in to_combine:
397 combined = combineConfigFiles(sub, config_path, fragment_key=fragment_key) or combined
398
399 # if there are no fragments to include we're done
400 if fragment_key not in local:
401 return combined
402
403 # Only dict nodes can have include keys
404 if not isinstance(local, dict):
405 return combined
406
407 # Normalize to a list of paths
408 value = local[fragment_key]
409 if isinstance(value, (str, pathlib.Path)):
410 warnings.warn(
411 f"{fragment_key} should be followed with a list of files",
412 TextConfigWarning,
413 stacklevel=2,
414 )
415 paths = [value]
416 elif isinstance(value, list):
417 paths = value
418 else:
419 raise TypeError(f"'{fragment_key}' must be a string path or a list of paths, got {type(value).__name__}")
420
421 # Build an accumulator of all fragments, earlier paths win on conflicts
422 fragments_acc = {}
423 for entry in paths:
424 fragment_path = _find_fragment(pathlib.Path(entry), config_path)
425 fragment = _load_fragment(fragment_path)
426
427 # Allow recursion inside each fragment, using the fragment's directory as base
428 combineConfigFiles(fragment, fragment_path.parent, fragment_key=fragment_key)
429
430 # Merge this fragment into the accumulator; earlier entries win
431 _merge_dicts(fragments_acc, fragment)
432
433 # Remove the key before merging to avoid re-processing it
434 del local[fragment_key]
435
436 # Merge fragments into local; local values take precedence
437 _merge_dicts(local, fragments_acc)
438
439 return True
440
441

◆ makeSequence()

python.ConfigText.makeSequence ( configPath,
* ,
flags = None,
algSeq = None,
noSystematics = None,
dataType = None,
geometry = None,
autoconfigFromFlags = None,
isPhyslite = None,
noPhysliteBroken = False )
 

Definition at line 321 of file ConfigText.py.

321def makeSequence(configPath, *, flags=None, algSeq=None, noSystematics=None, dataType=None, geometry=None, autoconfigFromFlags=None, isPhyslite=None, noPhysliteBroken=False):
322 """
323 """
324
325 # Historically we have used the identifier
326 # `autoconfigFromFlags`, but in the rest of the code base
327 # `flags` is used. So for now we allow either, and can hopefully
328 # at some point remove the former (21 Aug 25).
329 if autoconfigFromFlags is not None:
330 if flags is not None:
331 raise ValueError("Cannot pass both flags and autoconfigFromFlags arguments")
332 flags = autoconfigFromFlags
333 warnings.warn ('Using autoconfigFromFlags parameter is deprecated, use flags instead', category=deprecationWarningCategory, stacklevel=2)
334 elif flags is None:
335 warnings.warn ('it is deprecated to configure meta-data for analysis configuration manually, please read the configuration flags via the meta-data reader', category=deprecationWarningCategory, stacklevel=2)
336
337 from AnalysisAlgorithmsConfig.ConfigAccumulator import ConfigAccumulator
338
339 config = TextConfig(configPath)
340
341 logCPAlgTextCfg.info("Configuration file read in:")
342 config.printConfig()
343
344 logCPAlgTextCfg.info("Default algorithms:")
345 config.printAlgs(printOpts=True)
346
347 logCPAlgTextCfg.info("Configuring algorithms based on YAML file:")
348 configSeq = config.configure()
349
350 # defaults are added to config as algs are configured
351 logCPAlgTextCfg.info("Configuration used:")
352 config.printConfig()
353
354 # compile
355 configAccumulator = ConfigAccumulator(algSeq=algSeq, dataType=dataType, isPhyslite=isPhyslite, geometry=geometry, autoconfigFromFlags=autoconfigFromFlags, flags=flags, noSystematics=noSystematics)
356 configSeq.fullConfigure(configAccumulator)
357
358 # blocks can be reordered during configSeq.fullConfigure
359 logCPAlgTextCfg.info("ConfigBlocks and their configuration:")
360 configSeq.printOptions()
361
362 from AnaAlgorithm.DualUseConfig import isAthena, useComponentAccumulator
363 if isAthena and useComponentAccumulator:
364 return configAccumulator.CA
365 else:
366 return None
367
368
369# Combine configuration files
370#
371# See the README for more info on how this works
372#

◆ printYaml()

python.ConfigText.printYaml ( d,
sort = False,
jsonFormat = False )
Prints a dictionary as YAML

Definition at line 30 of file ConfigText.py.

30def printYaml(d, sort=False, jsonFormat=False):
31 """Prints a dictionary as YAML"""
32 print(yaml.dump(d, default_flow_style=jsonFormat, sort_keys=sort))
33
void print(char *figname, TCanvas *c1)

◆ readYaml()

python.ConfigText.readYaml ( yamlPath)
Loads YAML file into a dictionary

Definition at line 21 of file ConfigText.py.

21def readYaml(yamlPath):
22 """Loads YAML file into a dictionary"""
23 if not os.path.isfile(yamlPath):
24 raise ValueError(f"{yamlPath} is not a file.")
25 with open(yamlPath, 'r') as f:
26 textConfig = yaml.safe_load(f)
27 return textConfig
28
29

Variable Documentation

◆ logCPAlgTextCfg

python.ConfigText.logCPAlgTextCfg = logging.getLogger('CPAlgTextCfg')

Definition at line 18 of file ConfigText.py.