| The Gaudi Framework v29r0 (ff2e7097)

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

- Namespace List
- Namespace Members

Classes | Functions | Variables
GaudiTest Namespace Reference

## Classes
class | BasicOutputValidator
| Output Validation Classes. More...
class | BlockSkipper
class | CMT
class | FilePreprocessor
class | FilePreprocessorSequence
class | GaudiExeTest
class | GaudiFilterExecutable
class | HTMLResultStream
class | LineSkipper
class | LineSorter
class | ReferenceFileValidator
class | RegexpReplacer
class | TempDir
class | TempFile
class | TemporaryEnvironment
| Utility Classes. More...
class | XMLResultStream

## Functions
def | ROOT6WorkAroundEnabled (id=None)
def | total_seconds_replacement (timedelta)
def | which (executable)
def | rationalizepath (p)
def | hexreplace (match)
def | hexConvert (char)
def | convert_xml_illegal_chars (val)
def | escape_xml_illegal_chars (val, replacement='?')
def | findReferenceBlock (reference, stdout, result, causes, signature_offset=0, signature=None, id=None)
def | countErrorLines
def | _parseTTreeSummary (lines, pos)
def | findTTreeSummaries (stdout)
def | cmpTreesDicts (reference, to_check, ignore=None)
def | getCmpFailingValues (reference, to_check, fail_path)
def | parseHistosSummary (lines, pos)
def | findHistosSummaries (stdout)

## Variables
string | __author__ = 'Marco Clemencic CERN/PH-LBC'
| File: GaudiTest.py Author: Marco Clemencic CERN/PH-LBC. More...
| _illegal_xml_chars_RE
| maskPointers = RegexpReplacer("0x[0-9a-fA-F]{4,16}", "0x########")
| normalizeDate
| normalizeEOL = FilePreprocessor()
| __processLine__
| skipEmptyLines = FilePreprocessor()
| normalizeExamples = maskPointers+normalizeDate
| lineSkipper
| regexps
| 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 776 of file GaudiTest.py.

776 def _parseTTreeSummary(lines, pos):
777 """
778 Parse the TTree summary table in lines, starting from pos.
779 Returns a tuple with the dictionary with the digested informations and the
780 position of the first line after the summary.
781 """
782 result = {}
783 i = pos + 1 # first line is a sequence of '*'
784 count = len(lines)
785
786 def splitcols(l): return [f.strip() for f in l.strip("*\n").split(':', 2)]
787
788 def parseblock(ll):
789 r = {}
790 cols = splitcols(ll[0])
791 r["Name"], r["Title"] = cols[1:]
792
793 cols = splitcols(ll[1])
794 r["Entries"] = int(cols[1])
795
796 sizes = cols[2].split()
797 r["Total size"] = int(sizes[2])
798 if sizes[-1] == "memory":
799 r["File size"] = 0
800 else:
801 r["File size"] = int(sizes[-1])
802
803 cols = splitcols(ll[2])
804 sizes = cols[2].split()
805 if cols[0] == "Baskets":
806 r["Baskets"] = int(cols[1])
807 r["Basket size"] = int(sizes[2])
808 r["Compression"] = float(sizes[-1])
809 return r
810
811 if i < (count - 3) and lines[i].startswith("*Tree"):
812 result = parseblock(lines[i:i + 3])
813 result["Branches"] = {}
814 i += 4
815 while i < (count - 3) and lines[i].startswith("*Br"):
816 if i < (count - 2) and lines[i].startswith("*Branch "):
817 # skip branch header
818 i += 3
819 continue
820 branch = parseblock(lines[i:i + 3])
821 result["Branches"][branch["Name"]] = branch
822 i += 4
823
824 return (result, i)
825
826
GaudiTest._parseTTreeSummary
def _parseTTreeSummary(lines, pos)
Definition: GaudiTest.py:776

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

849 def cmpTreesDicts(reference, to_check, ignore=None):
850 """
851 Check that all the keys in reference are in to_check too, with the same value.
852 If the value is a dict, the function is called recursively. to_check can
853 contain more keys than reference, that will not be tested.
854 The function returns at the first difference found.
855 """
856 fail_keys = []
857 # filter the keys in the reference dictionary
858 if ignore:
859 ignore_re = re.compile(ignore)
860 keys = [key for key in reference if not ignore_re.match(key)]
861 else:
862 keys = reference.keys()
863 # loop over the keys (not ignored) in the reference dictionary
864 for k in keys:
865 if k in to_check: # the key must be in the dictionary to_check
866 if (type(reference[k]) is dict) and (type(to_check[k]) is dict):
867 # if both reference and to_check values are dictionaries, recurse
868 failed = fail_keys = cmpTreesDicts(
869 reference[k], to_check[k], ignore)
870 else:
871 # compare the two values
872 failed = to_check[k] != reference[k]
873 else: # handle missing keys in the dictionary to check (i.e. failure)
874 to_check[k] = None
875 failed = True
876 if failed:
877 fail_keys.insert(0, k)
878 break # exit from the loop at the first failure
879 return fail_keys # return the list of keys bringing to the different values
880
881
GaudiTest.cmpTreesDicts
def cmpTreesDicts(reference, to_check, ignore=None)
Definition: GaudiTest.py:849
gaudirun.type
type
Definition: gaudirun.py:133

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

Definition at line 357 of file GaudiTest.py.

357 def convert_xml_illegal_chars(val):
358 return _illegal_xml_chars_RE.sub(hexreplace, val)
359
360
GaudiTest.convert_xml_illegal_chars
def convert_xml_illegal_chars(val)
Definition: GaudiTest.py:357

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

Definition at line 738 of file GaudiTest.py.

738 def countErrorLines(expected={'ERROR': 0, 'FATAL': 0}, **kwargs):
739 """
740 Count the number of messages with required severity (by default ERROR and FATAL)
741 and check if their numbers match the expected ones (0 by default).
742 The dictionary "expected" can be used to tune the number of errors and fatals
743 allowed, or to limit the number of expected warnings etc.
744 """
745 stdout = kwargs["stdout"]
746 result = kwargs["result"]
747 causes = kwargs["causes"]
748
749 # prepare the dictionary to record the extracted lines
750 errors = {}
751 for sev in expected:
752 errors[sev] = []
753
754 outlines = stdout.splitlines()
755 from math import log10
756 fmt = "%%%dd - %%s" % (int(log10(len(outlines)) + 1))
757
758 linecount = 0
759 for l in outlines:
760 linecount += 1
761 words = l.split()
762 if len(words) >= 2 and words[1] in errors:
763 errors[words[1]].append(fmt % (linecount, l.rstrip()))
764
765 for e in errors:
766 if len(errors[e]) != expected[e]:
767 causes.append('%s(%d)' % (e, len(errors[e])))
768 result["GaudiTest.lines.%s" %
769 e] = result.Quote('\n'.join(errors[e]))
770 result["GaudiTest.lines.%s.expected#" %
771 e] = result.Quote(str(expected[e]))
772
773 return causes
774
775
GaudiTest.countErrorLines
def countErrorLines
Definition: GaudiTest.py:738

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

361 def escape_xml_illegal_chars(val, replacement='?'):
362 """Filter out characters that are illegal in XML.
363 Looks for any character in val that is not allowed in XML
364 and replaces it with replacement ('?' by default).
365
366 """
367 return _illegal_xml_chars_RE.sub(replacement, val)
368
GaudiTest.escape_xml_illegal_chars
def escape_xml_illegal_chars(val, replacement='?')
Definition: GaudiTest.py:361

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

    Scan stdout to find ROOT TTree summaries and digest them.

Definition at line 964 of file GaudiTest.py.

964 def findHistosSummaries(stdout):
965 """
966 Scan stdout to find ROOT TTree summaries and digest them.
967 """
968 outlines = stdout.splitlines()
969 nlines = len(outlines) - 1
970 summaries = {}
971 global h_count_re
972
973 pos = 0
974 while pos < nlines:
975 summ = {}
976 # find first line of block:
977 match = h_count_re.search(outlines[pos])
978 while pos < nlines and not match:
979 pos += 1
980 match = h_count_re.search(outlines[pos])
981 if match:
982 summ, pos = parseHistosSummary(outlines, pos)
983 summaries.update(summ)
984 return summaries
985
986
GaudiTest.parseHistosSummary
def parseHistosSummary(lines, pos)
Definition: GaudiTest.py:897
GaudiTest.findHistosSummaries
def findHistosSummaries(stdout)
Definition: GaudiTest.py:964

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

690 id=None):
691 """
692 Given a block of text, tries to find it in the output.
693 The block had to be identified by a signature line. By default, the first
694 line is used as signature, or the line pointed to by signature_offset. If
695 signature_offset points outside the block, a signature line can be passed as
696 signature argument. Note: if 'signature' is None (the default), a negative
697 signature_offset is interpreted as index in a list (e.g. -1 means the last
698 line), otherwise the it is interpreted as the number of lines before the
699 first one of the block the signature must appear.
700 The parameter 'id' allow to distinguish between different calls to this
701 function in the same validation code.
702 """
703 # split reference file, sanitize EOLs and remove empty lines
704 reflines = filter(None, map(lambda s: s.rstrip(), reference.splitlines()))
705 if not reflines:
706 raise RuntimeError("Empty (or null) reference")
707 # the same on standard output
708 outlines = filter(None, map(lambda s: s.rstrip(), stdout.splitlines()))
709
710 res_field = "GaudiTest.RefBlock"
711 if id:
712 res_field += "_%s" % id
713
714 if signature is None:
715 if signature_offset < 0:
716 signature_offset = len(reference) + signature_offset
717 signature = reflines[signature_offset]
718 # find the reference block in the output file
719 try:
720 pos = outlines.index(signature)
721 outlines = outlines[pos - signature_offset:pos +
722 len(reflines) - signature_offset]
723 if reflines != outlines:
724 msg = "standard output"
725 # I do not want 2 messages in causes if teh function is called twice
726 if not msg in causes:
727 causes.append(msg)
728 result[res_field + ".observed"] = result.Quote("\n".join(outlines))
729 except ValueError:
730 causes.append("missing signature")
731 result[res_field + ".signature"] = result.Quote(signature)
732 if len(reflines) > 1 or signature != reflines[0]:
733 result[res_field + ".expected"] = result.Quote("\n".join(reflines))
734
735 return causes
736
737
Containers::map
struct GAUDI_API map
Parametrisation class for map-like implementation.
Definition: KeyedObjectManager.h:26

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

    Scan stdout to find ROOT TTree summaries and digest them.

Definition at line 827 of file GaudiTest.py.

827 def findTTreeSummaries(stdout):
828 """
829 Scan stdout to find ROOT TTree summaries and digest them.
830 """
831 stars = re.compile(r"^\*+$")
832 outlines = stdout.splitlines()
833 nlines = len(outlines)
834 trees = {}
835
836 i = 0
837 while i < nlines: # loop over the output
838 # look for
839 while i < nlines and not stars.match(outlines[i]):
840 i += 1
841 if i < nlines:
842 tree, i = _parseTTreeSummary(outlines, i)
843 if tree:
844 trees[tree["Name"]] = tree
845
846 return trees
847
848
GaudiTest._parseTTreeSummary
def _parseTTreeSummary(lines, pos)
Definition: GaudiTest.py:776
GaudiTest.findTTreeSummaries
def findTTreeSummaries(stdout)
Definition: GaudiTest.py:827

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

Definition at line 882 of file GaudiTest.py.

882 def getCmpFailingValues(reference, to_check, fail_path):
883 c = to_check
884 r = reference
885 for k in fail_path:
886 c = c.get(k, None)
887 r = r.get(k, None)
888 if c is None or r is None:
889 break # one of the dictionaries is not deep enough
890 return (fail_path, r, c)
891
892
893 # signature of the print-out of the histograms
GaudiTest.getCmpFailingValues
def getCmpFailingValues(reference, to_check, fail_path)
Definition: GaudiTest.py:882

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

Definition at line 353 of file GaudiTest.py.

353 def hexConvert(char):
354 return hex(ord(char))
355
356
GaudiTest.hexConvert
def hexConvert(char)
Definition: GaudiTest.py:353
MSG::hex
MsgStream & hex(MsgStream &log)
Definition: MsgStream.h:304

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

Definition at line 348 of file GaudiTest.py.

348 def hexreplace(match):
349 "Return the hex string "
350 return "".join(map(hexConvert, match.group()))
351
352
GaudiTest.hexreplace
def hexreplace(match)
Definition: GaudiTest.py:348
Containers::map
struct GAUDI_API map
Parametrisation class for map-like implementation.
Definition: KeyedObjectManager.h:26

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

897 def parseHistosSummary(lines, pos):
898 """
899 Extract the histograms infos from the lines starting at pos.
900 Returns the position of the first line after the summary block.
901 """
902 global h_count_re
903 h_table_head = re.compile(
904 r'SUCCESS\s+List of booked (1D|2D|3D|1D profile|2D profile) histograms in directory\s+"(\w*)"')
905 h_short_summ = re.compile(r"ID=([^\"]+)\s+\"([^\"]+)\"\s+(.*)")
906
907 nlines = len(lines)
908
909 # decode header
910 m = h_count_re.search(lines[pos])
911 name = m.group(1).strip()
912 total = int(m.group(2))
913 header = {}
914 for k, v in [x.split("=") for x in m.group(3).split()]:
915 header[k] = int(v)
916 pos += 1
917 header["Total"] = total
918
919 summ = {}
920 while pos < nlines:
921 m = h_table_head.search(lines[pos])
922 if m:
923 t, d = m.groups(1) # type and directory
924 t = t.replace(" profile", "Prof")
925 pos += 1
926 if pos < nlines:
927 l = lines[pos]
928 else:
929 l = ""
930 cont = {}
931 if l.startswith(" | ID"):
932 # table format
933 titles = [x.strip() for x in l.split("|")][1:]
934 pos += 1
935 while pos < nlines and lines[pos].startswith(" |"):
936 l = lines[pos]
937 values = [x.strip() for x in l.split("|")][1:]
938 hcont = {}
939 for i in range(len(titles)):
940 hcont[titles[i]] = values[i]
941 cont[hcont["ID"]] = hcont
942 pos += 1
943 elif l.startswith(" ID="):
944 while pos < nlines and lines[pos].startswith(" ID="):
945 values = [x.strip()
946 for x in h_short_summ.search(lines[pos]).groups()]
947 cont[values[0]] = values
948 pos += 1
949 else: # not interpreted
950 raise RuntimeError(
951 "Cannot understand line %d: '%s'" % (pos, l))
952 if not d in summ:
953 summ[d] = {}
954 summ[d][t] = cont
955 summ[d]["header"] = header
956 else:
957 break
958 if not summ:
959 # If the full table is not present, we use only the header
960 summ[name] = {"header": header}
961 return summ, pos
962
963
GaudiTest.parseHistosSummary
def parseHistosSummary(lines, pos)
Definition: GaudiTest.py:897
Gaudi::Functional::details::zip::range
decltype(auto) range(Args &&...args)
Zips multiple containers together to form a single range.
Definition: FunctionalDetails.h:85

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

Definition at line 323 of file GaudiTest.py.

323 def rationalizepath(p):
324 np = os.path.normpath(os.path.expandvars(p))
325 if os.path.exists(np):
326 p = os.path.realpath(np)
327 return p
328
329
330 # XML Escaping character
GaudiTest.rationalizepath
def rationalizepath(p)
Definition: GaudiTest.py:323

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

Definition at line 25 of file GaudiTest.py.

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

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

Definition at line 41 of file GaudiTest.py.

41 def total_seconds_replacement(timedelta):
42 return timedelta.days * 86400 + timedelta.seconds + timedelta.microseconds / 1000000
43
44
GaudiTest.total_seconds_replacement
def total_seconds_replacement(timedelta)
Definition: GaudiTest.py:41

def GaudiTest.which | ( |  | executable | ) |

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

302 def which(executable):
303 """
304 Locates an executable in the executables path ($PATH) and returns the full
305 path to it. An application is looked for with or without the '.exe' suffix.
306 If the executable cannot be found, None is returned
307 """
308 if os.path.isabs(executable):
309 if not os.path.exists(executable):
310 if executable.endswith('.exe'):
311 if os.path.exists(executable[:-4]):
312 return executable[:-4]
313 return executable
314 for d in os.environ.get("PATH").split(os.pathsep):
315 fullpath = os.path.join(d, executable)
316 if os.path.exists(fullpath):
317 return fullpath
318 if executable.endswith('.exe'):
319 return which(executable[:-4])
320 return None
321
322
GaudiTest.which
def which(executable)
Definition: GaudiTest.py:302

## Variable Documentation

string GaudiTest.__author__ = 'Marco Clemencic CERN/PH-LBC'
| private

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

Definition at line 5 of file GaudiTest.py.

GaudiTest.__processLine__
| private

Definition at line 530 of file GaudiTest.py.

GaudiTest._illegal_xml_chars_RE
| private

Initial value:
1 = re.compile(
2 u'[\x00-\x08\x0b\x0c\x0e-\x1F\uD800-\uDFFF\uFFFE\uFFFF]')

Definition at line 344 of file GaudiTest.py.

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

Definition at line 894 of file GaudiTest.py.

GaudiTest.lineSkipper

Definition at line 581 of file GaudiTest.py.

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

Definition at line 526 of file GaudiTest.py.

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")
GaudiTest.RegexpReplacer
Definition: GaudiTest.py:504

Definition at line 527 of file GaudiTest.py.

GaudiTest.normalizeEOL = FilePreprocessor()

Definition at line 529 of file GaudiTest.py.

tuple GaudiTest.normalizeExamples = maskPointers+normalizeDate

Definition at line 556 of file GaudiTest.py.

GaudiTest.regexps

Definition at line 642 of file GaudiTest.py.

GaudiTest.skipEmptyLines = FilePreprocessor()

Definition at line 532 of file GaudiTest.py.