Gaudi Framework, version v25r2

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

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

772 def cmpTreesDicts(reference, to_check, ignore = None):
773  """
774  Check that all the keys in reference are in to_check too, with the same value.
775  If the value is a dict, the function is called recursively. to_check can
776  contain more keys than reference, that will not be tested.
777  The function returns at the first difference found.
778  """
779  fail_keys = []
780  # filter the keys in the reference dictionary
781  if ignore:
782  ignore_re = re.compile(ignore)
783  keys = [ key for key in reference if not ignore_re.match(key) ]
784  else:
785  keys = reference.keys()
786  # loop over the keys (not ignored) in the reference dictionary
787  for k in keys:
788  if k in to_check: # the key must be in the dictionary to_check
789  if (type(reference[k]) is dict) and (type(to_check[k]) is dict):
790  # if both reference and to_check values are dictionaries, recurse
791  failed = fail_keys = cmpTreesDicts(reference[k], to_check[k], ignore)
792  else:
793  # compare the two values
794  failed = to_check[k] != reference[k]
795  else: # handle missing keys in the dictionary to check (i.e. failure)
796  to_check[k] = None
797  failed = True
798  if failed:
799  fail_keys.insert(0, k)
800  break # exit from the loop at the first failure
801  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 665 of file GaudiTest.py.

666 def countErrorLines(expected = {'ERROR':0, 'FATAL':0}, **kwargs):
667  """
668  Count the number of messages with required severity (by default ERROR and FATAL)
669  and check if their numbers match the expected ones (0 by default).
670  The dictionary "expected" can be used to tune the number of errors and fatals
671  allowed, or to limit the number of expected warnings etc.
672  """
673  stdout = kwargs["stdout"]
674  result = kwargs["result"]
675  causes = kwargs["causes"]
676 
677  # prepare the dictionary to record the extracted lines
678  errors = {}
679  for sev in expected:
680  errors[sev] = []
681 
682  outlines = stdout.splitlines()
683  from math import log10
684  fmt = "%%%dd - %%s" % (int(log10(len(outlines))+1))
685 
686  linecount = 0
687  for l in outlines:
688  linecount += 1
689  words = l.split()
690  if len(words) >= 2 and words[1] in errors:
691  errors[words[1]].append(fmt%(linecount,l.rstrip()))
692 
693  for e in errors:
694  if len(errors[e]) != expected[e]:
695  causes.append('%s(%d)'%(e,len(errors[e])))
696  result["GaudiTest.lines.%s"%e] = result.Quote('\n'.join(errors[e]))
697  result["GaudiTest.lines.%s.expected#"%e] = result.Quote(str(expected[e]))
698 
699  return causes
700 
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 878 of file GaudiTest.py.

879 def findHistosSummaries(stdout):
880  """
881  Scan stdout to find ROOT TTree summaries and digest them.
882  """
883  outlines = stdout.splitlines()
884  nlines = len(outlines) - 1
885  summaries = {}
886  global h_count_re
887 
888  pos = 0
889  while pos < nlines:
890  summ = {}
891  # find first line of block:
892  match = h_count_re.search(outlines[pos])
893  while pos < nlines and not match:
894  pos += 1
895  match = h_count_re.search(outlines[pos])
896  if match:
897  summ, pos = parseHistosSummary(outlines, pos)
898  summaries.update(summ)
899  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 619 of file GaudiTest.py.

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

Definition at line 750 of file GaudiTest.py.

751 def findTTreeSummaries(stdout):
752  """
753  Scan stdout to find ROOT TTree summaries and digest them.
754  """
755  stars = re.compile(r"^\*+$")
756  outlines = stdout.splitlines()
757  nlines = len(outlines)
758  trees = {}
759 
760  i = 0
761  while i < nlines: #loop over the output
762  # look for
763  while i < nlines and not stars.match(outlines[i]):
764  i += 1
765  if i < nlines:
766  tree, i = _parseTTreeSummary(outlines, i)
767  if tree:
768  trees[tree["Name"]] = tree
769 
770  return trees
def GaudiTest.getCmpFailingValues (   reference,
  to_check,
  fail_path 
)

Definition at line 802 of file GaudiTest.py.

803 def getCmpFailingValues(reference, to_check, fail_path):
804  c = to_check
805  r = reference
806  for k in fail_path:
807  c = c.get(k,None)
808  r = r.get(k,None)
809  if c is None or r is None:
810  break # one of the dictionaries is not deep enough
811  return (fail_path, r, c)
812 
# 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 815 of file GaudiTest.py.

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

tuple GaudiTest.lineSkipper

Definition at line 526 of file GaudiTest.py.

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

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

tuple GaudiTest.normalizeEOL FilePreprocessor()

Definition at line 484 of file GaudiTest.py.

tuple GaudiTest.normalizeExamples maskPointers+normalizeDate

Definition at line 507 of file GaudiTest.py.

tuple GaudiTest.skipEmptyLines FilePreprocessor()

Definition at line 487 of file GaudiTest.py.


Generated at Wed Jun 4 2014 14:49:06 for Gaudi Framework, version v25r2 by Doxygen version 1.8.2 written by Dimitri van Heesch, © 1997-2004