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 Types

typedef HLT::TypeInformation::for_each_type_c< typenameEDMLIST::map, my_functor, my_result<>, my_arg< HLT::TypeInformation::get_cont, CONTAINER > >::type result

Public Member Functions

 __init__ (self)
 athHash (self)
 __hash__ (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)
 __call__ (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)
 _set (self, name, value)
 _get (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.

Member Typedef Documentation

◆ result

Definition at line 90 of file EDM_MasterSearch.h.

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

◆ __call__()

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

Definition at line 491 of file AthConfigFlags.py.

491 def __call__(self,name):
492 return self._get(name)
493

◆ __contains__()

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

Definition at line 307 of file AthConfigFlags.py.

307 def __contains__(self, name):
308 return hasattr(self, name)
309

◆ __delattr__()

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

Definition at line 290 of file AthConfigFlags.py.

290 def __delattr__(self, name):
291 del self[name]
292

◆ __delitem__()

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

Definition at line 299 of file AthConfigFlags.py.

299 def __delitem__(self, name):
300 self._tryModify()
301 self.loadAllDynamicFlags()
302 for key in list(self._flagdict):
303 if key.startswith(name):
304 del self._flagdict[key]
305 self._categoryCache.clear()
306

◆ __getattr__()

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

Definition at line 268 of file AthConfigFlags.py.

268 def __getattr__(self, name):
269 # Avoid infinite recursion looking up our own attributes
270 _flagdict = object.__getattribute__(self, "_flagdict")
271
272 # First try to get an already loaded flag or category
273 if name in _flagdict:
274 return self._get(name)
275
276 # Check (and load if needed) dynamic flags
277 if self.hasCategory(name):
278 return FlagAddress(self, name)
279
280 raise AttributeError(f"No such flag: {name}")
281

◆ __getitem__()

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

Definition at line 293 of file AthConfigFlags.py.

293 def __getitem__(self, name):
294 return getattr(self, name)
295

◆ __hash__()

python.AthConfigFlags.AthConfigFlags.__hash__ ( self)

Definition at line 255 of file AthConfigFlags.py.

255 def __hash__(self):
256 raise DeprecationWarning("__hash__ method in AthConfigFlags is deprecated. Probably called from function decorator, use AccumulatorCache decorator instead.")
257

◆ __iter__()

python.AthConfigFlags.AthConfigFlags.__iter__ ( self)

Definition at line 310 of file AthConfigFlags.py.

310 def __iter__(self):
311 self.loadAllDynamicFlags()
312 rmap = self._renamed_map()
313 used = set()
314 for flag in self._flagdict:
315 for r in rmap[flag]:
316 first = r.split('.',1)[0]
317 if first not in used:
318 yield first
319 used.add(first)
320

◆ __setattr__()

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

Definition at line 282 of file AthConfigFlags.py.

282 def __setattr__(self, name, value):
283 if name.startswith("_"):
284 return object.__setattr__(self, name, value)
285
286 if name in self._flagdict:
287 return self._set(name, value)
288 raise RuntimeError( "No such flag: "+ name+". The name is likely incomplete." )
289

◆ __setitem__()

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

Definition at line 296 of file AthConfigFlags.py.

296 def __setitem__(self, name, value):
297 setattr(self, name, value)
298

◆ _calculateHash()

python.AthConfigFlags.AthConfigFlags._calculateHash ( self)
protected

Definition at line 258 of file AthConfigFlags.py.

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

◆ _get()

python.AthConfigFlags.AthConfigFlags._get ( self,
name )
protected

Definition at line 482 of file AthConfigFlags.py.

482 def _get(self,name):
483 try:
484 return self._flagdict[name].get(self)
485 except KeyError:
486 closestMatch = get_close_matches(name,self._flagdict.keys(),1)
487 raise KeyError(f"No flag with name '{name}' found" +
488 (f". Did you mean '{closestMatch[0]}'?" if closestMatch else ""))
489
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition hcg.cxx:130

◆ _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 403 of file AthConfigFlags.py.

403 def _loadDynaFlags(self, name):
404 """
405 loads the flags of the form "A.B.C" first attempting the path "A" then "A.B" and then "A.B.C"
406 """
407
408 def __load_impl( flagBaseName ):
409 if flagBaseName in self._loaded:
410 _msg.debug("Flags %s already loaded",flagBaseName )
411 return
412 if flagBaseName in self._dynaflags:
413 _msg.debug("Dynamically loading the flags under %s", flagBaseName )
414 # Retain locked status and hash
415 isLocked = self._locked
416 myHash = self._hash
417 self._locked = False
418 generator, prefix = self._dynaflags[flagBaseName]
419 self.join( generator(), flagBaseName if prefix else "" )
420 self._locked = isLocked
421 self._hash = myHash
422 del self._dynaflags[flagBaseName]
423 self._loaded.add(flagBaseName)
424
425 pathfrags = name.split('.')
426 for maxf in range(1, len(pathfrags)+1):
427 __load_impl( '.'.join(pathfrags[:maxf]) )
428
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 331 of file AthConfigFlags.py.

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

◆ _set()

python.AthConfigFlags.AthConfigFlags._set ( self,
name,
value )
protected

Definition at line 473 of file AthConfigFlags.py.

473 def _set(self,name,value):
474 self._tryModify()
475 try:
476 self._flagdict[name].set(value)
477 except KeyError:
478 closestMatch = get_close_matches(name,self._flagdict.keys(),1)
479 raise KeyError(f"No flag with name '{name}' found" +
480 (f". Did you mean '{closestMatch[0]}'?" if closestMatch else ""))
481

◆ _subflag_itr()

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

This is used by the asdict() function.

Definition at line 356 of file AthConfigFlags.py.

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

◆ _tryModify()

python.AthConfigFlags.AthConfigFlags._tryModify ( self)
protected

Definition at line 504 of file AthConfigFlags.py.

504 def _tryModify(self):
505 if self._locked:
506 raise RuntimeError("Attempt to modify locked flag container")
507 else:
508 # if unlocked then invalidate hash
509 self._hash = None
510

◆ addFlag()

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

Definition at line 377 of file AthConfigFlags.py.

377 def addFlag(self, name, setDef, type=None, help=None):
378 self._tryModify()
379 if name in self._flagdict:
380 raise KeyError("Duplicated flag name: {}".format( name ))
381 self._flagdict[name]=CfgFlag(setDef, type, help)
382 return
383

◆ 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 384 of file AthConfigFlags.py.

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

◆ args()

python.AthConfigFlags.AthConfigFlags.args ( self)

Definition at line 654 of file AthConfigFlags.py.

654 def args(self):
655 return self._args
656
657

◆ 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 321 of file AthConfigFlags.py.

321 def asdict(self):
322 """Convert to a python dictionary
323
324 This is identical to the `asdict` in FlagAddress, but for all
325 the flags.
326
327 """
328 return _asdict(self._subflag_itr())
329
330

◆ 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 511 of file AthConfigFlags.py.

511 def clone(self):
512 """Return an unlocked copy of self (dynamic flags are not loaded)"""
513 cln = AthConfigFlags()
514 cln._flagdict = deepcopy(self._flagdict)
515 cln._dynaflags = copy(self._dynaflags)
516 cln._renames = deepcopy(self._renames)
517 return cln
518
519

◆ 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 520 of file AthConfigFlags.py.

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

◆ dump()

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

Definition at line 592 of file AthConfigFlags.py.

592 def dump(self, pattern=".*", evaluate=False, formatStr="{:40} : {}", maxLength=None):
593 import re
594 compiled = re.compile(pattern)
595 def truncate(s): return s[:maxLength] + ("..." if maxLength and len(s)>maxLength else "")
596 reverse_renames = {value: key for key, value in self._renames.items() if value is not None} # new name to old
597 for name in sorted(self._flagdict):
598 renamed = name
599 if any([name.startswith(r) for r in reverse_renames.keys() if r is not None]):
600 for oldprefix, newprefix in reverse_renames.items():
601 if name.startswith(oldprefix):
602 renamed = name.replace(oldprefix, newprefix)
603 break
604 if compiled.match(renamed):
605 if evaluate:
606 try:
607 rep = repr(self._flagdict[name] )
608 val = repr(self._flagdict[name].get(self))
609 if val != rep:
610 print(formatStr.format(renamed,truncate("{} {}".format( val, rep )) ))
611 else:
612 print(formatStr.format(renamed, truncate("{}".format(val)) ) )
613 except Exception as e:
614 print(formatStr.format(renamed, truncate("Exception: {}".format( e )) ))
615 else:
616 print(formatStr.format( renamed, truncate("{}".format(repr(self._flagdict[name] ) )) ))
617
618 if len(self._dynaflags) != 0 and any([compiled.match(x) for x in self._dynaflags.keys()]):
619 print("Flag categories that can be loaded dynamically")
620 print("{:25} : {:>30} : {}".format( "Category","Generator name", "Defined in" ) )
621 for name,gen_and_prefix in sorted(self._dynaflags.items()):
622 if compiled.match(name):
623 print("{:25} : {:>30} : {}".format( name, gen_and_prefix[0].__name__, '/'.join(gen_and_prefix[0].__code__.co_filename.split('/')[-2:]) ) )
624 if len(self._renames):
625 print("Flag categories that are redirected by the cloneAndReplace")
626 for alias,src in self._renames.items():
627 print("{:30} points to {:>30} ".format( alias, src if src else "nothing") )
628
629
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 699 of file AthConfigFlags.py.

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

◆ fillFromString()

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

Definition at line 658 of file AthConfigFlags.py.

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

◆ getArgumentParser()

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

Definition at line 639 of file AthConfigFlags.py.

639 def getArgumentParser(self, **kwargs):
640 """
641 Scripts calling AthConfigFlags.fillFromArgs can extend this parser, and pass their version to fillFromArgs
642 """
643 import argparse
644 from AthenaCommon.AthOptionsParser import getArgumentParser
645 parser = getArgumentParser(**kwargs)
646 parser.add_argument("---",dest="terminator",action='store_true', help=argparse.SUPPRESS) # special hidden option required to convert option terminator -- for --help calls
647
648 return parser
649

◆ hasCategory()

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

Definition at line 436 of file AthConfigFlags.py.

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

◆ hasFlag()

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

Definition at line 461 of file AthConfigFlags.py.

461 def hasFlag(self, name):
462 """Check if flag exists (loads dynamic flags if needed)"""
463 # Use attrgetter to check if attribute exists. As opposed to getattr,
464 # this also supports nested attributes, which is required to trigger loading
465 # of dynamics flags.
466 try:
467 attrgetter(name)(self)
468 # Now check if flag was found (taking into account renames)
469 return any(name in x for x in self._renamed_map().values())
470 except AttributeError:
471 return False
472

◆ initAll()

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

Definition at line 630 of file AthConfigFlags.py.

630 def initAll(self):
631 """
632 Mostly a self-test method
633 """
634 for n,f in list(self._flagdict.items()):
635 f.get(self)
636 return
637
638

◆ 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 571 of file AthConfigFlags.py.

571 def join(self, other, prefix=''):
572 """
573 Merges two flag containers
574 When the prefix is passed each flag from the "other" is prefixed by "prefix."
575 """
576 self._tryModify()
577
578 for (name,flag) in other._flagdict.items():
579 fullName = prefix+"."+name if prefix != "" else name
580 if fullName in self._flagdict:
581 raise KeyError("Duplicated flag name: {}".format( fullName ) )
582 self._flagdict[fullName]=flag
583
584 for (name,loader) in other._dynaflags.items():
585 fullName = prefix+"."+name if prefix != "" else name
586 if fullName in self._dynaflags:
587 raise KeyError("Duplicated dynamic flags name: {}".format( fullName ) )
588 _msg.debug("Joining dynamic flags with %s", fullName)
589 self._dynaflags[fullName] = loader
590 return
591

◆ loadAllDynamicFlags()

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

Definition at line 429 of file AthConfigFlags.py.

429 def loadAllDynamicFlags(self):
430 """Force load all the dynamic flags """
431 while len(self._dynaflags) != 0:
432 # Need to convert to a list since _loadDynaFlags may change the dict.
433 for prefix in list(self._dynaflags.keys()):
434 self._loadDynaFlags( prefix )
435

◆ lock()

python.AthConfigFlags.AthConfigFlags.lock ( self)

Definition at line 494 of file AthConfigFlags.py.

494 def lock(self):
495 if not self._locked:
496 # before locking, parse args if a parser was defined
497 if self._args is None and self._parser is not None: self.fillFromArgs()
498 self._locked = True
499 return
500

◆ locked()

python.AthConfigFlags.AthConfigFlags.locked ( self)

Definition at line 501 of file AthConfigFlags.py.

501 def locked(self):
502 return self._locked
503

◆ needFlagsCategory()

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

Definition at line 399 of file AthConfigFlags.py.

399 def needFlagsCategory(self, name):
400 """ public interface for _loadDynaFlags """
401 self._loadDynaFlags( name )
402

◆ parser()

python.AthConfigFlags.AthConfigFlags.parser ( self)

Definition at line 650 of file AthConfigFlags.py.

650 def parser(self):
651 if self._parser is None: self._parser = self.getArgumentParser()
652 return self._parser
653

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: