Gaudi Framework, version v23r9

Home   Generated: Thu Jul 18 2013
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
Classes | Functions | Variables
GaudiTest Namespace Reference

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+(.*)")
 

Function Documentation

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 631 of file GaudiTest.py.

632 def _parseTTreeSummary(lines, pos):
633  """
634  Parse the TTree summary table in lines, starting from pos.
635  Returns a tuple with the dictionary with the digested informations and the
636  position of the first line after the summary.
637  """
638  result = {}
639  i = pos + 1 # first line is a sequence of '*'
640  count = len(lines)
641 
642  splitcols = lambda l: [ f.strip() for f in l.strip("*\n").split(':',2) ]
643  def parseblock(ll):
644  r = {}
645  cols = splitcols(ll[0])
646  r["Name"], r["Title"] = cols[1:]
647 
648  cols = splitcols(ll[1])
649  r["Entries"] = int(cols[1])
650 
651  sizes = cols[2].split()
652  r["Total size"] = int(sizes[2])
653  if sizes[-1] == "memory":
654  r["File size"] = 0
655  else:
656  r["File size"] = int(sizes[-1])
657 
658  cols = splitcols(ll[2])
659  sizes = cols[2].split()
660  if cols[0] == "Baskets":
661  r["Baskets"] = int(cols[1])
662  r["Basket size"] = int(sizes[2])
663  r["Compression"] = float(sizes[-1])
664  return r
665 
666  if i < (count - 3) and lines[i].startswith("*Tree"):
667  result = parseblock(lines[i:i+3])
668  result["Branches"] = {}
669  i += 4
670  while i < (count - 3) and lines[i].startswith("*Br"):
671  if i < (count - 2) and lines[i].startswith("*Branch "):
672  # skip branch header
673  i += 3
674  continue
675  branch = parseblock(lines[i:i+3])
676  result["Branches"][branch["Name"]] = branch
677  i += 4
678 
679  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 701 of file GaudiTest.py.

702 def cmpTreesDicts(reference, to_check, ignore = None):
703  """
704  Check that all the keys in reference are in to_check too, with the same value.
705  If the value is a dict, the function is called recursively. to_check can
706  contain more keys than reference, that will not be tested.
707  The function returns at the first difference found.
708  """
709  fail_keys = []
710  # filter the keys in the reference dictionary
711  if ignore:
712  ignore_re = re.compile(ignore)
713  keys = [ key for key in reference if not ignore_re.match(key) ]
714  else:
715  keys = reference.keys()
716  # loop over the keys (not ignored) in the reference dictionary
717  for k in keys:
718  if k in to_check: # the key must be in the dictionary to_check
719  if (type(reference[k]) is dict) and (type(to_check[k]) is dict):
720  # if both reference and to_check values are dictionaries, recurse
721  failed = fail_keys = cmpTreesDicts(reference[k], to_check[k], ignore)
722  else:
723  # compare the two values
724  failed = to_check[k] != reference[k]
725  else: # handle missing keys in the dictionary to check (i.e. failure)
726  to_check[k] = None
727  failed = True
728  if failed:
729  fail_keys.insert(0, k)
730  break # exit from the loop at the first failure
731  return fail_keys # return the list of keys bringing to the different values
def GaudiTest.countErrorLines (   expected = {'ERROR':0,
  FATAL 
)

Definition at line 595 of file GaudiTest.py.

596 def countErrorLines(expected = {'ERROR':0, 'FATAL':0}, **kwargs):
597  """
598  Count the number of messages with required severity (by default ERROR and FATAL)
599  and check if their numbers match the expected ones (0 by default).
600  The dictionary "expected" can be used to tune the number of errors and fatals
601  allowed, or to limit the number of expected warnings etc.
602  """
603  stdout = kwargs["stdout"]
604  result = kwargs["result"]
605  causes = kwargs["causes"]
606 
607  # prepare the dictionary to record the extracted lines
608  errors = {}
609  for sev in expected:
610  errors[sev] = []
611 
612  outlines = stdout.splitlines()
613  from math import log10
614  fmt = "%%%dd - %%s" % (int(log10(len(outlines))+1))
615 
616  linecount = 0
617  for l in outlines:
618  linecount += 1
619  words = l.split()
620  if len(words) >= 2 and words[1] in errors:
621  errors[words[1]].append(fmt%(linecount,l.rstrip()))
622 
623  for e in errors:
624  if len(errors[e]) != expected[e]:
625  causes.append('%s(%d)'%(e,len(errors[e])))
626  result["GaudiTest.lines.%s"%e] = result.Quote('\n'.join(errors[e]))
627  result["GaudiTest.lines.%s.expected#"%e] = result.Quote(str(expected[e]))
628 
629  return causes
630 
def GaudiTest.findHistosSummaries (   stdout)
Scan stdout to find ROOT TTree summaries and digest them.

Definition at line 808 of file GaudiTest.py.

809 def findHistosSummaries(stdout):
810  """
811  Scan stdout to find ROOT TTree summaries and digest them.
812  """
813  outlines = stdout.splitlines()
814  nlines = len(outlines) - 1
815  summaries = {}
816  global h_count_re
817 
818  pos = 0
819  while pos < nlines:
820  summ = {}
821  # find first line of block:
822  match = h_count_re.search(outlines[pos])
823  while pos < nlines and not match:
824  pos += 1
825  match = h_count_re.search(outlines[pos])
826  if match:
827  summ, pos = parseHistosSummary(outlines, pos)
828  summaries.update(summ)
829  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 549 of file GaudiTest.py.

550  id = None):
551  """
552  Given a block of text, tries to find it in the output.
553  The block had to be identified by a signature line. By default, the first
554  line is used as signature, or the line pointed to by signature_offset. If
555  signature_offset points outside the block, a signature line can be passed as
556  signature argument. Note: if 'signature' is None (the default), a negative
557  signature_offset is interpreted as index in a list (e.g. -1 means the last
558  line), otherwise the it is interpreted as the number of lines before the
559  first one of the block the signature must appear.
560  The parameter 'id' allow to distinguish between different calls to this
561  function in the same validation code.
562  """
563  # split reference file, sanitize EOLs and remove empty lines
564  reflines = filter(None,map(lambda s: s.rstrip(), reference.splitlines()))
565  if not reflines:
566  raise RuntimeError("Empty (or null) reference")
567  # the same on standard output
568  outlines = filter(None,map(lambda s: s.rstrip(), stdout.splitlines()))
569 
570  res_field = "GaudiTest.RefBlock"
571  if id:
572  res_field += "_%s" % id
573 
574  if signature is None:
575  if signature_offset < 0:
576  signature_offset = len(reference)+signature_offset
577  signature = reflines[signature_offset]
578  # find the reference block in the output file
579  try:
580  pos = outlines.index(signature)
581  outlines = outlines[pos-signature_offset:pos+len(reflines)-signature_offset]
582  if reflines != outlines:
583  msg = "standard output"
584  # I do not want 2 messages in causes if teh function is called twice
585  if not msg in causes:
586  causes.append(msg)
587  result[res_field + ".observed"] = result.Quote("\n".join(outlines))
588  except ValueError:
589  causes.append("missing signature")
590  result[res_field + ".signature"] = result.Quote(signature)
591  if len(reflines) > 1 or signature != reflines[0]:
592  result[res_field + ".expected"] = result.Quote("\n".join(reflines))
593 
594  return causes
def GaudiTest.findTTreeSummaries (   stdout)
Scan stdout to find ROOT TTree summaries and digest them.

Definition at line 680 of file GaudiTest.py.

681 def findTTreeSummaries(stdout):
682  """
683  Scan stdout to find ROOT TTree summaries and digest them.
684  """
685  stars = re.compile(r"^\*+$")
686  outlines = stdout.splitlines()
687  nlines = len(outlines)
688  trees = {}
689 
690  i = 0
691  while i < nlines: #loop over the output
692  # look for
693  while i < nlines and not stars.match(outlines[i]):
694  i += 1
695  if i < nlines:
696  tree, i = _parseTTreeSummary(outlines, i)
697  if tree:
698  trees[tree["Name"]] = tree
699 
700  return trees
def GaudiTest.getCmpFailingValues (   reference,
  to_check,
  fail_path 
)

Definition at line 732 of file GaudiTest.py.

733 def getCmpFailingValues(reference, to_check, fail_path):
734  c = to_check
735  r = reference
736  for k in fail_path:
737  c = c.get(k,None)
738  r = r.get(k,None)
739  if c is None or r is None:
740  break # one of the dictionaries is not deep enough
741  return (fail_path, r, c)
742 
# signature of the print-out of the histograms
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 745 of file GaudiTest.py.

746 def parseHistosSummary(lines, pos):
747  """
748  Extract the histograms infos from the lines starting at pos.
749  Returns the position of the first line after the summary block.
750  """
751  global h_count_re
752  h_table_head = re.compile(r'SUCCESS\s+List of booked (1D|2D|3D|1D profile|2D profile) histograms in directory\s+"(\w*)"')
753  h_short_summ = re.compile(r"ID=([^\"]+)\s+\"([^\"]+)\"\s+(.*)")
754 
755  nlines = len(lines)
756 
757  # decode header
758  m = h_count_re.search(lines[pos])
759  name = m.group(1).strip()
760  total = int(m.group(2))
761  header = {}
762  for k, v in [ x.split("=") for x in m.group(3).split() ]:
763  header[k] = int(v)
764  pos += 1
765  header["Total"] = total
766 
767  summ = {}
768  while pos < nlines:
769  m = h_table_head.search(lines[pos])
770  if m:
771  t, d = m.groups(1) # type and directory
772  t = t.replace(" profile", "Prof")
773  pos += 1
774  if pos < nlines:
775  l = lines[pos]
776  else:
777  l = ""
778  cont = {}
779  if l.startswith(" | ID"):
780  # table format
781  titles = [ x.strip() for x in l.split("|")][1:]
782  pos += 1
783  while pos < nlines and lines[pos].startswith(" |"):
784  l = lines[pos]
785  values = [ x.strip() for x in l.split("|")][1:]
786  hcont = {}
787  for i in range(len(titles)):
788  hcont[titles[i]] = values[i]
789  cont[hcont["ID"]] = hcont
790  pos += 1
791  elif l.startswith(" ID="):
792  while pos < nlines and lines[pos].startswith(" ID="):
793  values = [ x.strip() for x in h_short_summ.search(lines[pos]).groups() ]
794  cont[values[0]] = values
795  pos += 1
796  else: # not interpreted
797  raise RuntimeError("Cannot understand line %d: '%s'" % (pos, l))
798  if not d in summ:
799  summ[d] = {}
800  summ[d][t] = cont
801  summ[d]["header"] = header
802  else:
803  break
804  if not summ:
805  # If the full table is not present, we use only the header
806  summ[name] = {"header": header}
807  return summ, pos
def GaudiTest.rationalizepath (   p)

Definition at line 283 of file GaudiTest.py.

284 def rationalizepath(p):
285  p = os.path.normpath(os.path.expandvars(p))
286  if os.path.exists(p):
287  p = os.path.realpath(p)
288  return p
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

Locates an executable in the executables path ($PATH) and returns the full
path to it.  An application is looked for with or without the '.exe' suffix.
If the executable cannot be found, None is returned

Definition at line 263 of file GaudiTest.py.

264 def which(executable):
265  """
266  Locates an executable in the executables path ($PATH) and returns the full
267  path to it. An application is looked for with or without the '.exe' suffix.
268  If the executable cannot be found, None is returned
269  """
270  if os.path.isabs(executable):
271  if not os.path.exists(executable):
272  if executable.endswith('.exe'):
273  if os.path.exists(executable[:-4]):
274  return executable[:-4]
275  return executable
276  for d in os.environ.get("PATH").split(os.pathsep):
277  fullpath = os.path.join(d, executable)
278  if os.path.exists(fullpath):
279  return fullpath
280  if executable.endswith('.exe'):
281  return which(executable[:-4])
282  return None

Variable Documentation

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 743 of file GaudiTest.py.

tuple GaudiTest.maskPointers RegexpReplacer("0x[0-9a-fA-F]{4,16}","0x########")

Definition at line 418 of file GaudiTest.py.

tuple GaudiTest.normalizeDate
Initial value:
1 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)?",
2  "00:00:00 1970-01-01")

Definition at line 419 of file GaudiTest.py.

tuple GaudiTest.normalizeEOL FilePreprocessor()

Definition at line 421 of file GaudiTest.py.

tuple GaudiTest.normalizeExamples maskPointers+normalizeDate

Definition at line 444 of file GaudiTest.py.

tuple GaudiTest.skipEmptyLines FilePreprocessor()

Definition at line 424 of file GaudiTest.py.


Generated at Thu Jul 18 2013 12:18:15 for Gaudi Framework, version v23r9 by Doxygen version 1.8.2 written by Dimitri van Heesch, © 1997-2004