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