PageRenderTime 43ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/support/mobileweb/mako/exceptions.py

http://github.com/appcelerator/titanium_mobile
Python | 255 lines | 217 code | 9 blank | 29 comment | 2 complexity | 8e28232d9debbf0aa063abf1e999a766 MD5 | raw file
Possible License(s): MIT, JSON, Apache-2.0, 0BSD, CC-BY-SA-3.0, BSD-2-Clause, MPL-2.0-no-copyleft-exception, BSD-3-Clause, CC-BY-3.0, Unlicense
  1. # exceptions.py
  2. # Copyright (C) 2006, 2007, 2008 Michael Bayer mike_mp@zzzcomputing.com
  3. #
  4. # This module is part of Mako and is released under
  5. # the MIT License: http://www.opensource.org/licenses/mit-license.php
  6. """exception classes"""
  7. import traceback, sys, re
  8. from mako import util
  9. class MakoException(Exception):
  10. pass
  11. class RuntimeException(MakoException):
  12. pass
  13. def _format_filepos(lineno, pos, filename):
  14. if filename is None:
  15. return " at line: %d char: %d" % (lineno, pos)
  16. else:
  17. return " in file '%s' at line: %d char: %d" % (filename, lineno, pos)
  18. class CompileException(MakoException):
  19. def __init__(self, message, source, lineno, pos, filename):
  20. MakoException.__init__(self, message + _format_filepos(lineno, pos, filename))
  21. self.lineno =lineno
  22. self.pos = pos
  23. self.filename = filename
  24. self.source = source
  25. class SyntaxException(MakoException):
  26. def __init__(self, message, source, lineno, pos, filename):
  27. MakoException.__init__(self, message + _format_filepos(lineno, pos, filename))
  28. self.lineno =lineno
  29. self.pos = pos
  30. self.filename = filename
  31. self.source = source
  32. class TemplateLookupException(MakoException):
  33. pass
  34. class TopLevelLookupException(TemplateLookupException):
  35. pass
  36. class RichTraceback(object):
  37. """pulls the current exception from the sys traceback and extracts Mako-specific
  38. template information.
  39. Usage:
  40. RichTraceback()
  41. Properties:
  42. error - the exception instance.
  43. source - source code of the file where the error occured. if the error occured within a compiled template,
  44. this is the template source.
  45. lineno - line number where the error occured. if the error occured within a compiled template, the line number
  46. is adjusted to that of the template source
  47. records - a list of 8-tuples containing the original python traceback elements, plus the
  48. filename, line number, source line, and full template source for the traceline mapped back to its originating source
  49. template, if any for that traceline (else the fields are None).
  50. reverse_records - the list of records in reverse
  51. traceback - a list of 4-tuples, in the same format as a regular python traceback, with template-corresponding
  52. traceback records replacing the originals
  53. reverse_traceback - the traceback list in reverse
  54. """
  55. def __init__(self, traceback=None):
  56. (self.source, self.lineno) = ("", 0)
  57. (t, self.error, self.records) = self._init(traceback)
  58. if self.error is None:
  59. self.error = t
  60. if isinstance(self.error, CompileException) or isinstance(self.error, SyntaxException):
  61. import mako.template
  62. self.source = self.error.source
  63. self.lineno = self.error.lineno
  64. self._has_source = True
  65. self.reverse_records = [r for r in self.records]
  66. self.reverse_records.reverse()
  67. def _get_reformatted_records(self, records):
  68. for rec in records:
  69. if rec[6] is not None:
  70. yield (rec[4], rec[5], rec[2], rec[6])
  71. else:
  72. yield tuple(rec[0:4])
  73. traceback = property(lambda self:self._get_reformatted_records(self.records), doc="""
  74. return a list of 4-tuple traceback records (i.e. normal python format)
  75. with template-corresponding lines remapped to the originating template
  76. """)
  77. reverse_traceback = property(lambda self:self._get_reformatted_records(self.reverse_records), doc="""
  78. return the same data as traceback, except in reverse order
  79. """)
  80. def _init(self, trcback):
  81. """format a traceback from sys.exc_info() into 7-item tuples, containing
  82. the regular four traceback tuple items, plus the original template
  83. filename, the line number adjusted relative to the template source, and
  84. code line from that line number of the template."""
  85. import mako.template
  86. mods = {}
  87. if not trcback:
  88. (type, value, trcback) = sys.exc_info()
  89. rawrecords = traceback.extract_tb(trcback)
  90. new_trcback = []
  91. for filename, lineno, function, line in rawrecords:
  92. try:
  93. (line_map, template_lines) = mods[filename]
  94. except KeyError:
  95. try:
  96. info = mako.template._get_module_info(filename)
  97. module_source = info.code
  98. template_source = info.source
  99. template_filename = info.template_filename or filename
  100. except KeyError:
  101. new_trcback.append((filename, lineno, function, line, None, None, None, None))
  102. continue
  103. template_ln = module_ln = 1
  104. line_map = {}
  105. for line in module_source.split("\n"):
  106. match = re.match(r'\s*# SOURCE LINE (\d+)', line)
  107. if match:
  108. template_ln = int(match.group(1))
  109. else:
  110. template_ln += 1
  111. module_ln += 1
  112. line_map[module_ln] = template_ln
  113. template_lines = [line for line in template_source.split("\n")]
  114. mods[filename] = (line_map, template_lines)
  115. template_ln = line_map[lineno]
  116. if template_ln <= len(template_lines):
  117. template_line = template_lines[template_ln - 1]
  118. else:
  119. template_line = None
  120. new_trcback.append((filename, lineno, function, line, template_filename, template_ln, template_line, template_source))
  121. if not self.source:
  122. for l in range(len(new_trcback)-1, 0, -1):
  123. if new_trcback[l][5]:
  124. self.source = new_trcback[l][7]
  125. self.lineno = new_trcback[l][5]
  126. break
  127. else:
  128. try:
  129. # A normal .py file (not a Template)
  130. fp = open(new_trcback[-1][0])
  131. encoding = util.parse_encoding(fp)
  132. fp.seek(0)
  133. self.source = fp.read()
  134. fp.close()
  135. if encoding:
  136. self.source = self.source.decode(encoding)
  137. except IOError:
  138. self.source = ''
  139. self.lineno = new_trcback[-1][1]
  140. return (type, value, new_trcback)
  141. def text_error_template(lookup=None):
  142. """provides a template that renders a stack trace in a similar format to the Python interpreter,
  143. substituting source template filenames, line numbers and code for that of the originating
  144. source template, as applicable."""
  145. import mako.template
  146. return mako.template.Template(r"""
  147. <%page args="traceback=None"/>
  148. <%!
  149. from mako.exceptions import RichTraceback
  150. %>\
  151. <%
  152. tback = RichTraceback(traceback=traceback)
  153. %>\
  154. Traceback (most recent call last):
  155. % for (filename, lineno, function, line) in tback.traceback:
  156. File "${filename}", line ${lineno}, in ${function or '?'}
  157. ${line | unicode.strip}
  158. % endfor
  159. ${str(tback.error.__class__.__name__)}: ${str(tback.error)}
  160. """)
  161. def html_error_template():
  162. """provides a template that renders a stack trace in an HTML format, providing an excerpt of
  163. code as well as substituting source template filenames, line numbers and code
  164. for that of the originating source template, as applicable.
  165. the template's default encoding_errors value is 'htmlentityreplace'. the template has
  166. two options:
  167. with the full option disabled, only a section of an HTML document is returned.
  168. with the css option disabled, the default stylesheet won't be included."""
  169. import mako.template
  170. return mako.template.Template(r"""
  171. <%!
  172. from mako.exceptions import RichTraceback
  173. %>
  174. <%page args="full=True, css=True, traceback=None"/>
  175. % if full:
  176. <html>
  177. <head>
  178. <title>Mako Runtime Error</title>
  179. % endif
  180. % if css:
  181. <style>
  182. body { font-family:verdana; margin:10px 30px 10px 30px;}
  183. .stacktrace { margin:5px 5px 5px 5px; }
  184. .highlight { padding:0px 10px 0px 10px; background-color:#9F9FDF; }
  185. .nonhighlight { padding:0px; background-color:#DFDFDF; }
  186. .sample { padding:10px; margin:10px 10px 10px 10px; font-family:monospace; }
  187. .sampleline { padding:0px 10px 0px 10px; }
  188. .sourceline { margin:5px 5px 10px 5px; font-family:monospace;}
  189. .location { font-size:80%; }
  190. </style>
  191. % endif
  192. % if full:
  193. </head>
  194. <body>
  195. % endif
  196. <h2>Error !</h2>
  197. <%
  198. tback = RichTraceback(traceback=traceback)
  199. src = tback.source
  200. line = tback.lineno
  201. if src:
  202. lines = src.split('\n')
  203. else:
  204. lines = None
  205. %>
  206. <h3>${str(tback.error.__class__.__name__)}: ${str(tback.error)}</h3>
  207. % if lines:
  208. <div class="sample">
  209. <div class="nonhighlight">
  210. % for index in range(max(0, line-4),min(len(lines), line+5)):
  211. % if index + 1 == line:
  212. <div class="highlight">${index + 1} ${lines[index] | h}</div>
  213. % else:
  214. <div class="sampleline">${index + 1} ${lines[index] | h}</div>
  215. % endif
  216. % endfor
  217. </div>
  218. </div>
  219. % endif
  220. <div class="stacktrace">
  221. % for (filename, lineno, function, line) in tback.reverse_traceback:
  222. <div class="location">${filename}, line ${lineno}:</div>
  223. <div class="sourceline">${line | h}</div>
  224. % endfor
  225. </div>
  226. % if full:
  227. </body>
  228. </html>
  229. % endif
  230. """, output_encoding=sys.getdefaultencoding(), encoding_errors='htmlentityreplace')