Gaudi Framework, version v21r4

Home   Generated: 7 Sep 2009

GaudiTest Namespace Reference


Classes

class  TemporaryEnvironment
class  TempDir
class  TempFile
class  CMT
class  BasicOutputValidator
class  FilePreprocessor
class  FilePreprocessorSequence
class  LineSkipper
class  BlockSkipper
class  RegexpReplacer
class  LineSorter
 Special preprocessor sorting the list of strings (whitespace separated) that follow a signature on a single line. More...
class  ReferenceFileValidator
class  GaudiFilterExecutable
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 594 of file GaudiTest.py.

00594                                   :
00595     """
00596     Parse the TTree summary table in lines, starting from pos.
00597     Returns a tuple with the dictionary with the digested informations and the
00598     position of the first line after the summary.
00599     """
00600     result = {}
00601     i = pos + 1 # first line is a sequence of '*'
00602     count = len(lines)
00603     
00604     splitcols = lambda l: [ f.strip() for f in l.strip("*\n").split(':',2) ]
00605     def parseblock(ll):
00606         r = {}
00607         cols = splitcols(ll[0])
00608         r["Name"], r["Title"] = cols[1:]
00609         
00610         cols = splitcols(ll[1])
00611         r["Entries"] = int(cols[1])
00612         
00613         sizes = cols[2].split()
00614         r["Total size"] = int(sizes[2])
00615         if sizes[-1] == "memory":
00616             r["File size"] = 0
00617         else:
00618             r["File size"] = int(sizes[-1])
00619         
00620         cols = splitcols(ll[2])
00621         sizes = cols[2].split()
00622         if cols[0] == "Baskets":
00623             r["Baskets"] = int(cols[1])
00624             r["Basket size"] = int(sizes[2])
00625         r["Compression"] = float(sizes[-1])
00626         return r    
00627         
00628     if i < (count - 3) and lines[i].startswith("*Tree"):
00629         result = parseblock(lines[i:i+3])
00630         result["Branches"] = {}
00631         i += 4
00632         while i < (count - 3) and lines[i].startswith("*Br"):
00633             branch = parseblock(lines[i:i+3])
00634             result["Branches"][branch["Name"]] = branch
00635             i += 4
00636         
00637     return (result, i)
00638 
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 660 of file GaudiTest.py.

00660                                                      :
00661     """
00662     Check that all the keys in reference are in to_check too, with the same value.
00663     If the value is a dict, the function is called recursively. to_check can
00664     contain more keys than reference, that will not be tested.
00665     The function returns at the first difference found. 
00666     """
00667     fail_keys = []
00668     # filter the keys in the reference dictionary
00669     if ignore:
00670         ignore_re = re.compile(ignore)
00671         keys = [ key for key in reference if not ignore_re.match(key) ]
00672     else:
00673         keys = reference.keys()
00674     # loop over the keys (not ignored) in the reference dictionary
00675     for k in keys:
00676         if k in to_check: # the key must be in the dictionary to_check
00677             if (type(reference[k]) is dict) and (type(to_check[k]) is dict):
00678                 # if both reference and to_check values are dictionaries, recurse
00679                 failed = fail_keys = cmpTreesDicts(reference[k], to_check[k], ignore)
00680             else:
00681                 # compare the two values
00682                 failed = to_check[k] != reference[k]
00683         else: # handle missing keys in the dictionary to check (i.e. failure)
00684             to_check[k] = None
00685             failed = True
00686         if failed:
00687             fail_keys.insert(0, k)
00688             break # exit from the loop at the first failure
00689     return fail_keys # return the list of keys bringing to the different values
00690 
def getCmpFailingValues(reference, to_check, fail_path):

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

Definition at line 558 of file GaudiTest.py.

00558                                {'ERROR':0, 'FATAL':0}, **kwargs):
00559     """
00560     Count the number of messages with required severity (by default ERROR and FATAL)
00561     and check if their numbers match the expected ones (0 by default).
00562     The dictionary "expected" can be used to tune the number of errors and fatals
00563     allowed, or to limit the number of expected warnings etc.
00564     """
00565     stdout = kwargs["stdout"]
00566     result = kwargs["result"]
00567     causes = kwargs["causes"]
00568     
00569     # prepare the dictionary to record the extracted lines
00570     errors = {}
00571     for sev in expected:
00572         errors[sev] = []
00573     
00574     outlines = stdout.splitlines()
00575     from math import log10
00576     fmt = "%%%dd - %%s" % (int(log10(len(outlines))+1))
00577     
00578     linecount = 0
00579     for l in outlines:
00580         linecount += 1
00581         words = l.split()
00582         if len(words) >= 2 and words[1] in errors:
00583             errors[words[1]].append(fmt%(linecount,l.rstrip()))
00584     
00585     for e in errors:
00586         if len(errors[e]) != expected[e]:
00587             causes.append('%s(%d)'%(e,len(errors[e])))
00588             result["GaudiTest.lines.%s"%e] = result.Quote('\n'.join(errors[e]))
00589             result["GaudiTest.lines.%s.expected#"%e] = result.Quote(str(expected[e]))
00590     
00591     return causes
00592 
00593 

def GaudiTest::findHistosSummaries (   stdout  ) 

Scan stdout to find ROOT TTree summaries and digest them.

Definition at line 767 of file GaudiTest.py.

00767                                :
00768     """
00769     Scan stdout to find ROOT TTree summaries and digest them.
00770     """
00771     outlines = stdout.splitlines()
00772     nlines = len(outlines) - 1
00773     summaries = {}
00774     global h_count_re
00775     
00776     pos = 0
00777     while pos < nlines:
00778         summ = {}
00779         # find first line of block:
00780         match = h_count_re.search(outlines[pos])
00781         while pos < nlines and not match:
00782             pos += 1
00783             match = h_count_re.search(outlines[pos])
00784         if match:
00785             summ, pos = parseHistosSummary(outlines, pos)
00786         summaries.update(summ)
00787     return summaries
00788 
class GaudiFilterExecutable(qm.executable.Filter):

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 511 of file GaudiTest.py.

00512                                  :
00513     """
00514     Given a block of text, tries to find it in the output.
00515     The block had to be identified by a signature line. By default, the first
00516     line is used as signature, or the line pointed to by signature_offset. If
00517     signature_offset points outside the block, a signature line can be passed as
00518     signature argument. Note: if 'signature' is None (the default), a negative
00519     signature_offset is interpreted as index in a list (e.g. -1 means the last
00520     line), otherwise the it is interpreted as the number of lines before the
00521     first one of the block the signature must appear.
00522     The parameter 'id' allow to distinguish between different calls to this
00523     function in the same validation code.
00524     """
00525     # split reference file, sanitize EOLs and remove empty lines
00526     reflines = filter(None,map(lambda s: s.rstrip(), reference.splitlines()))
00527     if not reflines:
00528         raise RuntimeError("Empty (or null) reference")
00529     # the same on standard output
00530     outlines = filter(None,map(lambda s: s.rstrip(), stdout.splitlines()))
00531     
00532     res_field = "GaudiTest.RefBlock"
00533     if id:
00534         res_field += "_%s" % id 
00535     
00536     if signature is None:
00537         if signature_offset < 0:
00538             signature_offset = len(reference)+signature_offset
00539         signature = reflines[signature_offset]
00540     # find the reference block in the output file
00541     try:
00542         pos = outlines.index(signature)
00543         outlines = outlines[pos-signature_offset:pos+len(reflines)-signature_offset]
00544         if reflines != outlines:
00545             msg = "standard output"
00546             # I do not want 2 messages in causes if teh function is called twice
00547             if not msg in causes: 
00548                 causes.append(msg)
00549             result[res_field + ".observed"] = result.Quote("\n".join(outlines))
00550     except ValueError:
00551         causes.append("missing signature")
00552     result[res_field + ".signature"] = result.Quote(signature)
00553     if len(reflines) > 1 or signature != reflines[0]:
00554         result[res_field + ".expected"] = result.Quote("\n".join(reflines))
00555     
00556     return causes
00557 
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 639 of file GaudiTest.py.

00639                               :
00640     """
00641     Scan stdout to find ROOT TTree summaries and digest them.
00642     """
00643     stars = re.compile(r"^\*+$")
00644     outlines = stdout.splitlines()
00645     nlines = len(outlines)
00646     trees = {}
00647     
00648     i = 0
00649     while i < nlines: #loop over the output
00650         # look for
00651         while i < nlines and not stars.match(outlines[i]):
00652             i += 1
00653         if i < nlines:
00654             tree, i = _parseTTreeSummary(outlines, i)
00655             if tree:
00656                 trees[tree["Name"]] = tree
00657     
00658     return trees
00659 
def cmpTreesDicts(reference, to_check, ignore = None):

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

Definition at line 691 of file GaudiTest.py.

00691                                                        :
00692     c = to_check
00693     r = reference
00694     for k in fail_path:
00695         c = c.get(k,None)
00696         r = r.get(k,None)
00697         if c is None or r is None:
00698             break # one of the dictionaries is not deep enough
00699     return (fail_path, r, c)
00700 
00701 # 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 704 of file GaudiTest.py.

00704                                   :
00705     """
00706     Extract the histograms infos from the lines starting at pos.
00707     Returns the position of the first line after the summary block.
00708     """
00709     global h_count_re
00710     h_table_head = re.compile(r'SUCCESS\s+List of booked (1D|2D|3D|1D profile|2D profile) histograms in directory\s+"(\w*)"')
00711     h_short_summ = re.compile(r"ID=([^\"]+)\s+\"([^\"]+)\"\s+(.*)")
00712     
00713     nlines = len(lines)
00714     
00715     # decode header
00716     m = h_count_re.search(lines[pos])
00717     name = m.group(1).strip()
00718     total = int(m.group(2))
00719     header = {}
00720     for k, v in [ x.split("=") for x in  m.group(3).split() ]:
00721         header[k] = int(v)
00722     pos += 1
00723     header["Total"] = total
00724     
00725     summ = {}
00726     while pos < nlines:
00727         m = h_table_head.search(lines[pos])
00728         if m:
00729             t, d = m.groups(1) # type and directory
00730             t = t.replace(" profile", "Prof")
00731             pos += 1
00732             if pos < nlines:
00733                 l = lines[pos]
00734             else:
00735                 l = ""
00736             cont = {}
00737             if l.startswith(" | ID"):
00738                 # table format
00739                 titles = [ x.strip() for x in l.split("|")][1:]
00740                 pos += 1
00741                 while pos < nlines and lines[pos].startswith(" |"):
00742                     l = lines[pos]
00743                     values = [ x.strip() for x in l.split("|")][1:]
00744                     hcont = {}
00745                     for i in range(len(titles)):
00746                         hcont[titles[i]] = values[i]
00747                     cont[hcont["ID"]] = hcont
00748                     pos += 1
00749             elif l.startswith(" ID="):
00750                 while pos < nlines and lines[pos].startswith(" ID="):
00751                     values = [ x.strip() for x in  h_short_summ.search(lines[pos]).groups() ]
00752                     cont[values[0]] = values
00753                     pos += 1
00754             else: # not interpreted
00755                 raise RuntimeError("Cannot understand line %d: '%s'" % (pos, l))
00756             if not d in summ:
00757                 summ[d] = {}
00758             summ[d][t] = cont
00759             summ[d]["header"] = header
00760         else:
00761             break
00762     if not summ:
00763         # If the full table is not present, we use only the header
00764         summ[name] = {"header": header}
00765     return summ, pos
00766 
def findHistosSummaries(stdout):


Variable Documentation

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

Definition at line 5 of file GaudiTest.py.

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

Definition at line 7 of file GaudiTest.py.

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

Definition at line 6 of file GaudiTest.py.

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

Definition at line 702 of file GaudiTest.py.

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

Definition at line 390 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 391 of file GaudiTest.py.

Definition at line 393 of file GaudiTest.py.

Definition at line 416 of file GaudiTest.py.

Definition at line 396 of file GaudiTest.py.


Generated at Mon Sep 7 18:26:43 2009 for Gaudi Framework, version v21r4 by Doxygen version 1.5.6 written by Dimitri van Heesch, © 1997-2004