24 from subprocess
import Popen, PIPE, STDOUT
28 if sys.version_info < (3, 5):
31 from codecs
import register_error, backslashreplace_errors
34 if isinstance(exc, UnicodeDecodeError):
35 code =
hex(ord(exc.object[exc.start]))
36 return (
u'\\' + code[1:], exc.start + 1)
38 return backslashreplace_errors(exc)
40 register_error(
'backslashreplace', _new_backslashreplace_errors)
42 del backslashreplace_errors
43 del _new_backslashreplace_errors
48 Take a string with invalid ASCII/UTF characters and quote them so that the 49 string can be used in an XML text. 51 >>> sanitize_for_xml('this is \x1b') 52 'this is [NON-XML-CHAR-0x1B]' 54 bad_chars = re.compile(
55 u'[\x00-\x08\x0b\x0c\x0e-\x1F\uD800-\uDFFF\uFFFE\uFFFF]')
59 return ''.join(
'[NON-XML-CHAR-0x%2X]' % ord(c)
for c
in match.group())
61 return bad_chars.sub(quote, data)
65 '''helper to debug GAUDI-1084, dump the list of processes''' 66 from getpass
import getuser
67 if 'WORKSPACE' in os.environ:
68 p = Popen([
'ps',
'-fH',
'-U', getuser()], stdout=PIPE)
69 with open(os.path.join(os.environ[
'WORKSPACE'], name),
'wb')
as f:
70 f.write(p.communicate()[0])
75 Send a signal to a process and all its child processes (starting from the 78 log = logging.getLogger(
'kill_tree')
79 ps_cmd = [
'ps',
'--no-headers',
'-o',
'pid',
'--ppid', str(ppid)]
80 get_children = Popen(ps_cmd, stdout=PIPE, stderr=PIPE)
81 children =
map(int, get_children.communicate()[0].split())
82 for child
in children:
85 log.debug(
'killing process %d', ppid)
87 except OSError
as err:
90 log.debug(
'no such process %d', ppid)
127 logging.debug(
'running test %s', self.
name)
131 r'from\s+Gaudi.Configuration\s+import\s+\*|' 132 'from\s+Configurables\s+import', self.
options):
133 optionFile = tempfile.NamedTemporaryFile(suffix=
'.py')
135 optionFile = tempfile.NamedTemporaryFile(suffix=
'.opts')
136 optionFile.file.write(self.
options.encode(
'utf-8'))
147 platform_id = (os.environ.get(
'BINARY_TAG')
148 or os.environ.get(
'CMTCONFIG')
or platform.platform())
152 if re.search(prex, platform_id)
162 workdir = tempfile.mkdtemp()
168 elif "GAUDIEXE" in os.environ:
169 prog = os.environ[
"GAUDIEXE"]
173 dummy, prog_ext = os.path.splitext(prog)
174 if prog_ext
not in [
".exe",
".py",
".bat"]:
178 prog =
which(prog)
or prog
180 args = list(
map(RationalizePath, self.
args))
182 if prog_ext ==
".py":
195 'TIMEOUT_DETAIL':
None 197 self.
result = validatorRes
205 logging.debug(
'executing %r in %s', params, workdir)
207 params, stdout=PIPE, stderr=PIPE, env=self.
environment)
208 logging.debug(
'(pid: %d)', self.
proc.pid)
209 out, err = self.
proc.communicate()
210 self.
out = out.decode(
'utf-8', errors=
'backslashreplace')
211 self.
err = err.decode(
'utf-8', errors=
'backslashreplace')
213 thread = threading.Thread(target=target)
218 if thread.is_alive():
219 logging.debug(
'time out in test %s (pid %d)', self.
name,
224 str(self.
proc.pid),
'--batch',
225 '--eval-command=thread apply all backtrace' 227 gdb = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT)
229 'utf-8', errors=
'backslashreplace')
233 if thread.is_alive():
235 self.
causes.append(
'timeout')
237 logging.debug(
'completed test %s', self.
name)
240 logging.debug(
'returnedCode = %s', self.
proc.returncode)
243 logging.debug(
'validating test...')
245 stdout=self.
out, stderr=self.
err, result=validatorRes)
249 shutil.rmtree(workdir,
True)
254 if self.
signal is not None:
256 self.
causes.append(
'exit code')
260 self.
causes.append(
'exit code')
263 self.
causes.append(
"exit code")
273 logging.debug(
'%s: %s', self.
name, self.
status)
275 'Exit Code':
'returnedCode',
278 'Environment':
'environment',
281 'Program Name':
'program',
283 'Validator':
'validator',
284 'Output Reference File':
'reference',
285 'Error Reference File':
'error_reference',
288 'Unsupported Platforms':
'unsupported_platforms',
289 'Stack Trace':
'stack_trace' 291 resultDict = [(key, getattr(self, attr))
292 for key, attr
in field_mapping.items()
293 if getattr(self, attr)]
294 resultDict.append((
'Working Directory',
296 os.path.join(os.getcwd(), self.
workdir))))
298 resultDict.extend(self.
result.annotations.items())
300 return dict(resultDict)
309 elif stderr.strip() != self.
stderr.strip():
310 self.
causes.append(
'standard error')
311 return result, self.
causes 322 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. 325 if reference
is None:
335 filter(
None,
map(
lambda s: s.rstrip(), reference.splitlines())))
337 raise RuntimeError(
"Empty (or null) reference")
340 filter(
None,
map(
lambda s: s.rstrip(), stdout.splitlines())))
342 res_field =
"GaudiTest.RefBlock" 344 res_field +=
"_%s" % id
346 if signature
is None:
347 if signature_offset < 0:
348 signature_offset = len(reference) + signature_offset
349 signature = reflines[signature_offset]
352 pos = outlines.index(signature)
353 outlines = outlines[pos - signature_offset:pos + len(reflines) -
355 if reflines != outlines:
356 msg =
"standard output" 359 if not msg
in causes:
361 result[res_field +
".observed"] = result.Quote(
364 causes.append(
"missing signature")
365 result[res_field +
".signature"] = result.Quote(signature)
366 if len(reflines) > 1
or signature != reflines[0]:
367 result[res_field +
".expected"] = result.Quote(
"\n".join(reflines))
379 Count the number of messages with required severity (by default ERROR and FATAL) 380 and check if their numbers match the expected ones (0 by default). 381 The dictionary "expected" can be used to tune the number of errors and fatals 382 allowed, or to limit the number of expected warnings etc. 397 outlines = stdout.splitlines()
398 from math
import log10
399 fmt =
"%%%dd - %%s" % (int(log10(len(outlines) + 1)))
405 if len(words) >= 2
and words[1]
in errors:
406 errors[words[1]].append(fmt % (linecount, l.rstrip()))
409 if len(errors[e]) != expected[e]:
410 causes.append(
'%s(%d)' % (e, len(errors[e])))
411 result[
"GaudiTest.lines.%s" % e] = result.Quote(
'\n'.join(
413 result[
"GaudiTest.lines.%s.expected#" % e] = result.Quote(
423 ignore=r"Basket|.*size|Compression"):
425 Compare the TTree summaries in stdout with the ones in trees_dict or in 426 the reference file. By default ignore the size, compression and basket 428 The presence of TTree summaries when none is expected is not a failure. 436 if trees_dict
is None:
439 if lreference
and os.path.isfile(lreference):
444 from pprint
import PrettyPrinter
447 result[
"GaudiTest.TTrees.expected"] = result.Quote(
448 pp.pformat(trees_dict))
450 result[
"GaudiTest.TTrees.ignore"] = result.Quote(ignore)
455 causes.append(
"trees summaries")
458 result[
"GaudiTest.TTrees.failure_on"] = result.Quote(msg)
459 result[
"GaudiTest.TTrees.found"] = result.Quote(pp.pformat(trees))
470 Compare the TTree summaries in stdout with the ones in trees_dict or in 471 the reference file. By default ignore the size, compression and basket 473 The presence of TTree summaries when none is expected is not a failure. 485 if lreference
and os.path.isfile(lreference):
490 from pprint
import PrettyPrinter
493 result[
"GaudiTest.Histos.expected"] = result.Quote(
496 result[
"GaudiTest.Histos.ignore"] = result.Quote(ignore)
501 causes.append(
"histos summaries")
503 result[
"GaudiTest.Histos.failure_on"] = result.Quote(msg)
504 result[
"GaudiTest.Histos.found"] = result.Quote(pp.pformat(histos))
515 Default validation acti*on: compare standard output and error to the 530 preproc = normalizeExamples
534 if lreference
and os.path.isfile(lreference):
536 lreference,
"standard output",
"Output Diff",
537 preproc=preproc)(stdout, result)
539 causes += [
"missing reference file"]
543 if causes
and lreference:
546 newrefname =
'.'.join([lreference,
'new'])
547 while os.path.exists(newrefname):
549 newrefname =
'.'.join([lreference,
'~%d~' % cnt,
'new'])
550 newref = open(newrefname,
"w")
552 for l
in stdout.splitlines():
553 newref.write(l.rstrip() +
'\n')
555 result[
'New Output Reference File'] = os.path.relpath(
566 if os.path.isfile(lreference):
571 preproc=preproc)(stderr, result)
573 newcauses += [
"missing error reference file"]
575 if newcauses
and lreference:
577 newrefname =
'.'.join([lreference,
'new'])
578 while os.path.exists(newrefname):
580 newrefname =
'.'.join([lreference,
'~%d~' % cnt,
'new'])
581 newref = open(newrefname,
"w")
583 for l
in stderr.splitlines():
584 newref.write(l.rstrip() +
'\n')
586 result[
'New Error Reference File'] = os.path.relpath(
590 "ExecTest.expected_stderr")(stderr,
600 def platformSplit(p):
602 delim = re.compile(
'-' in p
and r"[-+]" or r"_")
603 return set(delim.split(p))
605 reference = os.path.normpath(
606 os.path.join(self.
basedir, os.path.expandvars(reffile)))
609 spec_ref = reference[:-3] +
GetPlatform(self)[0:3] + reference[-3:]
610 if os.path.isfile(spec_ref):
614 dirname, basename = os.path.split(reference)
617 head = basename +
"." 620 if 'do0' in platform:
623 for f
in os.listdir(dirname):
624 if f.startswith(head):
625 req_plat = platformSplit(f[head_len:])
626 if platform.issuperset(req_plat):
627 candidates.append((len(req_plat), f))
632 reference = os.path.join(dirname, candidates[-1][1])
644 from GaudiKernel
import ROOT6WorkAroundEnabled
657 Function used to normalize the used path 659 newPath = os.path.normpath(os.path.expandvars(p))
660 if os.path.exists(newPath):
661 p = os.path.realpath(newPath)
667 Locates an executable in the executables path ($PATH) and returns the full 668 path to it. An application is looked for with or without the '.exe' suffix. 669 If the executable cannot be found, None is returned 671 if os.path.isabs(executable):
672 if not os.path.exists(executable):
673 if executable.endswith(
'.exe'):
674 if os.path.exists(executable[:-4]):
675 return executable[:-4]
677 head, executable = os.path.split(executable)
680 for d
in os.environ.get(
"PATH").split(os.pathsep):
681 fullpath = os.path.join(d, executable)
682 if os.path.exists(fullpath):
684 if executable.endswith(
'.exe'):
685 return which(executable[:-4])
700 UNTESTED =
'UNTESTED' 710 def __init__(self, kind=None, id=None, outcome=PASS, annotations={}):
714 assert isinstance(key, six.string_types)
718 assert isinstance(key, six.string_types)
720 value, six.string_types),
'{!r} is not a string'.
format(value)
743 """Validate the output of the program. 744 'stdout' -- A string containing the data written to the standard output 746 'stderr' -- A string containing the data written to the standard error 748 'result' -- A 'Result' object. It may be used to annotate 749 the outcome according to the content of stderr. 750 returns -- A list of strings giving causes of failure.""" 755 causes.append(self.
cause)
761 """Compare 's1' and 's2', ignoring line endings. 764 returns -- True if 's1' and 's2' are the same, ignoring 765 differences in line endings.""" 769 to_ignore = re.compile(
770 r'Warning in <TInterpreter::ReadRootmapFile>: .* is already in .*' 774 return not to_ignore.match(l)
776 return list(filter(keep_line, s1.splitlines())) == list(
777 filter(keep_line, s2.splitlines()))
779 return s1.splitlines() == s2.splitlines()
784 """ Base class for a callable that takes a file and returns a modified 799 if not isinstance(input, six.string_types):
803 lines = input.splitlines()
807 output =
'\n'.join(output)
836 if line.find(s) >= 0:
851 if self.
start in line:
854 elif self.
end in line:
864 when = re.compile(when)
868 if isinstance(rhs, RegexpReplacer):
870 res._operations = self.
_operations + rhs._operations
872 res = FilePreprocessor.__add__(self, rhs)
877 if w
is None or w.search(line):
878 line = o.sub(r, line)
885 "[0-2]?[0-9]:[0-5][0-9]:[0-5][0-9] [0-9]{4}[-/][01][0-9][-/][0-3][0-9][ A-Z]*",
886 "00:00:00 1970-01-01")
888 normalizeEOL.__processLine__ =
lambda line: str(line).rstrip() +
'\n' 892 skipEmptyLines.__processLine__ =
lambda line: (line.strip()
and line)
or None 906 line = line[:(pos + self.
siglen)]
907 lst = line[(pos + self.
siglen):].split()
909 line +=
" ".join(lst)
915 Sort group of lines matching a regular expression 919 self.
exp = exp
if hasattr(exp,
'match')
else re.compile(exp)
922 match = self.
exp.match
938 normalizeExamples = maskPointers + normalizeDate
941 (
"TIMER.TIMER",
r"\s+[+-]?[0-9]+[0-9.]*",
" 0"),
942 (
"release all pending",
r"^.*/([^/]*:.*)",
r"\1"),
943 (
"^#.*file",
r"file '.*[/\\]([^/\\]*)$",
r"file '\1"),
944 (
"^JobOptionsSvc.*options successfully read in from",
945 r"read in from .*[/\\]([^/\\]*)$",
949 r"[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}(?!-0{12})-[0-9A-Fa-f]{12}",
950 "00000000-0000-0000-0000-000000000000"),
952 (
"ServiceLocatorHelper::",
"ServiceLocatorHelper::(create|locate)Service",
953 "ServiceLocatorHelper::service"),
955 (
None,
r"e([-+])0([0-9][0-9])",
r"e\1\2"),
957 (
None,
r'Service reference count check:',
958 r'Looping over all active services...'),
961 r"^(.*(DEBUG|SUCCESS) List of ALL properties of .*#properties = )\d+",
963 (
'ApplicationMgr',
r'(declareMultiSvcType|addMultiSvc): ',
''),
964 (
"Property ['Name': Value]",
r"( = '[^']+':)'(.*)'",
r'\1\2'),
965 (
'DataObjectHandleBase',
r'DataObjectHandleBase\("([^"]*)"\)',
r"'\1'"),
972 "JobOptionsSvc INFO # ",
973 "JobOptionsSvc WARNING # ",
976 "This machine has a speed",
979 "ToolSvc.Sequenc... INFO",
980 "DataListenerSvc INFO XML written to file:",
983 "DEBUG No writable file catalog found which contains FID:",
984 "DEBUG Service base class initialized successfully",
986 "DEBUG Incident timing:",
990 "INFO 'CnvServices':[",
992 "DEBUG 'CnvServices':[",
997 'Histograms saving not required.',
1000 r"^JobOptionsSvc INFO *$",
1003 r"(Always|SUCCESS)\s*(Root f|[^ ]* F)ile version:",
1004 r"File '.*.xml' does not exist",
1005 r"INFO Refer to dataset .* by its file ID:",
1006 r"INFO Referring to dataset .* by its file ID:",
1007 r"INFO Disconnect from dataset",
1008 r"INFO Disconnected from dataset",
1009 r"INFO Disconnected data IO:",
1010 r"IncidentSvc\s*(DEBUG (Adding|Removing)|VERBOSE Calling)",
1012 r"^StatusCodeSvc.*listing all unchecked return codes:",
1013 r"^StatusCodeSvc\s*INFO\s*$",
1014 r"Num\s*\|\s*Function\s*\|\s*Source Library",
1017 r"ERROR Failed to modify file: .* Errno=2 No such file or directory",
1019 r"^ +[0-9]+ \|.*ROOT",
1020 r"^ +[0-9]+ \|.*\|.*Dict",
1022 r"StatusCodeSvc.*all StatusCode instances where checked",
1024 r"EventLoopMgr.*---> Loop Finished",
1025 r"HiveSlimEventLo.*---> Loop Finished",
1030 r"SUCCESS\s*Booked \d+ Histogram\(s\)",
1034 r"Property(.*)'Audit(Algorithm|Tool|Service)s':",
1035 r"Property(.*)'Audit(Begin|End)Run':",
1037 r"Property(.*)'AuditRe(start|initialize)':",
1038 r"Property(.*)'IsIOBound':",
1040 r"Property(.*)'ErrorCount(er)?':",
1042 r"Property(.*)'Sequential':",
1044 r"Property(.*)'FilterCircularDependencies':",
1046 r"Property(.*)'IsClonable':",
1048 r"Property update for OutputLevel : new value =",
1049 r"EventLoopMgr\s*DEBUG Creating OutputStream",
1056 r'Warning in <TInterpreter::ReadRootmapFile>: .* is already in .*',
1059 normalizeExamples = (
1060 lineSkipper + normalizeExamples + skipEmptyLines + normalizeEOL +
1068 def __init__(self, reffile, cause, result_key, preproc=normalizeExamples):
1076 if os.path.isfile(self.
reffile):
1077 orig = open(self.
reffile).readlines()
1080 result[self.
result_key +
'.preproc.orig'] = \
1081 result.Quote(
'\n'.join(
map(str.strip, orig)))
1084 new = stdout.splitlines()
1088 diffs = difflib.ndiff(orig, new, charjunk=difflib.IS_CHARACTER_JUNK)
1090 map(
lambda x: x.strip(), filter(
lambda x: x[0] !=
" ", diffs)))
1092 result[self.
result_key] = result.Quote(
"\n".join(filterdiffs))
1096 +) standard output of the test""")
1098 result.Quote(
'\n'.join(
map(str.strip, new)))
1099 causes.append(self.
cause)
1105 Scan stdout to find ROOT TTree summaries and digest them. 1107 stars = re.compile(
r"^\*+$")
1108 outlines = stdout.splitlines()
1109 nlines = len(outlines)
1115 while i < nlines
and not stars.match(outlines[i]):
1120 trees[tree[
"Name"]] = tree
1127 Check that all the keys in reference are in to_check too, with the same value. 1128 If the value is a dict, the function is called recursively. to_check can 1129 contain more keys than reference, that will not be tested. 1130 The function returns at the first difference found. 1135 ignore_re = re.compile(ignore)
1136 keys = [key
for key
in reference
if not ignore_re.match(key)]
1138 keys = reference.keys()
1142 if (
type(reference[k])
is dict)
and (
type(to_check[k])
is dict):
1145 failed = fail_keys =
cmpTreesDicts(reference[k], to_check[k],
1149 failed = to_check[k] != reference[k]
1154 fail_keys.insert(0, k)
1165 if c
is None or r
is None:
1167 return (fail_path, r, c)
1171 h_count_re = re.compile(
1172 r"^(.*)SUCCESS\s+Booked (\d+) Histogram\(s\) :\s+([\s\w=-]*)")
1177 Parse the TTree summary table in lines, starting from pos. 1178 Returns a tuple with the dictionary with the digested informations and the 1179 position of the first line after the summary. 1186 return [f.strip()
for f
in l.strip(
"*\n").split(
':', 2)]
1190 cols = splitcols(ll[0])
1191 r[
"Name"], r[
"Title"] = cols[1:]
1193 cols = splitcols(ll[1])
1194 r[
"Entries"] = int(cols[1])
1196 sizes = cols[2].split()
1197 r[
"Total size"] = int(sizes[2])
1198 if sizes[-1] ==
"memory":
1201 r[
"File size"] = int(sizes[-1])
1203 cols = splitcols(ll[2])
1204 sizes = cols[2].split()
1205 if cols[0] ==
"Baskets":
1206 r[
"Baskets"] = int(cols[1])
1207 r[
"Basket size"] = int(sizes[2])
1208 r[
"Compression"] = float(sizes[-1])
1211 if i < (count - 3)
and lines[i].startswith(
"*Tree"):
1212 result = parseblock(lines[i:i + 3])
1213 result[
"Branches"] = {}
1215 while i < (count - 3)
and lines[i].startswith(
"*Br"):
1216 if i < (count - 2)
and lines[i].startswith(
"*Branch "):
1220 branch = parseblock(lines[i:i + 3])
1221 result[
"Branches"][branch[
"Name"]] = branch
1229 Extract the histograms infos from the lines starting at pos. 1230 Returns the position of the first line after the summary block. 1233 h_table_head = re.compile(
1234 r'SUCCESS\s+(1D|2D|3D|1D profile|2D profile) histograms in directory\s+"(\w*)"' 1236 h_short_summ = re.compile(
r"ID=([^\"]+)\s+\"([^\"]+)\"\s+(.*)")
1241 m = h_count_re.search(lines[pos])
1242 name = m.group(1).strip()
1243 total = int(m.group(2))
1245 for k, v
in [x.split(
"=")
for x
in m.group(3).split()]:
1248 header[
"Total"] = total
1252 m = h_table_head.search(lines[pos])
1255 t = t.replace(
" profile",
"Prof")
1262 if l.startswith(
" | ID"):
1264 titles = [x.strip()
for x
in l.split(
"|")][1:]
1266 while pos < nlines
and lines[pos].startswith(
" |"):
1268 values = [x.strip()
for x
in l.split(
"|")][1:]
1270 for i
in range(len(titles)):
1271 hcont[titles[i]] = values[i]
1272 cont[hcont[
"ID"]] = hcont
1274 elif l.startswith(
" ID="):
1275 while pos < nlines
and lines[pos].startswith(
" ID="):
1278 for x
in h_short_summ.search(lines[pos]).groups()
1280 cont[values[0]] = values
1284 "Cannot understand line %d: '%s'" % (pos, l))
1288 summ[d][
"header"] = header
1293 summ[name] = {
"header": header}
1299 Scan stdout to find ROOT TTree summaries and digest them. 1301 outlines = stdout.splitlines()
1302 nlines = len(outlines) - 1
1310 match = h_count_re.search(outlines[pos])
1311 while pos < nlines
and not match:
1313 match = h_count_re.search(outlines[pos])
1316 summaries.update(summ)
1323 re.compile(x)
for x
in [str(y).strip()
for y
in unsupported_platforms]
1326 for p_re
in unsupported:
1327 if p_re.search(platform):
1328 result.SetOutcome(result.UNTESTED)
1329 result[result.CAUSE] =
'Platform not supported.' 1336 Return the platform Id defined in CMTCONFIG or SCRAM_ARCH. 1340 if "BINARY_TAG" in os.environ:
1341 arch = os.environ[
"BINARY_TAG"]
1342 elif "CMTCONFIG" in os.environ:
1343 arch = os.environ[
"CMTCONFIG"]
1344 elif "SCRAM_ARCH" in os.environ:
1345 arch = os.environ[
"SCRAM_ARCH"]
1351 Return True if the current platform is Windows. 1353 This function was needed because of the change in the CMTCONFIG format, 1354 from win32_vc71_dbg to i686-winxp-vc9-dbg. 1357 return "winxp" in platform
or platform.startswith(
"win")
GAUDI_API std::string format(const char *,...)
MsgStream format utility "a la sprintf(...)".
def PlatformIsNotSupported(self, context, result)
def __processLine__(self, line)
def __init__(self, start, end)
def __call__(self, input)
def validateWithReference(self, stdout=None, stderr=None, result=None, causes=None, preproc=None)
def __processLine__(self, line)
def cmpTreesDicts(reference, to_check, ignore=None)
def __processFile__(self, lines)
def ValidateOutput(self, stdout, stderr, result)
def read(f, regex='.*', skipevents=0)
def __processLine__(self, line)
def __processFile__(self, lines)
def __call__(self, out, result)
def findHistosSummaries(stdout)
MsgStream & hex(MsgStream &log)
def _parseTTreeSummary(lines, pos)
struct GAUDI_API map
Parametrisation class for map-like implementation.
def __call__(self, stdout, result)
def __processLine__(self, line)
def __init__(self, orig, repl="", when=None)
def _new_backslashreplace_errors(exc)
def __init__(self, signature)
def __call__(self, input)
def sanitize_for_xml(data)
def countErrorLines(self, expected={ 'ERROR':0, 'FATAL':0 }, stdout=None, result=None, causes=None)
def getCmpFailingValues(reference, to_check, fail_path)
def __init__(self, members=[])
def __init__(self, strings=[], regexps=[])
def __setitem__(self, key, value)
def __init__(self, kind=None, id=None, outcome=PASS, annotations={})
def __processLine__(self, line)
def parseHistosSummary(lines, pos)
def _expandReferenceFileName(self, reffile)
def findReferenceBlock(self, reference=None, stdout=None, result=None, causes=None, signature_offset=0, signature=None, id=None)
def CheckHistosSummaries(self, stdout=None, result=None, causes=None, dict=None, ignore=None)
def __CompareText(self, s1, s2)
def __init__(self, reffile, cause, result_key, preproc=normalizeExamples)
decltype(auto) range(Args &&... args)
Zips multiple containers together to form a single range.
def __getitem__(self, key)
def findTTreeSummaries(stdout)
def __init__(self, ref, cause, result_key)
def ROOT6WorkAroundEnabled(id=None)
def CheckTTreesSummaries(self, stdout=None, result=None, causes=None, trees_dict=None, ignore=r"Basket|.*size|Compression")