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