Gaudi Framework, version v21r8

Home   Generated: 17 Mar 2010

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
class  HTMLResultStream

Functions

def which
 Locates an executable in the executables path ($PATH) and returns the full path to it.
def rationalizepath
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 614 of file GaudiTest.py.

00614                                   :
00615     """
00616     Parse the TTree summary table in lines, starting from pos.
00617     Returns a tuple with the dictionary with the digested informations and the
00618     position of the first line after the summary.
00619     """
00620     result = {}
00621     i = pos + 1 # first line is a sequence of '*'
00622     count = len(lines)
00623     
00624     splitcols = lambda l: [ f.strip() for f in l.strip("*\n").split(':',2) ]
00625     def parseblock(ll):
00626         r = {}
00627         cols = splitcols(ll[0])
00628         r["Name"], r["Title"] = cols[1:]
00629         
00630         cols = splitcols(ll[1])
00631         r["Entries"] = int(cols[1])
00632         
00633         sizes = cols[2].split()
00634         r["Total size"] = int(sizes[2])
00635         if sizes[-1] == "memory":
00636             r["File size"] = 0
00637         else:
00638             r["File size"] = int(sizes[-1])
00639         
00640         cols = splitcols(ll[2])
00641         sizes = cols[2].split()
00642         if cols[0] == "Baskets":
00643             r["Baskets"] = int(cols[1])
00644             r["Basket size"] = int(sizes[2])
00645         r["Compression"] = float(sizes[-1])
00646         return r    
00647         
00648     if i < (count - 3) and lines[i].startswith("*Tree"):
00649         result = parseblock(lines[i:i+3])
00650         result["Branches"] = {}
00651         i += 4
00652         while i < (count - 3) and lines[i].startswith("*Br"):
00653             branch = parseblock(lines[i:i+3])
00654             result["Branches"][branch["Name"]] = branch
00655             i += 4
00656         
00657     return (result, i)
00658 
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 680 of file GaudiTest.py.

00680                                                      :
00681     """
00682     Check that all the keys in reference are in to_check too, with the same value.
00683     If the value is a dict, the function is called recursively. to_check can
00684     contain more keys than reference, that will not be tested.
00685     The function returns at the first difference found. 
00686     """
00687     fail_keys = []
00688     # filter the keys in the reference dictionary
00689     if ignore:
00690         ignore_re = re.compile(ignore)
00691         keys = [ key for key in reference if not ignore_re.match(key) ]
00692     else:
00693         keys = reference.keys()
00694     # loop over the keys (not ignored) in the reference dictionary
00695     for k in keys:
00696         if k in to_check: # the key must be in the dictionary to_check
00697             if (type(reference[k]) is dict) and (type(to_check[k]) is dict):
00698                 # if both reference and to_check values are dictionaries, recurse
00699                 failed = fail_keys = cmpTreesDicts(reference[k], to_check[k], ignore)
00700             else:
00701                 # compare the two values
00702                 failed = to_check[k] != reference[k]
00703         else: # handle missing keys in the dictionary to check (i.e. failure)
00704             to_check[k] = None
00705             failed = True
00706         if failed:
00707             fail_keys.insert(0, k)
00708             break # exit from the loop at the first failure
00709     return fail_keys # return the list of keys bringing to the different values
00710 
def getCmpFailingValues(reference, to_check, fail_path):

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

Definition at line 578 of file GaudiTest.py.

00578                                {'ERROR':0, 'FATAL':0}, **kwargs):
00579     """
00580     Count the number of messages with required severity (by default ERROR and FATAL)
00581     and check if their numbers match the expected ones (0 by default).
00582     The dictionary "expected" can be used to tune the number of errors and fatals
00583     allowed, or to limit the number of expected warnings etc.
00584     """
00585     stdout = kwargs["stdout"]
00586     result = kwargs["result"]
00587     causes = kwargs["causes"]
00588     
00589     # prepare the dictionary to record the extracted lines
00590     errors = {}
00591     for sev in expected:
00592         errors[sev] = []
00593     
00594     outlines = stdout.splitlines()
00595     from math import log10
00596     fmt = "%%%dd - %%s" % (int(log10(len(outlines))+1))
00597     
00598     linecount = 0
00599     for l in outlines:
00600         linecount += 1
00601         words = l.split()
00602         if len(words) >= 2 and words[1] in errors:
00603             errors[words[1]].append(fmt%(linecount,l.rstrip()))
00604     
00605     for e in errors:
00606         if len(errors[e]) != expected[e]:
00607             causes.append('%s(%d)'%(e,len(errors[e])))
00608             result["GaudiTest.lines.%s"%e] = result.Quote('\n'.join(errors[e]))
00609             result["GaudiTest.lines.%s.expected#"%e] = result.Quote(str(expected[e]))
00610     
00611     return causes
00612 
00613 

def GaudiTest::findHistosSummaries (   stdout  ) 

Scan stdout to find ROOT TTree summaries and digest them.

Definition at line 787 of file GaudiTest.py.

00787                                :
00788     """
00789     Scan stdout to find ROOT TTree summaries and digest them.
00790     """
00791     outlines = stdout.splitlines()
00792     nlines = len(outlines) - 1
00793     summaries = {}
00794     global h_count_re
00795     
00796     pos = 0
00797     while pos < nlines:
00798         summ = {}
00799         # find first line of block:
00800         match = h_count_re.search(outlines[pos])
00801         while pos < nlines and not match:
00802             pos += 1
00803             match = h_count_re.search(outlines[pos])
00804         if match:
00805             summ, pos = parseHistosSummary(outlines, pos)
00806         summaries.update(summ)
00807     return summaries
00808 
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 531 of file GaudiTest.py.

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

00659                               :
00660     """
00661     Scan stdout to find ROOT TTree summaries and digest them.
00662     """
00663     stars = re.compile(r"^\*+$")
00664     outlines = stdout.splitlines()
00665     nlines = len(outlines)
00666     trees = {}
00667     
00668     i = 0
00669     while i < nlines: #loop over the output
00670         # look for
00671         while i < nlines and not stars.match(outlines[i]):
00672             i += 1
00673         if i < nlines:
00674             tree, i = _parseTTreeSummary(outlines, i)
00675             if tree:
00676                 trees[tree["Name"]] = tree
00677     
00678     return trees
00679 
def cmpTreesDicts(reference, to_check, ignore = None):

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

Definition at line 711 of file GaudiTest.py.

00711                                                        :
00712     c = to_check
00713     r = reference
00714     for k in fail_path:
00715         c = c.get(k,None)
00716         r = r.get(k,None)
00717         if c is None or r is None:
00718             break # one of the dictionaries is not deep enough
00719     return (fail_path, r, c)
00720 
00721 # 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 724 of file GaudiTest.py.

00724                                   :
00725     """
00726     Extract the histograms infos from the lines starting at pos.
00727     Returns the position of the first line after the summary block.
00728     """
00729     global h_count_re
00730     h_table_head = re.compile(r'SUCCESS\s+List of booked (1D|2D|3D|1D profile|2D profile) histograms in directory\s+"(\w*)"')
00731     h_short_summ = re.compile(r"ID=([^\"]+)\s+\"([^\"]+)\"\s+(.*)")
00732     
00733     nlines = len(lines)
00734     
00735     # decode header
00736     m = h_count_re.search(lines[pos])
00737     name = m.group(1).strip()
00738     total = int(m.group(2))
00739     header = {}
00740     for k, v in [ x.split("=") for x in  m.group(3).split() ]:
00741         header[k] = int(v)
00742     pos += 1
00743     header["Total"] = total
00744     
00745     summ = {}
00746     while pos < nlines:
00747         m = h_table_head.search(lines[pos])
00748         if m:
00749             t, d = m.groups(1) # type and directory
00750             t = t.replace(" profile", "Prof")
00751             pos += 1
00752             if pos < nlines:
00753                 l = lines[pos]
00754             else:
00755                 l = ""
00756             cont = {}
00757             if l.startswith(" | ID"):
00758                 # table format
00759                 titles = [ x.strip() for x in l.split("|")][1:]
00760                 pos += 1
00761                 while pos < nlines and lines[pos].startswith(" |"):
00762                     l = lines[pos]
00763                     values = [ x.strip() for x in l.split("|")][1:]
00764                     hcont = {}
00765                     for i in range(len(titles)):
00766                         hcont[titles[i]] = values[i]
00767                     cont[hcont["ID"]] = hcont
00768                     pos += 1
00769             elif l.startswith(" ID="):
00770                 while pos < nlines and lines[pos].startswith(" ID="):
00771                     values = [ x.strip() for x in  h_short_summ.search(lines[pos]).groups() ]
00772                     cont[values[0]] = values
00773                     pos += 1
00774             else: # not interpreted
00775                 raise RuntimeError("Cannot understand line %d: '%s'" % (pos, l))
00776             if not d in summ:
00777                 summ[d] = {}
00778             summ[d][t] = cont
00779             summ[d]["header"] = header
00780         else:
00781             break
00782     if not summ:
00783         # If the full table is not present, we use only the header
00784         summ[name] = {"header": header}
00785     return summ, pos
00786 
def findHistosSummaries(stdout):

def GaudiTest::rationalizepath (   p  ) 

Definition at line 272 of file GaudiTest.py.

00272                       :
00273     p = os.path.normpath(os.path.expandvars(p))
00274     if os.path.exists(p):
00275         p = os.path.realpath(p)
00276     return p
00277 
########################################################################

def GaudiTest::which (   executable  ) 

Locates an executable in the executables path ($PATH) and returns the full path to it.

If the excutable cannot be found, None is returned

Definition at line 265 of file GaudiTest.py.

00265                      :
00266     for d in os.environ.get("PATH").split(os.pathsep):
00267         fullpath = os.path.join(d,executable)
00268         if os.path.exists(fullpath):
00269             return fullpath
00270     return None
00271 
def rationalizepath(p):


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

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

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

Definition at line 410 of file GaudiTest.py.

Definition at line 433 of file GaudiTest.py.

Definition at line 413 of file GaudiTest.py.


Generated at Wed Mar 17 18:21:56 2010 for Gaudi Framework, version v21r8 by Doxygen version 1.5.6 written by Dimitri van Heesch, © 1997-2004