Gaudi Framework, version v20r4

Generated: 8 Jan 2009

GaudiTest Namespace Reference


Classes

class  TemporaryEnvironment
class  TempDir
class  TempFile
class  CMT
class  BasicOutputValidator
class  FilePreprocessor
class  FilePreprocessorSequence
class  LineSkipper
class  RegexpReplacer
class  ReferenceFileValidator
class  GaudiExeTest

Functions

def findReferenceBlock
def countErrorLines
def _parseTTreeSummary
def findTTreeSummaries
def cmpTreesDicts
def getCmpFailingValues
def parseHistosSummary
def findHistosSummaries

Variables

string __author__ = 'Marco Clemencic CERN/PH-LBC'
string __version__ = "$Revision: 1.52 $"
string __tag__ = "$Name: $"
tuple maskPointers = RegexpReplacer("0x[0-9a-fA-F]{4,16}","0x########")
tuple normalizeDate
tuple normalizeEOL = FilePreprocessor()
tuple skipEmptyLines = FilePreprocessor()
 normalizeExamples = maskPointers+normalizeDate
tuple h_count_re = re.compile(r"SUCCESS\s+Booked (\d+) Histogram\(s\) :\s+(.*)")


Function Documentation

def GaudiTest::_parseTTreeSummary (   lines,
  pos 
) [private]

Parse the TTree summary table in lines, starting from pos.
Returns a tuple with the dictionary with the digested informations and the
position of the first line after the summary.

Definition at line 557 of file GaudiTest.py.

00557                                   :
00558     """
00559     Parse the TTree summary table in lines, starting from pos.
00560     Returns a tuple with the dictionary with the digested informations and the
00561     position of the first line after the summary.
00562     """
00563     result = {}
00564     i = pos + 1 # first line is a sequence of '*'
00565     count = len(lines)
00566     
00567     splitcols = lambda l: [ f.strip() for f in l.strip("*\n").split(':',2) ]
00568     def parseblock(ll):
00569         r = {}
00570         cols = splitcols(ll[0])
00571         r["Name"], r["Title"] = cols[1:]
00572         
00573         cols = splitcols(ll[1])
00574         r["Entries"] = int(cols[1])
00575         
00576         sizes = cols[2].split()
00577         r["Total size"] = int(sizes[2])
00578         if sizes[-1] == "memory":
00579             r["File size"] = 0
00580         else:
00581             r["File size"] = int(sizes[-1])
00582         
00583         cols = splitcols(ll[2])
00584         sizes = cols[2].split()
00585         if cols[0] == "Baskets":
00586             r["Baskets"] = int(cols[1])
00587             r["Basket size"] = int(sizes[2])
00588         r["Compression"] = float(sizes[-1])
00589         return r    
00590         
00591     if i < (count - 3) and lines[i].startswith("*Tree"):
00592         result = parseblock(lines[i:i+3])
00593         result["Branches"] = {}
00594         i += 4
00595         while i < (count - 3) and lines[i].startswith("*Br"):
00596             branch = parseblock(lines[i:i+3])
00597             result["Branches"][branch["Name"]] = branch
00598             i += 4
00599         
00600     return (result, i)
00601 
def findTTreeSummaries(stdout):

def GaudiTest::cmpTreesDicts (   reference,
  to_check,
  ignore = None 
)

Check that all the keys in reference are in to_check too, with the same value.
If the value is a dict, the function is called recursively. to_check can
contain more keys than reference, that will not be tested.
The function returns at the first difference found. 

Definition at line 623 of file GaudiTest.py.

00623                                                      :
00624     """
00625     Check that all the keys in reference are in to_check too, with the same value.
00626     If the value is a dict, the function is called recursively. to_check can
00627     contain more keys than reference, that will not be tested.
00628     The function returns at the first difference found. 
00629     """
00630     fail_keys = []
00631     # filter the keys in the reference dictionary
00632     if ignore:
00633         ignore_re = re.compile(ignore)
00634         keys = [ key for key in reference if not ignore_re.match(key) ]
00635     else:
00636         keys = reference.keys()
00637     # loop over the keys (not ignored) in the reference dictionary
00638     for k in keys:
00639         if k in to_check: # the key must be in the dictionary to_check
00640             if (type(reference[k]) is dict) and (type(to_check[k]) is dict):
00641                 # if both reference and to_check values are dictionaries, recurse
00642                 failed = fail_keys = cmpTreesDicts(reference[k], to_check[k], ignore)
00643             else:
00644                 # compare the two values
00645                 failed = to_check[k] != reference[k]
00646         else: # handle missing keys in the dictionary to check (i.e. failure)
00647             to_check[k] = None
00648             failed = True
00649         if failed:
00650             fail_keys.insert(0, k)
00651             break # exit from the loop at the first failure
00652     return fail_keys # return the list of keys bringing to the different values
00653 
def getCmpFailingValues(reference, to_check, fail_path):

def GaudiTest::countErrorLines (   expected = {'ERROR':0,
  FATAL 
)

Definition at line 521 of file GaudiTest.py.

00521                                {'ERROR':0, 'FATAL':0}, **kwargs):
00522     """
00523     Count the number of messages with required severity (by default ERROR and FATAL)
00524     and check if their numbers match the expected ones (0 by default).
00525     The dictionary "expected" can be used to tune the number of errors and fatals
00526     allowed, or to limit the number of expected warnings etc.
00527     """
00528     stdout = kwargs["stdout"]
00529     result = kwargs["result"]
00530     causes = kwargs["causes"]
00531     
00532     # prepare the dictionary to record the extracted lines
00533     errors = {}
00534     for sev in expected:
00535         errors[sev] = []
00536     
00537     outlines = stdout.splitlines()
00538     from math import log10
00539     fmt = "%%%dd - %%s" % (int(log10(len(outlines))+1))
00540     
00541     linecount = 0
00542     for l in outlines:
00543         linecount += 1
00544         words = l.split()
00545         if len(words) >= 2 and words[1] in errors:
00546             errors[words[1]].append(fmt%(linecount,l.rstrip()))
00547     
00548     for e in errors:
00549         if len(errors[e]) != expected[e]:
00550             causes.append('%s(%d)'%(e,len(errors[e])))
00551             result["GaudiTest.lines.%s"%e] = result.Quote('\n'.join(errors[e]))
00552             result["GaudiTest.lines.%s.expected#"%e] = result.Quote(str(expected[e]))
00553     
00554     return causes
00555 
00556 

def GaudiTest::findHistosSummaries (   stdout  ) 

Scan stdout to find ROOT TTree summaries and digest them.

Definition at line 726 of file GaudiTest.py.

00726                                :
00727     """
00728     Scan stdout to find ROOT TTree summaries and digest them.
00729     """
00730     outlines = stdout.splitlines()
00731     nlines = len(outlines) - 1
00732     summaries = {}
00733     global h_count_re
00734     
00735     pos = 0
00736     while pos < nlines:
00737         summ = {}
00738         # find first line of block:
00739         match = h_count_re.search(outlines[pos])
00740         while pos < nlines and not match:
00741             pos += 1
00742             match = h_count_re.search(outlines[pos])
00743         if match:
00744             summ, pos = parseHistosSummary(outlines, pos)
00745         summaries.update(summ)
00746     return summaries
00747     
########################################################################

def GaudiTest::findReferenceBlock (   reference,
  stdout,
  result,
  causes,
  signature_offset = 0,
  signature = None,
  id = None 
)

Given a block of text, tries to find it in the output.
The block had to be identified by a signature line. By default, the first
line is used as signature, or the line pointed to by signature_offset. If
signature_offset points outside the block, a signature line can be passed as
signature argument. Note: if 'signature' is None (the default), a negative
signature_offset is interpreted as index in a list (e.g. -1 means the last
line), otherwise the it is interpreted as the number of lines before the
first one of the block the signature must appear.
The parameter 'id' allow to distinguish between different calls to this
function in the same validation code.

Definition at line 474 of file GaudiTest.py.

00475                                  :
00476     """
00477     Given a block of text, tries to find it in the output.
00478     The block had to be identified by a signature line. By default, the first
00479     line is used as signature, or the line pointed to by signature_offset. If
00480     signature_offset points outside the block, a signature line can be passed as
00481     signature argument. Note: if 'signature' is None (the default), a negative
00482     signature_offset is interpreted as index in a list (e.g. -1 means the last
00483     line), otherwise the it is interpreted as the number of lines before the
00484     first one of the block the signature must appear.
00485     The parameter 'id' allow to distinguish between different calls to this
00486     function in the same validation code.
00487     """
00488     # split reference file, sanitize EOLs and remove empty lines
00489     reflines = filter(None,map(lambda s: s.rstrip(), reference.splitlines()))
00490     if not reflines:
00491         raise RuntimeError("Empty (or null) reference")
00492     # the same on standard output
00493     outlines = filter(None,map(lambda s: s.rstrip(), stdout.splitlines()))
00494     
00495     res_field = "GaudiTest.RefBlock"
00496     if id:
00497         res_field += "_%s" % id 
00498     
00499     if signature is None:
00500         if signature_offset < 0:
00501             signature_offset = len(reference)+signature_offset
00502         signature = reflines[signature_offset]
00503     # find the reference block in the output file
00504     try:
00505         pos = outlines.index(signature)
00506         outlines = outlines[pos-signature_offset:pos+len(reflines)-signature_offset]
00507         if reflines != outlines:
00508             msg = "standard output"
00509             # I do not want 2 messages in causes if teh function is called twice
00510             if not msg in causes: 
00511                 causes.append(msg)
00512             result[res_field + ".observed"] = result.Quote("\n".join(outlines))
00513     except ValueError:
00514         causes.append("missing signature")
00515     result[res_field + ".signature"] = result.Quote(signature)
00516     if len(reflines) > 1 or signature != reflines[0]:
00517         result[res_field + ".expected"] = result.Quote("\n".join(reflines))
00518     
00519     return causes
00520 
def countErrorLines(expected = {'ERROR':0, 'FATAL':0}, **kwargs):

def GaudiTest::findTTreeSummaries (   stdout  ) 

Scan stdout to find ROOT TTree summaries and digest them.

Definition at line 602 of file GaudiTest.py.

00602                               :
00603     """
00604     Scan stdout to find ROOT TTree summaries and digest them.
00605     """
00606     stars = re.compile(r"^\*+$")
00607     outlines = stdout.splitlines()
00608     nlines = len(outlines)
00609     trees = {}
00610     
00611     i = 0
00612     while i < nlines: #loop over the output
00613         # look for
00614         while i < nlines and not stars.match(outlines[i]):
00615             i += 1
00616         if i < nlines:
00617             tree, i = _parseTTreeSummary(outlines, i)
00618             if tree:
00619                 trees[tree["Name"]] = tree
00620     
00621     return trees
00622 
def cmpTreesDicts(reference, to_check, ignore = None):

def GaudiTest::getCmpFailingValues (   reference,
  to_check,
  fail_path 
)

Definition at line 654 of file GaudiTest.py.

00654                                                        :
00655     c = to_check
00656     r = reference
00657     for k in fail_path:
00658         c = c.get(k,None)
00659         r = r.get(k,None)
00660         if c is None or r is None:
00661             break # one of the dictionaries is not deep enough
00662     return (fail_path, r, c)
00663 
00664 # signature of the print-out of the histograms
h_count_re = re.compile(r"SUCCESS\s+Booked (\d+) Histogram\(s\) :\s+(.*)")

def GaudiTest::parseHistosSummary (   lines,
  pos 
)

Extract the histograms infos from the lines starting at pos.
Returns the position of the first line after the summary block.

Definition at line 667 of file GaudiTest.py.

00667                                   :
00668     """
00669     Extract the histograms infos from the lines starting at pos.
00670     Returns the position of the first line after the summary block.
00671     """
00672     global h_count_re
00673     h_table_head = re.compile(r'SUCCESS\s+List of booked (1D|2D|3D|1D profile|2D profile) histograms in directory\s+"(\w*)"')
00674     h_short_summ = re.compile(r"ID=([^\"]+)\s+\"([^\"]+)\"\s+(.*)")
00675     
00676     nlines = len(lines)
00677     
00678     # decode header
00679     m = h_count_re.search(lines[pos])
00680     total = int(m.group(1))
00681     partials = {}
00682     for k, v in [ x.split("=") for x in  m.group(2).split() ]:
00683         partials[k] = int(v)
00684     pos += 1
00685     
00686     summ = {}
00687     while pos < nlines:
00688         m = h_table_head.search(lines[pos])
00689         if m:
00690             t, d = m.groups(1) # type and directory
00691             t = t.replace(" profile", "Prof")
00692             pos += 1
00693             if pos < nlines:
00694                 l = lines[pos]
00695             else:
00696                 l = ""
00697             cont = {}
00698             if l.startswith(" | ID"):
00699                 # table format
00700                 titles = [ x.strip() for x in l.split("|")][1:]
00701                 pos += 1
00702                 while pos < nlines and lines[pos].startswith(" |"):
00703                     l = lines[pos]
00704                     values = [ x.strip() for x in l.split("|")][1:]
00705                     hcont = {}
00706                     for i in range(len(titles)):
00707                         hcont[titles[i]] = values[i]
00708                     cont[hcont["ID"]] = hcont
00709                     pos += 1
00710             elif l.startswith(" ID="):
00711                 while pos < nlines and lines[pos].startswith(" ID="):
00712                     values = [ x.strip() for x in  h_short_summ.search(lines[pos]).groups() ]
00713                     cont[values[0]] = values
00714                     pos += 1
00715             else: # not interpreted
00716                 raise RuntimeError("Cannot understand line %d: '%s'" % (pos, l))
00717             if not d in summ:
00718                 summ[d] = {}
00719             summ[d][t] = cont
00720             summ[d]["header"] = partials
00721             summ[d]["header"]["Total"] = total
00722         else:
00723             break
00724     return summ, pos
00725 
def findHistosSummaries(stdout):


Variable Documentation

string GaudiTest::__author__ = 'Marco Clemencic CERN/PH-LBC'

Definition at line 24 of file GaudiTest.py.

string GaudiTest::__tag__ = "$Name: $"

Definition at line 26 of file GaudiTest.py.

string GaudiTest::__version__ = "$Revision: 1.52 $"

Definition at line 25 of file GaudiTest.py.

tuple GaudiTest::h_count_re = re.compile(r"SUCCESS\s+Booked (\d+) Histogram\(s\) :\s+(.*)")

Definition at line 665 of file GaudiTest.py.

tuple GaudiTest::maskPointers = RegexpReplacer("0x[0-9a-fA-F]{4,16}","0x########")

Definition at line 372 of file GaudiTest.py.

Initial value:

RegexpReplacer("[0-2]?[0-9]:[0-5][0-9]:[0-5][0-9] [0-9]{4}[-/][01][0-9][-/][0-3][0-9] *(CES?T)?",
                               "00:00:00 1970-01-01")

Definition at line 373 of file GaudiTest.py.

Definition at line 375 of file GaudiTest.py.

Definition at line 383 of file GaudiTest.py.

Definition at line 378 of file GaudiTest.py.


Generated at Thu Jan 8 17:53:59 2009 for Gaudi Framework, version v20r4 by Doxygen version 1.5.6 written by Dimitri van Heesch, © 1997-2004