Gaudi Framework, version v25r0

Home   Generated: Mon Feb 17 2014
 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
 
class  XMLResultStream
 

Functions

def ROOT6WorkAroundEnabled
 
def total_seconds_replacement
 
def which
 Locates an executable in the executables path ($PATH) and returns the full path to it.
 
def rationalizepath
 
def hexreplace
 
def hexConvert
 
def convert_xml_illegal_chars
 
def escape_xml_illegal_chars
 
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 _illegal_xml_chars_RE re.compile(u'[\x00-\x08\x0b\x0c\x0e-\x1F\uD800-\uDFFF\uFFFE\uFFFF]')
 
tuple maskPointers RegexpReplacer("0x[0-9a-fA-F]{4,16}","0x########")
 
tuple normalizeDate
 
tuple normalizeEOL FilePreprocessor()
 
tuple skipEmptyLines FilePreprocessor()
 
 normalizeExamples maskPointers+normalizeDate
 
tuple lineSkipper
 
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 690 of file GaudiTest.py.

691 def _parseTTreeSummary(lines, pos):
692  """
693  Parse the TTree summary table in lines, starting from pos.
694  Returns a tuple with the dictionary with the digested informations and the
695  position of the first line after the summary.
696  """
697  result = {}
698  i = pos + 1 # first line is a sequence of '*'
699  count = len(lines)
700 
701  splitcols = lambda l: [ f.strip() for f in l.strip("*\n").split(':',2) ]
702  def parseblock(ll):
703  r = {}
704  cols = splitcols(ll[0])
705  r["Name"], r["Title"] = cols[1:]
706 
707  cols = splitcols(ll[1])
708  r["Entries"] = int(cols[1])
709 
710  sizes = cols[2].split()
711  r["Total size"] = int(sizes[2])
712  if sizes[-1] == "memory":
713  r["File size"] = 0
714  else:
715  r["File size"] = int(sizes[-1])
716 
717  cols = splitcols(ll[2])
718  sizes = cols[2].split()
719  if cols[0] == "Baskets":
720  r["Baskets"] = int(cols[1])
721  r["Basket size"] = int(sizes[2])
722  r["Compression"] = float(sizes[-1])
723  return r
724 
725  if i < (count - 3) and lines[i].startswith("*Tree"):
726  result = parseblock(lines[i:i+3])
727  result["Branches"] = {}
728  i += 4
729  while i < (count - 3) and lines[i].startswith("*Br"):
730  if i < (count - 2) and lines[i].startswith("*Branch "):
731  # skip branch header
732  i += 3
733  continue
734  branch = parseblock(lines[i:i+3])
735  result["Branches"][branch["Name"]] = branch
736  i += 4
737 
738  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 760 of file GaudiTest.py.

761 def cmpTreesDicts(reference, to_check, ignore = None):
762  """
763  Check that all the keys in reference are in to_check too, with the same value.
764  If the value is a dict, the function is called recursively. to_check can
765  contain more keys than reference, that will not be tested.
766  The function returns at the first difference found.
767  """
768  fail_keys = []
769  # filter the keys in the reference dictionary
770  if ignore:
771  ignore_re = re.compile(ignore)
772  keys = [ key for key in reference if not ignore_re.match(key) ]
773  else:
774  keys = reference.keys()
775  # loop over the keys (not ignored) in the reference dictionary
776  for k in keys:
777  if k in to_check: # the key must be in the dictionary to_check
778  if (type(reference[k]) is dict) and (type(to_check[k]) is dict):
779  # if both reference and to_check values are dictionaries, recurse
780  failed = fail_keys = cmpTreesDicts(reference[k], to_check[k], ignore)
781  else:
782  # compare the two values
783  failed = to_check[k] != reference[k]
784  else: # handle missing keys in the dictionary to check (i.e. failure)
785  to_check[k] = None
786  failed = True
787  if failed:
788  fail_keys.insert(0, k)
789  break # exit from the loop at the first failure
790  return fail_keys # return the list of keys bringing to the different values
def GaudiTest.convert_xml_illegal_chars (   val)

Definition at line 335 of file GaudiTest.py.

337  return _illegal_xml_chars_RE.sub(hexreplace, val)
def GaudiTest.countErrorLines (   expected = {'ERROR':0,
  FATAL 
)

Definition at line 654 of file GaudiTest.py.

655 def countErrorLines(expected = {'ERROR':0, 'FATAL':0}, **kwargs):
656  """
657  Count the number of messages with required severity (by default ERROR and FATAL)
658  and check if their numbers match the expected ones (0 by default).
659  The dictionary "expected" can be used to tune the number of errors and fatals
660  allowed, or to limit the number of expected warnings etc.
661  """
662  stdout = kwargs["stdout"]
663  result = kwargs["result"]
664  causes = kwargs["causes"]
665 
666  # prepare the dictionary to record the extracted lines
667  errors = {}
668  for sev in expected:
669  errors[sev] = []
670 
671  outlines = stdout.splitlines()
672  from math import log10
673  fmt = "%%%dd - %%s" % (int(log10(len(outlines))+1))
674 
675  linecount = 0
676  for l in outlines:
677  linecount += 1
678  words = l.split()
679  if len(words) >= 2 and words[1] in errors:
680  errors[words[1]].append(fmt%(linecount,l.rstrip()))
681 
682  for e in errors:
683  if len(errors[e]) != expected[e]:
684  causes.append('%s(%d)'%(e,len(errors[e])))
685  result["GaudiTest.lines.%s"%e] = result.Quote('\n'.join(errors[e]))
686  result["GaudiTest.lines.%s.expected#"%e] = result.Quote(str(expected[e]))
687 
688  return causes
689 
def GaudiTest.escape_xml_illegal_chars (   val,
  replacement = '?' 
)
Filter out characters that are illegal in XML.
Looks for any character in val that is not allowed in XML
and replaces it with replacement ('?' by default).

Definition at line 338 of file GaudiTest.py.

339 def escape_xml_illegal_chars(val, replacement='?'):
340  """Filter out characters that are illegal in XML.
341  Looks for any character in val that is not allowed in XML
342  and replaces it with replacement ('?' by default).
343 
344  """
345  return _illegal_xml_chars_RE.sub(replacement, val)
def GaudiTest.findHistosSummaries (   stdout)
Scan stdout to find ROOT TTree summaries and digest them.

Definition at line 867 of file GaudiTest.py.

868 def findHistosSummaries(stdout):
869  """
870  Scan stdout to find ROOT TTree summaries and digest them.
871  """
872  outlines = stdout.splitlines()
873  nlines = len(outlines) - 1
874  summaries = {}
875  global h_count_re
876 
877  pos = 0
878  while pos < nlines:
879  summ = {}
880  # find first line of block:
881  match = h_count_re.search(outlines[pos])
882  while pos < nlines and not match:
883  pos += 1
884  match = h_count_re.search(outlines[pos])
885  if match:
886  summ, pos = parseHistosSummary(outlines, pos)
887  summaries.update(summ)
888  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 608 of file GaudiTest.py.

609  id = None):
610  """
611  Given a block of text, tries to find it in the output.
612  The block had to be identified by a signature line. By default, the first
613  line is used as signature, or the line pointed to by signature_offset. If
614  signature_offset points outside the block, a signature line can be passed as
615  signature argument. Note: if 'signature' is None (the default), a negative
616  signature_offset is interpreted as index in a list (e.g. -1 means the last
617  line), otherwise the it is interpreted as the number of lines before the
618  first one of the block the signature must appear.
619  The parameter 'id' allow to distinguish between different calls to this
620  function in the same validation code.
621  """
622  # split reference file, sanitize EOLs and remove empty lines
623  reflines = filter(None,map(lambda s: s.rstrip(), reference.splitlines()))
624  if not reflines:
625  raise RuntimeError("Empty (or null) reference")
626  # the same on standard output
627  outlines = filter(None,map(lambda s: s.rstrip(), stdout.splitlines()))
628 
629  res_field = "GaudiTest.RefBlock"
630  if id:
631  res_field += "_%s" % id
632 
633  if signature is None:
634  if signature_offset < 0:
635  signature_offset = len(reference)+signature_offset
636  signature = reflines[signature_offset]
637  # find the reference block in the output file
638  try:
639  pos = outlines.index(signature)
640  outlines = outlines[pos-signature_offset:pos+len(reflines)-signature_offset]
641  if reflines != outlines:
642  msg = "standard output"
643  # I do not want 2 messages in causes if teh function is called twice
644  if not msg in causes:
645  causes.append(msg)
646  result[res_field + ".observed"] = result.Quote("\n".join(outlines))
647  except ValueError:
648  causes.append("missing signature")
649  result[res_field + ".signature"] = result.Quote(signature)
650  if len(reflines) > 1 or signature != reflines[0]:
651  result[res_field + ".expected"] = result.Quote("\n".join(reflines))
652 
653  return causes
def GaudiTest.findTTreeSummaries (   stdout)
Scan stdout to find ROOT TTree summaries and digest them.

Definition at line 739 of file GaudiTest.py.

740 def findTTreeSummaries(stdout):
741  """
742  Scan stdout to find ROOT TTree summaries and digest them.
743  """
744  stars = re.compile(r"^\*+$")
745  outlines = stdout.splitlines()
746  nlines = len(outlines)
747  trees = {}
748 
749  i = 0
750  while i < nlines: #loop over the output
751  # look for
752  while i < nlines and not stars.match(outlines[i]):
753  i += 1
754  if i < nlines:
755  tree, i = _parseTTreeSummary(outlines, i)
756  if tree:
757  trees[tree["Name"]] = tree
758 
759  return trees
def GaudiTest.getCmpFailingValues (   reference,
  to_check,
  fail_path 
)

Definition at line 791 of file GaudiTest.py.

792 def getCmpFailingValues(reference, to_check, fail_path):
793  c = to_check
794  r = reference
795  for k in fail_path:
796  c = c.get(k,None)
797  r = r.get(k,None)
798  if c is None or r is None:
799  break # one of the dictionaries is not deep enough
800  return (fail_path, r, c)
801 
# signature of the print-out of the histograms
def GaudiTest.hexConvert (   char)

Definition at line 333 of file GaudiTest.py.

334 def hexConvert(char):
return hex(ord(char))
def GaudiTest.hexreplace (   match)

Definition at line 329 of file GaudiTest.py.

330 def hexreplace( match ):
331  "Return the hex string "
332  return "".join(map(hexConvert,match.group()))
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 804 of file GaudiTest.py.

805 def parseHistosSummary(lines, pos):
806  """
807  Extract the histograms infos from the lines starting at pos.
808  Returns the position of the first line after the summary block.
809  """
810  global h_count_re
811  h_table_head = re.compile(r'SUCCESS\s+List of booked (1D|2D|3D|1D profile|2D profile) histograms in directory\s+"(\w*)"')
812  h_short_summ = re.compile(r"ID=([^\"]+)\s+\"([^\"]+)\"\s+(.*)")
813 
814  nlines = len(lines)
815 
816  # decode header
817  m = h_count_re.search(lines[pos])
818  name = m.group(1).strip()
819  total = int(m.group(2))
820  header = {}
821  for k, v in [ x.split("=") for x in m.group(3).split() ]:
822  header[k] = int(v)
823  pos += 1
824  header["Total"] = total
825 
826  summ = {}
827  while pos < nlines:
828  m = h_table_head.search(lines[pos])
829  if m:
830  t, d = m.groups(1) # type and directory
831  t = t.replace(" profile", "Prof")
832  pos += 1
833  if pos < nlines:
834  l = lines[pos]
835  else:
836  l = ""
837  cont = {}
838  if l.startswith(" | ID"):
839  # table format
840  titles = [ x.strip() for x in l.split("|")][1:]
841  pos += 1
842  while pos < nlines and lines[pos].startswith(" |"):
843  l = lines[pos]
844  values = [ x.strip() for x in l.split("|")][1:]
845  hcont = {}
846  for i in range(len(titles)):
847  hcont[titles[i]] = values[i]
848  cont[hcont["ID"]] = hcont
849  pos += 1
850  elif l.startswith(" ID="):
851  while pos < nlines and lines[pos].startswith(" ID="):
852  values = [ x.strip() for x in h_short_summ.search(lines[pos]).groups() ]
853  cont[values[0]] = values
854  pos += 1
855  else: # not interpreted
856  raise RuntimeError("Cannot understand line %d: '%s'" % (pos, l))
857  if not d in summ:
858  summ[d] = {}
859  summ[d][t] = cont
860  summ[d]["header"] = header
861  else:
862  break
863  if not summ:
864  # If the full table is not present, we use only the header
865  summ[name] = {"header": header}
866  return summ, pos
def GaudiTest.rationalizepath (   p)

Definition at line 307 of file GaudiTest.py.

308 def rationalizepath(p):
309  np = os.path.normpath(os.path.expandvars(p))
310  if os.path.exists(np):
311  p = os.path.realpath(np)
312  return p
313 
# XML Escaping character
def GaudiTest.ROOT6WorkAroundEnabled (   id = None)

Definition at line 23 of file GaudiTest.py.

23 
24  def ROOT6WorkAroundEnabled(id=None):
25  # dummy implementation
26  return False
27 
28 # ensure the preferred locale
29 os.environ['LC_ALL'] = 'C'
30 
31 # Needed for the XML wrapper
try:
def GaudiTest.total_seconds_replacement (   timedelta)

Definition at line 37 of file GaudiTest.py.

37 
38 def total_seconds_replacement(timedelta) :
39  return timedelta.days*86400 + timedelta.seconds + timedelta.microseconds/1000000
40 
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 287 of file GaudiTest.py.

288 def which(executable):
289  """
290  Locates an executable in the executables path ($PATH) and returns the full
291  path to it. An application is looked for with or without the '.exe' suffix.
292  If the executable cannot be found, None is returned
293  """
294  if os.path.isabs(executable):
295  if not os.path.exists(executable):
296  if executable.endswith('.exe'):
297  if os.path.exists(executable[:-4]):
298  return executable[:-4]
299  return executable
300  for d in os.environ.get("PATH").split(os.pathsep):
301  fullpath = os.path.join(d, executable)
302  if os.path.exists(fullpath):
303  return fullpath
304  if executable.endswith('.exe'):
305  return which(executable[:-4])
306  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._illegal_xml_chars_RE re.compile(u'[\x00-\x08\x0b\x0c\x0e-\x1F\uD800-\uDFFF\uFFFE\uFFFF]')

Definition at line 327 of file GaudiTest.py.

tuple GaudiTest.h_count_re re.compile(r"^(.*)SUCCESS\s+Booked (\d+) Histogram\(s\) :\s+(.*)")

Definition at line 802 of file GaudiTest.py.

tuple GaudiTest.lineSkipper

Definition at line 520 of file GaudiTest.py.

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

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

tuple GaudiTest.normalizeEOL FilePreprocessor()

Definition at line 478 of file GaudiTest.py.

tuple GaudiTest.normalizeExamples maskPointers+normalizeDate

Definition at line 501 of file GaudiTest.py.

tuple GaudiTest.skipEmptyLines FilePreprocessor()

Definition at line 481 of file GaudiTest.py.


Generated at Mon Feb 17 2014 14:38:19 for Gaudi Framework, version v25r0 by Doxygen version 1.8.2 written by Dimitri van Heesch, © 1997-2004