|
Gaudi Framework, version v22r4 |
| Home | Generated: Fri Sep 2 2011 |
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 branch = parseblock(lines[i:i+3]) 00661 result["Branches"][branch["Name"]] = branch 00662 i += 4 00663 00664 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 686 of file GaudiTest.py.
00687 : 00688 """ 00689 Check that all the keys in reference are in to_check too, with the same value. 00690 If the value is a dict, the function is called recursively. to_check can 00691 contain more keys than reference, that will not be tested. 00692 The function returns at the first difference found. 00693 """ 00694 fail_keys = [] 00695 # filter the keys in the reference dictionary 00696 if ignore: 00697 ignore_re = re.compile(ignore) 00698 keys = [ key for key in reference if not ignore_re.match(key) ] 00699 else: 00700 keys = reference.keys() 00701 # loop over the keys (not ignored) in the reference dictionary 00702 for k in keys: 00703 if k in to_check: # the key must be in the dictionary to_check 00704 if (type(reference[k]) is dict) and (type(to_check[k]) is dict): 00705 # if both reference and to_check values are dictionaries, recurse 00706 failed = fail_keys = cmpTreesDicts(reference[k], to_check[k], ignore) 00707 else: 00708 # compare the two values 00709 failed = to_check[k] != reference[k] 00710 else: # handle missing keys in the dictionary to check (i.e. failure) 00711 to_check[k] = None 00712 failed = True 00713 if failed: 00714 fail_keys.insert(0, k) 00715 break # exit from the loop at the first failure 00716 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 793 of file GaudiTest.py.
00794 : 00795 """ 00796 Scan stdout to find ROOT TTree summaries and digest them. 00797 """ 00798 outlines = stdout.splitlines() 00799 nlines = len(outlines) - 1 00800 summaries = {} 00801 global h_count_re 00802 00803 pos = 0 00804 while pos < nlines: 00805 summ = {} 00806 # find first line of block: 00807 match = h_count_re.search(outlines[pos]) 00808 while pos < nlines and not match: 00809 pos += 1 00810 match = h_count_re.search(outlines[pos]) 00811 if match: 00812 summ, pos = parseHistosSummary(outlines, pos) 00813 summaries.update(summ) 00814 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 665 of file GaudiTest.py.
00666 : 00667 """ 00668 Scan stdout to find ROOT TTree summaries and digest them. 00669 """ 00670 stars = re.compile(r"^\*+$") 00671 outlines = stdout.splitlines() 00672 nlines = len(outlines) 00673 trees = {} 00674 00675 i = 0 00676 while i < nlines: #loop over the output 00677 # look for 00678 while i < nlines and not stars.match(outlines[i]): 00679 i += 1 00680 if i < nlines: 00681 tree, i = _parseTTreeSummary(outlines, i) 00682 if tree: 00683 trees[tree["Name"]] = tree 00684 00685 return trees
| def GaudiTest::getCmpFailingValues | ( | reference, | |
| to_check, | |||
| fail_path | |||
| ) |
Definition at line 717 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 730 of file GaudiTest.py.
00731 : 00732 """ 00733 Extract the histograms infos from the lines starting at pos. 00734 Returns the position of the first line after the summary block. 00735 """ 00736 global h_count_re 00737 h_table_head = re.compile(r'SUCCESS\s+List of booked (1D|2D|3D|1D profile|2D profile) histograms in directory\s+"(\w*)"') 00738 h_short_summ = re.compile(r"ID=([^\"]+)\s+\"([^\"]+)\"\s+(.*)") 00739 00740 nlines = len(lines) 00741 00742 # decode header 00743 m = h_count_re.search(lines[pos]) 00744 name = m.group(1).strip() 00745 total = int(m.group(2)) 00746 header = {} 00747 for k, v in [ x.split("=") for x in m.group(3).split() ]: 00748 header[k] = int(v) 00749 pos += 1 00750 header["Total"] = total 00751 00752 summ = {} 00753 while pos < nlines: 00754 m = h_table_head.search(lines[pos]) 00755 if m: 00756 t, d = m.groups(1) # type and directory 00757 t = t.replace(" profile", "Prof") 00758 pos += 1 00759 if pos < nlines: 00760 l = lines[pos] 00761 else: 00762 l = "" 00763 cont = {} 00764 if l.startswith(" | ID"): 00765 # table format 00766 titles = [ x.strip() for x in l.split("|")][1:] 00767 pos += 1 00768 while pos < nlines and lines[pos].startswith(" |"): 00769 l = lines[pos] 00770 values = [ x.strip() for x in l.split("|")][1:] 00771 hcont = {} 00772 for i in range(len(titles)): 00773 hcont[titles[i]] = values[i] 00774 cont[hcont["ID"]] = hcont 00775 pos += 1 00776 elif l.startswith(" ID="): 00777 while pos < nlines and lines[pos].startswith(" ID="): 00778 values = [ x.strip() for x in h_short_summ.search(lines[pos]).groups() ] 00779 cont[values[0]] = values 00780 pos += 1 00781 else: # not interpreted 00782 raise RuntimeError("Cannot understand line %d: '%s'" % (pos, l)) 00783 if not d in summ: 00784 summ[d] = {} 00785 summ[d][t] = cont 00786 summ[d]["header"] = header 00787 else: 00788 break 00789 if not summ: 00790 # If the full table is not present, we use only the header 00791 summ[name] = {"header": header} 00792 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 728 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.