ATLAS Offline Software
ConfigBlock.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
2 
3 import textwrap
4 
5 from AnaAlgorithm.Logging import logging
6 logCPAlgCfgBlock = logging.getLogger('CPAlgCfgBlock')
7 
8 
10  """the information for a single option on a configuration block"""
11 
12  def __init__ (self, type=None, info='', noneAction='ignore', required=False,
13  default=None) :
14  self.type = type
15  self.info = info
16  self.required = required
17  self.noneAction = noneAction
18  self.default = default
19 
20 
21 
23  """Class encoding a blocks dependence on other blocks."""
24 
25  def __init__(self, blockName, required=True):
26  self.blockName = blockName
27  self.required = required
28 
29 
30  def __eq__(self, name):
31  return self.blockName == name
32 
33 
34  def __str__(self):
35  return self.blockName
36 
37 
38  def __repr__(self):
39  return f'ConfigBlockDependency(blockName="{self.blockName}", required={self.required})'
40 
41 
43  """the base class for classes implementing individual blocks of
44  configuration
45 
46  A configuration block is a sequence of one or more algorithms that
47  should always be scheduled together, e.g. the muon four momentum
48  corrections could be a single block, muon selection could then be
49  another block. The blocks themselves generally have their own
50  configuration options/properties specific to the block, and will
51  perform a dynamic configuration based on those options as well as
52  the overall job.
53 
54  The actual configuration of the algorithms in the block will
55  depend on what other blocks are scheduled before and afterwards,
56  most importantly some algorithms will introduce shallow copies
57  that subsequent algorithms will need to run on, and some
58  algorithms will add selection decorations that subquent algorithms
59  should use as preselections.
60 
61  The algorithms get created in a multi-step process (that may be
62  extended in the future): As a first step each block retrieves
63  references to the containers it uses (essentially marking its spot
64  in the processing chain) and also registering any shallow copies
65  that will be made. In the second/last step each block then
66  creates the fully configured algorithms.
67 
68  One goal is that when the algorithms get created they will have
69  their final configuration and there needs to be no
70  meta-configuration data attached to the algorithms, essentially an
71  inversion of the approach in AnaAlgSequence in which the
72  algorithms got created first with associated meta-configuration
73  and then get modified in susequent configuration steps.
74 
75  For now this is mostly an empty base class, but another goal of
76  this approach is to make it easier to build another configuration
77  layer on top of this one, and this class will likely be extended
78  and get data members at that point.
79 
80  The child class needs to implement two methods,
81  `collectReferences` and `makeAlgs` which are each given a single
82  `ConfigAccumulator` type argument. The first is for the first
83  configuration step, and should only collect references to the
84  containers to be used. The second is for the second configuration
85  step, and should create the actual algorithms.
86 
87  """
88 
89  def __init__ (self) :
90  self._blockName = ''
91  self._dependencies = []
92  self._options = {}
93  # used with block configuration to set arbitrary option
94  self.addOption('groupName', '', type=str,
95  info=('Used to specify this block when setting an'
96  ' option at an arbitrary location.'))
97 
98 
99  def setBlockName(self, name):
100  """Set blockName"""
101  self._blockName = name
102 
103  def getBlockName(self, name):
104  """Get blockName"""
105  return self._blockName
106 
107  def addDependency(self, dependencyName, required=True):
108  """
109  Add a dependency for the block. Dependency is corresponds to the
110  blockName of another block. If required is True, will throw an
111  error if dependency is not present; otherwise will move this
112  block after the required block. If required is False, will do
113  nothing if required block is not present; otherwise, it will
114  move block after required block.
115  """
116  if not self.hasDependencies():
117  # add option to block ignore dependencies
118  self.addOption('ignoreDependencies', [], type=list,
119  info='List of dependencies defined in the ConfigBlock to ignore.')
120  self._dependencies.append(ConfigBlockDependency(dependencyName, required))
121 
122  def hasDependencies(self):
123  """Return True if there is a dependency."""
124  return bool(self._dependencies)
125 
126  def getDependencies(self):
127  """Return the list of dependencies. """
128  return self._dependencies
129 
130  def addOption (self, name, defaultValue, *,
131  type, info='', noneAction='ignore', required=False) :
132  """declare the given option on the configuration block
133 
134  This should only be called in the constructor of the
135  configuration block.
136 
137  NOTE: The backend to option handling is slated to be replaced
138  at some point. This particular function should essentially
139  stay the same, but some behavior may change.
140  """
141  if name in self._options :
142  raise KeyError (f'duplicate option: {name}')
143  if type not in [str, bool, int, float, list, None] :
144  raise TypeError (f'unknown option type: {type}')
145  noneActions = ['error', 'set', 'ignore']
146  if noneAction not in noneActions :
147  raise ValueError (f'invalid noneAction: {noneAction} [allowed values: {noneActions}]')
148  setattr (self, name, defaultValue)
149  self._options[name] = ConfigBlockOption(type=type, info=info,
150  noneAction=noneAction, required=required, default=defaultValue)
151 
152 
153  def setOptionValue (self, name, value) :
154  """set the given option on the configuration block
155 
156  NOTE: The backend to option handling is slated to be replaced
157  at some point. This particular function should essentially
158  stay the same, but some behavior may change.
159  """
160 
161  if name not in self._options :
162  raise KeyError (f'unknown option "{name}" in block "{self.__class__.__name__}"')
163  noneAction = self._options[name].noneAction
164  if value is not None or noneAction == 'set' :
165  # check type if specified
166  optType = self._options[name].type
167  # convert int to float to prevent crash
168  if optType is float and type(value) is int:
169  value = float(value)
170  if optType is not None and optType != type(value):
171  raise ValueError(f'{name} for block {self.__class__.__name__} should '
172  f'be of type {optType} not {type(value)}')
173  setattr (self, name, value)
174  elif noneAction == 'ignore' :
175  pass
176  elif noneAction == 'error' :
177  raise ValueError (f'passed None for setting option {name} with noneAction=error')
178 
179 
180  def getOptionValue(self, name):
181  """Returns config option value, if present; otherwise return None"""
182  if name in self._options:
183  return getattr(self, name)
184 
185 
186  def getOptions(self):
187  """Return a copy of the options associated with the block"""
188  return self._options.copy()
189 
190 
191  def printOptions(self, verbose=False, width=60, indent=" "):
192  """
193  Prints options and their values
194  """
195  def printWrap(text, width=60, indent=" "):
196  wrapper = textwrap.TextWrapper(width=width, initial_indent=indent,
197  subsequent_indent=indent)
198  for line in wrapper.wrap(text=text):
199  logCPAlgCfgBlock.info(line)
200 
201  for opt, vals in self.getOptions().items():
202  if verbose:
203  logCPAlgCfgBlock.info(indent + f"\033[4m{opt}\033[0m: {self.getOptionValue(opt)}")
204  logCPAlgCfgBlock.info(indent*2 + f"\033[4mtype\033[0m: {vals.type}")
205  logCPAlgCfgBlock.info(indent*2 + f"\033[4mdefault\033[0m: {vals.default}")
206  logCPAlgCfgBlock.info(indent*2 + f"\033[4mrequired\033[0m: {vals.required}")
207  logCPAlgCfgBlock.info(indent*2 + f"\033[4mnoneAction\033[0m: {vals.noneAction}")
208  printWrap(f"\033[4minfo\033[0m: {vals.info}", indent=indent*2)
209  else:
210  logCPAlgCfgBlock.info(indent + f"{ opt}: {self.getOptionValue(opt)}")
211 
212 
213  def hasOption (self, name) :
214  """whether the configuration block has the given option
215 
216  WARNING: The backend to option handling is slated to be
217  replaced at some point. This particular function may change
218  behavior, interface or be removed/replaced entirely.
219  """
220  return name in self._options
221 
222 
223  def __eq__(self, blockName):
224  """
225  Implementation of == operator. Used for seaching configSeque.
226  E.g. if blockName in configSeq:
227  """
228  return self._blockName == blockName
229 
230 
231  def __str__(self):
232  return self._blockName
python.ConfigBlock.ConfigBlock.hasOption
def hasOption(self, name)
Definition: ConfigBlock.py:213
python.ConfigBlock.ConfigBlockDependency
Definition: ConfigBlock.py:22
python.ConfigBlock.ConfigBlockOption.noneAction
noneAction
Definition: ConfigBlock.py:16
python.ConfigBlock.ConfigBlock.hasDependencies
def hasDependencies(self)
Definition: ConfigBlock.py:122
python.ConfigBlock.ConfigBlock.addDependency
def addDependency(self, dependencyName, required=True)
Definition: ConfigBlock.py:107
python.ConfigBlock.ConfigBlock.__str__
def __str__(self)
Definition: ConfigBlock.py:231
python.ConfigBlock.ConfigBlock.setOptionValue
def setOptionValue(self, name, value)
Definition: ConfigBlock.py:153
python.ConfigBlock.ConfigBlockOption.type
type
Definition: ConfigBlock.py:13
python.ConfigBlock.ConfigBlock.getDependencies
def getDependencies(self)
Definition: ConfigBlock.py:126
python.ConfigBlock.ConfigBlockOption.info
info
Definition: ConfigBlock.py:14
python.ConfigBlock.ConfigBlock.getOptions
def getOptions(self)
Definition: ConfigBlock.py:186
dumpHVPathFromNtuple.append
bool append
Definition: dumpHVPathFromNtuple.py:91
python.ConfigBlock.ConfigBlockDependency.__str__
def __str__(self)
Definition: ConfigBlock.py:34
python.ConfigBlock.ConfigBlockOption.required
required
Definition: ConfigBlock.py:15
python.ConfigBlock.ConfigBlockOption.default
default
Definition: ConfigBlock.py:17
python.ConfigBlock.ConfigBlockDependency.__eq__
def __eq__(self, name)
Definition: ConfigBlock.py:30
python.ConfigBlock.ConfigBlock._dependencies
_dependencies
Definition: ConfigBlock.py:91
python.ConfigBlock.ConfigBlockDependency.blockName
blockName
Definition: ConfigBlock.py:26
python.ConfigBlock.ConfigBlockDependency.required
required
Definition: ConfigBlock.py:27
python.ConfigBlock.ConfigBlock.__init__
def __init__(self)
Definition: ConfigBlock.py:89
python.ConfigBlock.ConfigBlock.printOptions
def printOptions(self, verbose=False, width=60, indent=" ")
Definition: ConfigBlock.py:191
python.ConfigBlock.ConfigBlock.addOption
def addOption(self, name, defaultValue, *type, info='', noneAction='ignore', required=False)
Definition: ConfigBlock.py:130
python.ConfigBlock.ConfigBlock.getOptionValue
def getOptionValue(self, name)
Definition: ConfigBlock.py:180
python.ConfigBlock.ConfigBlock.getBlockName
def getBlockName(self, name)
Definition: ConfigBlock.py:103
TrigJetMonitorAlgorithm.items
items
Definition: TrigJetMonitorAlgorithm.py:79
python.ConfigBlock.ConfigBlock.__eq__
def __eq__(self, blockName)
Definition: ConfigBlock.py:223
python.ConfigBlock.ConfigBlock._blockName
_blockName
Definition: ConfigBlock.py:90
python.CaloScaleNoiseConfig.type
type
Definition: CaloScaleNoiseConfig.py:78
python.ConfigBlock.ConfigBlockDependency.__init__
def __init__(self, blockName, required=True)
Definition: ConfigBlock.py:25
python.ConfigBlock.ConfigBlockDependency.__repr__
def __repr__(self)
Definition: ConfigBlock.py:38
calibdata.copy
bool copy
Definition: calibdata.py:27
python.ConfigBlock.ConfigBlock._options
_options
Definition: ConfigBlock.py:92
python.ConfigBlock.ConfigBlockOption.__init__
def __init__(self, type=None, info='', noneAction='ignore', required=False, default=None)
Definition: ConfigBlock.py:12
xAOD::bool
setBGCode setTAP setLVL2ErrorBits bool
Definition: TrigDecision_v1.cxx:60
readCCLHist.float
float
Definition: readCCLHist.py:83
python.ConfigBlock.ConfigBlock
Definition: ConfigBlock.py:42
python.ConfigBlock.ConfigBlockOption
Definition: ConfigBlock.py:9
python.ConfigBlock.ConfigBlock.setBlockName
def setBlockName(self, name)
Definition: ConfigBlock.py:99