| # 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.

tuple GaudiTest::normalizeDate

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.

tuple GaudiTest::normalizeEOL = FilePreprocessor()

Definition at line 375 of file GaudiTest.py.

tuple GaudiTest::normalizeExamples = maskPointers+normalizeDate

Definition at line 383 of file GaudiTest.py.

tuple GaudiTest::skipEmptyLines = FilePreprocessor()

Definition at line 378 of file GaudiTest.py.