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

Classes

class  TextConfigWarning
class  TextConfig

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 (Path fragment_path)
 _find_fragment (Path fragment_path, list[Path] config_paths)
 _merge_dicts (local, fragment)

Variables

 logCPAlgTextCfg = logging.getLogger('CPAlgTextCfg')

Function Documentation

◆ _find_fragment()

python.ConfigText._find_fragment ( Path fragment_path,
list[Path] config_paths )
protected

Definition at line 475 of file ConfigText.py.

475def _find_fragment(fragment_path: Path, config_paths: list[Path]):
476 paths_to_check = [
477 fragment_path,
478 *[path / fragment_path for path in config_paths],
479 *[x / fragment_path for x in os.environ["DATAPATH"].split(":")]
480 ]
481 for path in paths_to_check:
482 if path.exists():
483 return path
484
485 raise FileNotFoundError(fragment_path)
486
487
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:179

◆ _load_fragment()

python.ConfigText._load_fragment ( 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 458 of file ConfigText.py.

458def _load_fragment(fragment_path: Path):
459 """Load a YAML or JSON fragment
460
461 This function is superfluous as of the yaml 1.2 spec (which
462 has not been implemented in ATLAS Yaml dependencies).
463 Once https://github.com/yaml/pyyaml/issues/173 is resolved
464 pyyaml will support yaml 1.2, which is compatable with json.
465 Until then yaml and json behave differently in some scientific
466 notation edge cases.
467 """
468
469 with open(fragment_path, 'r') as fragment_file:
470 if fragment_path.suffix.lower() == '.json':
471 return json.load(fragment_file)
472 else:
473 return yaml.safe_load(fragment_file)
474

◆ _merge_dicts()

python.ConfigText._merge_dicts ( local,
fragment )
protected

Definition at line 488 of file ConfigText.py.

488def _merge_dicts(local, fragment):
489 # In the list case append the fragment to the local list
490 if isinstance(local, list):
491 local += fragment
492 return
493 # In the dict case, append only missing values to local: the local
494 # values take precedence over the fragment ones.
495 if isinstance(local, dict):
496 for key, value in fragment.items():
497 if key in local:
498 _merge_dicts(local[key], value)
499 else:
500 local[key] = value
501 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 377 of file ConfigText.py.

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

◆ makeSequence()

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

Definition at line 329 of file ConfigText.py.

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

◆ printYaml()

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

Definition at line 31 of file ConfigText.py.

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

◆ readYaml()

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

Definition at line 22 of file ConfigText.py.

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

Variable Documentation

◆ logCPAlgTextCfg

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

Definition at line 19 of file ConfigText.py.