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