ATLAS Offline Software
ConfigurableMeta.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
2 
3 # File: AthenaCommon/python/ConfigurableMeta.py
4 # Author: Wim Lavrijsen (WLavrijsen@lbl.gov)
5 
6 import weakref
7 from AthenaCommon import Logging, PropertyProxy
8 
9 
10 
11 __version__ = '1.2.0'
12 __author__ = 'Wim Lavrijsen (WLavrijsen@lbl.gov)'
13 
14 __all__ = [ 'ConfigurableMeta' ]
15 
16 
17 
18 log = Logging.logging.getLogger( 'ConfigurableMeta' )
19 
20 
21 
23  """The setting of Gaudi component properties needs to be deferred and
24  history of who set what where needs to be collected. This is done
25  by using PropertyProxy descriptors rather than the default ones."""
26 
27  def __new__( self, name, bases, dct ):
28  # enforce use of classmethod for getType() and setDefaults()
29  if 'getType' in dct and not isinstance( dct[ 'getType' ], classmethod ):
30  dct[ 'getType' ] = classmethod( dct[ 'getType' ] )
31 
32  if 'setDefaults' in dct and not isinstance( dct[ 'setDefaults' ], classmethod ):
33  dct[ 'setDefaults' ] = classmethod( dct[ 'setDefaults' ] )
34 
35  # collect what are properties (basically, any public name; C++ variables
36  # shouldn't start with an '_' because of portability constraints, hence
37  # it is safe to assume that any such vars are python private ones)
38  newclass = type.__new__( self, name, bases, dct )
39 
40  if 'AthenaCommon' not in newclass.__module__:
41  # check for required methods and the right number of arguments
42  # meths = { 'getServices' : 1, # retrieve list of services to configure
43  meths = { 'getDlls' : 1, # provide list of Dlls to load
44  'getGaudiType' : 1, # return string describing component class
45  'getHandle' : 1, # provide access to C++ side component instance
46  'getType' : 1 } # return the type of the actual C++ component
47 
48  for meth, nArgs in meths.items():
49  try:
50  f = getattr( newclass, meth )
51  except AttributeError:
52  raise NotImplementedError("%s is missing in class %s" % (meth,str(newclass)))
53 
54  # in addition, verify the number of arguments w/o defaults
55  nargcount = f.__code__.co_argcount
56  dflts = f.__defaults__
57  ndefaults = dflts and len(dflts) or 0
58  if not nargcount - ndefaults <= nArgs <= nargcount:
59  raise TypeError("%s.%s requires exactly %d arguments" % (newclass,meth,nArgs))
60 
61  # cache references of instances by name for duplicate removal
62  newclass.configurables = weakref.WeakValueDictionary()
63 
64  # loop over slots, which are all assumed to be properties, create proxies, defaults
65  properties = {}
66  slots = dct.get( '__slots__' )
67  if slots:
68  props = [ x for x in slots if x[0] != '_' ]
69  propDict = dct.get('_propertyDocDct')
70  for prop in props:
71  docString = propDict and propDict.get(prop)
72  if type(slots) is dict:
73  default = slots[prop]
74  else:
75  default = None
76  proxy = PropertyProxy.PropertyProxyFactory(
77  getattr( newclass, prop ), docString, default )
78 
79  properties[ prop ] = proxy
80  setattr( newclass, prop, proxy )
81 
82  # complete set of properties includes those from base classes
83  for base in bases:
84  try:
85  bprops = base._properties.copy()
86  bprops.update( properties )
87  properties = bprops
88  except AttributeError:
89  pass
90 
91  newclass._properties = properties
92 
93  return newclass
94 
95  def __call__( cls, *args, **kwargs ):
96  """To Gaudi, any object with the same type/name is the same object. Hence,
97  this is mimicked in the configuration: instantiating a new Configurable
98  of a type with the same name will return the same instance."""
99 
100  # Get the instance: `singleton' logic needs to be in __new__, not here,
101  # for compatibililty with pickling.)
102  cfg = cls.__new__( cls, *args, **kwargs )
103 
104  # Initialize the object, if not done already.
105  if cfg and ( not hasattr(cfg, '_fInitOk') or not cfg._fInitOk ):
106  cls.__init__( cfg, *args, **kwargs )
107 
108  return cfg
python.ConfigurableMeta.ConfigurableMeta.__new__
def __new__(self, name, bases, dct)
Definition: ConfigurableMeta.py:27
python.ConfigurableMeta.ConfigurableMeta.__call__
def __call__(cls, *args, **kwargs)
Definition: ConfigurableMeta.py:95
python.CaloScaleNoiseConfig.type
type
Definition: CaloScaleNoiseConfig.py:78
str
Definition: BTagTrackIpAccessor.cxx:11
python.ConfigurableMeta.ConfigurableMeta
this metaclass installs PropertyProxy descriptors for Gaudi properties
Definition: ConfigurableMeta.py:22