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

462def _find_fragment(fragment_path, config_path):
463 paths_to_check = [
464 fragment_path,
465 config_path / fragment_path,
466 *[x / fragment_path for x in os.environ["DATAPATH"].split(":")]
467 ]
468 for path in paths_to_check:
469 if path.exists():
470 return path
471
472 raise FileNotFoundError(fragment_path)
473
474
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 445 of file ConfigText.py.

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

◆ _merge_dicts()

python.ConfigText._merge_dicts ( local,
fragment )
protected

Definition at line 475 of file ConfigText.py.

475def _merge_dicts(local, fragment):
476 # In the list case append the fragment to the local list
477 if isinstance(local, list):
478 local += fragment
479 return
480 # In the dict case, append only missing values to local: the local
481 # values take precedence over the fragment ones.
482 if isinstance(local, dict):
483 for key, value in fragment.items():
484 if key in local:
485 _merge_dicts(local[key], value)
486 else:
487 local[key] = value
488 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 376 of file ConfigText.py.

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

◆ makeSequence()

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

Definition at line 328 of file ConfigText.py.

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

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