Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/mako/exceptions.py: 40%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

147 statements  

1# mako/exceptions.py 

2# Copyright 2006-2026 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 

6 

7"""exception classes""" 

8 

9import sys 

10import traceback 

11 

12from mako import compat 

13from mako import util 

14 

15 

16class MakoException(Exception): 

17 pass 

18 

19 

20class RuntimeException(MakoException): 

21 pass 

22 

23 

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) 

29 

30 

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 

40 

41 

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 

51 

52 

53class UnsupportedError(MakoException): 

54 """raised when a retired feature is used.""" 

55 

56 

57class NameConflictError(MakoException): 

58 """raised when a reserved word is used inappropriately""" 

59 

60 

61class TemplateLookupException(MakoException): 

62 pass 

63 

64 

65class TopLevelLookupException(TemplateLookupException): 

66 pass 

67 

68 

69class RichTraceback: 

70 """Pull the current exception from the ``sys`` traceback and extracts 

71 Mako-specific template information. 

72 

73 See the usage examples in :ref:`handling_exceptions`. 

74 

75 """ 

76 

77 def __init__(self, error=None, traceback=None): 

78 self.source, self.lineno = "", 0 

79 

80 if error is None or traceback is None: 

81 t, value, tback = sys.exc_info() 

82 

83 if error is None: 

84 error = value or t 

85 

86 if traceback is None: 

87 traceback = tback 

88 

89 self.error = error 

90 self.records = self._init(traceback) 

91 

92 if isinstance(self.error, (CompileException, SyntaxException)): 

93 self.source = self.error.source 

94 self.lineno = self.error.lineno 

95 self._has_source = True 

96 

97 self._init_message() 

98 

99 @property 

100 def errorname(self): 

101 return compat.exception_name(self.error) 

102 

103 def _init_message(self): 

104 """Find a unicode representation of self.error""" 

105 try: 

106 self.message = str(self.error) 

107 except UnicodeError: 

108 try: 

109 self.message = str(self.error) 

110 except UnicodeEncodeError: 

111 # Fallback to args as neither unicode nor 

112 # str(Exception(u'\xe6')) work in Python < 2.6 

113 self.message = self.error.args[0] 

114 if not isinstance(self.message, str): 

115 self.message = str(self.message, "ascii", "replace") 

116 

117 def _get_reformatted_records(self, records): 

118 for rec in records: 

119 if rec[6] is not None: 

120 yield (rec[4], rec[5], rec[2], rec[6]) 

121 else: 

122 yield tuple(rec[0:4]) 

123 

124 @property 

125 def traceback(self): 

126 """Return a list of 4-tuple traceback records (i.e. normal python 

127 format) with template-corresponding lines remapped to the originating 

128 template. 

129 

130 """ 

131 return list(self._get_reformatted_records(self.records)) 

132 

133 @property 

134 def reverse_records(self): 

135 return reversed(self.records) 

136 

137 @property 

138 def reverse_traceback(self): 

139 """Return the same data as traceback, except in reverse order.""" 

140 

141 return list(self._get_reformatted_records(self.reverse_records)) 

142 

143 def _init(self, trcback): 

144 """format a traceback from sys.exc_info() into 7-item tuples, 

145 containing the regular four traceback tuple items, plus the original 

146 template filename, the line number adjusted relative to the template 

147 source, and code line from that line number of the template.""" 

148 

149 import mako.template 

150 

151 mods = {} 

152 rawrecords = traceback.extract_tb(trcback) 

153 new_trcback = [] 

154 for filename, lineno, function, line in rawrecords: 

155 if not line: 

156 line = "" 

157 try: 

158 line_map, template_lines, template_filename = mods[filename] 

159 except KeyError: 

160 try: 

161 info = mako.template._get_module_info(filename) 

162 module_source = info.code 

163 template_source = info.source 

164 template_filename = ( 

165 info.template_filename or info.template_uri or filename 

166 ) 

167 except KeyError: 

168 # A normal .py file (not a Template) 

169 new_trcback.append( 

170 ( 

171 filename, 

172 lineno, 

173 function, 

174 line, 

175 None, 

176 None, 

177 None, 

178 None, 

179 ) 

180 ) 

181 continue 

182 

183 template_ln = 1 

184 

185 mtm = mako.template.ModuleInfo 

186 source_map = mtm.get_module_source_metadata( 

187 module_source, full_line_map=True 

188 ) 

189 line_map = source_map["full_line_map"] 

190 

191 template_lines = [ 

192 line_ for line_ in template_source.split("\n") 

193 ] 

194 mods[filename] = (line_map, template_lines, template_filename) 

195 

196 template_ln = line_map[lineno - 1] 

197 

198 if template_ln <= len(template_lines): 

199 template_line = template_lines[template_ln - 1] 

200 else: 

201 template_line = None 

202 new_trcback.append( 

203 ( 

204 filename, 

205 lineno, 

206 function, 

207 line, 

208 template_filename, 

209 template_ln, 

210 template_line, 

211 template_source, 

212 ) 

213 ) 

214 if not self.source: 

215 for l in range(len(new_trcback) - 1, 0, -1): 

216 if new_trcback[l][5]: 

217 self.source = new_trcback[l][7] 

218 self.lineno = new_trcback[l][5] 

219 break 

220 else: 

221 if new_trcback: 

222 try: 

223 # A normal .py file (not a Template) 

224 with open(new_trcback[-1][0], "rb") as fp: 

225 encoding = util.parse_encoding(fp) 

226 if not encoding: 

227 encoding = "utf-8" 

228 fp.seek(0) 

229 self.source = fp.read() 

230 if encoding: 

231 self.source = self.source.decode(encoding) 

232 except IOError: 

233 self.source = "" 

234 self.lineno = new_trcback[-1][1] 

235 return new_trcback 

236 

237 

238def text_error_template(lookup=None): 

239 """Provides a template that renders a stack trace in a similar format to 

240 the Python interpreter, substituting source template filenames, line 

241 numbers and code for that of the originating source template, as 

242 applicable. 

243 

244 """ 

245 import mako.template 

246 

247 return mako.template.Template(r""" 

248<%page args="error=None, traceback=None"/> 

249<%! 

250 from mako.exceptions import RichTraceback 

251%>\ 

252<% 

253 tback = RichTraceback(error=error, traceback=traceback) 

254%>\ 

255Traceback (most recent call last): 

256% for (filename, lineno, function, line) in tback.traceback: 

257 File "${filename}", line ${lineno}, in ${function or '?'} 

258 ${line | trim} 

259% endfor 

260${tback.errorname}: ${tback.message} 

261""") 

262 

263 

264def _install_pygments(): 

265 global syntax_highlight, pygments_html_formatter 

266 from mako.ext.pygmentplugin import syntax_highlight # noqa 

267 from mako.ext.pygmentplugin import pygments_html_formatter # noqa 

268 

269 

270def _install_fallback(): 

271 global syntax_highlight, pygments_html_formatter 

272 from mako.filters import html_escape 

273 

274 pygments_html_formatter = None 

275 

276 def syntax_highlight(filename="", language=None): 

277 return html_escape 

278 

279 

280def _install_highlighting(): 

281 try: 

282 _install_pygments() 

283 except ImportError: 

284 _install_fallback() 

285 

286 

287_install_highlighting() 

288 

289 

290def html_error_template(): 

291 """Provides a template that renders a stack trace in an HTML format, 

292 providing an excerpt of code as well as substituting source template 

293 filenames, line numbers and code for that of the originating source 

294 template, as applicable. 

295 

296 The template's default ``encoding_errors`` value is 

297 ``'htmlentityreplace'``. The template has two options. With the 

298 ``full`` option disabled, only a section of an HTML document is 

299 returned. With the ``css`` option disabled, the default stylesheet 

300 won't be included. 

301 

302 """ 

303 import mako.template 

304 

305 return mako.template.Template( 

306 r""" 

307<%! 

308 from mako.exceptions import RichTraceback, syntax_highlight,\ 

309 pygments_html_formatter 

310%> 

311<%page args="full=True, css=True, error=None, traceback=None"/> 

312% if full: 

313<html> 

314<head> 

315 <title>Mako Runtime Error</title> 

316% endif 

317% if css: 

318 <style> 

319 body { font-family:verdana; margin:10px 30px 10px 30px;} 

320 .stacktrace { margin:5px 5px 5px 5px; } 

321 .highlight { padding:0px 10px 0px 10px; background-color:#9F9FDF; } 

322 .nonhighlight { padding:0px; background-color:#DFDFDF; } 

323 .sample { padding:10px; margin:10px 10px 10px 10px; 

324 font-family:monospace; } 

325 .sampleline { padding:0px 10px 0px 10px; } 

326 .sourceline { margin:5px 5px 10px 5px; font-family:monospace;} 

327 .location { font-size:80%; } 

328 .highlight { white-space:pre; } 

329 .sampleline { white-space:pre; } 

330 

331 % if pygments_html_formatter: 

332 ${pygments_html_formatter.get_style_defs()} 

333 .linenos { min-width: 2.5em; text-align: right; } 

334 pre { margin: 0; } 

335 .syntax-highlighted { padding: 0 10px; } 

336 .syntax-highlightedtable { border-spacing: 1px; } 

337 .nonhighlight { border-top: 1px solid #DFDFDF; 

338 border-bottom: 1px solid #DFDFDF; } 

339 .stacktrace .nonhighlight { margin: 5px 15px 10px; } 

340 .sourceline { margin: 0 0; font-family:monospace; } 

341 .code { background-color: #F8F8F8; width: 100%; } 

342 .error .code { background-color: #FFBDBD; } 

343 .error .syntax-highlighted { background-color: #FFBDBD; } 

344 % endif 

345 

346 </style> 

347% endif 

348% if full: 

349</head> 

350<body> 

351% endif 

352 

353<h2>Error !</h2> 

354<% 

355 tback = RichTraceback(error=error, traceback=traceback) 

356 src = tback.source 

357 line = tback.lineno 

358 if src: 

359 lines = src.split('\n') 

360 else: 

361 lines = None 

362%> 

363<h3>${tback.errorname}: ${tback.message|h}</h3> 

364 

365% if lines: 

366 <div class="sample"> 

367 <div class="nonhighlight"> 

368% for index in range(max(0, line-4),min(len(lines), line+5)): 

369 <% 

370 if pygments_html_formatter: 

371 pygments_html_formatter.linenostart = index + 1 

372 %> 

373 % if index + 1 == line: 

374 <% 

375 if pygments_html_formatter: 

376 old_cssclass = pygments_html_formatter.cssclass 

377 pygments_html_formatter.cssclass = 'error ' + old_cssclass 

378 %> 

379 ${lines[index] | syntax_highlight(language='mako')} 

380 <% 

381 if pygments_html_formatter: 

382 pygments_html_formatter.cssclass = old_cssclass 

383 %> 

384 % else: 

385 ${lines[index] | syntax_highlight(language='mako')} 

386 % endif 

387% endfor 

388 </div> 

389 </div> 

390% endif 

391 

392<div class="stacktrace"> 

393% for (filename, lineno, function, line) in tback.reverse_traceback: 

394 <div class="location">${filename}, line ${lineno}:</div> 

395 <div class="nonhighlight"> 

396 <% 

397 if pygments_html_formatter: 

398 pygments_html_formatter.linenostart = lineno 

399 %> 

400 <div class="sourceline">${line | syntax_highlight(filename)}</div> 

401 </div> 

402% endfor 

403</div> 

404 

405% if full: 

406</body> 

407</html> 

408% endif 

409""", 

410 output_encoding=sys.getdefaultencoding(), 

411 encoding_errors="htmlentityreplace", 

412 )