Gaudi Framework, version v21r7

Home   Generated: 22 Jan 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

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

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

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

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

Definition at line 577 of file GaudiTest.py.

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

def GaudiTest::findHistosSummaries (   stdout  ) 

Scan stdout to find ROOT TTree summaries and digest them.

Definition at line 786 of file GaudiTest.py.

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

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

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

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

Definition at line 710 of file GaudiTest.py.

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

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

def GaudiTest::rationalizepath (   p  ) 

Definition at line 271 of file GaudiTest.py.

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

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

00264                      :
00265     for d in os.environ.get("PATH").split(os.pathsep):
00266         fullpath = os.path.join(d,executable)
00267         if os.path.exists(fullpath):
00268             return fullpath
00269     return None
00270 
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 721 of file GaudiTest.py.

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

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

Definition at line 409 of file GaudiTest.py.

Definition at line 432 of file GaudiTest.py.

Definition at line 412 of file GaudiTest.py.


Generated at Fri Jan 22 20:44:57 2010 for Gaudi Framework, version v21r7 by Doxygen version 1.5.6 written by Dimitri van Heesch, © 1997-2004