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

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 

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 

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

56 

57 

58class NameConflictError(MakoException): 

59 

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

61 

62 

63class TemplateLookupException(MakoException): 

64 pass 

65 

66 

67class TopLevelLookupException(TemplateLookupException): 

68 pass 

69 

70 

71class RichTraceback: 

72 

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

74 Mako-specific template information. 

75 

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

77 

78 """ 

79 

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

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

82 

83 if error is None or traceback is None: 

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

85 

86 if error is None: 

87 error = value or t 

88 

89 if traceback is None: 

90 traceback = tback 

91 

92 self.error = error 

93 self.records = self._init(traceback) 

94 

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

96 self.source = self.error.source 

97 self.lineno = self.error.lineno 

98 self._has_source = True 

99 

100 self._init_message() 

101 

102 @property 

103 def errorname(self): 

104 return compat.exception_name(self.error) 

105 

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") 

119 

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]) 

126 

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. 

132 

133 """ 

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

135 

136 @property 

137 def reverse_records(self): 

138 return reversed(self.records) 

139 

140 @property 

141 def reverse_traceback(self): 

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

143 

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

145 

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.""" 

151 

152 import mako.template 

153 

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 

185 

186 template_ln = 1 

187 

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"] 

193 

194 template_lines = [ 

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

196 ] 

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

198 

199 template_ln = line_map[lineno - 1] 

200 

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 

239 

240 

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. 

246 

247 """ 

248 import mako.template 

249 

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 ) 

267 

268 

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 

273 

274 

275def _install_fallback(): 

276 global syntax_highlight, pygments_html_formatter 

277 from mako.filters import html_escape 

278 

279 pygments_html_formatter = None 

280 

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

282 return html_escape 

283 

284 

285def _install_highlighting(): 

286 try: 

287 _install_pygments() 

288 except ImportError: 

289 _install_fallback() 

290 

291 

292_install_highlighting() 

293 

294 

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. 

300 

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. 

306 

307 """ 

308 import mako.template 

309 

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; } 

335 

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 

350 

351 </style> 

352% endif 

353% if full: 

354</head> 

355<body> 

356% endif 

357 

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> 

369 

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 

396 

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> 

409 

410% if full: 

411</body> 

412</html> 

413% endif 

414""", 

415 output_encoding=sys.getdefaultencoding(), 

416 encoding_errors="htmlentityreplace", 

417 )