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 (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 479 of file ConfigText.py.

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

◆ _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 462 of file ConfigText.py.

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

◆ _merge_dicts()

python.ConfigText._merge_dicts ( local,
fragment )
protected

Definition at line 492 of file ConfigText.py.

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

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

◆ makeSequence()

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

Definition at line 333 of file ConfigText.py.

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

◆ 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.