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

Public Member Functions

 __init__ (self)
 athHash (self)
 __getattr__ (self, name)
 __setattr__ (self, name, value)
 __delattr__ (self, name)
 __getitem__ (self, name)
 __setitem__ (self, name, value)
 __delitem__ (self, name)
 __contains__ (self, name)
 __iter__ (self)
 asdict (self)
 addFlag (self, name, setDef, type=None, help=None)
 addFlagsCategory (self, path, generator, prefix=False)
 needFlagsCategory (self, name)
 loadAllDynamicFlags (self)
 hasCategory (self, name)
 hasFlag (self, name)
 lock (self)
 locked (self)
 clone (self)
 cloneAndReplace (self, subsetToReplace, replacementSubset, keepOriginal=False)
 join (self, other, prefix='')
 dump (self, pattern=".*", evaluate=False, formatStr="{:40} : {}", maxLength=None)
 initAll (self)
 getArgumentParser (self, **kwargs)
 parser (self)
 args (self)
 fillFromString (self, flag_string)
 fillFromArgs (self, listOfArgs=None, parser=None, return_unknown=False)

Protected Member Functions

 _calculateHash (self)
 _renamed_map (self)
 _subflag_itr (self)
 _loadDynaFlags (self, name)
 _tryModify (self)

Protected Attributes

 _flagdict = dict()
bool _locked = False
 _dynaflags = dict()
 _loaded = set()
 _categoryCache = set()
 _hash = None
 _parser = None
 _args = None
dict _renames = {}

Static Protected Attributes

list _hashedFlags = []

Detailed Description

Definition at line 230 of file AthConfigFlags.py.

Constructor & Destructor Documentation

◆ __init__()

python.AthConfigFlags.AthConfigFlags.__init__ ( self)

Definition at line 237 of file AthConfigFlags.py.

237 def __init__(self):
238 self._flagdict=dict()
239 self._locked=False
240 self._dynaflags = dict()
241 self._loaded = set() # dynamic flags that were loaded
242 self._categoryCache = set() # cache for already found categories
243 self._hash = None
244 self._parser = None
245 self._args = None # user args from parser
246 self._renames = {}
247
STL class.

Member Function Documentation

◆ __contains__()

python.AthConfigFlags.AthConfigFlags.__contains__ ( self,
name )

Definition at line 316 of file AthConfigFlags.py.

316 def __contains__(self, name):
317 return hasattr(self, name)
318

◆ __delattr__()

python.AthConfigFlags.AthConfigFlags.__delattr__ ( self,
name )

Definition at line 293 of file AthConfigFlags.py.

293 def __delattr__(self, name):
294 del self[name]
295

◆ __delitem__()

python.AthConfigFlags.AthConfigFlags.__delitem__ ( self,
name )

Definition at line 308 of file AthConfigFlags.py.

308 def __delitem__(self, name):
309 self._tryModify()
310 self.loadAllDynamicFlags()
311 for key in list(self._flagdict):
312 if key.startswith(name):
313 del self._flagdict[key]
314 self._categoryCache.clear()
315
void clear()
Empty the pool.

◆ __getattr__()

python.AthConfigFlags.AthConfigFlags.__getattr__ ( self,
name )

Definition at line 265 of file AthConfigFlags.py.

265 def __getattr__(self, name):
266 # Avoid infinite recursion looking up our own attributes
267 _flagdict = object.__getattribute__(self, "_flagdict")
268
269 # First try to get an already loaded flag or category.
270 # Note: Check and lookup is faster than try/except here. Because for nested
271 # flags a failure is normal before we descend into the category.
272 if name in _flagdict:
273 return _flagdict[name].get(self)
274
275 # Check (and load if needed) dynamic flags
276 if self.hasCategory(name):
277 return FlagAddress(self, name)
278
279 raise AttributeError(f"No such flag: {name}")
280
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition hcg.cxx:132

◆ __getitem__()

python.AthConfigFlags.AthConfigFlags.__getitem__ ( self,
name )

Definition at line 296 of file AthConfigFlags.py.

296 def __getitem__(self, name):
297 try:
298 return getattr(self, name)
299 except AttributeError as e:
300 raise KeyError(e) # convert exception to follow Python convention for [] operator
301

◆ __iter__()

python.AthConfigFlags.AthConfigFlags.__iter__ ( self)

Definition at line 319 of file AthConfigFlags.py.

319 def __iter__(self):
320 self.loadAllDynamicFlags()
321 rmap = self._renamed_map()
322 used = set()
323 for flag in self._flagdict:
324 for r in rmap[flag]:
325 first = r.split('.',1)[0]
326 if first not in used:
327 yield first
328 used.add(first)
329

◆ __setattr__()

python.AthConfigFlags.AthConfigFlags.__setattr__ ( self,
name,
value )

Definition at line 281 of file AthConfigFlags.py.

281 def __setattr__(self, name, value):
282 if name.startswith("_"):
283 return object.__setattr__(self, name, value)
284
285 self._tryModify()
286 try:
287 self._flagdict[name].set(value)
288 except KeyError:
289 closestMatch = get_close_matches(name,self._flagdict.keys(),1)
290 raise KeyError(f"No flag with name '{name}' found" +
291 (f". Did you mean '{closestMatch[0]}'?" if closestMatch else ""))
292

◆ __setitem__()

python.AthConfigFlags.AthConfigFlags.__setitem__ ( self,
name,
value )

Definition at line 302 of file AthConfigFlags.py.

302 def __setitem__(self, name, value):
303 try:
304 setattr(self, name, value)
305 except AttributeError as e:
306 raise KeyError(e) # convert exception to follow Python convention for [] operator
307

◆ _calculateHash()

python.AthConfigFlags.AthConfigFlags._calculateHash ( self)
protected

Definition at line 255 of file AthConfigFlags.py.

255 def _calculateHash(self):
256 # Once we've hashed a flags instance, we need to be sure that
257 # it never goes away. Otherwise, since we base the hash
258 # on just the id of the dictionary, if a flags object is deleted
259 # and a new one created, the hash of the new one could match the
260 # hash of the old, even if contents are different.
261 # See ATLASRECTS-8070.
262 AthConfigFlags._hashedFlags.append (self)
263 return hash( (frozenset({k: v for k, v in self._renames.items() if k != v}), id(self._flagdict)) )
264

◆ _loadDynaFlags()

python.AthConfigFlags.AthConfigFlags._loadDynaFlags ( self,
name )
protected
loads the flags of the form "A.B.C" first attempting the path "A" then "A.B" and then "A.B.C"

Definition at line 412 of file AthConfigFlags.py.

412 def _loadDynaFlags(self, name):
413 """
414 loads the flags of the form "A.B.C" first attempting the path "A" then "A.B" and then "A.B.C"
415 """
416
417 def __load_impl( flagBaseName ):
418 if flagBaseName in self._loaded:
419 _msg.debug("Flags %s already loaded",flagBaseName )
420 return
421 if flagBaseName in self._dynaflags:
422 _msg.debug("Dynamically loading the flags under %s", flagBaseName )
423 # Retain locked status and hash
424 isLocked = self._locked
425 myHash = self._hash
426 self._locked = False
427 generator, prefix = self._dynaflags[flagBaseName]
428 self.join( generator(), flagBaseName if prefix else "" )
429 self._locked = isLocked
430 self._hash = myHash
431 del self._dynaflags[flagBaseName]
432 self._loaded.add(flagBaseName)
433
434 pathfrags = name.split('.')
435 for maxf in range(1, len(pathfrags)+1):
436 __load_impl( '.'.join(pathfrags[:maxf]) )
437
bool add(const std::string &hname, TKey *tobj)
Definition fastadd.cxx:55

◆ _renamed_map()

python.AthConfigFlags.AthConfigFlags._renamed_map ( self)
protected
mapping from the old names to the new names

This is the inverse of _renamed, which maps new names to old
names

Returns a list of the new names corresponding to the old names
(since cloneAndReplace may or may not disable access to the old name,
it is possible that an old name renames to multiple new names)

Definition at line 340 of file AthConfigFlags.py.

340 def _renamed_map(self):
341 """mapping from the old names to the new names
342
343 This is the inverse of _renamed, which maps new names to old
344 names
345
346 Returns a list of the new names corresponding to the old names
347 (since cloneAndReplace may or may not disable access to the old name,
348 it is possible that an old name renames to multiple new names)
349 """
350 revmap = defaultdict(list)
351
352 for new, old in self._renames.items():
353 if old is not None:
354 revmap[old].append(new)
355
356 def rename(key):
357 for old, newlist in revmap.items():
358 if key.startswith(old + '.'):
359 stem = key.removeprefix(old)
360 return [ f'{new}{stem}' if new else '' for new in newlist ]
361 return [ key ]
362
363 return {x:rename(x) for x in self._flagdict.keys()}
364

◆ _subflag_itr()

python.AthConfigFlags.AthConfigFlags._subflag_itr ( self)
protected
Subflag iterator for all flags

This is used by the asdict() function.

Definition at line 365 of file AthConfigFlags.py.

365 def _subflag_itr(self):
366 """Subflag iterator for all flags
367
368 This is used by the asdict() function.
369 """
370 self.loadAllDynamicFlags()
371
372 for old, newlist in self._renamed_map().items():
373 for new in newlist:
374 # Lots of modules are missing in analysis releases. I
375 # tried to prevent imports using the _addFlagsCategory
376 # function which checks if some module exists, but this
377 # turned in to quite a rabbit hole. Catching and ignoring
378 # the missing module exception seems to work, even if it's
379 # not pretty.
380 try:
381 yield new, getattr(self, old)
382 except ModuleNotFoundError as err:
383 _msg.debug(f'missing module: {err}')
384 pass
385

◆ _tryModify()

python.AthConfigFlags.AthConfigFlags._tryModify ( self)
protected

Definition at line 492 of file AthConfigFlags.py.

492 def _tryModify(self):
493 if self._locked:
494 raise RuntimeError("Attempt to modify locked flag container")
495 else:
496 # if unlocked then invalidate hash
497 self._hash = None
498

◆ addFlag()

python.AthConfigFlags.AthConfigFlags.addFlag ( self,
name,
setDef,
type = None,
help = None )

Definition at line 386 of file AthConfigFlags.py.

386 def addFlag(self, name, setDef, type=None, help=None):
387 self._tryModify()
388 if name in self._flagdict:
389 raise KeyError("Duplicated flag name: {}".format( name ))
390 self._flagdict[name]=CfgFlag(setDef, type, help)
391 return
392

◆ addFlagsCategory()

python.AthConfigFlags.AthConfigFlags.addFlagsCategory ( self,
path,
generator,
prefix = False )
The path is the beginning of the flag name (e.g. "X" for flags generated with name "X.*").
The generator is a function that returns a flags container, the flags have to start with the same path.
When the prefix is True the flags created by the generator are prefixed by "path".

Supported calls are then:
 addFlagsCategory("A", g) - where g is function creating flags  is f.addFlag("A.x", someValue)
 addFlagsCategory("A", g, True) - when flags are defined in g like this: f.addFalg("x", somevalue),
The latter option allows to share one generator among flags that are later loaded in different paths.

Definition at line 393 of file AthConfigFlags.py.

393 def addFlagsCategory(self, path, generator, prefix=False):
394 """
395 The path is the beginning of the flag name (e.g. "X" for flags generated with name "X.*").
396 The generator is a function that returns a flags container, the flags have to start with the same path.
397 When the prefix is True the flags created by the generator are prefixed by "path".
398
399 Supported calls are then:
400 addFlagsCategory("A", g) - where g is function creating flags is f.addFlag("A.x", someValue)
401 addFlagsCategory("A", g, True) - when flags are defined in g like this: f.addFalg("x", somevalue),
402 The latter option allows to share one generator among flags that are later loaded in different paths.
403 """
404 self._tryModify()
405 _msg.debug("Adding flag category %s", path)
406 self._dynaflags[path] = (generator, prefix)
407

◆ args()

python.AthConfigFlags.AthConfigFlags.args ( self)

Definition at line 642 of file AthConfigFlags.py.

642 def args(self):
643 return self._args
644
645

◆ asdict()

python.AthConfigFlags.AthConfigFlags.asdict ( self)
Convert to a python dictionary

This is identical to the `asdict` in FlagAddress, but for all
the flags.

Definition at line 330 of file AthConfigFlags.py.

330 def asdict(self):
331 """Convert to a python dictionary
332
333 This is identical to the `asdict` in FlagAddress, but for all
334 the flags.
335
336 """
337 return _asdict(self._subflag_itr())
338
339

◆ athHash()

python.AthConfigFlags.AthConfigFlags.athHash ( self)

Definition at line 248 of file AthConfigFlags.py.

248 def athHash(self):
249 if self._locked is False:
250 raise RuntimeError("Cannot calculate hash of unlocked flag container")
251 elif self._hash is None:
252 self._hash = self._calculateHash()
253 return self._hash
254

◆ clone()

python.AthConfigFlags.AthConfigFlags.clone ( self)
Return an unlocked copy of self (dynamic flags are not loaded)

Definition at line 499 of file AthConfigFlags.py.

499 def clone(self):
500 """Return an unlocked copy of self (dynamic flags are not loaded)"""
501 cln = AthConfigFlags()
502 cln._flagdict = deepcopy(self._flagdict)
503 cln._dynaflags = copy(self._dynaflags)
504 cln._renames = deepcopy(self._renames)
505 return cln
506
507

◆ cloneAndReplace()

python.AthConfigFlags.AthConfigFlags.cloneAndReplace ( self,
subsetToReplace,
replacementSubset,
keepOriginal = False )
This is to replace subsets of configuration flags like

Example:
newflags = flags.cloneAndReplace('Muon', 'Trigger.Offline.Muon')

Definition at line 508 of file AthConfigFlags.py.

508 def cloneAndReplace(self,subsetToReplace,replacementSubset, keepOriginal=False):
509 """
510 This is to replace subsets of configuration flags like
511
512 Example:
513 newflags = flags.cloneAndReplace('Muon', 'Trigger.Offline.Muon')
514 """
515
516 _msg.debug("cloning flags and replacing %s by %s", subsetToReplace, replacementSubset)
517
518 self._loadDynaFlags( subsetToReplace )
519 self._loadDynaFlags( replacementSubset )
520
521 subsetToReplace = subsetToReplace.strip(".")
522 replacementSubset = replacementSubset.strip(".")
523
524 #Sanity check: Don't replace a by a
525 if (subsetToReplace == replacementSubset):
526 raise RuntimeError(f'Can not replace flags {subsetToReplace} with themselves')
527
528 # protect against subsequent remaps within remaps: clone = flags.cloneAndReplace('Y', 'X').cloneAndReplace('X.b', 'X.a')
529 for alias,src in self._renames.items():
530 if src is None: continue
531 if src+"." in subsetToReplace:
532 raise RuntimeError(f'Can not replace flags {subsetToReplace} by {replacementSubset} because of already present replacement of {alias} by {src}')
533
534
535 newFlags = copy(self) # shallow copy
536 newFlags._renames = deepcopy(self._renames) #maintains renames
537
538 if replacementSubset in newFlags._renames: #and newFlags._renames[replacementSubset]:
539 newFlags._renames[subsetToReplace] = newFlags._renames[replacementSubset]
540 else:
541 newFlags._renames[subsetToReplace] = replacementSubset
542
543 if not keepOriginal:
544 if replacementSubset not in newFlags._renames or newFlags._renames[replacementSubset] == replacementSubset:
545 newFlags._renames[replacementSubset] = None # block access to original flags
546 else:
547 del newFlags._renames[replacementSubset]
548 #If replacementSubset was a "pure renaming" of another set of flags,
549 #the original set of flags gets propagated down to its potential further renamings:
550 #no need to worry about maintaining the intermediate steps in the renaming.
551 else:
552 if replacementSubset not in newFlags._renames:
553 newFlags._renames[replacementSubset] = replacementSubset
554 #For _renamed_map to know that these flags still work.
555 newFlags._hash = None
556 return newFlags
557
558

◆ dump()

python.AthConfigFlags.AthConfigFlags.dump ( self,
pattern = ".*",
evaluate = False,
formatStr = "{:40} : {}",
maxLength = None )

Definition at line 580 of file AthConfigFlags.py.

580 def dump(self, pattern=".*", evaluate=False, formatStr="{:40} : {}", maxLength=None):
581 import re
582 compiled = re.compile(pattern)
583 def truncate(s): return s[:maxLength] + ("..." if maxLength and len(s)>maxLength else "")
584 reverse_renames = {value: key for key, value in self._renames.items() if value is not None} # new name to old
585 for name in sorted(self._flagdict):
586 renamed = name
587 if any([name.startswith(r) for r in reverse_renames.keys() if r is not None]):
588 for oldprefix, newprefix in reverse_renames.items():
589 if name.startswith(oldprefix):
590 renamed = name.replace(oldprefix, newprefix)
591 break
592 if compiled.match(renamed):
593 if evaluate:
594 try:
595 rep = repr(self._flagdict[name] )
596 val = repr(self._flagdict[name].get(self))
597 if val != rep:
598 print(formatStr.format(renamed,truncate("{} {}".format( val, rep )) ))
599 else:
600 print(formatStr.format(renamed, truncate("{}".format(val)) ) )
601 except Exception as e:
602 print(formatStr.format(renamed, truncate("Exception: {}".format( e )) ))
603 else:
604 print(formatStr.format( renamed, truncate("{}".format(repr(self._flagdict[name] ) )) ))
605
606 if len(self._dynaflags) != 0 and any([compiled.match(x) for x in self._dynaflags.keys()]):
607 print("Flag categories that can be loaded dynamically")
608 print("{:25} : {:>30} : {}".format( "Category","Generator name", "Defined in" ) )
609 for name,gen_and_prefix in sorted(self._dynaflags.items()):
610 if compiled.match(name):
611 print("{:25} : {:>30} : {}".format( name, gen_and_prefix[0].__name__, '/'.join(gen_and_prefix[0].__code__.co_filename.split('/')[-2:]) ) )
612 if len(self._renames):
613 print("Flag categories that are redirected by the cloneAndReplace")
614 for alias,src in self._renames.items():
615 print("{:30} points to {:>30} ".format( alias, src if src else "nothing") )
616
617
void print(char *figname, TCanvas *c1)
-event-from-file

◆ fillFromArgs()

python.AthConfigFlags.AthConfigFlags.fillFromArgs ( self,
listOfArgs = None,
parser = None,
return_unknown = False )
Used to set flags from command-line parameters, like flags.fillFromArgs(sys.argv[1:])

if return_unknown=False, returns: args 
               otherwise returns: args, uknown_args
     where unknown_args is the list of arguments that did not correspond to one of the flags 

Definition at line 687 of file AthConfigFlags.py.

687 def fillFromArgs(self, listOfArgs=None, parser=None, return_unknown=False):
688 """
689 Used to set flags from command-line parameters, like flags.fillFromArgs(sys.argv[1:])
690
691 if return_unknown=False, returns: args
692 otherwise returns: args, uknown_args
693 where unknown_args is the list of arguments that did not correspond to one of the flags
694 """
695 import sys
696
697 self._tryModify()
698
699 if parser is None:
700 parser = self.parser()
701 self._parser = parser # set our parser to given one
702 argList = listOfArgs if listOfArgs is not None else sys.argv[1:]
703 do_help = False
704 # We will now do a pre-parse of the command line arguments to propagate these to the flags
705 # the reason for this is so that we can use the help messaging to display the values of all
706 # flags as they would be *after* any parsing takes place. This is nice to see e.g. the value
707 # that any derived flag (functional flag) will take after, say, the filesInput are set
708 import argparse
709 unrequiredActions = []
710 if "-h" in argList or "--help" in argList:
711 do_help = True
712 if "-h" in argList: argList.remove("-h")
713 if "--help" in argList: argList.remove("--help")
714 # need to unrequire any required arguments in order to do a "pre parse"
715 for a in parser._actions:
716 if a.required:
717 unrequiredActions.append(a)
718 a.required = False
719 (args,leftover)=parser.parse_known_args(argList)
720 for a in unrequiredActions: a.required=True
721
722 # remove the leftovers from the argList ... for later use in the do_help
723 argList = [a for a in argList if a not in leftover]
724
725 # First, handle athena.py-like arguments (if available in parser):
726 def arg_set(dest):
727 """Check if dest is available in parser and has been set"""
728 return vars(args).get(dest, None) is not None
729
730 if arg_set('debug'):
731 self.Exec.DebugStage=args.debug
732
733 if arg_set('evtMax'):
734 self.Exec.MaxEvents=args.evtMax
735
736 if arg_set('interactive'):
737 self.Exec.Interactive=args.interactive
738
739 if arg_set('skipEvents'):
740 self.Exec.SkipEvents=args.skipEvents
741
742 if arg_set('filesInput'):
743 self.Input.Files = [] # remove generic
744 for f in args.filesInput.split(","):
745 found = glob.glob(f)
746 # if not found, add string directly
747 self.Input.Files += found if found else [f]
748
749 if "-l" in argList or "--loglevel" in argList: # different check b.c. has a default value so will always be in args
750 from AthenaCommon import Constants
751 self.Exec.OutputLevel = getattr(Constants, args.loglevel)
752
753 if arg_set('config_only') and args.config_only is not False:
754 from os import environ
755 environ["PICKLECAFILE"] = "" if args.config_only is True else args.config_only
756
757 if arg_set('threads'):
758 self.Concurrency.NumThreads = args.threads
759 #Work-around a possible inconsistency of NumThreads and NumConcurrentEvents that may
760 #occur when these values are set by the transforms and overwritten by --athenaopts ..
761 #See also ATEAM-907
762 if args.concurrent_events is None and self.Concurrency.NumConcurrentEvents==0:
763 self.Concurrency.NumConcurrentEvents = args.threads
764
765 if arg_set('concurrent_events'):
766 self.Concurrency.NumConcurrentEvents = args.concurrent_events
767
768 if arg_set('nprocs'):
769 self.Concurrency.NumProcs = args.nprocs
770
771 if arg_set('perfmon'):
772 from PerfMonComps.PerfMonConfigHelpers import setPerfmonFlagsFromRunArgs
773 setPerfmonFlagsFromRunArgs(self, args)
774
775 if arg_set('mtes'):
776 self.Exec.MTEventService = args.mtes
777
778 if arg_set('mtes_channel'):
779 self.Exec.MTEventServiceChannel = args.mtes_channel
780
781 if arg_set('profile_python'):
782 from AthenaCommon.Debugging import dumpPythonProfile
783 import atexit, cProfile, functools
784 cProfile._athena_python_profiler = cProfile.Profile()
785 cProfile._athena_python_profiler.enable()
786
787 # Save stats to file at exit
788 atexit.register(functools.partial(dumpPythonProfile, args.profile_python))
789
790 if arg_set('mpi'):
791 self.Exec.MPI = args.mpi
792
793 # All remaining arguments are assumed to be key=value pairs to set arbitrary flags:
794 unknown_args = []
795 for arg in leftover:
796 if arg=='--':
797 argList += ["---"]
798 continue # allows for multi-value arguments to be terminated by a " -- "
799 if do_help and '=' not in arg:
800 argList += arg.split(".") # put arg back back for help (but split by sub-categories)
801 continue
802 try:
803 self.fillFromString(arg)
804 except (KeyError,ValueError) as e:
805 if return_unknown:
806 unknown_args += [arg]
807 else:
808 raise e
809
810 if do_help:
811 if parser.epilog is None: parser.epilog=""
812 parser.epilog += " Note: Specify additional flags in form <flagName>=<value>."
813 subparsers = {"":[parser,parser.add_subparsers(help=argparse.SUPPRESS)]} # first is category's parser, second is subparsers (effectively the category's subcategories)
814 # silence logging and ROOT errors while evaluating flags
815 logging.root.setLevel(logging.ERROR)
816 os.environ["TDAQ_ERS_WARNING"] = "null"
817 os.environ["TDAQ_ERS_ERROR"] = "null"
818 import ROOT
819 ignoreLevel = ROOT.gErrorIgnoreLevel
820 ROOT.gErrorIgnoreLevel=ROOT.kFatal
821
822 def getParser(category): # get parser for a given category
823 if category not in subparsers.keys():
824 cat1,cat2 = category.rsplit(".",1) if "." in category else ("",category)
825 p,subp = getParser(cat1)
826 if subp.help==argparse.SUPPRESS:
827 subp.help = "Flag subcategories:"
828 newp = subp.add_parser(cat2,help="{} flags".format(category),
829 formatter_class = argparse.ArgumentDefaultsHelpFormatter,usage=argparse.SUPPRESS)
830 newp._positionals.title = "flags"
831 subparsers[category] = [newp,newp.add_subparsers(help=argparse.SUPPRESS)]
832 return subparsers[category]
833 self.loadAllDynamicFlags()
834 for name in sorted(self._flagdict):
835 category,flagName = name.rsplit(".",1) if "." in name else ("",name)
836 flag = self._flagdict[name]
837 try:
838 val = repr(flag.get(self))
839 except Exception:
840 val = None
841 if flag._help != argparse.SUPPRESS:
842 helptext = ""
843 if flag._help is not None:
844 helptext = f": {flag._help}"
845 if flag._type is not None:
846 helptext += f' [type: {flag._type.__name__}]'
847 if val is not None and helptext == "":
848 helptext = ": " # ensures default values are displayed even if there's no help text
849 getParser(category)[0].add_argument(name, nargs='?', default=val, help=helptext)
850
851 parser._positionals.title = 'flags and positional arguments'
852 parser.parse_known_args(argList + ["--help"])
853 ROOT.gErrorIgnoreLevel=ignoreLevel # this is quite unnecessary since we are about to exit, but people worry about touching msg levels
854
855 self._args = args
856
857 if return_unknown:
858 return args,unknown_args
859 else:
860 return args
861
862
863

◆ fillFromString()

python.AthConfigFlags.AthConfigFlags.fillFromString ( self,
flag_string )
Fill the flags from a string of type key=value

Definition at line 646 of file AthConfigFlags.py.

646 def fillFromString(self, flag_string):
647 """Fill the flags from a string of type key=value"""
648 import ast
649
650 try:
651 key, value = flag_string.split("=")
652 except ValueError:
653 raise ValueError(f"Cannot interpret argument {flag_string}, expected a key=value format")
654
655 key = key.strip()
656 value = value.strip()
657
658 # also allow key+=value to append
659 oper = "="
660 if (key[-1]=="+"):
661 oper = "+="
662 key = key[:-1]
663
664 if key not in self._flagdict:
665 self._loadDynaFlags( '.'.join(key.split('.')[:-1]) ) # for a flag A.B.C dynamic flags from category A.B
666 if key not in self._flagdict:
667 raise KeyError(f"{key} is not a known configuration flag")
668
669 flag_type = self._flagdict[key]._type
670 if flag_type is None:
671 # Regular flag
672 try:
673 ast.literal_eval(value)
674 except Exception: # Can't determine type, assume we got an un-quoted string
675 value=f"\"{value}\""
676
677 elif isinstance(flag_type, EnumMeta):
678 # Flag is an enum, so we need to import the module containing the enum
679 ENUM = importlib.import_module(flag_type.__module__) # noqa: F841 (used in exec)
680 value=f"ENUM.{value}"
681
682 # Set the value (this also does the type checking if needed)
683 exec(f"self.{key}{oper}{value}")
684
685

◆ getArgumentParser()

python.AthConfigFlags.AthConfigFlags.getArgumentParser ( self,
** kwargs )
Scripts calling AthConfigFlags.fillFromArgs can extend this parser, and pass their version to fillFromArgs

Definition at line 627 of file AthConfigFlags.py.

627 def getArgumentParser(self, **kwargs):
628 """
629 Scripts calling AthConfigFlags.fillFromArgs can extend this parser, and pass their version to fillFromArgs
630 """
631 import argparse
632 from AthenaCommon.AthOptionsParser import getArgumentParser
633 parser = getArgumentParser(**kwargs)
634 parser.add_argument("---",dest="terminator",action='store_true', help=argparse.SUPPRESS) # special hidden option required to convert option terminator -- for --help calls
635
636 return parser
637

◆ hasCategory()

python.AthConfigFlags.AthConfigFlags.hasCategory ( self,
name )
Check if category exists (loads dynamic flags if needed)

Definition at line 445 of file AthConfigFlags.py.

445 def hasCategory(self, name):
446 """Check if category exists (loads dynamic flags if needed)"""
447 # We cache successfully found categories
448 if name in self._categoryCache:
449 return True
450
451 if (re_name := self._renames.get(name)) is not None and re_name != name:
452 return self.hasCategory(re_name)
453
454 # Load dynamic flags if needed
455 self._loadDynaFlags(name)
456
457 # If not found do search through all keys.
458 # TODO: could be improved by using a trie for _flagdict
459 for f in self._flagdict.keys():
460 if f.startswith(name+'.'):
461 self._categoryCache.add(name)
462 return True
463 for c in self._dynaflags.keys():
464 if c.startswith(name):
465 self._categoryCache.add(name)
466 return True
467
468 return False
469

◆ hasFlag()

python.AthConfigFlags.AthConfigFlags.hasFlag ( self,
name )
Check if flag exists (loads dynamic flags if needed)

Definition at line 470 of file AthConfigFlags.py.

470 def hasFlag(self, name):
471 """Check if flag exists (loads dynamic flags if needed)"""
472 # Use attrgetter to check if attribute exists. As opposed to getattr,
473 # this also supports nested attributes, which is required to trigger loading
474 # of dynamics flags.
475 try:
476 attrgetter(name)(self)
477 # Now check if flag was found (taking into account renames)
478 return any(name in x for x in self._renamed_map().values())
479 except AttributeError:
480 return False
481

◆ initAll()

python.AthConfigFlags.AthConfigFlags.initAll ( self)
Mostly a self-test method

Definition at line 618 of file AthConfigFlags.py.

618 def initAll(self):
619 """
620 Mostly a self-test method
621 """
622 for n,f in list(self._flagdict.items()):
623 f.get(self)
624 return
625
626

◆ join()

python.AthConfigFlags.AthConfigFlags.join ( self,
other,
prefix = '' )
Merges two flag containers
When the prefix is passed each flag from the "other" is prefixed by "prefix."

Definition at line 559 of file AthConfigFlags.py.

559 def join(self, other, prefix=''):
560 """
561 Merges two flag containers
562 When the prefix is passed each flag from the "other" is prefixed by "prefix."
563 """
564 self._tryModify()
565
566 for (name,flag) in other._flagdict.items():
567 fullName = prefix+"."+name if prefix != "" else name
568 if fullName in self._flagdict:
569 raise KeyError("Duplicated flag name: {}".format( fullName ) )
570 self._flagdict[fullName]=flag
571
572 for (name,loader) in other._dynaflags.items():
573 fullName = prefix+"."+name if prefix != "" else name
574 if fullName in self._dynaflags:
575 raise KeyError("Duplicated dynamic flags name: {}".format( fullName ) )
576 _msg.debug("Joining dynamic flags with %s", fullName)
577 self._dynaflags[fullName] = loader
578 return
579

◆ loadAllDynamicFlags()

python.AthConfigFlags.AthConfigFlags.loadAllDynamicFlags ( self)
Force load all the dynamic flags 

Definition at line 438 of file AthConfigFlags.py.

438 def loadAllDynamicFlags(self):
439 """Force load all the dynamic flags """
440 while len(self._dynaflags) != 0:
441 # Need to convert to a list since _loadDynaFlags may change the dict.
442 for prefix in list(self._dynaflags.keys()):
443 self._loadDynaFlags( prefix )
444

◆ lock()

python.AthConfigFlags.AthConfigFlags.lock ( self)

Definition at line 482 of file AthConfigFlags.py.

482 def lock(self):
483 if not self._locked:
484 # before locking, parse args if a parser was defined
485 if self._args is None and self._parser is not None: self.fillFromArgs()
486 self._locked = True
487 return
488
virtual void lock()=0
Interface to allow an object to lock itself when made const in SG.

◆ locked()

python.AthConfigFlags.AthConfigFlags.locked ( self)

Definition at line 489 of file AthConfigFlags.py.

489 def locked(self):
490 return self._locked
491

◆ needFlagsCategory()

python.AthConfigFlags.AthConfigFlags.needFlagsCategory ( self,
name )
public interface for _loadDynaFlags 

Definition at line 408 of file AthConfigFlags.py.

408 def needFlagsCategory(self, name):
409 """ public interface for _loadDynaFlags """
410 self._loadDynaFlags( name )
411

◆ parser()

python.AthConfigFlags.AthConfigFlags.parser ( self)

Definition at line 638 of file AthConfigFlags.py.

638 def parser(self):
639 if self._parser is None: self._parser = self.getArgumentParser()
640 return self._parser
641

Member Data Documentation

◆ _args

python.AthConfigFlags.AthConfigFlags._args = None
protected

Definition at line 245 of file AthConfigFlags.py.

◆ _categoryCache

python.AthConfigFlags.AthConfigFlags._categoryCache = set()
protected

Definition at line 242 of file AthConfigFlags.py.

◆ _dynaflags

python.AthConfigFlags.AthConfigFlags._dynaflags = dict()
protected

Definition at line 240 of file AthConfigFlags.py.

◆ _flagdict

python.AthConfigFlags.AthConfigFlags._flagdict = dict()
protected

Definition at line 238 of file AthConfigFlags.py.

◆ _hash

python.AthConfigFlags.AthConfigFlags._hash = None
protected

Definition at line 243 of file AthConfigFlags.py.

◆ _hashedFlags

list python.AthConfigFlags.AthConfigFlags._hashedFlags = []
staticprotected

Definition at line 235 of file AthConfigFlags.py.

◆ _loaded

python.AthConfigFlags.AthConfigFlags._loaded = set()
protected

Definition at line 241 of file AthConfigFlags.py.

◆ _locked

bool python.AthConfigFlags.AthConfigFlags._locked = False
protected

Definition at line 239 of file AthConfigFlags.py.

◆ _parser

python.AthConfigFlags.AthConfigFlags._parser = None
protected

Definition at line 244 of file AthConfigFlags.py.

◆ _renames

python.AthConfigFlags.AthConfigFlags._renames = {}
protected

Definition at line 246 of file AthConfigFlags.py.


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