ATLAS Offline Software
Loading...
Searching...
No Matches
ConfigurableDb.py
Go to the documentation of this file.
1# Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
2
3# File: AthenaCommon/python/ConfigurableDb.py
4# Author: Sebastien Binet (binet@cern.ch)
5# Modified: Wim Lavrijsen (WLavrijsen@lbl.gov)
6# Modified: Marco Clemencic
7
8"""Provides cfgDb, a Singleton that holds the information on the whereabouts
9of all the accessible, automatically generated, Configurables.
10This repository of (informations on) Configurables is used by the PropertyProxy
11class to locate Configurables and feed the JobOptionsSvc. It could also be used
12to feed the AthenaEmacs module..."""
13
14
15__version__ = '3.0.0'
16__author__ = 'Sebastien Binet (binet@cern.ch)'
17
18__all__ = [ 'CfgDb', 'cfgDb',
19 'loadConfigurableDb', 'unloadConfigurableDb',
20 'getConfigurable' ]
21
22_transtable = str.maketrans('<>&*,: ().', '__rp__s___')
23
24
26 nFiles = loadConfigurableDb()
27 cfgDb.msg.info( "Read module info for %d configurables from %d genConfDb files",
28 len(cfgDb), nFiles )
29
30 if 0 < len( cfgDb.duplicates() ):
31 cfgDb.msg.warning( "Found %d duplicates among the %d genConfDb files :",
32 len(cfgDb.duplicates()), nFiles )
33 cfgDb.msg.warning( "--------------------------------------------------" )
34 cfgDb.msg.warning( " -%s: %s - %s",
35 "<component name>", "<module>", "[ <duplicates> ]" )
36 cfgDb.msg.warning( "--------------------------------------------------" )
37
38 dups = cfgDb.duplicates()
39 for cfgName in dups.keys():
40 cfgDb.msg.warning( " -%s: %s - %s",
41 cfgName,
42 cfgDb[cfgName]['module'],
43 str([ d['module'] for d in dups[cfgName]]) )
44 del dups
45
46 else:
47 cfgDb.msg.info( "No duplicates have been found: that's good !" )
48
49
50
51class _CfgDb( dict ):
52 """
53 A singleton class holding informations about automatically generated
54 Configurables.
55 --> package holding that Configurable
56 --> library holding the components related to that Configurable
57 --> python module holding the Configurable
58 --> a dictionary of duplicates
59 """
60
61 __slots__ = {
62 '_duplicates' : { },
63 '_msg' : None,
64 }
65
66 def __init__(self):
67 object.__init__( self )
68 self._duplicates = {}
69 self._msg = None
70
71 @property
72 def msg(self):
73 if self._msg is None:
74
75 from . import Logging
76 self._msg = Logging.logging.getLogger( 'ConfigurableDb' )
77 return self._msg
78
79 def add( self, configurable, package, module, lib ):
80 """Method to populate the Db.
81 It is called from the auto-generated Xyz_confDb.py files (genconf.cpp)
82 @param configurable: the name of the configurable being added
83 @param package: the name of the package which holds this Configurable
84 @param module: the name of the python module holding the Configurable
85 @param lib: the name of the library holding the component(s) (ie: the
86 C++ Gaudi component which is mapped by the Configurable)
87 """
88
89 cfg = { 'package' : package,
90 'module' : module,
91 'lib' : lib }
92
93 if configurable in self:
94 # check if it comes from the same library...
95 if cfg['lib'] != self[configurable]['lib']:
96 self.msg.verbose( "dup!! [%s] p=%s m=%s lib=%s",
97 configurable, package, module, lib )
98 if configurable in self._duplicates:
99 self._duplicates[configurable] += [ cfg ]
100 else:
101 self._duplicates[configurable] = [ cfg ]
102
103 else:
104 self.msg.verbose( "added [%s] p=%s m=%s lib=%s",
105 configurable, package, module, lib )
106 self[configurable] = cfg
107
108 def duplicates(self):
109 return self._duplicates
110
111
112 def _loadModule(self, fname):
113 f = open(fname)
114 for i,ll in enumerate(f):
115 l = ll.strip()
116 if l.startswith('#') or len(l) <= 0:
117 continue
118 try:
119 line = l.split()
120 cname = line[2]
121 pkg = line[0].split('.')[0]
122 module = line[0]
123 lib = line[1]
124 self.add(cname, pkg, module, lib)
125 except Exception:
126 f.close()
127 raise Exception(
128 "invalid line format: %s:%d: %r" %
129 (fname, i+1, ll)
130 )
131 f.close()
132
133
135 """Load all ConfigurableDb files (modules) holding informations about
136 Configurables available in the release
137 """
138
139 import os
140 from os.path import join as path_join
141
142 cfgDb.msg.debug( "loading confDb files..." )
143 nFiles = 0
144 pathlist = os.getenv("LD_LIBRARY_PATH", "").split(os.pathsep)
145 for path in pathlist:
146 if not os.path.isdir(path):
147 continue
148 cfgDb.msg.verbose( "walking in [%s]..." % path )
149 confDbFiles = [f for f in [path_join(path, f) for f in os.listdir(path)
150 if f.endswith('.confdb')]
151 if os.path.isfile(f)]
152
153 # check if we use "*_merged.confdb"
154 mergedConfDbFiles = [f for f in confDbFiles
155 if f.endswith('_merged.confdb')]
156 if mergedConfDbFiles:
157 # use only the merged ones
158 confDbFiles = mergedConfDbFiles
159
160 for confDb in confDbFiles:
161 cfgDb.msg.debug( "\t-loading [%s]...", confDb )
162 try:
163 cfgDb._loadModule( confDb )
164 except Exception as err:
165 import traceback
166 traceback.print_exc()
167 cfgDb.msg.warning( "Could not load file [%s] !", confDb )
168 cfgDb.msg.warning( "Reason: %s", err )
169 nFiles += 1
170 cfgDb.msg.debug( "loading confDb files... [DONE]" )
171 nPkgs = len( set([k['package'] for k in cfgDb.values()]) )
172 cfgDb.msg.debug( "loaded %i confDb packages", nPkgs )
173 return nFiles
174
175
176
178 """UNload all ConfigurableDb files (modules) holding informations about
179 Configurables available in the release:
180 - remove imported modules from sys.modules
181 - clear the configurable Db
182 """
183
184 confModules = set( [ cfgDb.get(k).get('module') for k in cfgDb ] +
185 [ cfgDb.get(k).get('package') for k in cfgDb ] )
186 cfgDb.clear()
187 import sys
188 for m in sys.modules.keys():
189 if m in confModules or \
190 m.count("_merged_confDb") > 0 or \
191 m.count(".GaudiHandles" ) > 0 or \
192 m.count("ConfigurableDb") > 0 or \
193 m.count("AthenaPython") > 0:
194
195 if hasattr(sys.modules[m], '__dict__'):
196 for i in sys.modules[m].__dict__.keys():
197 del sys.modules[m].__dict__[i]
198 del sys.modules[m]
199 del confModules
200
201
202def getConfigurable( className, requester = '', assumeCxxClass = True ):
203 """Localize and load a Configurable class based on the (C++) class name.
204 """
205
206 # fill the configurable dict, first time only
207 try:
208 global _fillConfDict
210 del _fillConfDict
211 except NameError:
212 pass
213
214 confClass = className
215 if assumeCxxClass:
216 # assume className is C++: --> translate to python
217 confClass = str.translate( confClass, _transtable )
218
219 # attempt to retrieve existing information
220 confClassInfo = cfgDb.get( confClass )
221
222 # get the python module, if info available
223 confMod = confClassInfo and confClassInfo.get( 'module' )
224 if not confMod:
225 cfgDb.msg.warning( "%s: Class %s not in database", requester, className )
226 return None
227
228 # load the module
229 try:
230 mod = __import__( confMod, globals(), locals(), confClass, level=0 )
231 except ImportError:
232 cfgDb.msg.warning( "%s: Module %s not found (needed for configurable %s)",
233 requester, confMod, className )
234 return None
235
236 # localize class
237 try:
238 confClass = getattr( mod, confClass )
239 except AttributeError:
240 cfgDb.msg.warning( "%s: Configurable %s not found in module %s",
241 requester, confClass, confMod )
242 return None
243
244 # got this far, assume confClass to be valid
245 cfgDb.msg.debug( "%s: Found configurable %s in module %s",
246 requester, confClass, confMod )
247
248 return confClass
249
250
251
253 # the object this singleton is holding
254 # No other object will be created...
255 __obj = _CfgDb()
256
257 def __call__( self ):
258 return self.__obj
259
260CfgDb = _Singleton()
261cfgDb = CfgDb() # default name for CfgDb instance
262
263del _CfgDb, _Singleton
264
265
266
267if __name__ == '__main__':
268 # we'll get a recursive import, so point to ourselves
269 import sys, __main__
270 sys.modules[ 'AthenaCommon.ConfigurableDb' ] = __main__ # for clients
271 sys.modules[ 'ConfigurableDb' ] = __main__ # for siblings
272
273 # retrieve a configurable
274 conf = getConfigurable( 'StoreGateSvc' )
275
276 # now make sure it is what we think it is
277 from StoreGate.StoreGateConf import StoreGateSvc
278 assert( conf is StoreGateSvc )
singleton holding configurable and loadable information ---------------—
add(self, configurable, package, module, lib)
create configurable DB, and pre-fill it, then clean-up remnants -------—
STL class.
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition hcg.cxx:130
bool verbose
Definition hcg.cxx:73
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:177
_fillConfDict()
helpers ---------------------------------------------------------------—
getConfigurable(className, requester='', assumeCxxClass=True)
unloadConfigurableDb()
function to UNload all ConfigurableDb informations --------------------—
MsgStream & msg
Definition testRead.cxx:32