ATLAS Offline Software
Loading...
Searching...
No Matches
Configurables.py
Go to the documentation of this file.
1# Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
2
3# @file: Configurables.py
4# @purpose: a set of Configurables for the PyAthena components
5# @author: Sebastien Binet <binet@cern.ch>, Frank Winklmeier
6# @author: Frank Winklmeier (rewrite for GaudiConfig2)
7
8import GaudiConfig2
9from AthenaConfiguration.ComponentAccumulator import isComponentAccumulatorCfg
10from AthenaCommon.Configurable import (Configurable as LegacyConfigurable,
11 ConfigurableAlgorithm,
12 ConfigurableService,
13 ConfigurableAlgTool,
14 ConfigurableAuditor)
15
16
17
19 """@c PyComponents is a placeholder where all factories for the python
20 components will be collected and stored for easy look-up and call from
21 the C++ side.
22 The @a PyComponents.instances dictionary will store the instance
23 e.g.:
24 PyComponents.instances[ 'alg1' ] = <PyAthena::Alg/alg1 instance>
25 All this boilerplate code will of course be done automatically for the user
26 as soon as she uses the (python) @PyConfigurable classes.
27 """
28 instances = {}
29 pass
30
31
32def _get_prop_value(pycomp, propname):
33 v = pycomp.properties()[propname]
34 if v == pycomp.propertyNoValue:
35 from AthenaCommon.AppMgr import ServiceMgr as svcMgr
36 if propname == 'OutputLevel' and hasattr (svcMgr, 'MessageSvc'):
37 # special case of OutputLevel...
38 v = getattr(svcMgr.MessageSvc, propname)
39 else:
40 v = pycomp.getDefaultProperty(propname)
41 pass
42 return v
43
44
45
47 def __init__(self, name, **kw):
48 self.__dict__['__cpp_type__'] = self.getType()
49 for n,v in kw.items():
50 setattr(self, n, v)
51
52 def getDlls(self):
53 return 'AthenaPython'
54
55 @property
56 def msg(self):
57 import AthenaCommon.Logging as _L
58 return _L.logging.getLogger( self.getName() )
59
60 def getHandle(self):
61 return None
62
63 def __getstate__(self):
64 state = super().__getstate__()
65 state.update(self.__dict__)
66 return state
67
68 def __setstate__(self, state):
69 self.__dict__.update(state)
70 super().__setstate__(state)
71
72 def setup(self):
73 if isinstance(self, LegacyConfigurable):
74 from AthenaCommon.AppMgr import ServiceMgr as svcMgr
75 if not hasattr( svcMgr, 'PyComponentMgr' ):
76 from AthenaPython.AthenaPythonCompsConf import PyAthena__PyComponentMgr
77 svcMgr += PyAthena__PyComponentMgr('PyComponentMgr')
78
79
81 self.OutputLevel = _get_prop_value (self, 'OutputLevel')
82
83
84 o = PyComponents.instances.get(self.getName(), None)
85 if not (o is None) and not (o is self):
86 err = "A python component [%r] has already been "\
87 "registered with the PyComponents registry !" % o
88 raise RuntimeError(err)
89 PyComponents.instances[self.getName()] = self
90
91 def merge(self, other):
92 """Basic merge for Python components.
93 Checks that all attributes/properties are identical.
94 """
95 if self is other:
96 return self
97
98 if type(self) is not type(other):
99 raise TypeError(f"cannot merge instance of {type(other).__name__} into "
100 f"an instance of { type(self).__name__}")
101
102 if self.name != other.name:
103 raise ValueError(f"cannot merge configurables with different names ({self.name} and {other.name})")
104
105 for prop in other.__dict__:
106 if (hasattr(self, prop) and getattr(self, prop) == getattr(other, prop)):
107 continue
108 else:
109 raise ValueError(f"conflicting settings for property {prop} of {self.name}: "
110 f"{getattr(self,prop)} vs {getattr(other,prop)}")
111 return self
112
113
114
120if isComponentAccumulatorCfg():
121 _alg_base = _svc_base = _tool_base = _aud_base = GaudiConfig2.Configurable
122else:
123 _alg_base = ConfigurableAlgorithm
124 _svc_base = ConfigurableService
125 _tool_base = ConfigurableAlgTool
126 _aud_base = ConfigurableAuditor
127
128
129
130class CfgPyAlgorithm( CfgPyComponent, _alg_base ):
131 def __init__( self, name, **kw ):
132 if isinstance(self, LegacyConfigurable):
133 _alg_base.__init__(self, name)
134 else:
135 _alg_base.__init__(self, name, **kw)
136 CfgPyComponent.__init__(self, name, **kw)
137
138 def getGaudiType( self ): return 'Algorithm'
139 def getType(self): return 'PyAthena::Alg'
140
141 def setup(self):
142
143 from AthenaPython import PyAthena
144 setattr(PyAthena.algs, self.getName(), self)
145
146
147 CfgPyComponent.setup(self)
148 if isinstance(self, LegacyConfigurable):
149 ConfigurableAlgorithm.setup(self)
150
151
152
153class CfgPyService( CfgPyComponent, _svc_base ):
154 def __init__( self, name, **kw ):
155 if isinstance(self, LegacyConfigurable):
156 _svc_base.__init__(self, name)
157 else:
158 _svc_base.__init__(self, name, **kw)
159 CfgPyComponent.__init__(self, name, **kw)
160
161 def getGaudiType( self ): return 'Service'
162 def getType(self): return 'PyAthena::Svc'
163
164 def setup(self):
165
166 from AthenaPython import PyAthena
167 setattr(PyAthena.services, self.getName(), self)
168
169
170 CfgPyComponent.setup(self)
171 if isinstance(self, LegacyConfigurable):
172 _svc_base.setup(self)
173
174
175
176class CfgPyAlgTool( CfgPyComponent, _tool_base ):
177 def __init__( self, name, **kw ):
178 if isinstance(self, LegacyConfigurable):
179 _tool_base.__init__(self, name)
180 else:
181 _tool_base.__init__(self, name, **kw)
182 CfgPyComponent.__init__(self, name, **kw)
183
184 def getGaudiType( self ): return 'AlgTool'
185 def getType(self): return 'PyAthena::Tool'
186
187 def setup(self):
188 CfgPyComponent.setup(self)
189 if isinstance(self, LegacyConfigurable):
190 _tool_base.setup(self)
191
192
193
194class CfgPyAud( CfgPyComponent, _aud_base ):
195 def __init__( self, name, **kw ):
196 _aud_base.__init__(self, name)
197 CfgPyComponent.__init__(self, name, **kw)
198
199 def getGaudiType( self ): return 'Auditor'
200 def getType(self): return 'PyAthena::Aud'
201
202 def setup(self):
203 CfgPyComponent.setup(self)
204 if isinstance(self, LegacyConfigurable):
205 _aud_base.setup(self)
206
207
208
210 """a class to mimic the gaudi C++ {Tool,Svc}Handle classes: automatic call
211 to `initialize` when __getattr__ is called on the instance.
212 """
213 def __init__(self, parent, attr_name):
214 msg = parent.msg.verbose
215 try:
216 parentName=parent.name()
217 except TypeError:
218 parentName=parent.name
219 msg('installing py-comp-handle for [%s.%s]...',
220 parentName, attr_name)
221 self.__dict__.update({
222 '_parent': parent,
223 '_name': attr_name,
224 '_attr': getattr(parent, attr_name),
225 '_init_called': False,
226 })
227 msg('installing py-comp-handle for [%s.%s]... [done]',
228 parentName, attr_name)
229 return
230
231 def _init_once(self, obj):
232 if self.__dict__['_init_called']:
233 return
234 parent = self.__dict__['_parent']
235 # FIXME: should we raise something in case initialize failed ?
236 obj.initialize()
237 self.__dict__['_init_called'] = True
238 # replace the handle with the proxied object
239 setattr(parent, self.__dict__['_name'], obj)
240
241 def __getattribute__(self, n):
242 if n.startswith('_'):
243 return super().__getattribute__(n)
244 obj = self.__dict__['_attr']
245 self._init_once(obj)
246 return getattr(obj, n)
247
248 def __setattr__(self, n, v):
249 if n.startswith('_'):
250 return super().__setattr__(n,v)
251 obj = self.__dict__['_attr']
252 self._init_once(obj)
253 return setattr(obj, n, v)
254
255
256def _is_pycomp(obj):
257 return isinstance(
258 obj,
259 (CfgPyAlgorithm, CfgPyService, CfgPyAlgTool, CfgPyAud)
260 )
261
263 """loop over all pycomponents, inspect their attributes and install
264 a handle in place of (sub) pycomponents to trigger the auto-initialize
265 behaviour of (C++) XyzHandles.
266 """
267 import PyUtils.Logging as L
268 msg = L.logging.getLogger('PyComponentMgr').verbose
269 comps = PyComponents.instances.items()
270 ncomps = len(comps)
271 msg('installing fancy getattrs... (%i)', ncomps)
272 for k,comp in comps:
273 msg('handling [%s]...', k)
274 for attr_name, attr in comp.__dict__.items():
275 if _is_pycomp(attr):
276 msg(' ==> [%s]...', attr_name)
277 setattr(comp, attr_name,
278 _PyCompHandle(parent=comp, attr_name=attr_name))
279 msg(' ==> [%s]... [done]', attr_name)
280 msg('installing fancy getattrs... (%i) [done]',ncomps)
Configurable base class for PyAlgorithms -------------------------------—.
Configurable base class for all Py compmonents -------------------------—.
OutputLevel
special case of the OutputLevel: take the value from the svcMgr.MessageSvc if none already set by use...
__init__(self, parent, attr_name)
Definition merge.py:1
_get_prop_value(pycomp, propname)
MsgStream & msg
Definition testRead.cxx:32