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