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