ATLAS Offline Software
Public Member Functions | Static Public Attributes | Private Member Functions | Private Attributes | List of all members
python.ConfigBlock.ConfigBlock Class Reference
Inheritance diagram for python.ConfigBlock.ConfigBlock:
Collaboration diagram for python.ConfigBlock.ConfigBlock:

Public Member Functions

def __init__ (self)
 
def setBlockName (self, name)
 
def getBlockName (self)
 
def factoryName (self)
 
def setFactoryName (self, name)
 
def instanceName (self)
 
def isUsedForConfig (self, config)
 
def applyConfigOverrides (self, config)
 
def addDependency (self, dependencyName, required=True)
 
def hasDependencies (self)
 
def getDependencies (self)
 
def addOption (self, name, defaultValue, *type, info='', noneAction='ignore', required=False, expertMode=None)
 
def setOptionValue (self, name, value)
 
def getOptionValue (self, name)
 
def getOptions (self)
 
def printOptions (self, verbose=False, width=60, indent=" ")
 
def hasOption (self, name)
 
def __eq__ (self, blockName)
 
def __str__ (self)
 
def get_instance_count (cls)
 
def checkExpertSettings (self, config)
 
def __new__ (cls, name, bases, dct)
 

Static Public Attributes

dictionary instance_counts = {}
 

Private Member Functions

def _is_expert_value (self, rule, value)
 

Private Attributes

 _blockName
 
 _factoryName
 
 _dependencies
 
 _options
 
 _expertModeSettings
 

Detailed Description

the base class for classes implementing individual blocks of
configuration

A configuration block is a sequence of one or more algorithms that
should always be scheduled together, e.g. the muon four momentum
corrections could be a single block, muon selection could then be
another block.  The blocks themselves generally have their own
configuration options/properties specific to the block, and will
perform a dynamic configuration based on those options as well as
the overall job.

The actual configuration of the algorithms in the block will
depend on what other blocks are scheduled before and afterwards,
most importantly some algorithms will introduce shallow copies
that subsequent algorithms will need to run on, and some
algorithms will add selection decorations that subquent algorithms
should use as preselections.

The algorithms get created in a multi-step process (that may be
extended in the future): As a first step each block retrieves
references to the containers it uses (essentially marking its spot
in the processing chain) and also registering any shallow copies
that will be made.  In the second/last step each block then
creates the fully configured algorithms.

One goal is that when the algorithms get created they will have
their final configuration and there needs to be no
meta-configuration data attached to the algorithms, essentially an
inversion of the approach in AnaAlgSequence in which the
algorithms got created first with associated meta-configuration
and then get modified in susequent configuration steps.

For now this is mostly an empty base class, but another goal of
this approach is to make it easier to build another configuration
layer on top of this one, and this class will likely be extended
and get data members at that point.

The child class needs to implement the method `makeAlgs` which is
given a single `ConfigAccumulator` type argument. This is meant to
create the sequence of algorithms that this block configures. This
is currently (28 Jul 2025) called twice and should do the same thing
during both calls, but the plan is to change that to a single call.

The child class should also implement the method `getInstanceName`
which should return a string that is used to distinguish between
multiple instances of the same block. This is used to append the
instance name to the names of all algorithms created by this block,
and may in the future also be used to distinguish between multiple
instances of the block.

Definition at line 92 of file ConfigBlock.py.

Constructor & Destructor Documentation

◆ __init__()

def python.ConfigBlock.ConfigBlock.__init__ (   self)

Definition at line 147 of file ConfigBlock.py.

147  def __init__ (self) :
148  self._blockName = ''
149  self._factoryName = None
150  self._dependencies = []
151  self._options = {} # used with block configuration to set arbitrary option
152  self._expertModeSettings = {} # dictionary to track expert mode requirements for each option
153  self.addOption('groupName', '', type=str,
154  info=('Used to specify this block when setting an'
155  ' option at an arbitrary location.'))
156  self.addOption('skipOnData', False, type=bool,
157  info=('User option to prevent the block from running'
158  ' on data. This only affects blocks that are'
159  ' intended to run on data.'))
160  self.addOption('skipOnMC', False, type=bool,
161  info=('User option to prevent the block from running'
162  ' on MC. This only affects blocks that are'
163  ' intended to run on MC.'))
164  self.addOption('onlyForDSIDs', [], type=list,
165  info=('Used to specify which MC DSIDs to allow this'
166  ' block to run on. Each element of the list'
167  ' can be a full DSID (e.g. 410470), or a regex'
168  ' (e.g. 410.* to select all 410xxx DSIDs, or'
169  ' ^(?!410) to veto them). An empty list means no'
170  ' DSID restriction.'))
171  self.addOption('propertyOverrides', {}, type=None,
172  info=('EXPERT USE ONLY: A dictionary of properties to'
173  ' override at the end of configuration. This should'
174  ' take the form'
175  ' {"algName.toolName.propertyName": value, ...},'
176  ' without any automatically applied postfixes for'
177  ' the algorithm name. THIS IS MEANT TO BE EXPERT'
178  ' USAGE ONLY. Properties that need to be set by'
179  ' the user should be declared as options on the'
180  ' block itself. EXPERT USE ONLY!'),
181  expertMode=True)
182  # Increment the instance count for the current class
183  cls = type(self) # Get the actual class of the instance (also derived!)
184  if cls not in ConfigBlock.instance_counts:
185  ConfigBlock.instance_counts[cls] = 0
186  # Note: we do need to check in the call stack that we are
187  # in a real makeConfig situation, and not e.g. printAlgs
188  stack = inspect.stack()
189  for frame_info in stack:
190  # Get the class name (if any) from the frame
191  parent_cls = frame_info.frame.f_locals.get('self', None)
192  if parent_cls is None or not isinstance(parent_cls, ConfigBlock):
193  # If the frame does not belong to an instance of ConfigBlock, it's an external caller
194  if frame_info.function == "makeConfig":
195  ConfigBlock.instance_counts[cls] += 1
196  break
197 
198 

Member Function Documentation

◆ __eq__()

def python.ConfigBlock.ConfigBlock.__eq__ (   self,
  blockName 
)
Implementation of == operator. Used for seaching configSeque.
E.g. if blockName in configSeq:

Definition at line 419 of file ConfigBlock.py.

419  def __eq__(self, blockName):
420  """
421  Implementation of == operator. Used for seaching configSeque.
422  E.g. if blockName in configSeq:
423  """
424  return self._blockName == blockName
425 
426 

◆ __new__()

def python.ConfigBlock.BlockNameProcessorMeta.__new__ (   cls,
  name,
  bases,
  dct 
)
inherited

Definition at line 53 of file ConfigBlock.py.

53  def __new__(cls, name, bases, dct):
54  # Automatically apply alphanumeric-only decorator to 'instanceName()' method
55  if 'instanceName' in dct and callable(dct['instanceName']):
56  dct['instanceName'] = alphanumeric_block_name(dct['instanceName'])
57  return super().__new__(cls, name, bases, dct)
58 

◆ __str__()

def python.ConfigBlock.ConfigBlock.__str__ (   self)

Definition at line 427 of file ConfigBlock.py.

427  def __str__(self):
428  return self._blockName
429 
430 

◆ _is_expert_value()

def python.ConfigBlock.ConfigBlock._is_expert_value (   self,
  rule,
  value 
)
private
Check whether value matches an expert mode rule.
Rule can be:
- A literal (compared with ==)
- A callable predicate (called with value)
- A special marker string (common callable)

Definition at line 436 of file ConfigBlock.py.

436  def _is_expert_value(self, rule, value):
437  """
438  Check whether value matches an expert mode rule.
439  Rule can be:
440  - A literal (compared with ==)
441  - A callable predicate (called with value)
442  - A special marker string (common callable)
443  """
444  if callable(rule):
445  return rule(value)
446 
447  if isinstance(rule, str):
448  if rule == "nonemptystring":
449  return isinstance(value, str) and value != ""
450  if rule == "nonemptylist":
451  return isinstance(value, list) and value != []
452  if rule == "positiveint":
453  return isinstance(value, int) and value > 0
454 
455  # Fallback: direct value comparison
456  return value == rule
457 

◆ addDependency()

def python.ConfigBlock.ConfigBlock.addDependency (   self,
  dependencyName,
  required = True 
)
Add a dependency for the block. Dependency is corresponds to the
blockName of another block. If required is True, will throw an
error if dependency is not present; otherwise will move this
block after the required block. If required is False, will do
nothing if required block is not present; otherwise, it will
move block after required block.

Definition at line 291 of file ConfigBlock.py.

291  def addDependency(self, dependencyName, required=True):
292  """
293  Add a dependency for the block. Dependency is corresponds to the
294  blockName of another block. If required is True, will throw an
295  error if dependency is not present; otherwise will move this
296  block after the required block. If required is False, will do
297  nothing if required block is not present; otherwise, it will
298  move block after required block.
299  """
300  if not self.hasDependencies():
301  # add option to block ignore dependencies
302  self.addOption('ignoreDependencies', [], type=list,
303  info='List of dependencies defined in the ConfigBlock to ignore.')
304  self._dependencies.append(ConfigBlockDependency(dependencyName, required))
305 

◆ addOption()

def python.ConfigBlock.ConfigBlock.addOption (   self,
  name,
  defaultValue,
type,
  info = '',
  noneAction = 'ignore',
  required = False,
  expertMode = None 
)
declare the given option on the configuration block

This should only be called in the constructor of the
configuration block.

NOTE: The backend to option handling is slated to be replaced
at some point.  This particular function should essentially
stay the same, but some behavior may change.

Definition at line 314 of file ConfigBlock.py.

314  def addOption (self, name, defaultValue, *,
315  type, info='', noneAction='ignore', required=False, expertMode=None) :
316  """declare the given option on the configuration block
317 
318  This should only be called in the constructor of the
319  configuration block.
320 
321  NOTE: The backend to option handling is slated to be replaced
322  at some point. This particular function should essentially
323  stay the same, but some behavior may change.
324  """
325  if name in self._options :
326  raise KeyError (f'duplicate option: {name}')
327  if type not in [str, bool, int, float, list, None] :
328  raise TypeError (f'unknown option type: {type}')
329  noneActions = ['error', 'set', 'ignore']
330  if noneAction not in noneActions :
331  raise ValueError (f'invalid noneAction: {noneAction} [allowed values: {noneActions}]')
332 
333  # Store expert mode settings if provided
334  if expertMode is not None:
335  if expertMode is True:
336  # in this case we will just check against the default value
337  self._expertModeSettings[name] = True
338  elif not isinstance(expertMode, list):
339  raise TypeError (f'expertMode must be a list, got {type(expertMode)}')
340  else:
341  # here we will check against a list of custom values
342  self._expertModeSettings[name] = expertMode
343 
344  setattr (self, name, defaultValue)
345  self._options[name] = ConfigBlockOption(type=type, info=info,
346  noneAction=noneAction, required=required, default=defaultValue)
347 
348 

◆ applyConfigOverrides()

def python.ConfigBlock.ConfigBlock.applyConfigOverrides (   self,
  config 
)
Apply any configuration overrides specified in the block's
`propertyOverrides` option. This is meant to be called at the
end of the configuration process, after all algorithms have been
created and configured.

Definition at line 266 of file ConfigBlock.py.

266  def applyConfigOverrides(self, config):
267  """
268  Apply any configuration overrides specified in the block's
269  `propertyOverrides` option. This is meant to be called at the
270  end of the configuration process, after all algorithms have been
271  created and configured.
272  """
273  for key, value in self.propertyOverrides.items():
274  # Split the key into algorithm name, tool name, and property name
275  parts = key.split('.')
276  if len(parts) < 2:
277  raise Exception(f"Invalid override key format: {key}")
278  alg = config.getAlgorithm(parts[0])
279  if alg is None:
280  raise Exception(f"Algorithm {parts[0]} not found in config for override: {key}")
281  for name in parts[1:-1]:
282  # Navigate through tools if necessary
283  if hasattr(alg, name):
284  alg = getattr(alg, name)
285  else:
286  raise Exception(f"Tool {name} not found for override: {key}")
287  # Set the property on the algorithm/tool. This is probably a
288  # horrible hack, but `setattr` didn't work for me.
289  alg.__setattr__(parts[-1], value)
290 

◆ checkExpertSettings()

def python.ConfigBlock.ConfigBlock.checkExpertSettings (   self,
  config 
)
Check if any settings require expert mode and validate accordingly.
If any setting is set to a value that requires expert mode but we're
not in expert mode, raise an error.

Definition at line 458 of file ConfigBlock.py.

458  def checkExpertSettings(self, config):
459  """
460  Check if any settings require expert mode and validate accordingly.
461  If any setting is set to a value that requires expert mode but we're
462  not in expert mode, raise an error.
463  """
464  for option_name, expert_rule in self._expertModeSettings.items():
465  current_value = self.getOptionValue(option_name)
466  default_value = self._options[option_name].default
467 
468  if expert_rule is True:
469  # Any deviation from the default requires expert mode
470  if current_value != default_value:
471  warnings.warn(
472  f"Block '{self.factoryName()}' option '{option_name}' "
473  f"set to '{current_value}' (default '{default_value}'), "
474  f"requires expert mode.",
475  ExpertModeWarning, stacklevel=2
476  )
477 
478  else: # it's a list of expert values/markers/predicates
479  for ev in expert_rule:
480  if self._is_expert_value(ev, current_value):
481  warnings.warn(
482  f"Block '{self.factoryName()}' option '{option_name}' "
483  f"set to expert-only value '{current_value}'. "
484  f"Requires expert mode.",
485  ExpertModeWarning, stacklevel=2
486  )
487  # All checks passed
488  return

◆ factoryName()

def python.ConfigBlock.ConfigBlock.factoryName (   self)
get the factory name for this block

This is mostly to give a reliable means of identifying the type
of block we have in error messages. This is meant to be
automatically set by the factory based on the requested block
name, but there are a number of fallbacks. It is best not to
assume a specific format, this is mostly meant to be used as an
identifier in output messages.

Definition at line 207 of file ConfigBlock.py.

207  def factoryName(self):
208  """get the factory name for this block
209 
210  This is mostly to give a reliable means of identifying the type
211  of block we have in error messages. This is meant to be
212  automatically set by the factory based on the requested block
213  name, but there are a number of fallbacks. It is best not to
214  assume a specific format, this is mostly meant to be used as an
215  identifier in output messages.
216  """
217  if self._factoryName is not None and self._factoryName != '':
218  return self._factoryName
219  # If no factory name is set and the block has a name, use that
220  if self._blockName is not None and self._blockName != '':
221  return self._blockName
222  # Use the class name as a fallback
223  return self.__class__.__name__
224 

◆ get_instance_count()

def python.ConfigBlock.ConfigBlock.get_instance_count (   cls)

Definition at line 432 of file ConfigBlock.py.

432  def get_instance_count(cls):
433  # Access the current count for this class
434  return ConfigBlock.instance_counts.get(cls, 0)
435 

◆ getBlockName()

def python.ConfigBlock.ConfigBlock.getBlockName (   self)
Get blockName

Definition at line 203 of file ConfigBlock.py.

203  def getBlockName(self):
204  """Get blockName"""
205  return self._blockName
206 

◆ getDependencies()

def python.ConfigBlock.ConfigBlock.getDependencies (   self)
Return the list of dependencies. 

Definition at line 310 of file ConfigBlock.py.

310  def getDependencies(self):
311  """Return the list of dependencies. """
312  return self._dependencies
313 

◆ getOptions()

def python.ConfigBlock.ConfigBlock.getOptions (   self)
Return a copy of the options associated with the block

Definition at line 382 of file ConfigBlock.py.

382  def getOptions(self):
383  """Return a copy of the options associated with the block"""
384  return self._options.copy()
385 
386 

◆ getOptionValue()

def python.ConfigBlock.ConfigBlock.getOptionValue (   self,
  name 
)
Returns config option value, if present; otherwise return None

Definition at line 376 of file ConfigBlock.py.

376  def getOptionValue(self, name):
377  """Returns config option value, if present; otherwise return None"""
378  if name in self._options:
379  return getattr(self, name)
380 
381 

◆ hasDependencies()

def python.ConfigBlock.ConfigBlock.hasDependencies (   self)
Return True if there is a dependency.

Definition at line 306 of file ConfigBlock.py.

306  def hasDependencies(self):
307  """Return True if there is a dependency."""
308  return bool(self._dependencies)
309 

◆ hasOption()

def python.ConfigBlock.ConfigBlock.hasOption (   self,
  name 
)
whether the configuration block has the given option

WARNING: The backend to option handling is slated to be
replaced at some point.  This particular function may change
behavior, interface or be removed/replaced entirely.

Definition at line 409 of file ConfigBlock.py.

409  def hasOption (self, name) :
410  """whether the configuration block has the given option
411 
412  WARNING: The backend to option handling is slated to be
413  replaced at some point. This particular function may change
414  behavior, interface or be removed/replaced entirely.
415  """
416  return name in self._options
417 
418 

◆ instanceName()

def python.ConfigBlock.ConfigBlock.instanceName (   self)
Get the name of the instance

The name of the instance is used to distinguish between multiple
instances of the same block. Most importantly, this will be
appended to the names of all algorithms created by this block.
This defaults to an empty string, but block implementations
should override it with an appropriate name based on identifying
options set on this instance. A typical example would be the
name of the (main) container, plus potentially the selection or
working point.

Ideally all blocks should override this method, but for backward
compatibility (28 Jul 25) it defaults to an empty string.

Definition at line 234 of file ConfigBlock.py.

234  def instanceName(self):
235  """Get the name of the instance
236 
237  The name of the instance is used to distinguish between multiple
238  instances of the same block. Most importantly, this will be
239  appended to the names of all algorithms created by this block.
240  This defaults to an empty string, but block implementations
241  should override it with an appropriate name based on identifying
242  options set on this instance. A typical example would be the
243  name of the (main) container, plus potentially the selection or
244  working point.
245 
246  Ideally all blocks should override this method, but for backward
247  compatibility (28 Jul 25) it defaults to an empty string.
248  """
249  return ''
250 

◆ isUsedForConfig()

def python.ConfigBlock.ConfigBlock.isUsedForConfig (   self,
  config 
)
whether this block should be used for the given configuration

This is used by `ConfigSequence` to determine whether this block
should be included in the configuration.

Definition at line 251 of file ConfigBlock.py.

251  def isUsedForConfig(self, config):
252  """
253  whether this block should be used for the given configuration
254 
255  This is used by `ConfigSequence` to determine whether this block
256  should be included in the configuration.
257  """
258  if self.skipOnData and config.dataType() is DataType.Data:
259  return False
260  if self.skipOnMC and config.dataType() is not DataType.Data:
261  return False
262  if not filter_dsids(self.onlyForDSIDs, config):
263  return False
264  return True
265 

◆ printOptions()

def python.ConfigBlock.ConfigBlock.printOptions (   self,
  verbose = False,
  width = 60,
  indent = "    " 
)
Prints options and their values

Definition at line 387 of file ConfigBlock.py.

387  def printOptions(self, verbose=False, width=60, indent=" "):
388  """
389  Prints options and their values
390  """
391  def printWrap(text, width=60, indent=" "):
392  wrapper = textwrap.TextWrapper(width=width, initial_indent=indent,
393  subsequent_indent=indent)
394  for line in wrapper.wrap(text=text):
395  logCPAlgCfgBlock.info(line)
396 
397  for opt, vals in self.getOptions().items():
398  if verbose:
399  logCPAlgCfgBlock.info(indent + f"\033[4m{opt}\033[0m: {self.getOptionValue(opt)}")
400  logCPAlgCfgBlock.info(indent*2 + f"\033[4mtype\033[0m: {vals.type}")
401  logCPAlgCfgBlock.info(indent*2 + f"\033[4mdefault\033[0m: {vals.default}")
402  logCPAlgCfgBlock.info(indent*2 + f"\033[4mrequired\033[0m: {vals.required}")
403  logCPAlgCfgBlock.info(indent*2 + f"\033[4mnoneAction\033[0m: {vals.noneAction}")
404  printWrap(f"\033[4minfo\033[0m: {vals.info}", indent=indent*2)
405  else:
406  logCPAlgCfgBlock.info(indent + f"{ opt}: {self.getOptionValue(opt)}")
407 
408 

◆ setBlockName()

def python.ConfigBlock.ConfigBlock.setBlockName (   self,
  name 
)
Set blockName

Definition at line 199 of file ConfigBlock.py.

199  def setBlockName(self, name):
200  """Set blockName"""
201  self._blockName = name
202 

◆ setFactoryName()

def python.ConfigBlock.ConfigBlock.setFactoryName (   self,
  name 
)
set the factory name for this block

This is meant to be called automatically by the factory based on
the requested block name. If you are creating a block without a factory,
you can call this method to set the factory name manually.

Definition at line 225 of file ConfigBlock.py.

225  def setFactoryName(self, name):
226  """set the factory name for this block
227 
228  This is meant to be called automatically by the factory based on
229  the requested block name. If you are creating a block without a factory,
230  you can call this method to set the factory name manually.
231  """
232  self._factoryName = name
233 

◆ setOptionValue()

def python.ConfigBlock.ConfigBlock.setOptionValue (   self,
  name,
  value 
)
set the given option on the configuration block

NOTE: The backend to option handling is slated to be replaced
at some point.  This particular function should essentially
stay the same, but some behavior may change.

Definition at line 349 of file ConfigBlock.py.

349  def setOptionValue (self, name, value) :
350  """set the given option on the configuration block
351 
352  NOTE: The backend to option handling is slated to be replaced
353  at some point. This particular function should essentially
354  stay the same, but some behavior may change.
355  """
356 
357  if name not in self._options :
358  raise KeyError (f'unknown option "{name}" in block "{self.__class__.__name__}"')
359  noneAction = self._options[name].noneAction
360  if value is not None or noneAction == 'set' :
361  # check type if specified
362  optType = self._options[name].type
363  # convert int to float to prevent crash
364  if optType is float and type(value) is int:
365  value = float(value)
366  if optType is not None and optType != type(value):
367  raise ValueError(f'{name} for block {self.__class__.__name__} should '
368  f'be of type {optType} not {type(value)}')
369  setattr (self, name, value)
370  elif noneAction == 'ignore' :
371  pass
372  elif noneAction == 'error' :
373  raise ValueError (f'passed None for setting option {name} with noneAction=error')
374 
375 

Member Data Documentation

◆ _blockName

python.ConfigBlock.ConfigBlock._blockName
private

Definition at line 148 of file ConfigBlock.py.

◆ _dependencies

python.ConfigBlock.ConfigBlock._dependencies
private

Definition at line 150 of file ConfigBlock.py.

◆ _expertModeSettings

python.ConfigBlock.ConfigBlock._expertModeSettings
private

Definition at line 152 of file ConfigBlock.py.

◆ _factoryName

python.ConfigBlock.ConfigBlock._factoryName
private

Definition at line 149 of file ConfigBlock.py.

◆ _options

python.ConfigBlock.ConfigBlock._options
private

Definition at line 151 of file ConfigBlock.py.

◆ instance_counts

dictionary python.ConfigBlock.ConfigBlock.instance_counts = {}
static

Definition at line 145 of file ConfigBlock.py.


The documentation for this class was generated from the following file:
python.processes.powheg.ZZj_MiNNLO.ZZj_MiNNLO.__init__
def __init__(self, base_directory, **kwargs)
Constructor: all process options are set here.
Definition: ZZj_MiNNLO.py:18
python.ConfigBlock.alphanumeric_block_name
def alphanumeric_block_name(func)
Definition: ConfigBlock.py:31
dumpHVPathFromNtuple.append
bool append
Definition: dumpHVPathFromNtuple.py:91
python.CaloAddPedShiftConfig.type
type
Definition: CaloAddPedShiftConfig.py:42
FlavorTagInference::getOptions
GNNOptions getOptions(const GNNToolProperties &)
Definition: GNNToolifiers.cxx:24
TrigJetMonitorAlgorithm.items
items
Definition: TrigJetMonitorAlgorithm.py:71
python.ConfigBlock.filter_dsids
def filter_dsids(filterList, config)
Definition: ConfigBlock.py:14
calibdata.copy
bool copy
Definition: calibdata.py:26
xAOD::bool
setBGCode setTAP setLVL2ErrorBits bool
Definition: TrigDecision_v1.cxx:60
python.LArMinBiasAlgConfig.float
float
Definition: LArMinBiasAlgConfig.py:65