The Gaudi Framework  master (53935a5b)
Loading...
Searching...
No Matches
preprocessors.py
Go to the documentation of this file.
11import re
12
13
15 """Base class for a callable that takes a file and returns a modified
16 version of it."""
17
18 def __processLine__(self, line):
19 return line
20
21 def __processFile__(self, lines):
22 output = []
23 for l in lines:
24 l = self.__processLine__(l)
25 if l:
26 output.append(l)
27 return output
28
29 def __call__(self, input):
30 if not isinstance(input, str):
31 lines = input
32 mergeback = False
33 else:
34 lines = input.splitlines()
35 mergeback = True
36 output = self.__processFile__(lines)
37 if mergeback:
38 output = "\n".join(output)
39 return output
40
41 def __add__(self, rhs):
42 return FilePreprocessorSequence([self, rhs])
43
44
46 def __init__(self, members=[]):
47 self.members = members
48
49 def __add__(self, rhs):
50 return FilePreprocessorSequence(self.members + [rhs])
51
52 def __call__(self, input):
53 output = input
54 for pp in self.members:
55 output = pp(output)
56 return output
57
58
59def _search_pattern(regexp):
60 """Drop a redundant leading ".*", which makes re.search quadratic in line length."""
61 if isinstance(regexp, str):
62 return re.sub(r"^\.\*(?![*+?{])", "", regexp)
63 return regexp
64
65
67 def __init__(self, strings=[], regexps=[]):
68 import re
69
70 self.strings = strings
71 self.regexps = [re.compile(_search_pattern(r)) for r in regexps]
72
73 def __processLine__(self, line):
74 for s in self.strings:
75 if line.find(s) >= 0:
76 return None
77 for r in self.regexps:
78 if r.search(line):
79 return None
80 return line
81
82
84 def __init__(self, start, end):
85 self.start = start
86 self.end = end
87 self._skipping = False
88
89 def __processLine__(self, line):
90 if self.start in line:
91 self._skipping = True
92 return None
93 elif self.end in line:
94 self._skipping = False
95 elif self._skipping:
96 return None
97 return line
98
99
101 """Ignore ROOT's environment-dependent registration message and its color reset."""
102
103 def __processFile__(self, lines):
104 return re.sub(
105 r"^TROOT[ \t]+INFO Object auto registration disabled using the environment variable ROOT_OBJECT_AUTO_REGISTRATION$"
106 r"(?:\n\x1b\‍[m$)?",
107 "",
108 "\n".join(lines),
109 flags=re.MULTILINE,
110 ).splitlines()
111
112
114 def __init__(self, orig, repl="", when=None):
115 if when:
116 when = re.compile(when)
117 self._operations = [(when, re.compile(orig), repl)]
118
119 def __add__(self, rhs):
120 if isinstance(rhs, RegexpReplacer):
121 res = RegexpReplacer("", "", None)
122 res._operations = self._operations + rhs._operations
123 else:
124 res = FilePreprocessor.__add__(self, rhs)
125 return res
126
127 def __processLine__(self, line):
128 for w, o, r in self._operations:
129 if w is None or w.search(line):
130 line = o.sub(r, line)
131 return line
132
133
134# Common preprocessors
135maskPointers = RegexpReplacer("0x[0-9a-fA-F]{4,16}", "0x########")
136normalizeDate = RegexpReplacer(
137 "[0-2]?[0-9]:[0-5][0-9]:[0-5][0-9] [0-9]{4}[-/][01][0-9][-/][0-3][0-9][ A-Z]*",
138 "00:00:00 1970-01-01",
139)
140normalizeEOL = FilePreprocessor()
141normalizeEOL.__processLine__ = lambda line: str(line).rstrip() + "\n"
142
143skipEmptyLines = FilePreprocessor()
144# FIXME: that's ugly
145skipEmptyLines.__processLine__ = lambda line: (line.strip() and line) or None
146
147# Special preprocessor sorting the list of strings (whitespace separated)
148# that follow a signature on a single line
149
150
152 def __init__(self, signature):
153 self.signature = signature
154 self.siglen = len(signature)
155
156 def __processLine__(self, line):
157 pos = line.find(self.signature)
158 if pos >= 0:
159 line = line[: (pos + self.siglen)]
160 lst = line[(pos + self.siglen) :].split()
161 lst.sort()
162 line += " ".join(lst)
163 return line
164
165
167 """
168 Sort group of lines matching a regular expression
169 """
170
171 def __init__(self, exp):
172 self.exp = exp if hasattr(exp, "match") else re.compile(exp)
173
174 def __processFile__(self, lines):
175 match = self.exp.match
176 output = []
177 group = []
178 for l in lines:
179 if match(l):
180 group.append(l)
181 else:
182 if group:
183 group.sort()
184 output.extend(group)
185 group = []
186 output.append(l)
187 return output
188
189
190# Preprocessors for GaudiTestSuite
191normalizeTestSuite = maskPointers + normalizeDate
192for w, o, r in [
193 ("TIMER", r"\s+[+-]?[0-9]+[0-9.e+-]*", " 0"), # Normalize time output
194 ("release all pending", r"^.*/([^/]*:.*)", r"\1"),
195 ("^#.*file", r"file '.*[/\\]([^/\\]*)$", r"file '\1"),
196 (
197 "^JobOptionsSvc.*options successfully read in from",
198 r"read in from .*[/\\]([^/\\]*)$",
199 r"file \1",
200 ), # normalize path to options
201 # Normalize UUID, except those ending with all 0s (i.e. the class IDs)
202 (
203 None,
204 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}",
205 "00000000-0000-0000-0000-000000000000",
206 ),
207 # Ignore count of declared properties (anyway they are all printed)
208 (
209 None,
210 r"^(.*(DEBUG|SUCCESS) List of ALL properties of .*#properties = )\d+",
211 r"\1NN",
212 ),
213 (r"Property \‍['Name': Value\‍]", r"( = '[^']+':)'(.*)'", r"\1\2"),
214 ("TimelineSvc", "to file 'TimelineFile':", "to file "),
215 ("DataObjectHandleBase", r'DataObjectHandleBase\‍("([^"]*)"\‍)', r"'\1'"),
216]:
217 normalizeTestSuite += RegexpReplacer(o, r, w)
218
219lineSkipper = LineSkipper(
220 [
221 "Time User",
222 "Welcome to",
223 "running on",
224 "[INFO]",
225 "[WARNING]",
226 "DEBUG No writable file catalog found which contains FID:",
227 "DEBUG Service base class initialized successfully",
228 # changed between v20 and v21
229 "DEBUG Incident timing:",
230 # message removed because could be printed in constructor
231 "DEBUG 'CnvServices':[",
232 # The signal handler complains about SIGXCPU not
233 # defined on some platforms
234 "SIGXCPU",
235 # Ignore warnings for properties case mismatch
236 "mismatching case for property name:",
237 # Message added in gaudi/Gaudi!577
238 "Properties are dumped into",
239 # Messages changed in gaudi/Gaudi!1426
240 "WARNING no ROOT output file name",
241 "INFO Writing ROOT histograms to:",
242 "INFO Completed update of ROOT histograms in:",
243 "INFO Disconnect from dataset",
244 "INFO Disconnected from dataset",
245 "INFO Disconnected data IO:",
246 # absorb changes in data dependencies reports (https://gitlab.cern.ch/gaudi/Gaudi/-/merge_requests/1348)
247 "Data Deps for ",
248 "data dependencies:",
249 ],
250 regexps=[
251 # Job property printouts
252 r"^JobOptionsSvc\s+INFO # ",
253 r"^JobOptionsSvc\s+WARNING # ",
254 r"^JobOptionsSvc\s+INFO *$",
255 r"^# ", # Ignore python comments
256 # skip the message reporting the version of the root file
257 r"(Always|SUCCESS)\s*(Root f|[^ ]* F)ile version:",
258 r"File '.*.xml' does not exist",
259 r"INFO Referring to dataset .* by its file ID:",
260 r"IncidentSvc\s*(DEBUG (Adding|Removing)|VERBOSE Calling)",
261 # skip '---'
262 r"^[-+]*\s*$",
263 # Hide EventLoopMgr total timing report
264 r"EventLoopMgr.*---> Loop Finished",
265 r"HiveSlimEventLo.*---> Loop Finished",
266 # Remove ROOT TTree summary table, which changes from one version to the other
267 r"^\*.*\*$",
268 # Remove Histos Summaries
269 r"SUCCESS\s*Booked \d+ Histogram\‍(s\‍)",
270 r"^ \|",
271 r"^ ID=",
272 # ignore uninteresting/obsolete messages
273 r"Property update for OutputLevel : new value =",
274 ],
275)
276
277normalizeTestSuite = (
279 + lineSkipper
280 + normalizeTestSuite
281 + skipEmptyLines
282 + normalizeEOL
283 + LineSorter("Services to release : ")
284 + SortGroupOfLines(r"^\S+\s+(DEBUG|SUCCESS) Property \‍[\'Name\':")
285)
__init__(self, strings=[], regexps=[])
__init__(self, orig, repl="", when=None)