Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/mako/exceptions.py: 40%
146 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:02 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:02 +0000
1# mako/exceptions.py
2# Copyright 2006-2023 the Mako authors and contributors <see AUTHORS file>
3#
4# This module is part of Mako and is released under
5# the MIT License: http://www.opensource.org/licenses/mit-license.php
7"""exception classes"""
9import sys
10import traceback
12from mako import compat
13from mako import util
16class MakoException(Exception):
17 pass
20class RuntimeException(MakoException):
21 pass
24def _format_filepos(lineno, pos, filename):
25 if filename is None:
26 return " at line: %d char: %d" % (lineno, pos)
27 else:
28 return " in file '%s' at line: %d char: %d" % (filename, lineno, pos)
31class CompileException(MakoException):
32 def __init__(self, message, source, lineno, pos, filename):
33 MakoException.__init__(
34 self, message + _format_filepos(lineno, pos, filename)
35 )
36 self.lineno = lineno
37 self.pos = pos
38 self.filename = filename
39 self.source = source
42class SyntaxException(MakoException):
43 def __init__(self, message, source, lineno, pos, filename):
44 MakoException.__init__(
45 self, message + _format_filepos(lineno, pos, filename)
46 )
47 self.lineno = lineno
48 self.pos = pos
49 self.filename = filename
50 self.source = source
53class UnsupportedError(MakoException):
55 """raised when a retired feature is used."""
58class NameConflictError(MakoException):
60 """raised when a reserved word is used inappropriately"""
63class TemplateLookupException(MakoException):
64 pass
67class TopLevelLookupException(TemplateLookupException):
68 pass
71class RichTraceback:
73 """Pull the current exception from the ``sys`` traceback and extracts
74 Mako-specific template information.
76 See the usage examples in :ref:`handling_exceptions`.
78 """
80 def __init__(self, error=None, traceback=None):
81 self.source, self.lineno = "", 0
83 if error is None or traceback is None:
84 t, value, tback = sys.exc_info()
86 if error is None:
87 error = value or t
89 if traceback is None:
90 traceback = tback
92 self.error = error
93 self.records = self._init(traceback)
95 if isinstance(self.error, (CompileException, SyntaxException)):
96 self.source = self.error.source
97 self.lineno = self.error.lineno
98 self._has_source = True
100 self._init_message()
102 @property
103 def errorname(self):
104 return compat.exception_name(self.error)
106 def _init_message(self):
107 """Find a unicode representation of self.error"""
108 try:
109 self.message = str(self.error)
110 except UnicodeError:
111 try:
112 self.message = str(self.error)
113 except UnicodeEncodeError:
114 # Fallback to args as neither unicode nor
115 # str(Exception(u'\xe6')) work in Python < 2.6
116 self.message = self.error.args[0]
117 if not isinstance(self.message, str):
118 self.message = str(self.message, "ascii", "replace")
120 def _get_reformatted_records(self, records):
121 for rec in records:
122 if rec[6] is not None:
123 yield (rec[4], rec[5], rec[2], rec[6])
124 else:
125 yield tuple(rec[0:4])
127 @property
128 def traceback(self):
129 """Return a list of 4-tuple traceback records (i.e. normal python
130 format) with template-corresponding lines remapped to the originating
131 template.
133 """
134 return list(self._get_reformatted_records(self.records))
136 @property
137 def reverse_records(self):
138 return reversed(self.records)
140 @property
141 def reverse_traceback(self):
142 """Return the same data as traceback, except in reverse order."""
144 return list(self._get_reformatted_records(self.reverse_records))
146 def _init(self, trcback):
147 """format a traceback from sys.exc_info() into 7-item tuples,
148 containing the regular four traceback tuple items, plus the original
149 template filename, the line number adjusted relative to the template
150 source, and code line from that line number of the template."""
152 import mako.template
154 mods = {}
155 rawrecords = traceback.extract_tb(trcback)
156 new_trcback = []
157 for filename, lineno, function, line in rawrecords:
158 if not line:
159 line = ""
160 try:
161 (line_map, template_lines, template_filename) = mods[filename]
162 except KeyError:
163 try:
164 info = mako.template._get_module_info(filename)
165 module_source = info.code
166 template_source = info.source
167 template_filename = (
168 info.template_filename or info.template_uri or filename
169 )
170 except KeyError:
171 # A normal .py file (not a Template)
172 new_trcback.append(
173 (
174 filename,
175 lineno,
176 function,
177 line,
178 None,
179 None,
180 None,
181 None,
182 )
183 )
184 continue
186 template_ln = 1
188 mtm = mako.template.ModuleInfo
189 source_map = mtm.get_module_source_metadata(
190 module_source, full_line_map=True
191 )
192 line_map = source_map["full_line_map"]
194 template_lines = [
195 line_ for line_ in template_source.split("\n")
196 ]
197 mods[filename] = (line_map, template_lines, template_filename)
199 template_ln = line_map[lineno - 1]
201 if template_ln <= len(template_lines):
202 template_line = template_lines[template_ln - 1]
203 else:
204 template_line = None
205 new_trcback.append(
206 (
207 filename,
208 lineno,
209 function,
210 line,
211 template_filename,
212 template_ln,
213 template_line,
214 template_source,
215 )
216 )
217 if not self.source:
218 for l in range(len(new_trcback) - 1, 0, -1):
219 if new_trcback[l][5]:
220 self.source = new_trcback[l][7]
221 self.lineno = new_trcback[l][5]
222 break
223 else:
224 if new_trcback:
225 try:
226 # A normal .py file (not a Template)
227 with open(new_trcback[-1][0], "rb") as fp:
228 encoding = util.parse_encoding(fp)
229 if not encoding:
230 encoding = "utf-8"
231 fp.seek(0)
232 self.source = fp.read()
233 if encoding:
234 self.source = self.source.decode(encoding)
235 except IOError:
236 self.source = ""
237 self.lineno = new_trcback[-1][1]
238 return new_trcback
241def text_error_template(lookup=None):
242 """Provides a template that renders a stack trace in a similar format to
243 the Python interpreter, substituting source template filenames, line
244 numbers and code for that of the originating source template, as
245 applicable.
247 """
248 import mako.template
250 return mako.template.Template(
251 r"""
252<%page args="error=None, traceback=None"/>
253<%!
254 from mako.exceptions import RichTraceback
255%>\
256<%
257 tback = RichTraceback(error=error, traceback=traceback)
258%>\
259Traceback (most recent call last):
260% for (filename, lineno, function, line) in tback.traceback:
261 File "${filename}", line ${lineno}, in ${function or '?'}
262 ${line | trim}
263% endfor
264${tback.errorname}: ${tback.message}
265"""
266 )
269def _install_pygments():
270 global syntax_highlight, pygments_html_formatter
271 from mako.ext.pygmentplugin import syntax_highlight # noqa
272 from mako.ext.pygmentplugin import pygments_html_formatter # noqa
275def _install_fallback():
276 global syntax_highlight, pygments_html_formatter
277 from mako.filters import html_escape
279 pygments_html_formatter = None
281 def syntax_highlight(filename="", language=None):
282 return html_escape
285def _install_highlighting():
286 try:
287 _install_pygments()
288 except ImportError:
289 _install_fallback()
292_install_highlighting()
295def html_error_template():
296 """Provides a template that renders a stack trace in an HTML format,
297 providing an excerpt of code as well as substituting source template
298 filenames, line numbers and code for that of the originating source
299 template, as applicable.
301 The template's default ``encoding_errors`` value is
302 ``'htmlentityreplace'``. The template has two options. With the
303 ``full`` option disabled, only a section of an HTML document is
304 returned. With the ``css`` option disabled, the default stylesheet
305 won't be included.
307 """
308 import mako.template
310 return mako.template.Template(
311 r"""
312<%!
313 from mako.exceptions import RichTraceback, syntax_highlight,\
314 pygments_html_formatter
315%>
316<%page args="full=True, css=True, error=None, traceback=None"/>
317% if full:
318<html>
319<head>
320 <title>Mako Runtime Error</title>
321% endif
322% if css:
323 <style>
324 body { font-family:verdana; margin:10px 30px 10px 30px;}
325 .stacktrace { margin:5px 5px 5px 5px; }
326 .highlight { padding:0px 10px 0px 10px; background-color:#9F9FDF; }
327 .nonhighlight { padding:0px; background-color:#DFDFDF; }
328 .sample { padding:10px; margin:10px 10px 10px 10px;
329 font-family:monospace; }
330 .sampleline { padding:0px 10px 0px 10px; }
331 .sourceline { margin:5px 5px 10px 5px; font-family:monospace;}
332 .location { font-size:80%; }
333 .highlight { white-space:pre; }
334 .sampleline { white-space:pre; }
336 % if pygments_html_formatter:
337 ${pygments_html_formatter.get_style_defs()}
338 .linenos { min-width: 2.5em; text-align: right; }
339 pre { margin: 0; }
340 .syntax-highlighted { padding: 0 10px; }
341 .syntax-highlightedtable { border-spacing: 1px; }
342 .nonhighlight { border-top: 1px solid #DFDFDF;
343 border-bottom: 1px solid #DFDFDF; }
344 .stacktrace .nonhighlight { margin: 5px 15px 10px; }
345 .sourceline { margin: 0 0; font-family:monospace; }
346 .code { background-color: #F8F8F8; width: 100%; }
347 .error .code { background-color: #FFBDBD; }
348 .error .syntax-highlighted { background-color: #FFBDBD; }
349 % endif
351 </style>
352% endif
353% if full:
354</head>
355<body>
356% endif
358<h2>Error !</h2>
359<%
360 tback = RichTraceback(error=error, traceback=traceback)
361 src = tback.source
362 line = tback.lineno
363 if src:
364 lines = src.split('\n')
365 else:
366 lines = None
367%>
368<h3>${tback.errorname}: ${tback.message|h}</h3>
370% if lines:
371 <div class="sample">
372 <div class="nonhighlight">
373% for index in range(max(0, line-4),min(len(lines), line+5)):
374 <%
375 if pygments_html_formatter:
376 pygments_html_formatter.linenostart = index + 1
377 %>
378 % if index + 1 == line:
379 <%
380 if pygments_html_formatter:
381 old_cssclass = pygments_html_formatter.cssclass
382 pygments_html_formatter.cssclass = 'error ' + old_cssclass
383 %>
384 ${lines[index] | syntax_highlight(language='mako')}
385 <%
386 if pygments_html_formatter:
387 pygments_html_formatter.cssclass = old_cssclass
388 %>
389 % else:
390 ${lines[index] | syntax_highlight(language='mako')}
391 % endif
392% endfor
393 </div>
394 </div>
395% endif
397<div class="stacktrace">
398% for (filename, lineno, function, line) in tback.reverse_traceback:
399 <div class="location">${filename}, line ${lineno}:</div>
400 <div class="nonhighlight">
401 <%
402 if pygments_html_formatter:
403 pygments_html_formatter.linenostart = lineno
404 %>
405 <div class="sourceline">${line | syntax_highlight(filename)}</div>
406 </div>
407% endfor
408</div>
410% if full:
411</body>
412</html>
413% endif
414""",
415 output_encoding=sys.getdefaultencoding(),
416 encoding_errors="htmlentityreplace",
417 )