| # Gaudi Framework, version v25r0 |

Home |  | Generated: Mon Feb 17 2014

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- Namespace List
- Namespace Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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
class | XMLResultStream

## Functions
def | ROOT6WorkAroundEnabled
def | total_seconds_replacement
def | which
| Locates an executable in the executables path ($PATH) and returns the full path to it.
def | rationalizepath
def | hexreplace
def | hexConvert
def | convert_xml_illegal_chars
def | escape_xml_illegal_chars
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 | _illegal_xml_chars_RE re.compile(u'[\x00-\x08\x0b\x0c\x0e-\x1F\uD800-\uDFFF\uFFFE\uFFFF]')
tuple | maskPointers RegexpReplacer("0x[0-9a-fA-F]{4,16}","0x########")
tuple | normalizeDate
tuple | normalizeEOL FilePreprocessor()
tuple | skipEmptyLines FilePreprocessor()
| normalizeExamples maskPointers+normalizeDate
tuple | lineSkipper
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 690 of file GaudiTest.py.

690
691 def _parseTTreeSummary(lines, pos):
692 """
693 Parse the TTree summary table in lines, starting from pos.
694 Returns a tuple with the dictionary with the digested informations and the
695 position of the first line after the summary.
696 """
697 result = {}
698 i = pos + 1 # first line is a sequence of '*'
699 count = len(lines)
700
701 splitcols = lambda l: [ f.strip() for f in l.strip("*\n").split(':',2) ]
702 def parseblock(ll):
703 r = {}
704 cols = splitcols(ll[0])
705 r["Name"], r["Title"] = cols[1:]
706
707 cols = splitcols(ll[1])
708 r["Entries"] = int(cols[1])
709
710 sizes = cols[2].split()
711 r["Total size"] = int(sizes[2])
712 if sizes[-1] == "memory":
713 r["File size"] = 0
714 else:
715 r["File size"] = int(sizes[-1])
716
717 cols = splitcols(ll[2])
718 sizes = cols[2].split()
719 if cols[0] == "Baskets":
720 r["Baskets"] = int(cols[1])
721 r["Basket size"] = int(sizes[2])
722 r["Compression"] = float(sizes[-1])
723 return r
724
725 if i < (count - 3) and lines[i].startswith("*Tree"):
726 result = parseblock(lines[i:i+3])
727 result["Branches"] = {}
728 i += 4
729 while i < (count - 3) and lines[i].startswith("*Br"):
730 if i < (count - 2) and lines[i].startswith("*Branch "):
731 # skip branch header
732 i += 3
733 continue
734 branch = parseblock(lines[i:i+3])
735 result["Branches"][branch["Name"]] = branch
736 i += 4
737
738 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 760 of file GaudiTest.py.

760
761 def cmpTreesDicts(reference, to_check, ignore = None):
762 """
763 Check that all the keys in reference are in to_check too, with the same value.
764 If the value is a dict, the function is called recursively. to_check can
765 contain more keys than reference, that will not be tested.
766 The function returns at the first difference found.
767 """
768 fail_keys = []
769 # filter the keys in the reference dictionary
770 if ignore:
771 ignore_re = re.compile(ignore)
772 keys = [ key for key in reference if not ignore_re.match(key) ]
773 else:
774 keys = reference.keys()
775 # loop over the keys (not ignored) in the reference dictionary
776 for k in keys:
777 if k in to_check: # the key must be in the dictionary to_check
778 if (type(reference[k]) is dict) and (type(to_check[k]) is dict):
779 # if both reference and to_check values are dictionaries, recurse
780 failed = fail_keys = cmpTreesDicts(reference[k], to_check[k], ignore)
781 else:
782 # compare the two values
783 failed = to_check[k] != reference[k]
784 else: # handle missing keys in the dictionary to check (i.e. failure)
785 to_check[k] = None
786 failed = True
787 if failed:
788 fail_keys.insert(0, k)
789 break # exit from the loop at the first failure
790 return fail_keys # return the list of keys bringing to the different values

def GaudiTest.convert_xml_illegal_chars | ( |  | val | ) |

Definition at line 335 of file GaudiTest.py.

335
336 def convert_xml_illegal_chars(val):
337 return _illegal_xml_chars_RE.sub(hexreplace, val)

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

Definition at line 654 of file GaudiTest.py.

654
655 def countErrorLines(expected = {'ERROR':0, 'FATAL':0}, **kwargs):
656 """
657 Count the number of messages with required severity (by default ERROR and FATAL)
658 and check if their numbers match the expected ones (0 by default).
659 The dictionary "expected" can be used to tune the number of errors and fatals
660 allowed, or to limit the number of expected warnings etc.
661 """
662 stdout = kwargs["stdout"]
663 result = kwargs["result"]
664 causes = kwargs["causes"]
665
666 # prepare the dictionary to record the extracted lines
667 errors = {}
668 for sev in expected:
669 errors[sev] = []
670
671 outlines = stdout.splitlines()
672 from math import log10
673 fmt = "%%%dd - %%s" % (int(log10(len(outlines))+1))
674
675 linecount = 0
676 for l in outlines:
677 linecount += 1
678 words = l.split()
679 if len(words) >= 2 and words[1] in errors:
680 errors[words[1]].append(fmt%(linecount,l.rstrip()))
681
682 for e in errors:
683 if len(errors[e]) != expected[e]:
684 causes.append('%s(%d)'%(e,len(errors[e])))
685 result["GaudiTest.lines.%s"%e] = result.Quote('\n'.join(errors[e]))
686 result["GaudiTest.lines.%s.expected#"%e] = result.Quote(str(expected[e]))
687
688 return causes
689

def GaudiTest.escape_xml_illegal_chars | ( |  | val,
|  |  | replacement = `'?'`
| ) |  |

    Filter out characters that are illegal in XML.
    Looks for any character in val that is not allowed in XML
    and replaces it with replacement ('?' by default).

Definition at line 338 of file GaudiTest.py.

338
339 def escape_xml_illegal_chars(val, replacement='?'):
340 """Filter out characters that are illegal in XML.
341 Looks for any character in val that is not allowed in XML
342 and replaces it with replacement ('?' by default).
343
344 """
345 return _illegal_xml_chars_RE.sub(replacement, val)

def GaudiTest.findHistosSummaries | ( |  | stdout | ) |

    Scan stdout to find ROOT TTree summaries and digest them.

Definition at line 867 of file GaudiTest.py.

867
868 def findHistosSummaries(stdout):
869 """
870 Scan stdout to find ROOT TTree summaries and digest them.
871 """
872 outlines = stdout.splitlines()
873 nlines = len(outlines) - 1
874 summaries = {}
875 global h_count_re
876
877 pos = 0
878 while pos < nlines:
879 summ = {}
880 # find first line of block:
881 match = h_count_re.search(outlines[pos])
882 while pos < nlines and not match:
883 pos += 1
884 match = h_count_re.search(outlines[pos])
885 if match:
886 summ, pos = parseHistosSummary(outlines, pos)
887 summaries.update(summ)
888 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 608 of file GaudiTest.py.

608
609 id = None):
610 """
611 Given a block of text, tries to find it in the output.
612 The block had to be identified by a signature line. By default, the first
613 line is used as signature, or the line pointed to by signature_offset. If
614 signature_offset points outside the block, a signature line can be passed as
615 signature argument. Note: if 'signature' is None (the default), a negative
616 signature_offset is interpreted as index in a list (e.g. -1 means the last
617 line), otherwise the it is interpreted as the number of lines before the
618 first one of the block the signature must appear.
619 The parameter 'id' allow to distinguish between different calls to this
620 function in the same validation code.
621 """
622 # split reference file, sanitize EOLs and remove empty lines
623 reflines = filter(None,map(lambda s: s.rstrip(), reference.splitlines()))
624 if not reflines:
625 raise RuntimeError("Empty (or null) reference")
626 # the same on standard output
627 outlines = filter(None,map(lambda s: s.rstrip(), stdout.splitlines()))
628
629 res_field = "GaudiTest.RefBlock"
630 if id:
631 res_field += "_%s" % id
632
633 if signature is None:
634 if signature_offset < 0:
635 signature_offset = len(reference)+signature_offset
636 signature = reflines[signature_offset]
637 # find the reference block in the output file
638 try:
639 pos = outlines.index(signature)
640 outlines = outlines[pos-signature_offset:pos+len(reflines)-signature_offset]
641 if reflines != outlines:
642 msg = "standard output"
643 # I do not want 2 messages in causes if teh function is called twice
644 if not msg in causes:
645 causes.append(msg)
646 result[res_field + ".observed"] = result.Quote("\n".join(outlines))
647 except ValueError:
648 causes.append("missing signature")
649 result[res_field + ".signature"] = result.Quote(signature)
650 if len(reflines) > 1 or signature != reflines[0]:
651 result[res_field + ".expected"] = result.Quote("\n".join(reflines))
652
653 return causes

def GaudiTest.findTTreeSummaries | ( |  | stdout | ) |

    Scan stdout to find ROOT TTree summaries and digest them.

Definition at line 739 of file GaudiTest.py.

739
740 def findTTreeSummaries(stdout):
741 """
742 Scan stdout to find ROOT TTree summaries and digest them.
743 """
744 stars = re.compile(r"^\*+$")
745 outlines = stdout.splitlines()
746 nlines = len(outlines)
747 trees = {}
748
749 i = 0
750 while i < nlines: #loop over the output
751 # look for
752 while i < nlines and not stars.match(outlines[i]):
753 i += 1
754 if i < nlines:
755 tree, i = _parseTTreeSummary(outlines, i)
756 if tree:
757 trees[tree["Name"]] = tree
758
759 return trees

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

Definition at line 791 of file GaudiTest.py.

791
792 def getCmpFailingValues(reference, to_check, fail_path):
793 c = to_check
794 r = reference
795 for k in fail_path:
796 c = c.get(k,None)
797 r = r.get(k,None)
798 if c is None or r is None:
799 break # one of the dictionaries is not deep enough
800 return (fail_path, r, c)
801
# signature of the print-out of the histograms

def GaudiTest.hexConvert | ( |  | char | ) |

Definition at line 333 of file GaudiTest.py.

333
334 def hexConvert(char):
return hex(ord(char))

def GaudiTest.hexreplace | ( |  | match | ) |

Definition at line 329 of file GaudiTest.py.

329
330 def hexreplace( match ):
331 "Return the hex string "
332 return "".join(map(hexConvert,match.group()))

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

804
805 def parseHistosSummary(lines, pos):
806 """
807 Extract the histograms infos from the lines starting at pos.
808 Returns the position of the first line after the summary block.
809 """
810 global h_count_re
811 h_table_head = re.compile(r'SUCCESS\s+List of booked (1D|2D|3D|1D profile|2D profile) histograms in directory\s+"(\w*)"')
812 h_short_summ = re.compile(r"ID=([^\"]+)\s+\"([^\"]+)\"\s+(.*)")
813
814 nlines = len(lines)
815
816 # decode header
817 m = h_count_re.search(lines[pos])
818 name = m.group(1).strip()
819 total = int(m.group(2))
820 header = {}
821 for k, v in [ x.split("=") for x in m.group(3).split() ]:
822 header[k] = int(v)
823 pos += 1
824 header["Total"] = total
825
826 summ = {}
827 while pos < nlines:
828 m = h_table_head.search(lines[pos])
829 if m:
830 t, d = m.groups(1) # type and directory
831 t = t.replace(" profile", "Prof")
832 pos += 1
833 if pos < nlines:
834 l = lines[pos]
835 else:
836 l = ""
837 cont = {}
838 if l.startswith(" | ID"):
839 # table format
840 titles = [ x.strip() for x in l.split("|")][1:]
841 pos += 1
842 while pos < nlines and lines[pos].startswith(" |"):
843 l = lines[pos]
844 values = [ x.strip() for x in l.split("|")][1:]
845 hcont = {}
846 for i in range(len(titles)):
847 hcont[titles[i]] = values[i]
848 cont[hcont["ID"]] = hcont
849 pos += 1
850 elif l.startswith(" ID="):
851 while pos < nlines and lines[pos].startswith(" ID="):
852 values = [ x.strip() for x in h_short_summ.search(lines[pos]).groups() ]
853 cont[values[0]] = values
854 pos += 1
855 else: # not interpreted
856 raise RuntimeError("Cannot understand line %d: '%s'" % (pos, l))
857 if not d in summ:
858 summ[d] = {}
859 summ[d][t] = cont
860 summ[d]["header"] = header
861 else:
862 break
863 if not summ:
864 # If the full table is not present, we use only the header
865 summ[name] = {"header": header}
866 return summ, pos

def GaudiTest.rationalizepath | ( |  | p | ) |

Definition at line 307 of file GaudiTest.py.

307
308 def rationalizepath(p):
309 np = os.path.normpath(os.path.expandvars(p))
310 if os.path.exists(np):
311 p = os.path.realpath(np)
312 return p
313
# XML Escaping character

def GaudiTest.ROOT6WorkAroundEnabled | ( |  | id = `None` | ) |

Definition at line 23 of file GaudiTest.py.

23
24 def ROOT6WorkAroundEnabled(id=None):
25 # dummy implementation
26 return False
27
28 # ensure the preferred locale
29 os.environ['LC_ALL'] = 'C'
30
31 # Needed for the XML wrapper
try:

def GaudiTest.total_seconds_replacement | ( |  | timedelta | ) |

Definition at line 37 of file GaudiTest.py.

37
38 def total_seconds_replacement(timedelta) :
39 return timedelta.days*86400 + timedelta.seconds + timedelta.microseconds/1000000
40

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

    Locates an executable in the executables path ($PATH) and returns the full
    path to it.  An application is looked for with or without the '.exe' suffix.
    If the executable cannot be found, None is returned

Definition at line 287 of file GaudiTest.py.

287
288 def which(executable):
289 """
290 Locates an executable in the executables path ($PATH) and returns the full
291 path to it. An application is looked for with or without the '.exe' suffix.
292 If the executable cannot be found, None is returned
293 """
294 if os.path.isabs(executable):
295 if not os.path.exists(executable):
296 if executable.endswith('.exe'):
297 if os.path.exists(executable[:-4]):
298 return executable[:-4]
299 return executable
300 for d in os.environ.get("PATH").split(os.pathsep):
301 fullpath = os.path.join(d, executable)
302 if os.path.exists(fullpath):
303 return fullpath
304 if executable.endswith('.exe'):
305 return which(executable[:-4])
306 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._illegal_xml_chars_RE re.compile(u'[\x00-\x08\x0b\x0c\x0e-\x1F\uD800-\uDFFF\uFFFE\uFFFF]')

Definition at line 327 of file GaudiTest.py.

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

Definition at line 802 of file GaudiTest.py.

tuple GaudiTest.lineSkipper

Definition at line 520 of file GaudiTest.py.

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

Definition at line 475 of file GaudiTest.py.

tuple GaudiTest.normalizeDate

Initial value:
1 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)?",
2 "00:00:00 1970-01-01")

Definition at line 476 of file GaudiTest.py.

tuple GaudiTest.normalizeEOL FilePreprocessor()

Definition at line 478 of file GaudiTest.py.

tuple GaudiTest.normalizeExamples maskPointers+normalizeDate

Definition at line 501 of file GaudiTest.py.

tuple GaudiTest.skipEmptyLines FilePreprocessor()

Definition at line 481 of file GaudiTest.py.