| # Gaudi Framework, version v21r6 |

Home |  | Generated: 11 Nov 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 | 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 612 of file GaudiTest.py.

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

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

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

Definition at line 576 of file GaudiTest.py.

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

def GaudiTest::findHistosSummaries | ( |  | stdout | ) |

    Scan stdout to find ROOT TTree summaries and digest them.

Definition at line 785 of file GaudiTest.py.

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

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

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

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

Definition at line 709 of file GaudiTest.py.

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

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

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

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

tuple GaudiTest::normalizeEOL = FilePreprocessor()

Definition at line 409 of file GaudiTest.py.

tuple GaudiTest::normalizeExamples = maskPointers+normalizeDate

Definition at line 432 of file GaudiTest.py.

tuple GaudiTest::skipEmptyLines = FilePreprocessor()

Definition at line 412 of file GaudiTest.py.