00001 """
00002 DybDbi python package provides access to most Dbi functionality,
00003 with generation of classes based on .spec files and wrapping of the
00004 python classes for easier usage, enabling access to model objects via::
00005
00006 from DybDbi import GCalibPmtSpec
00007 from DybDbi import *
00008
00009
00010 Example of introspecting the specification::
00011
00012 sk = GCalibPmtSpec.SpecKeys().aslist() # list of row names
00013 sk
00014 ['PmtId',
00015 'Describ',
00016 'Status',
00017 ...
00018
00019 sl = GCalibPmtSpec.SpecList().aslod() # list of row maps ... list-of-dict
00020 sl
00021 [{'code2db': '',
00022 'codetype': 'int',
00023 'dbtype': 'int(11)',
00024 'description': '',
00025 'legacy': 'PMTID',
00026 'memb': 'm_pmtId',
00027 'name': 'PmtId'},
00028 ...
00029
00030 sm = GCalibPmtSpec.SpecMap().asdod() # map of row maps, keyed by name dict-of-dict
00031 sm
00032 {'AfterPulseProb': {'code2db': '',
00033 'codetype': 'double',
00034 'dbtype': 'float',
00035 'description': 'Probability of afterpulsing',
00036 'legacy': 'PMTAFTERPULSE',
00037 'memb': 'm_afterPulseProb',
00038 'name': 'AfterPulseProb'},
00039 ...
00040
00041 sm['TimeOffset']['description'] # access any aspect of spec "matrix" directly by name
00042 'Relative transit time offset'
00043
00044
00045 sk = cls.SpecKeys().aslist()
00046 sm = cls.SpecMap().asdod()
00047 for k in sk:
00048 print sm[k]
00049
00050
00051
00052 """
00053 import os, pprint, inspect, logging
00054
00055 class NullHandler(logging.Handler):
00056 def emit(self, record):
00057 pass
00058 h = NullHandler()
00059 log = logging.getLogger("DybDbi")
00060 log.addHandler(h)
00061
00062
00063
00064 __all__ = """
00065 Detector DetectorSensor
00066 ServiceMode Context Site DetectorId SimFlag TimeStamp ContextRange
00067 DbiSqlValPacket DbiValRecSet DbiTableProxyRegistry DbiValidityRec DbiSqlContext DbiCascader DbiConnection DbiStatement DbiCache DbiTableProxy Dbi
00068 DybDbi DbiCtx Ctx
00069 """.strip().split()
00070
00071
00072 from ROOT import TObject,TList,TMap
00073
00074
00075 TMap.__getitem__ = lambda self,k:self.GetValue(k)
00076 TMap.asdict = lambda self:dict([(str(k),self.GetValue(k)) for k in self])
00077 TList.aslist = lambda self:list([str(k) for k in self])
00078 TList.aslod = lambda self:list([k.asdict() for k in self])
00079 TMap.asdod = lambda self:dict([(str(k),self.GetValue(k).asdict()) for k in self])
00080
00081
00082
00083 from GaudiPython import gbl
00084 _getattr = lambda n:(n,getattr(gbl,n,None) or getattr(gbl,"DayaBay::%s" % n) )
00085 clss = map(_getattr,__all__)
00086 locals().update( clss )
00087
00088
00089 DybDbi.Instance()
00090 gDbi = gbl.gDbi
00091 __all__ += "gDbi".split()
00092
00093
00094 import genDbi
00095 dtrs = inspect.getmembers(genDbi,lambda o:inspect.isclass(o) and o.__name__[0] == 'G')
00096 locals().update( dtrs )
00097 GNAMES = map( lambda _:_[0] , dtrs )
00098 __all__ += GNAMES + ["GNAMES"]
00099
00100
00101 DbiCascader.__skip__ = "Connection DbName DbNo Status StatusAsString URL TableDbNo".split()
00102 DbiValidityRec.__skip__ = "Owner Index Row RowByIndex TableProxy".split()
00103 DbiTableProxy.__skip__ = "Cascader DBProxy MetaData MetaValid RowName TableName".split()
00104 DbiTableProxyRegistry.__skip__ = "TableProxy".split()
00105
00106
00107 attfn = dict(
00108 UpdateMask=lambda obj:("UpdateMask",Ctx.StringFromMask( obj.GetUpdateMask() )),
00109 Mask=lambda obj:("Mask", Ctx.StringFromMask( obj.GetMask() )),
00110 SimMask=lambda obj:("SimMask",SimFlag.StringFromMask( obj.GetSimMask() )),
00111 SiteMask=lambda obj:("SiteMask",Site.StringFromMask( obj.GetSiteMask() )),
00112 )
00113
00114
00115
00116 from csvrw import CSV, Source
00117 from mapper import Mapper
00118
00119
00120
00121 from wrap import Wrap
00122 for n,cls in clss:
00123
00124 Wrap.wrap(cls, attfn)
00125
00126
00127 for n,dtr in dtrs:
00128
00129 dtr.__skip__ = "Owner Index Row RowByIndex".split()
00130 if hasattr( dtr, 'Docstring' ):
00131 dtr.__doc__ = dtr.Docstring
00132 Wrap.wrap( dtr )
00133 Wrap.wrap( getattr(gbl, "DbiRpt<%s>" % n ) )
00134 Wrap.wrap( getattr(gbl, "DbiWrt<%s>" % n ) )
00135
00136 def DbiCascader__getitem__(self, i ):
00137 l = self.GetNumDb()
00138 if -1 < i < l:
00139 return self.GetConnection(i)
00140 raise IndexError("out of range for index %d" % i )
00141 DbiCascader.__getitem__ = DbiCascader__getitem__
00142 DbiCascader.__len__ = DbiCascader.GetNumDb
00143
00144 def DbiCascader__repr__(self):
00145 smry = "DbiCascader numdb %s authorisingdbno %s (1st with GLOBALSEQNO) " % ( self.GetNumDb(), self.GetAuthorisingDbNo() )
00146 return "\n".join([smry] + [ "%-10s %s " % ( self.GetStatusAsString(i), repr(con)) for i,con in enumerate(self) ])
00147 DbiCascader.__repr__ = DbiCascader__repr__
00148
00149 def DbiCascader__check(self):
00150 for i,con in enumerate(self):
00151 n = con.numconnectedstatements
00152 assert n == 0 , ( n, i, con )
00153 DbiCascader.check = DbiCascader__check
00154
00155 def DbiConnection__repr__(self):
00156 return " %-20s #%d %-10s %-10s %s " % ( self.GetDbName(), self.GetNumConnectedStatements(), ("not-tmp","tmp")[self.IsTemporary()] , ("open","closed")[self.IsClosed()] , self.GetUrl() )
00157 DbiConnection.__repr__ = DbiConnection__repr__
00158
00159 def DbiStatement__del__(self):
00160 print "DbiStatement__del__ committing hari-kari "
00161 self.IsA().Destructor(self)
00162 DbiStatement.__del__ = DbiStatement__del__
00163
00164
00165 def DbiCtx__repr__(self):
00166 """
00167 Special handling of the DbiCtx repr so that only properties
00168 that have been set (as recorded in the "mask" property ) are shown
00169 """
00170 getters = Wrap(DbiCtx).getters
00171 prps = [ (g,getattr(self,'Get%s'%g)()) for g in getters if getattr( Ctx,'k%s'%g , 0) & self.mask > 0 or getattr( Ctx,'k%s'%g , 0) == 0 ]
00172 return pprint.pformat( dict( prps ) ,indent=4)
00173 DbiCtx.__repr__ = DbiCtx__repr__
00174
00175 def DbiCtx__call__( self, *args , **kwa ):
00176 """
00177 Shorthand context attribute setting in kwa style
00178 """
00179 for arg in args:
00180 self.Update(arg)
00181 for k,v in kwa.items():
00182 setattr( self, k, v )
00183 return self
00184 DbiCtx.__call__ = DbiCtx__call__
00185
00186
00187 def DybDbi__comment( self, *args , **kwa ):
00188 """
00189 Cheap trick to scribble on the mysql command list ... in order to see the order of things::
00190
00191 gDbi.comment("hello","world")
00192
00193 """
00194 dbno = kwa.pop('dbno', 0)
00195 comment = "\n".join(map(lambda l:"# %s"%l, args))
00196 log.info( comment )
00197 self.cascader[dbno].CreatePreparedStatement( comment )
00198 pass
00199 DybDbi.comment = DybDbi__comment
00200
00201
00202
00203
00204
00205
00206
00207 detector_reps = dict(
00208 detName=lambda x:x.detName(),
00209 site=lambda x:Site.AsString(x.site()) ,
00210 detectorId=lambda x:DetectorId.AsString(x.detectorId()),
00211 sensorId=lambda x:x.sensorId(),
00212 ring=lambda x:x.ring(),
00213 column=lambda x:x.column(),
00214 wallNumber=lambda x:x.wallNumber(),
00215 wallSpot=lambda x:x.wallSpot(),
00216 panelRow=lambda x:x.panelRow(),
00217 layer=lambda x:x.layer(),
00218 strip=lambda x:x.strip(),
00219 )
00220 DetectorSensor.__repr__ = lambda self:pprint.pformat(dict([(n,detector_reps[n](self) ) for n in dir(DetectorSensor) if n in detector_reps ]), indent=4 )
00221
00222
00223 from TimeStampExt import *
00224
00225
00226
00227 from nose.tools import make_decorator
00228 from datetime import datetime
00229
00230
00231 from DybPython import DBConf, DBCas
00232
00233 class Level(int):
00234 """
00235
00236 =============== =========================================
00237 OutputLevel
00238 =============== =========================================
00239 WARNING (110) quiet enough for overview of errors
00240 INFO (100) normal
00241 DEBUG (50) quite a few errors to chase
00242 =============== =========================================
00243 """
00244 levels = dict( VERBOSE=1, DEBUG3=60, DEBUG2=70, DEBUG1=80, MONITOR=90, INFO=100, WARNING=110, ERROR=130, FATAL=140, NEVER=99999 )
00245 def From(cls, s):
00246 """Converts level names to DBI OutputLevel enum integers, or vv """
00247 if isinstance( s, basestring):
00248 val = cls.levels.get( s.upper() , None)
00249 assert val , "level %s is not recogized %s " % ( s, repr(cls.levels) )
00250 return Level(val)
00251 elif isinstance( s, int ):
00252 return Level(s)
00253 else:
00254 return None
00255 From = classmethod(From)
00256 def __repr__(self):
00257 return "Level %s " % ( int(self) )
00258
00259 def LOG(level="INFO"):
00260 """
00261 By wrapping a test function with this decorator,
00262 the logging level is changed to the chosen level
00263 while the test is running.
00264 """
00265 level = Level.From(level)
00266 def _decorate(func):
00267 def _wrapper(*args, **kargs):
00268 gDbi.comment("entering %s " % func.__name__ , "")
00269 ol = gDbi.GetOutputLevel()
00270 gDbi.SetOutputLevel(level)
00271 func(*args, **kargs)
00272 gDbi.SetOutputLevel(ol)
00273 gDbi.comment("exiting %s " % func.__name__ , "")
00274 _wrapper = make_decorator(func)(_wrapper)
00275 return _wrapper
00276 return _decorate
00277
00278 def MYSQLDUMP(level="INFO", opt=" --extended-insert=0 --skip-comments " , cfdir=None, reference=False ):
00279 """
00280 By wrapping a test function with this decorator,
00281 the database is mysqldumped after the test has run
00282
00283 The output dumps are saved in a directory created at path
00284 based on the names of test module and function
00285 """
00286 level = Level.From(level)
00287 def _decorate(func):
00288 def _wrapper(*args, **kargs):
00289 print "MYSQLDUMP for func %s " % ( func.__name__ )
00290 ol = gDbi.GetOutputLevel()
00291 gDbi.SetOutputLevel(level)
00292 func(*args, **kargs)
00293 gDbi.SetOutputLevel(ol)
00294 dir = os.path.join( os.getcwd(), "tests", func.__module__ , func.__name__ )
00295 DBCas.Dump( dir=dir, opt=opt , cfdir=cfdir, reference=reference )
00296 _wrapper = make_decorator(func)(_wrapper)
00297 return _wrapper
00298 return _decorate
00299
00300
00301 def POST(level="WARNING"):
00302 """
00303 By wrapping a test function with this decorator, some
00304 post test checks are performed on the cascade
00305
00306 Distributing usage of this throughout the a collection of
00307 nosetests is useful when searching for which test is messing something up.
00308 """
00309 level = Level.From(level)
00310 def _decorate(func):
00311 def _wrapper(*args, **kargs):
00312 print "POST for func %s " % ( func.__name__ )
00313 ol = gDbi.outputlevel
00314 gDbi.outputlevel = level
00315 func(*args, **kargs)
00316 gDbi.cascader.check()
00317 gDbi.outputlevel = ol
00318 _wrapper = make_decorator(func)(_wrapper)
00319 return _wrapper
00320 return _decorate
00321
00322
00323
00324
00325 __all__ += "LOG MYSQLDUMP POST".split()
00326
00327
00328
00329