ATLAS Offline Software
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
9 of all the accessible, automatically generated, Configurables.
10 This repository of (informations on) Configurables is used by the PropertyProxy
11 class to locate Configurables and feed the JobOptionsSvc. It could also be used
12 to 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 
51 class _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 
202 def 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
209  _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 
260 CfgDb = _Singleton()
261 cfgDb = CfgDb() # default name for CfgDb instance
262 
263 del _CfgDb, _Singleton
264 
265 
266 
267 if __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 )
python.ConfigurableDb.CfgDb
CfgDb
Definition: ConfigurableDb.py:260
python.ConfigurableDb._Singleton
create configurable DB, and pre-fill it, then clean-up remnants -------—
Definition: ConfigurableDb.py:252
python.ConfigurableDb._CfgDb._duplicates
_duplicates
Definition: ConfigurableDb.py:68
python.ConfigurableDb.getConfigurable
def getConfigurable(className, requester='', assumeCxxClass=True)
Definition: ConfigurableDb.py:202
python.ConfigurableDb._CfgDb.msg
def msg(self)
Definition: ConfigurableDb.py:72
python.ConfigurableDb._CfgDb.add
def add(self, configurable, package, module, lib)
Definition: ConfigurableDb.py:79
python.ConfigurableDb.unloadConfigurableDb
def unloadConfigurableDb()
function to UNload all ConfigurableDb informations --------------------—
Definition: ConfigurableDb.py:177
python.ConfigurableDb._CfgDb._msg
_msg
for messaging
Definition: ConfigurableDb.py:69
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:232
python.ConfigurableDb._CfgDb._loadModule
def _loadModule(self, fname)
Definition: ConfigurableDb.py:112
python.ConfigurableDb._CfgDb.duplicates
def duplicates(self)
Definition: ConfigurableDb.py:108
Trk::open
@ open
Definition: BinningType.h:40
python.ConfigurableDb._CfgDb.__init__
def __init__(self)
Definition: ConfigurableDb.py:66
python.ConfigurableDb._CfgDb
singleton holding configurable and loadable information ---------------—
Definition: ConfigurableDb.py:51
python.TriggerHandler.verbose
verbose
Definition: TriggerHandler.py:296
get
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition: hcg.cxx:130
python.ConfigurableDb.loadConfigurableDb
def loadConfigurableDb()
Definition: ConfigurableDb.py:134
pickleTool.object
object
Definition: pickleTool.py:29
str
Definition: BTagTrackIpAccessor.cxx:11
python.ConfigurableDb._Singleton.__obj
__obj
Definition: ConfigurableDb.py:255
python.ConfigurableDb._fillConfDict
def _fillConfDict()
helpers ---------------------------------------------------------------—
Definition: ConfigurableDb.py:25
python.ConfigurableDb._Singleton.__call__
def __call__(self)
Definition: ConfigurableDb.py:257
Trk::split
@ split
Definition: LayerMaterialProperties.h:38