Gaudi Framework, version v22r4

Home   Generated: Fri Sep 2 2011
Classes | Functions | Variables

GaudiTest Namespace Reference

Classes

class  TemporaryEnvironment
 Utility Classes. More...
class  TempDir
class  TempFile
class  CMT
class  BasicOutputValidator
 Output Validation Classes. More...
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'
 File: GaudiTest.py Author: Marco Clemencic CERN/PH-LBC.
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 620 of file GaudiTest.py.

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

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

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

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

Definition at line 584 of file GaudiTest.py.

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

Definition at line 793 of file GaudiTest.py.

00794                                :
00795     """
00796     Scan stdout to find ROOT TTree summaries and digest them.
00797     """
00798     outlines = stdout.splitlines()
00799     nlines = len(outlines) - 1
00800     summaries = {}
00801     global h_count_re
00802 
00803     pos = 0
00804     while pos < nlines:
00805         summ = {}
00806         # find first line of block:
00807         match = h_count_re.search(outlines[pos])
00808         while pos < nlines and not match:
00809             pos += 1
00810             match = h_count_re.search(outlines[pos])
00811         if match:
00812             summ, pos = parseHistosSummary(outlines, pos)
00813         summaries.update(summ)
00814     return summaries

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

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

def GaudiTest::findTTreeSummaries (   stdout )
Scan stdout to find ROOT TTree summaries and digest them.

Definition at line 665 of file GaudiTest.py.

00666                               :
00667     """
00668     Scan stdout to find ROOT TTree summaries and digest them.
00669     """
00670     stars = re.compile(r"^\*+$")
00671     outlines = stdout.splitlines()
00672     nlines = len(outlines)
00673     trees = {}
00674 
00675     i = 0
00676     while i < nlines: #loop over the output
00677         # look for
00678         while i < nlines and not stars.match(outlines[i]):
00679             i += 1
00680         if i < nlines:
00681             tree, i = _parseTTreeSummary(outlines, i)
00682             if tree:
00683                 trees[tree["Name"]] = tree
00684 
00685     return trees

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

Definition at line 717 of file GaudiTest.py.

00718                                                        :
00719     c = to_check
00720     r = reference
00721     for k in fail_path:
00722         c = c.get(k,None)
00723         r = r.get(k,None)
00724         if c is None or r is None:
00725             break # one of the dictionaries is not deep enough
00726     return (fail_path, r, c)
00727 
# signature of the print-out of the histograms
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 730 of file GaudiTest.py.

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

def GaudiTest::rationalizepath (   p )

Definition at line 272 of file GaudiTest.py.

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

def GaudiTest::which (   executable )

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

If the executable cannot be found, None is returned

Definition at line 263 of file GaudiTest.py.

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


Variable Documentation

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

File: GaudiTest.py Author: Marco Clemencic CERN/PH-LBC.

Definition at line 5 of file GaudiTest.py.

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

Definition at line 728 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:
00001 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)?",
00002                                "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.

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Defines

Generated at Fri Sep 2 2011 16:26:02 for Gaudi Framework, version v22r4 by Doxygen version 1.7.2 written by Dimitri van Heesch, © 1997-2004