Gaudi Framework, version v24r2

Home   Generated: Wed Dec 4 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 636 of file GaudiTest.py.

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

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

Definition at line 600 of file GaudiTest.py.

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

Definition at line 813 of file GaudiTest.py.

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

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

Definition at line 685 of file GaudiTest.py.

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

Definition at line 737 of file GaudiTest.py.

738 def getCmpFailingValues(reference, to_check, fail_path):
739  c = to_check
740  r = reference
741  for k in fail_path:
742  c = c.get(k,None)
743  r = r.get(k,None)
744  if c is None or r is None:
745  break # one of the dictionaries is not deep enough
746  return (fail_path, r, c)
747 
# 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 750 of file GaudiTest.py.

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

Definition at line 286 of file GaudiTest.py.

287 def rationalizepath(p):
288  p = os.path.normpath(os.path.expandvars(p))
289  if os.path.exists(p):
290  p = os.path.realpath(p)
291  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 266 of file GaudiTest.py.

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

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

Definition at line 421 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 422 of file GaudiTest.py.

tuple GaudiTest.normalizeEOL FilePreprocessor()

Definition at line 424 of file GaudiTest.py.

tuple GaudiTest.normalizeExamples maskPointers+normalizeDate

Definition at line 447 of file GaudiTest.py.

tuple GaudiTest.skipEmptyLines FilePreprocessor()

Definition at line 427 of file GaudiTest.py.


Generated at Wed Dec 4 2013 14:33:23 for Gaudi Framework, version v24r2 by Doxygen version 1.8.2 written by Dimitri van Heesch, © 1997-2004