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