/search.css" rel="stylesheet" type="text/css"/> /search.js">
00001 #!/usr/bin/env python 00002 """ 00003 For debugging:: 00004 00005 ipython vrb.py 00006 00007 """ 00008 00009 import os, logging 00010 from pprint import pformat 00011 log = logging.getLogger(__name__) 00012 00013 def parse_cfg( val ): 00014 """ 00015 Parse config like the below into dict:: 00016 00017 [mig20120820] 00018 src = GCalibPmtHighGainPariah -1 27877 6533 00019 tgt = GCalibPmtFineGain 1 1410 6533 00020 00021 """ 00022 bits = val.split(' ') ; assert len(bits) == 4, "unexpected fields in value %s %s " % (repr(bits), val) 00023 return dict(kln=bits[0],task=int(bits[1]),offseq=int(bits[2]),count=int(bits[3])) 00024 00025 00026 class CFConf(dict): 00027 """ 00028 Usage:: 00029 00030 from tools impoty CFConf 00031 def handler( val ): 00032 return dict() 00033 cfc = CFConf("offsets.cfg", "mig20120820", handler ) 00034 00035 The handler parses the config value and returns a dict 00036 00037 """ 00038 def __init__(self, path, section , parse_cfg_ = lambda _:{} ): 00039 dict.__init__(self) 00040 from ConfigParser import ConfigParser 00041 cfp = ConfigParser() 00042 cfp.optionxform = str ## avoid lowercasing keys, making the keys case sensitive 00043 path = os.path.expandvars(os.path.expanduser(path)) 00044 cfp.read(path) 00045 assert cfp.has_section(section), "section %s not present in config file %s " % ( section, path) 00046 for key, val in cfp.items(section): 00047 self[key] = parse_cfg_( val ) 00048 00049 def __repr__(self): 00050 return pformat(dict(self)) 00051 00052 00053 00054 def pydigest_( rpt , first=0 ): 00055 """ 00056 :param first: index of first column to include in digest 00057 00058 The default `first=0` duplicates the C++ `rpt.digest`. 00059 The python version can in addition restrict the comparison to ignore columns. 00060 00061 The vals are strings like:: 00062 00063 67241993 20.937 0.203 6.333 0.94 00064 67241994 18.892 0.146 5.217 1.03 00065 00066 Thus using a `first=1` allows digest content 00067 comparisons between tables using sensorid and channelid keys 00068 00069 """ 00070 from ROOT import TMD5 00071 md5 = TMD5() 00072 for i,r in enumerate(rpt): 00073 vals = " ".join(r.values.split(" ")[first:]) 00074 if i == 0: 00075 log.debug(vals) 00076 md5.Update(vals, len(vals)) 00077 md5.Final() 00078 return md5.AsString() 00079 00080 00081 class CompareVrb(dict): 00082 def __init__(self, **kwa): 00083 dict.__init__(self, **kwa) 00084 00085 def __call__(self): 00086 rpt = {} 00087 ldict = {} 00088 for tag, vrb in self.items(): 00089 ldict[tag] = len(vrb) 00090 rpt[tag] = vrb.kls.Rpt().Clone() 00091 self.rpt = rpt 00092 00093 lset = list(set(ldict.values())) # uniquing by passing thru the set 00094 assert len(lset) == 1, ("all argument vrb required to have the same length", ldict ) 00095 self.length = lset[0] 00096 00097 def check_payload(self, first=0, check=None): 00098 """ 00099 SEQNO by SEQNO comparisons of digests between tables 00100 00101 :param first: column index to start the digest from, 1 to skip first column, 0 to include all 00102 :param check: function that accepts single arguement, the single seqno dict 00103 00104 C++ digests `rpt.digest` are constructed from all values in the payloads allowing 00105 a quick way to check payload correspondence between multiple tables 00106 """ 00107 for i in range(self.length): 00108 d = dict(index=i) 00109 for tag,vrb in self.items(): 00110 vrec = vrb.offseq_(i) 00111 self.rpt[tag].ctx( validityrec=vrec ) 00112 d[tag] = dict(seqno=vrec.seqno,digest=self.rpt[tag].digest,pydigest=pydigest_(self.rpt[tag], first=first)) 00113 tags = self.keys() 00114 for tag in tags[1:]: 00115 assert d[tags[0]]['pydigest'] == d[tag]['pydigest'], ("pydigest mismatch", d ) 00116 if check: 00117 check(d) 00118 00119 def check_validity(self, check=None ): 00120 """ 00121 SEQNO by SEQNO comparisons of validity fields between tables 00122 """ 00123 pass 00124 for i in range(self.length): 00125 v = dict(index=i) 00126 for tag,vrb in self.items(): 00127 vrec = vrb.offseq_(i) 00128 for qwn in Vrec.qwns: 00129 if qwn not in v: 00130 v[qwn] = {} 00131 qbit = qwn.split(".") 00132 if len(qbit) == 2: 00133 g_ = lambda vrec:getattr(getattr(vrec,qbit[0]),qbit[1]) 00134 else: 00135 g_ = lambda vrec:getattr(vrec,qwn) 00136 v[qwn][tag] = g_(vrec) 00137 pass 00138 if check: 00139 check(v) 00140 00141 00142 00143 00144 class Vrec(object): 00145 qwns = "contextrange.timestart contextrange.timeend contextrange.sitemask contextrange.simmask subsite task aggregateno versiondate".split() 00146 def __init__(self, vrec ): 00147 self.vrec = vrec 00148 00149 def vdict(self): 00150 v = {} 00151 for qwn in self.qwns: 00152 qbit = qwn.split(".") 00153 g_ = lambda vrec:getattr(getattr(vrec,qbit[0]),qbit[1]) if len(qbit) == 2 else lambda vrec:getattr(vrec,qwn) 00154 v[qwn] = g_(self.vrec) 00155 return v 00156 00157 00158 class Vrb(object): 00159 def __init__(self, kls, task=-1, offseq=0, sqlcontext="1=1", subsite=-1 ): 00160 """ 00161 :param kls: 00162 :param task: 00163 :param offseq: seqno offset, used by offseq_ for comparison between tables with shifted SEQNO 00164 """ 00165 self.vrb = kls.GetTableProxy().MakeValidityRecBuilder( sqlcontext, subsite, task ) 00166 self.seqnos = map(lambda _:_.seqno, self.vrb) 00167 self.seqnos.sort() 00168 self.kls = kls 00169 self.offseq = offseq 00170 self.cursor = 0 00171 00172 00173 def __len__(self): 00174 return len(self.vrb) 00175 00176 def __getitem__(self, rowNo ): 00177 """ 00178 List access with square brackets queries by rowNo. 00179 But the ordering appears to make no sense, so not very useful. 00180 """ 00181 return self.vrb.__getitem__(rowNo) 00182 00183 def offseq_( self, count ): 00184 return self( self.offseq + count + 1 ) 00185 00186 def __call__(self, seqno): 00187 """ 00188 Call access with round brackets queries by SEQNO 00189 00190 :param seqno: 00191 """ 00192 return self.vrb.GetValidityRecFromSeqNo(seqno) 00193 00194 def purge(self): 00195 self.kls.GetTableProxy().GetCache().Purge() 00196 00197 def __iter__(self): 00198 return self 00199 00200 def next(self): 00201 """ 00202 Adds iterability to the Vrb providing (seqno, vrec) tuples 00203 """ 00204 if self.cursor >= len(self.seqnos) or self.cursor < 0: 00205 raise StopIteration 00206 else: 00207 seqno = self.seqnos[self.cursor] 00208 vrec = self(seqno) 00209 assert seqno == vrec.seqno, ("seqno vrec.seqno mismatch", seqno, vrec.seqno) 00210 self.cursor += 1 00211 return ( seqno, vrec ) 00212 00213 def replace_insertdate( self, ts=None, seqnos=[], dbno=0 ): 00214 """ 00215 The functionality of changeing INSERTDATES is not for general use. 00216 It is intended for special purpose usage only, as INSERTDATEs are subsequently 00217 fastforwarded to real times anyhow as part of the Standard Operation Procedures. 00218 """ 00219 nrep = 0 00220 if not ts: 00221 ts = TimeStamp() 00222 tbProxy = self.kls.GetTableProxy() 00223 dbProxy = tbProxy.GetDBProxy() 00224 for seqno,vrec in self: 00225 if len(seqnos) == 0 or seqno in seqnos: 00226 print "%-4s %s %s " % ( seqno, vrec.insertdate, ts ) 00227 dbProxy.ReplaceInsertDate( ts, seqno, dbno ) 00228 nrep +=1 00229 return nrep 00230 00231 00232 00233 if __name__ == '__main__': 00234 os.environ.setdefault('DBCONF','tmp_offline_db') 00235 cfconf = 'test' 00236 cfc = CFConf("cfconf.cfg",cfconf, parse_cfg ) 00237 00238 import DybDbi 00239 DybDbi.gDbi.level = "WARNING" 00240 00241 cv = CompareVrb() 00242 for k, d in cfc.items(): 00243 kls = getattr(DybDbi, d['kln'] ) 00244 vrb = Vrb(kls, d['task'], offseq=d['offseq'] ) 00245 assert len(vrb) == d['count'], ("unexpected length", d, vrb ) 00246 cv[k] = vrb 00247 cv() 00248 00249 vrb = cv['tgt'] 00250 vrec = vrb.offseq_(0) 00251 vrec_ = Vrec(vrec) 00252 print vrec_.vdict() 00253 00254 00255