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