Coverage for /home/martinb/.local/share/virtualenvs/camcops/lib/python3.6/site-packages/mako/exceptions.py : 25%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# mako/exceptions.py
2# Copyright 2006-2020 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(object):
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 = compat.text_type(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, compat.text_type):
118 self.message = compat.text_type(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.
143 """
145 return list(self._get_reformatted_records(self.reverse_records))
147 def _init(self, trcback):
148 """format a traceback from sys.exc_info() into 7-item tuples,
149 containing the regular four traceback tuple items, plus the original
150 template filename, the line number adjusted relative to the template
151 source, and code line from that line number of the template."""
153 import mako.template
155 mods = {}
156 rawrecords = traceback.extract_tb(trcback)
157 new_trcback = []
158 for filename, lineno, function, line in rawrecords:
159 if not line:
160 line = ""
161 try:
162 (line_map, template_lines, template_filename) = mods[filename]
163 except KeyError:
164 try:
165 info = mako.template._get_module_info(filename)
166 module_source = info.code
167 template_source = info.source
168 template_filename = (
169 info.template_filename or info.template_uri or filename
170 )
171 except KeyError:
172 # A normal .py file (not a Template)
173 if not compat.py3k:
174 try:
175 fp = open(filename, "rb")
176 encoding = util.parse_encoding(fp)
177 fp.close()
178 except IOError:
179 encoding = None
180 if encoding:
181 line = line.decode(encoding)
182 else:
183 line = line.decode("ascii", "replace")
184 new_trcback.append(
185 (
186 filename,
187 lineno,
188 function,
189 line,
190 None,
191 None,
192 None,
193 None,
194 )
195 )
196 continue
198 template_ln = 1
200 mtm = mako.template.ModuleInfo
201 source_map = mtm.get_module_source_metadata(
202 module_source, full_line_map=True
203 )
204 line_map = source_map["full_line_map"]
206 template_lines = [
207 line_ for line_ in template_source.split("\n")
208 ]
209 mods[filename] = (line_map, template_lines, template_filename)
211 template_ln = line_map[lineno - 1]
213 if template_ln <= len(template_lines):
214 template_line = template_lines[template_ln - 1]
215 else:
216 template_line = None
217 new_trcback.append(
218 (
219 filename,
220 lineno,
221 function,
222 line,
223 template_filename,
224 template_ln,
225 template_line,
226 template_source,
227 )
228 )
229 if not self.source:
230 for l in range(len(new_trcback) - 1, 0, -1):
231 if new_trcback[l][5]:
232 self.source = new_trcback[l][7]
233 self.lineno = new_trcback[l][5]
234 break
235 else:
236 if new_trcback:
237 try:
238 # A normal .py file (not a Template)
239 fp = open(new_trcback[-1][0], "rb")
240 encoding = util.parse_encoding(fp)
241 if compat.py3k and not encoding:
242 encoding = "utf-8"
243 fp.seek(0)
244 self.source = fp.read()
245 fp.close()
246 if encoding:
247 self.source = self.source.decode(encoding)
248 except IOError:
249 self.source = ""
250 self.lineno = new_trcback[-1][1]
251 return new_trcback
254def text_error_template(lookup=None):
255 """Provides a template that renders a stack trace in a similar format to
256 the Python interpreter, substituting source template filenames, line
257 numbers and code for that of the originating source template, as
258 applicable.
260 """
261 import mako.template
263 return mako.template.Template(
264 r"""
265<%page args="error=None, traceback=None"/>
266<%!
267 from mako.exceptions import RichTraceback
268%>\
269<%
270 tback = RichTraceback(error=error, traceback=traceback)
271%>\
272Traceback (most recent call last):
273% for (filename, lineno, function, line) in tback.traceback:
274 File "${filename}", line ${lineno}, in ${function or '?'}
275 ${line | trim}
276% endfor
277${tback.errorname}: ${tback.message}
278"""
279 )
282def _install_pygments():
283 global syntax_highlight, pygments_html_formatter
284 from mako.ext.pygmentplugin import syntax_highlight # noqa
285 from mako.ext.pygmentplugin import pygments_html_formatter # noqa
288def _install_fallback():
289 global syntax_highlight, pygments_html_formatter
290 from mako.filters import html_escape
292 pygments_html_formatter = None
294 def syntax_highlight(filename="", language=None):
295 return html_escape
298def _install_highlighting():
299 try:
300 _install_pygments()
301 except ImportError:
302 _install_fallback()
305_install_highlighting()
308def html_error_template():
309 """Provides a template that renders a stack trace in an HTML format,
310 providing an excerpt of code as well as substituting source template
311 filenames, line numbers and code for that of the originating source
312 template, as applicable.
314 The template's default ``encoding_errors`` value is
315 ``'htmlentityreplace'``. The template has two options. With the
316 ``full`` option disabled, only a section of an HTML document is
317 returned. With the ``css`` option disabled, the default stylesheet
318 won't be included.
320 """
321 import mako.template
323 return mako.template.Template(
324 r"""
325<%!
326 from mako.exceptions import RichTraceback, syntax_highlight,\
327 pygments_html_formatter
328%>
329<%page args="full=True, css=True, error=None, traceback=None"/>
330% if full:
331<html>
332<head>
333 <title>Mako Runtime Error</title>
334% endif
335% if css:
336 <style>
337 body { font-family:verdana; margin:10px 30px 10px 30px;}
338 .stacktrace { margin:5px 5px 5px 5px; }
339 .highlight { padding:0px 10px 0px 10px; background-color:#9F9FDF; }
340 .nonhighlight { padding:0px; background-color:#DFDFDF; }
341 .sample { padding:10px; margin:10px 10px 10px 10px;
342 font-family:monospace; }
343 .sampleline { padding:0px 10px 0px 10px; }
344 .sourceline { margin:5px 5px 10px 5px; font-family:monospace;}
345 .location { font-size:80%; }
346 .highlight { white-space:pre; }
347 .sampleline { white-space:pre; }
349 % if pygments_html_formatter:
350 ${pygments_html_formatter.get_style_defs()}
351 .linenos { min-width: 2.5em; text-align: right; }
352 pre { margin: 0; }
353 .syntax-highlighted { padding: 0 10px; }
354 .syntax-highlightedtable { border-spacing: 1px; }
355 .nonhighlight { border-top: 1px solid #DFDFDF;
356 border-bottom: 1px solid #DFDFDF; }
357 .stacktrace .nonhighlight { margin: 5px 15px 10px; }
358 .sourceline { margin: 0 0; font-family:monospace; }
359 .code { background-color: #F8F8F8; width: 100%; }
360 .error .code { background-color: #FFBDBD; }
361 .error .syntax-highlighted { background-color: #FFBDBD; }
362 % endif
364 </style>
365% endif
366% if full:
367</head>
368<body>
369% endif
371<h2>Error !</h2>
372<%
373 tback = RichTraceback(error=error, traceback=traceback)
374 src = tback.source
375 line = tback.lineno
376 if src:
377 lines = src.split('\n')
378 else:
379 lines = None
380%>
381<h3>${tback.errorname}: ${tback.message|h}</h3>
383% if lines:
384 <div class="sample">
385 <div class="nonhighlight">
386% for index in range(max(0, line-4),min(len(lines), line+5)):
387 <%
388 if pygments_html_formatter:
389 pygments_html_formatter.linenostart = index + 1
390 %>
391 % if index + 1 == line:
392 <%
393 if pygments_html_formatter:
394 old_cssclass = pygments_html_formatter.cssclass
395 pygments_html_formatter.cssclass = 'error ' + old_cssclass
396 %>
397 ${lines[index] | syntax_highlight(language='mako')}
398 <%
399 if pygments_html_formatter:
400 pygments_html_formatter.cssclass = old_cssclass
401 %>
402 % else:
403 ${lines[index] | syntax_highlight(language='mako')}
404 % endif
405% endfor
406 </div>
407 </div>
408% endif
410<div class="stacktrace">
411% for (filename, lineno, function, line) in tback.reverse_traceback:
412 <div class="location">${filename}, line ${lineno}:</div>
413 <div class="nonhighlight">
414 <%
415 if pygments_html_formatter:
416 pygments_html_formatter.linenostart = lineno
417 %>
418 <div class="sourceline">${line | syntax_highlight(filename)}</div>
419 </div>
420% endfor
421</div>
423% if full:
424</body>
425</html>
426% endif
427""",
428 output_encoding=sys.getdefaultencoding(),
429 encoding_errors="htmlentityreplace",
430 )