ATLAS Offline Software
TransformConfig.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
2 
3 __author__ = "clat@hep.ph.bham.ac.uk"
4 
5 import os,sys
6 from PyJobTransformsCore.trferr import TransformConfigError
7 from future.utils import with_metaclass
8 
9 
11  """Base class for all fixed types, implemented as descriptors. Each instance of a specific fixed type
12  (a derived class) can be set either to None (to indicate no value has been set), or to a type specified
13  by the derived class. The type is checked by the derived class by implementing the member function
14  _checkType()"""
15 
16  def __init__(self,doc,default,allowedValues=None):
17  self.__name = '\"%s\"' % doc # Temporary name overwritten by JobConfigMetaClass
18  self.__doc = doc
19  self.__allowed = []
20  if allowedValues is not None:
21  try:
22  allowedValues.__iter__
23  except AttributeError:
24  allowedValues = [ allowedValues ]
25  varName = "%s.allowedValues" % self.__name
26  self.__allowed = self._checkAllowedValues( varName, allowedValues )
27  # allow None as a value for all types
28  if default is not None:
29  # check type and value of default
30  varName = "%s default" % self.__name
31  default = self._checkType( varName, default )
32  default = self._checkValue( varName, default )
33  self.__default = default
34 
35  def __get__(self,instance,owner):
36  if instance is None:
37  return self
38  return instance._attributeDictionary().get(self._attributeName(instance),self.__default)
39 
40 
41  def __set__(self,instance,value):
42  varName = "%s.%s" % (instance.name(), self.__name) # for error/debug printout
43  # allow None as a value for all types
44  if value is not None:
45  # do value and/or type checking and possibly change type and/or value
46  value = self._checkType(varName,value)
47  value = self._checkValue(varName,value)
48  # Do possible additional actions
49  self._setValue(varName,value)
50  instance._attributeDictionary()[self._attributeName(instance)] = value # store the value
51 
52 
53  def _attributeName(self,instance):
54  return '_%s__%s' % (instance.__class__.__name__,self.__name)
55 
56 
57  def name(self):
58  return self.__name
59 
60 
61  def default(self):
62  return self.__default
63 
64 
65  def doc(self):
66  """The documentation string"""
67  return self.__doc
68 
69 
70  def help(self):
71  """The help string: type, documentation and possible values"""
72  hlp = '(%s) %s' % (self.__class__.__name__, self.__doc)
73  if self.__allowed:
74  hlp += '. Possible values: %s' % self.__allowed
75 
76  return hlp
77 
78 
79  def allowedValues(self):
80  return self.__allowed
81 
82 
83  def _checkType(self,variableName,value):
84  """Private helper functin to check the type of <value>. May convert to another type.
85  This implementation does nothing, it just returns value.
86  This function can be overridden in derived class to do type checking.
87  It should return the value (possible with new type), or raise a TransformConfigError
88  exception in case of problems. """
89  return value
90 
91 
92  def _checkValue(self,variableName,value):
93  """Private helper function to check the value of <value>. This function is
94  called after calling _checkType. <value> can therefore be considered to be
95  of the correct type.
96  This implementation checks that the value is one of the allowed values (if defined).
97  This function can be overridden in derived class to do type & additional value checking.
98  It has to return the value (adapted if needed) if all is OK. It has to raise
99  a TransformConfigError exception in case of problems.
100  <variableName> is the name of the variable that is being set and is typically
101  only used for error messages."""
102  if self.__allowed and value not in self.__allowed:
103  raise TransformConfigError( '%s value %r is not in %s' %
104  (variableName, value, self.__allowed) )
105 
106  return value
107 
108 
109  def _setValue(self,variableName,value):
110  """Private helper function which is called when the value of the object is set.
111  It is called after _checkType() and _checkValue(), so the value can be
112  assumed to be correct.
113  This function can be overridden in a derived class, typically to trigger additional action
114  when the value is set.
115  In case of error, raise a TransformConfigError exception, otherwise just return.
116  This implementation does nothing.
117  <variableName> is the name of the variable that is being set and is typically
118  only used for error messages."""
119  pass
120 
121 
122  def _checkAllowedValues(self,variableName,allowedValues):
123  # Check all allowed values
124  for v in allowedValues:
125  self._checkType(variableName,v)
126  return allowedValues
127 
128 
129 
131  def __init__(self,doc,default='',allowedValues=None):
132  Descriptor.__init__(self,doc,default,allowedValues)
133 
134 
135  def _checkValue(self,variableName,value):
136  valType = type(value).__name__
137  if valType != 'str':
138  raise TransformConfigError( '%s should be a string. Got %s instead.' % (variableName, valType) )
139 
140  # check the value against list of possible values
141  return Descriptor._checkValue(self,variableName,value)
142 
143 
144 
146  def __init__(self,doc,default):
147  Descriptor.__init__(self,doc,default,[True,False])
148 
149 
150 
152  def __init__(self,doc,default,allowedValues=None):
153  Descriptor.__init__(self,doc,default,allowedValues)
154 
155 
156  def _checkValue(self,variableName,value):
157  try:
158  value = float(value)
159  except Exception:
160  raise TransformConfigError( '%s value %s is not a float' % (variableName, value) )
161 
162  # check the value against list of possible values
163  return Descriptor._checkValue(self,variableName,value)
164 
165 
166 
168  def __init__(self,doc,default,allowedValues=None):
169  Descriptor.__init__(self,doc,default,allowedValues)
170 
171 
172  def _checkValue(self,variableName,value):
173  inValue = value
174  try:
175  value = int(value)
176  except Exception:
177  raise TransformConfigError( '%s value %s is not an int' % (variableName, value) )
178 
179  if value != float(inValue):
180  raise TransformConfigError( '%s value %s is not an int' % (variableName, value) )
181 
182  # check the value against list of possible values
183  return Descriptor._checkValue(self,variableName,value)
184 
185 
186 
188  """List with a unique set of entries (duplicates are removed).
189  List of allowed values are the entries that are allowed in the list."""
190  def __init__(self,doc,default=None,allowedValues=None):
191  if default is None: default = [] # trick needed to avoid sharing among instances
192  Descriptor.__init__(self,doc,default,allowedValues)
193 
194 
195  def _checkType(self,variableName,value):
196  """Check that <value> is of type list of tuple, and convert to a list if it is a tuple."""
197 # # check types
198 # valType = type(value).__name__
199 # if valType != 'list' and valType != 'tuple':
200 # raise TransformConfigError( '%s should be a list or tuple. Got %s instead.' % \
201 # (variableName, valType) )
202 # if valType == 'tuple':
203 # # convert to a list
204 # value = list(value)
205 # return value
206  try:
207  value.__iter__
208  return list( value )
209  except Exception:
210  raise TransformConfigError( '%s should be a list or tuple. Got %s instead.' %
211  ( variableName, type( value ).__name__ ) )
212 
213 
214  def _checkValue(self,variableName,value):
215  # check that entries are allowed
216  allowed = self.allowedValues()
217  if allowed:
218  for v in value:
219  if v not in allowed:
220  raise TransformConfigError( '%s value %r is not one of %s' %
221  (variableName, value, allowed) )
222  # make entries unique
223  newValue = set() #[]
224  for v in value:
225  newValue.add( v )
226  return list( newValue )
227 
228 
229  def _checkAllowedValues(self,variableName,allowedValues):
230  # Convert values to list before calling _checkType, and back to entry
231  newAllowed = set() # []
232  for v in allowedValues:
233  newAllowed.add( self._checkType(variableName,[v])[0] )
234  return list( newAllowed )
235 
236 
237 
239  """List with a unique set of strings (duplicates are removed)"""
240  def __init__(self,doc,default=None,allowedValues=None):
241  UniqueList.__init__(self,doc,default,allowedValues)
242 
243 
244  def _checkType(self,variableName,value):
245  """Add check that all entries are strings"""
246  # check that <value> is a list or tuple
247  value = UniqueList._checkType(self,variableName,value)
248  # check that all entries are strings
249  for v in value:
250  if not isinstance( v, str ):
251  raise TransformConfigError("Entry %r in %s is not a string (but an %s)" %
252  ( v, variableName, type( v ).__name__ ) )
253  return value
254 
255 
256 
258  def __init__(self,expression):
259  """Any python (string) boolean expression where 'value' stands for the value.
260  For example, for a number range check: \"0 < value < 100\" """
261  self.expression = expression
262 
263 
264  def __contains__(self,value):
265  return eval(self.expression)
266 
267 
268  def __str__(self):
269  return self.expression
270 
271 
272  def __iter__(self):
273  return self
274 
275 
276  def next(self):
277  """No iteration"""
278  raise StopIteration
279 
280 
281  def __next__(self):
282  """No iteration"""
283  raise StopIteration
284 
285 
286 
287 
289  def __init__( self, name, bases, dict ):
290  if '__slots__' not in dict:
291  raise TransformConfigError('Class %s does not have member __slots__. Please add __slots__ = ()'
292  ' to the class definition' % (name,) )
293  #
294  # add list of properties
295  #
296  # first add it to __slots__
297  slots = self.__slots__
298  descrName = '__properties'
299  if descrName not in slots:
300  # add variable
301  slots += ( descrName, )
302  # synchronise dict
303  dict['__slots__'] = slots
304  # then add the list itself
305  setattr(self,descrName,[])
306  descrList = getattr(self,descrName)
307  # set names of properties and add them to the list of properties
308  for n,attrib in dict.items():
309  if isinstance(attrib,Descriptor):
310  setattr(attrib,'_Descriptor__name',n) # noqa: B010 (private property)
311  descrList.append(attrib)
312 
313  type.__init__(self,name,bases,dict)
314 
315 
316 
317 class JobConfig(with_metaclass(JobConfigMetaClass,object)):
318  __slots__ = ( '__name', '__attributes' )
319 
320  def __init__(self,name=None):
321  """name is used in printout. The default name is derived from the filename of the python file
322  where constructor is called"""
323 
324  if name is None:
325  filename = os.path.basename(sys._getframe(1).f_code.co_filename)
326  name = os.path.splitext(filename)[0]
327  self.__name = name
328  self.__attributes = {} # dictionary to store values of attributes (managed by Descriptors)
329 
330 
331  def __str__(self,prefix=''):
332  prefix += self.__name
333  me = []
334  for descr in self.properties():
335  name = descr.name()
336  value = getattr(self,name)
337  me.append( "%s.%s = %r \t# %s" % (prefix,name,value,descr.help()) )
338  prefix = ' '*len(prefix)
339  return os.linesep.join(me)
340 
341 
342  def __len__(self):
343  """Return the total number of properties (this class plus all base classes)"""
344  return len(self.properties())
345 
346 
347  def __iter__(self):
348  """Provide iteration over the full list of properties (the Descriptors, not the values)"""
349  return iter(self.properties())
350 
351 
353  """Dictionary to store the values. Used in the class Descriptor."""
354  return self.__attributes
355 
356 
357  def properties(self):
358  """Return the full list of properties (the descriptors, not the values)"""
359 
360  descr = []
361  for cl in self.__class__.__bases__ + (self.__class__,):
362  descr += getattr(cl,'__properties') # noqa: B009 (private property)
363  return descr
364 
365 
366  def getProperty(self,name):
367  """Get the property (the descriptor, not the value) named <name>.
368  It raises an TransformConfigError if the class does not have proporty <name>."""
369  for d in self.properties():
370  if d.name() == name: return d
371 
372  raise TransformConfigError('class %s does not have property %s' % (self.__class__.__name__, name))
373 
374 
375  def hasProperty(self,name):
376  """Return bool indicating if this class has property <name>"""
377  try:
378  self.getProperty(name)
379  return True
380  except TransformConfigError:
381  return False
382 
383 
384  def attributes(self):
385  """Dictionary with the attibutes (name:value). It is a copy to make it read-only."""
386  return self.__attributes.copy()
387 
388 
389  def name(self):
390  """The name of the configuration instance (mainly for printout)"""
391  return self.__name
392 
393 
394 
396  """Configuration class for JobTransforms.
397  It has a number of properties shared among all jobtransforms. Those properties are
398  processed by class JobTransform."""
399  __slots__ = ( '__metadata', )
400 
401  # add basic configuration properties
402  auxfiles = ListOfStrings("List of needed auxiliary files (to be found in DATAPATH)")
403  minevents = Integer("minimum number of events in output file",0, AllowedExpression("value >= 0"))
404  maxeventsfactor = Float("maximum number of output events = minevents * maxeventsfactor",2.0,
405  AllowedExpression("value >= 1.0"))
406  maxeventsstrategy = String("what to do if number of input events is less than maxEvents",'INPUTEVENTS',
407  ['IGNORE','INPUTEVENTS','ABORT'])
408  efficiency = Float("Event filtering efficiency (acceptance factor)", 1.0, AllowedExpression("0.0 < value <= 1.0") )
409 
410 
411  def __init__(self,name=None,metaData=None):
412  """name is used in printout. The default name is derived from the filename of the python file
413  where constructor is called"""
414  JobConfig.__init__(self,name)
415  self.__metadata = []
416  if metaData is not None:
417  propertyNames = [ d.name() for d in self.properties() ]
418  for m in metaData:
419  if m not in propertyNames:
420  raise TransformConfigError('Requested metadata %s is not an attribute of %s' % (m,self.name()) )
421  self.__metadata.append(m)
422 
423 
424  def __str__(self,prefix=''):
425  me = JobConfig.__str__(self,prefix)
426  #
427  # add list of metadata
428  #
429  prefix += ' '*len(self.name())
430  me += os.linesep + prefix + 'MetaData attributes: '
431  if self.__metadata:
432  me += ','.join(self.__metadata)
433  else:
434  me += '(None)'
435  return me
436 
437 
438  def metaData(self):
439  """A dictionary of metadata to be added to the metadata of the output files.
440  Values set to None will not be added to the list. Values will be converted to strings.
441  Python lists will be transformed to a string with comma separated entries."""
442  meta = {}
443  for name in self.__metadata:
444  value = getattr(self,name)
445  if value is not None:
446  # turn a python list into a string with comma separated entries
447  if type(value).__name__ == 'list': value = ','.join([str(v) for v in value])
448  meta[name] = str(value)
449  return meta
450 
python.TransformConfig.AllowedExpression.__contains__
def __contains__(self, value)
Definition: TransformConfig.py:264
python.TransformConfig.JobConfig.__attributes
__attributes
Definition: TransformConfig.py:328
python.TransformConfig.Descriptor.__allowed
__allowed
Definition: TransformConfig.py:19
python.TransformConfig.AllowedExpression.__iter__
def __iter__(self)
Definition: TransformConfig.py:272
python.TransformConfig.JobConfigMetaClass
Definition: TransformConfig.py:288
python.TransformConfig.JobConfigMetaClass.__init__
def __init__(self, name, bases, dict)
Definition: TransformConfig.py:289
python.TransformConfig.TransformConfig.__init__
def __init__(self, name=None, metaData=None)
Definition: TransformConfig.py:411
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
python.TransformConfig.Descriptor.__name
__name
Definition: TransformConfig.py:17
python.TransformConfig.Integer._checkValue
def _checkValue(self, variableName, value)
Definition: TransformConfig.py:172
python.TransformConfig.String
Definition: TransformConfig.py:130
python.TransformConfig.Descriptor.__doc
__doc
Definition: TransformConfig.py:18
python.TransformConfig.Descriptor.allowedValues
def allowedValues(self)
Definition: TransformConfig.py:79
python.TransformConfig.TransformConfig
Definition: TransformConfig.py:395
python.TransformConfig.getProperty
def getProperty(self, name)
Definition: TransformConfig.py:366
python.TransformConfig.Descriptor.default
def default(self)
Definition: TransformConfig.py:61
python.TransformConfig.JobConfig
Definition: TransformConfig.py:317
python.TransformConfig.JobConfig._attributeDictionary
def _attributeDictionary(self)
Definition: TransformConfig.py:352
python.TransformConfig.name
def name(self)
Definition: TransformConfig.py:389
python.TransformConfig.AllowedExpression.__next__
def __next__(self)
Definition: TransformConfig.py:281
python.TransformConfig.ListOfStrings.__init__
def __init__(self, doc, default=None, allowedValues=None)
Definition: TransformConfig.py:240
python.TransformConfig.Float.__init__
def __init__(self, doc, default, allowedValues=None)
Definition: TransformConfig.py:152
python.TransformConfig.Descriptor._checkValue
def _checkValue(self, variableName, value)
Definition: TransformConfig.py:92
python.TransformConfig.UniqueList._checkType
def _checkType(self, variableName, value)
Definition: TransformConfig.py:195
python.TransformConfig.ListOfStrings._checkType
def _checkType(self, variableName, value)
Definition: TransformConfig.py:244
dumpHVPathFromNtuple.append
bool append
Definition: dumpHVPathFromNtuple.py:91
python.TransformConfig.JobConfig.__len__
def __len__(self)
Definition: TransformConfig.py:342
python.TransformConfig.hasProperty
def hasProperty(self, name)
Definition: TransformConfig.py:375
python.TransformConfig.JobConfig.__init__
def __init__(self, name=None)
Definition: TransformConfig.py:320
python.TransformConfig.AllowedExpression.__str__
def __str__(self)
Definition: TransformConfig.py:268
python.TransformConfig.AllowedExpression.__init__
def __init__(self, expression)
Definition: TransformConfig.py:258
python.TransformConfig.TransformConfig.__metadata
__metadata
Definition: TransformConfig.py:415
python.TransformConfig.Descriptor.__default
__default
Definition: TransformConfig.py:33
python.TransformConfig.Descriptor
Definition: TransformConfig.py:10
python.TransformConfig.UniqueList._checkValue
def _checkValue(self, variableName, value)
Definition: TransformConfig.py:214
python.TransformConfig.UniqueList.__init__
def __init__(self, doc, default=None, allowedValues=None)
Definition: TransformConfig.py:190
python.TransformConfig.JobConfig.properties
def properties(self)
Definition: TransformConfig.py:357
histSizes.list
def list(name, path='/')
Definition: histSizes.py:38
python.TransformConfig.Integer.__init__
def __init__(self, doc, default, allowedValues=None)
Definition: TransformConfig.py:168
python.TransformConfig.String.__init__
def __init__(self, doc, default='', allowedValues=None)
Definition: TransformConfig.py:131
python.TransformConfig.Descriptor.__set__
def __set__(self, instance, value)
Definition: TransformConfig.py:41
python.TransformConfig.AllowedExpression.expression
expression
Definition: TransformConfig.py:261
python.TransformConfig.String._checkValue
def _checkValue(self, variableName, value)
Definition: TransformConfig.py:135
python.TransformConfig.Descriptor._checkType
def _checkType(self, variableName, value)
Definition: TransformConfig.py:83
CxxUtils::set
constexpr std::enable_if_t< is_bitmask_v< E >, E & > set(E &lhs, E rhs)
Convenience function to set bits in a class enum bitmask.
Definition: bitmask.h:224
python.TransformConfig.Descriptor.name
def name(self)
Definition: TransformConfig.py:57
TCS::join
std::string join(const std::vector< std::string > &v, const char c=',')
Definition: Trigger/TrigT1/L1Topo/L1TopoCommon/Root/StringUtils.cxx:10
python.TransformConfig.Descriptor.doc
def doc(self)
Definition: TransformConfig.py:65
python.TransformConfig.JobConfig.__iter__
def __iter__(self)
Definition: TransformConfig.py:347
python.TransformConfig.UniqueList
Definition: TransformConfig.py:187
python.TransformConfig.Descriptor._setValue
def _setValue(self, variableName, value)
Definition: TransformConfig.py:109
python.TransformConfig.JobConfig.__name
__name
Definition: TransformConfig.py:327
python.TransformConfig.Descriptor._attributeName
def _attributeName(self, instance)
Definition: TransformConfig.py:53
python.TransformConfig.AllowedExpression.next
def next(self)
Definition: TransformConfig.py:276
python.TransformConfig.Integer
Definition: TransformConfig.py:167
python.TransformConfig.TransformConfig.__str__
def __str__(self, prefix='')
Definition: TransformConfig.py:424
python.TransformConfig.Float._checkValue
def _checkValue(self, variableName, value)
Definition: TransformConfig.py:156
python.TransformConfig.Float
Definition: TransformConfig.py:151
python.TransformConfig.ListOfStrings
Definition: TransformConfig.py:238
python.TransformConfig.Descriptor.help
def help(self)
Definition: TransformConfig.py:70
python.TransformConfig.AllowedExpression
Definition: TransformConfig.py:257
python.CaloScaleNoiseConfig.type
type
Definition: CaloScaleNoiseConfig.py:78
python.TransformConfig.Descriptor._checkAllowedValues
def _checkAllowedValues(self, variableName, allowedValues)
Definition: TransformConfig.py:122
python.TransformConfig.UniqueList._checkAllowedValues
def _checkAllowedValues(self, variableName, allowedValues)
Definition: TransformConfig.py:229
python.TransformConfig.Descriptor.__get__
def __get__(self, instance, owner)
Definition: TransformConfig.py:35
get
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition: hcg.cxx:127
python.TransformConfig.TransformConfig.metaData
def metaData(self)
Definition: TransformConfig.py:438
python.TransformConfig.Boolean.__init__
def __init__(self, doc, default)
Definition: TransformConfig.py:146
pickleTool.object
object
Definition: pickleTool.py:30
str
Definition: BTagTrackIpAccessor.cxx:11
calibdata.copy
bool copy
Definition: calibdata.py:27
python.TransformConfig.JobConfig.__str__
def __str__(self, prefix='')
Definition: TransformConfig.py:331
python.TransformConfig.Descriptor.__init__
def __init__(self, doc, default, allowedValues=None)
Definition: TransformConfig.py:16
python.TransformConfig.Boolean
Definition: TransformConfig.py:145
readCCLHist.float
float
Definition: readCCLHist.py:83
python.TransformConfig.attributes
def attributes(self)
Definition: TransformConfig.py:384