|
Gaudi Framework, version v23r4 |
| Home | Generated: Mon Sep 17 2012 |
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 |
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' |
| File: GaudiTest.py Author: Marco Clemencic CERN/PH-LBC. | |
| 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+(.*)") |
| 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 631 of file GaudiTest.py.
00632 : 00633 """ 00634 Parse the TTree summary table in lines, starting from pos. 00635 Returns a tuple with the dictionary with the digested informations and the 00636 position of the first line after the summary. 00637 """ 00638 result = {} 00639 i = pos + 1 # first line is a sequence of '*' 00640 count = len(lines) 00641 00642 splitcols = lambda l: [ f.strip() for f in l.strip("*\n").split(':',2) ] 00643 def parseblock(ll): 00644 r = {} 00645 cols = splitcols(ll[0]) 00646 r["Name"], r["Title"] = cols[1:] 00647 00648 cols = splitcols(ll[1]) 00649 r["Entries"] = int(cols[1]) 00650 00651 sizes = cols[2].split() 00652 r["Total size"] = int(sizes[2]) 00653 if sizes[-1] == "memory": 00654 r["File size"] = 0 00655 else: 00656 r["File size"] = int(sizes[-1]) 00657 00658 cols = splitcols(ll[2]) 00659 sizes = cols[2].split() 00660 if cols[0] == "Baskets": 00661 r["Baskets"] = int(cols[1]) 00662 r["Basket size"] = int(sizes[2]) 00663 r["Compression"] = float(sizes[-1]) 00664 return r 00665 00666 if i < (count - 3) and lines[i].startswith("*Tree"): 00667 result = parseblock(lines[i:i+3]) 00668 result["Branches"] = {} 00669 i += 4 00670 while i < (count - 3) and lines[i].startswith("*Br"): 00671 if i < (count - 2) and lines[i].startswith("*Branch "): 00672 # skip branch header 00673 i += 3 00674 continue 00675 branch = parseblock(lines[i:i+3]) 00676 result["Branches"][branch["Name"]] = branch 00677 i += 4 00678 00679 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 701 of file GaudiTest.py.
00702 : 00703 """ 00704 Check that all the keys in reference are in to_check too, with the same value. 00705 If the value is a dict, the function is called recursively. to_check can 00706 contain more keys than reference, that will not be tested. 00707 The function returns at the first difference found. 00708 """ 00709 fail_keys = [] 00710 # filter the keys in the reference dictionary 00711 if ignore: 00712 ignore_re = re.compile(ignore) 00713 keys = [ key for key in reference if not ignore_re.match(key) ] 00714 else: 00715 keys = reference.keys() 00716 # loop over the keys (not ignored) in the reference dictionary 00717 for k in keys: 00718 if k in to_check: # the key must be in the dictionary to_check 00719 if (type(reference[k]) is dict) and (type(to_check[k]) is dict): 00720 # if both reference and to_check values are dictionaries, recurse 00721 failed = fail_keys = cmpTreesDicts(reference[k], to_check[k], ignore) 00722 else: 00723 # compare the two values 00724 failed = to_check[k] != reference[k] 00725 else: # handle missing keys in the dictionary to check (i.e. failure) 00726 to_check[k] = None 00727 failed = True 00728 if failed: 00729 fail_keys.insert(0, k) 00730 break # exit from the loop at the first failure 00731 return fail_keys # return the list of keys bringing to the different values
| def GaudiTest::countErrorLines | ( | expected = {'ERROR':0, |
|
| FATAL | |||
| ) |
Definition at line 595 of file GaudiTest.py.
00595 {'ERROR':0, 'FATAL':0}, **kwargs): 00596 """ 00597 Count the number of messages with required severity (by default ERROR and FATAL) 00598 and check if their numbers match the expected ones (0 by default). 00599 The dictionary "expected" can be used to tune the number of errors and fatals 00600 allowed, or to limit the number of expected warnings etc. 00601 """ 00602 stdout = kwargs["stdout"] 00603 result = kwargs["result"] 00604 causes = kwargs["causes"] 00605 00606 # prepare the dictionary to record the extracted lines 00607 errors = {} 00608 for sev in expected: 00609 errors[sev] = [] 00610 00611 outlines = stdout.splitlines() 00612 from math import log10 00613 fmt = "%%%dd - %%s" % (int(log10(len(outlines))+1)) 00614 00615 linecount = 0 00616 for l in outlines: 00617 linecount += 1 00618 words = l.split() 00619 if len(words) >= 2 and words[1] in errors: 00620 errors[words[1]].append(fmt%(linecount,l.rstrip())) 00621 00622 for e in errors: 00623 if len(errors[e]) != expected[e]: 00624 causes.append('%s(%d)'%(e,len(errors[e]))) 00625 result["GaudiTest.lines.%s"%e] = result.Quote('\n'.join(errors[e])) 00626 result["GaudiTest.lines.%s.expected#"%e] = result.Quote(str(expected[e])) 00627 00628 return causes 00629 00630
| def GaudiTest::findHistosSummaries | ( | stdout ) |
Scan stdout to find ROOT TTree summaries and digest them.
Definition at line 808 of file GaudiTest.py.
00809 : 00810 """ 00811 Scan stdout to find ROOT TTree summaries and digest them. 00812 """ 00813 outlines = stdout.splitlines() 00814 nlines = len(outlines) - 1 00815 summaries = {} 00816 global h_count_re 00817 00818 pos = 0 00819 while pos < nlines: 00820 summ = {} 00821 # find first line of block: 00822 match = h_count_re.search(outlines[pos]) 00823 while pos < nlines and not match: 00824 pos += 1 00825 match = h_count_re.search(outlines[pos]) 00826 if match: 00827 summ, pos = parseHistosSummary(outlines, pos) 00828 summaries.update(summ) 00829 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 548 of file GaudiTest.py.
00550 : 00551 """ 00552 Given a block of text, tries to find it in the output. 00553 The block had to be identified by a signature line. By default, the first 00554 line is used as signature, or the line pointed to by signature_offset. If 00555 signature_offset points outside the block, a signature line can be passed as 00556 signature argument. Note: if 'signature' is None (the default), a negative 00557 signature_offset is interpreted as index in a list (e.g. -1 means the last 00558 line), otherwise the it is interpreted as the number of lines before the 00559 first one of the block the signature must appear. 00560 The parameter 'id' allow to distinguish between different calls to this 00561 function in the same validation code. 00562 """ 00563 # split reference file, sanitize EOLs and remove empty lines 00564 reflines = filter(None,map(lambda s: s.rstrip(), reference.splitlines())) 00565 if not reflines: 00566 raise RuntimeError("Empty (or null) reference") 00567 # the same on standard output 00568 outlines = filter(None,map(lambda s: s.rstrip(), stdout.splitlines())) 00569 00570 res_field = "GaudiTest.RefBlock" 00571 if id: 00572 res_field += "_%s" % id 00573 00574 if signature is None: 00575 if signature_offset < 0: 00576 signature_offset = len(reference)+signature_offset 00577 signature = reflines[signature_offset] 00578 # find the reference block in the output file 00579 try: 00580 pos = outlines.index(signature) 00581 outlines = outlines[pos-signature_offset:pos+len(reflines)-signature_offset] 00582 if reflines != outlines: 00583 msg = "standard output" 00584 # I do not want 2 messages in causes if teh function is called twice 00585 if not msg in causes: 00586 causes.append(msg) 00587 result[res_field + ".observed"] = result.Quote("\n".join(outlines)) 00588 except ValueError: 00589 causes.append("missing signature") 00590 result[res_field + ".signature"] = result.Quote(signature) 00591 if len(reflines) > 1 or signature != reflines[0]: 00592 result[res_field + ".expected"] = result.Quote("\n".join(reflines)) 00593 00594 return causes
| def GaudiTest::findTTreeSummaries | ( | stdout ) |
Scan stdout to find ROOT TTree summaries and digest them.
Definition at line 680 of file GaudiTest.py.
00681 : 00682 """ 00683 Scan stdout to find ROOT TTree summaries and digest them. 00684 """ 00685 stars = re.compile(r"^\*+$") 00686 outlines = stdout.splitlines() 00687 nlines = len(outlines) 00688 trees = {} 00689 00690 i = 0 00691 while i < nlines: #loop over the output 00692 # look for 00693 while i < nlines and not stars.match(outlines[i]): 00694 i += 1 00695 if i < nlines: 00696 tree, i = _parseTTreeSummary(outlines, i) 00697 if tree: 00698 trees[tree["Name"]] = tree 00699 00700 return trees
| def GaudiTest::getCmpFailingValues | ( | reference, | |
| to_check, | |||
| fail_path | |||
| ) |
Definition at line 732 of file GaudiTest.py.
| 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 745 of file GaudiTest.py.
00746 : 00747 """ 00748 Extract the histograms infos from the lines starting at pos. 00749 Returns the position of the first line after the summary block. 00750 """ 00751 global h_count_re 00752 h_table_head = re.compile(r'SUCCESS\s+List of booked (1D|2D|3D|1D profile|2D profile) histograms in directory\s+"(\w*)"') 00753 h_short_summ = re.compile(r"ID=([^\"]+)\s+\"([^\"]+)\"\s+(.*)") 00754 00755 nlines = len(lines) 00756 00757 # decode header 00758 m = h_count_re.search(lines[pos]) 00759 name = m.group(1).strip() 00760 total = int(m.group(2)) 00761 header = {} 00762 for k, v in [ x.split("=") for x in m.group(3).split() ]: 00763 header[k] = int(v) 00764 pos += 1 00765 header["Total"] = total 00766 00767 summ = {} 00768 while pos < nlines: 00769 m = h_table_head.search(lines[pos]) 00770 if m: 00771 t, d = m.groups(1) # type and directory 00772 t = t.replace(" profile", "Prof") 00773 pos += 1 00774 if pos < nlines: 00775 l = lines[pos] 00776 else: 00777 l = "" 00778 cont = {} 00779 if l.startswith(" | ID"): 00780 # table format 00781 titles = [ x.strip() for x in l.split("|")][1:] 00782 pos += 1 00783 while pos < nlines and lines[pos].startswith(" |"): 00784 l = lines[pos] 00785 values = [ x.strip() for x in l.split("|")][1:] 00786 hcont = {} 00787 for i in range(len(titles)): 00788 hcont[titles[i]] = values[i] 00789 cont[hcont["ID"]] = hcont 00790 pos += 1 00791 elif l.startswith(" ID="): 00792 while pos < nlines and lines[pos].startswith(" ID="): 00793 values = [ x.strip() for x in h_short_summ.search(lines[pos]).groups() ] 00794 cont[values[0]] = values 00795 pos += 1 00796 else: # not interpreted 00797 raise RuntimeError("Cannot understand line %d: '%s'" % (pos, l)) 00798 if not d in summ: 00799 summ[d] = {} 00800 summ[d][t] = cont 00801 summ[d]["header"] = header 00802 else: 00803 break 00804 if not summ: 00805 # If the full table is not present, we use only the header 00806 summ[name] = {"header": header} 00807 return summ, pos
| def GaudiTest::rationalizepath | ( | p ) |
Definition at line 283 of file GaudiTest.py.
| 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 263 of file GaudiTest.py.
00264 : 00265 """ 00266 Locates an executable in the executables path ($PATH) and returns the full 00267 path to it. An application is looked for with or without the '.exe' suffix. 00268 If the executable cannot be found, None is returned 00269 """ 00270 if os.path.isabs(executable): 00271 if not os.path.exists(executable): 00272 if executable.endswith('.exe'): 00273 if os.path.exists(executable[:-4]): 00274 return executable[:-4] 00275 return executable 00276 for d in os.environ.get("PATH").split(os.pathsep): 00277 fullpath = os.path.join(d, executable) 00278 if os.path.exists(fullpath): 00279 return fullpath 00280 if executable.endswith('.exe'): 00281 return which(executable[:-4]) 00282 return None
| 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::h_count_re = re.compile(r"^(.*)SUCCESS\s+Booked (\d+) Histogram\(s\) :\s+(.*)") |
Definition at line 743 of file GaudiTest.py.
| tuple GaudiTest::maskPointers = RegexpReplacer("0x[0-9a-fA-F]{4,16}","0x########") |
Definition at line 418 of file GaudiTest.py.
| tuple GaudiTest::normalizeDate |
00001 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)?", 00002 "00:00:00 1970-01-01")
Definition at line 419 of file GaudiTest.py.
| tuple GaudiTest::normalizeEOL = FilePreprocessor() |
Definition at line 421 of file GaudiTest.py.
Definition at line 444 of file GaudiTest.py.
| tuple GaudiTest::skipEmptyLines = FilePreprocessor() |
Definition at line 424 of file GaudiTest.py.