Gaudi Framework, version v23r10

Home   Generated: Mon Sep 30 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 634 of file GaudiTest.py.

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

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

Definition at line 598 of file GaudiTest.py.

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

Definition at line 811 of file GaudiTest.py.

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

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

Definition at line 683 of file GaudiTest.py.

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

Definition at line 735 of file GaudiTest.py.

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

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