Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 355 lines (316 sloc) 12.341 kb
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
1 """
2 pretty debug errors
3 (part of web.py)
4
77a17f8 New functions: sendmail, emailerrors
aaronsw authored
5 portions adapted from Django <djangoproject.com>
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
6 Copyright (c) 2005, the Lawrence Journal-World
7 Used under the modified BSD license:
8 http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5
9 """
10
77a17f8 New functions: sendmail, emailerrors
aaronsw authored
11 __all__ = ["debugerror", "djangoerror", "emailerrors"]
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
12
77a17f8 New functions: sendmail, emailerrors
aaronsw authored
13 import sys, urlparse, pprint, traceback
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
14 from net import websafe
15 from template import Template
b7d17b1 @anandology attachment support for web.sendmail (tx gregglind)
anandology authored
16 from utils import sendmail, safestr
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
17 import webapi as web
18
19 import os, os.path
20 whereami = os.path.join(os.getcwd(), __file__)
21 whereami = os.path.sep.join(whereami.split(os.path.sep)[:-1])
22 djangoerror_t = """\
23 $def with (exception_type, exception_value, frames)
24 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
25 <html lang="en">
26 <head>
27 <meta http-equiv="content-type" content="text/html; charset=utf-8" />
28 <meta name="robots" content="NONE,NOARCHIVE" />
29 <title>$exception_type at $ctx.path</title>
30 <style type="text/css">
31 html * { padding:0; margin:0; }
32 body * { padding:10px 20px; }
33 body * * { padding:0; }
34 body { font:small sans-serif; }
35 body>div { border-bottom:1px solid #ddd; }
36 h1 { font-weight:normal; }
37 h2 { margin-bottom:.8em; }
38 h2 span { font-size:80%; color:#666; font-weight:normal; }
39 h3 { margin:1em 0 .5em 0; }
40 h4 { margin:0 0 .5em 0; font-weight: normal; }
41 table {
42 border:1px solid #ccc; border-collapse: collapse; background:white; }
43 tbody td, tbody th { vertical-align:top; padding:2px 3px; }
44 thead th {
45 padding:1px 6px 1px 3px; background:#fefefe; text-align:left;
46 font-weight:normal; font-size:11px; border:1px solid #ddd; }
47 tbody th { text-align:right; color:#666; padding-right:.5em; }
48 table.vars { margin:5px 0 2px 40px; }
49 table.vars td, table.req td { font-family:monospace; }
50 table td.code { width:100%;}
51 table td.code div { overflow:hidden; }
52 table.source th { color:#666; }
53 table.source td {
54 font-family:monospace; white-space:pre; border-bottom:1px solid #eee; }
55 ul.traceback { list-style-type:none; }
56 ul.traceback li.frame { margin-bottom:1em; }
57 div.context { margin: 10px 0; }
58 div.context ol {
59 padding-left:30px; margin:0 10px; list-style-position: inside; }
60 div.context ol li {
61 font-family:monospace; white-space:pre; color:#666; cursor:pointer; }
62 div.context ol.context-line li { color:black; background-color:#ccc; }
63 div.context ol.context-line li span { float: right; }
64 div.commands { margin-left: 40px; }
65 div.commands a { color:black; text-decoration:none; }
66 #summary { background: #ffc; }
67 #summary h2 { font-weight: normal; color: #666; }
68 #explanation { background:#eee; }
69 #template, #template-not-exist { background:#f6f6f6; }
70 #template-not-exist ul { margin: 0 0 0 20px; }
71 #traceback { background:#eee; }
72 #requestinfo { background:#f6f6f6; padding-left:120px; }
73 #summary table { border:none; background:transparent; }
74 #requestinfo h2, #requestinfo h3 { position:relative; margin-left:-100px; }
75 #requestinfo h3 { margin-bottom:-1em; }
76 .error { background: #ffc; }
77 .specific { color:#cc3300; font-weight:bold; }
78 </style>
79 <script type="text/javascript">
80 //<!--
81 function getElementsByClassName(oElm, strTagName, strClassName){
82 // Written by Jonathan Snook, http://www.snook.ca/jon;
83 // Add-ons by Robert Nyman, http://www.robertnyman.com
84 var arrElements = (strTagName == "*" && document.all)? document.all :
85 oElm.getElementsByTagName(strTagName);
86 var arrReturnElements = new Array();
87 strClassName = strClassName.replace(/\-/g, "\\-");
70455f2 @anandology fix template in djangoerror
anandology authored
88 var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$$)");
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
89 var oElement;
90 for(var i=0; i<arrElements.length; i++){
91 oElement = arrElements[i];
92 if(oRegExp.test(oElement.className)){
93 arrReturnElements.push(oElement);
94 }
95 }
96 return (arrReturnElements)
97 }
98 function hideAll(elems) {
99 for (var e = 0; e < elems.length; e++) {
100 elems[e].style.display = 'none';
101 }
102 }
103 window.onload = function() {
104 hideAll(getElementsByClassName(document, 'table', 'vars'));
105 hideAll(getElementsByClassName(document, 'ol', 'pre-context'));
106 hideAll(getElementsByClassName(document, 'ol', 'post-context'));
107 }
108 function toggle() {
109 for (var i = 0; i < arguments.length; i++) {
110 var e = document.getElementById(arguments[i]);
111 if (e) {
112 e.style.display = e.style.display == 'none' ? 'block' : 'none';
113 }
114 }
115 return false;
116 }
117 function varToggle(link, id) {
118 toggle('v' + id);
119 var s = link.getElementsByTagName('span')[0];
120 var uarr = String.fromCharCode(0x25b6);
121 var darr = String.fromCharCode(0x25bc);
122 s.innerHTML = s.innerHTML == uarr ? darr : uarr;
123 return false;
124 }
125 //-->
126 </script>
127 </head>
128 <body>
129
7a1ff8f fix debug error
Anand authored
130 $def dicttable (d, kls='req', id=None):
131 $ items = d and d.items() or []
132 $items.sort()
133 $:dicttable_items(items, kls, id)
134
135 $def dicttable_items(items, kls='req', id=None):
136 $if items:
137 <table class="$kls"
138 $if id: id="$id"
139 ><thead><tr><th>Variable</th><th>Value</th></tr></thead>
140 <tbody>
141 $for k, v in items:
142 <tr><td>$k</td><td class="code"><div>$prettify(v)</div></td></tr>
143 </tbody>
144 </table>
145 $else:
146 <p>No data.</p>
147
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
148 <div id="summary">
149 <h1>$exception_type at $ctx.path</h1>
150 <h2>$exception_value</h2>
151 <table><tr>
152 <th>Python</th>
153 <td>$frames[0].filename in $frames[0].function, line $frames[0].lineno</td>
154 </tr><tr>
155 <th>Web</th>
156 <td>$ctx.method $ctx.home$ctx.path</td>
157 </tr></table>
158 </div>
159 <div id="traceback">
160 <h2>Traceback <span>(innermost first)</span></h2>
161 <ul class="traceback">
162 $for frame in frames:
163 <li class="frame">
164 <code>$frame.filename</code> in <code>$frame.function</code>
6561539 @anandology hide unwanted tracebacks in debugerror (idea from py.test)
anandology authored
165 $if frame.context_line is not None:
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
166 <div class="context" id="c$frame.id">
167 $if frame.pre_context:
168 <ol start="$frame.pre_context_lineno" class="pre-context" id="pre$frame.id">
169 $for line in frame.pre_context:
170 <li onclick="toggle('pre$frame.id', 'post$frame.id')">$line</li>
171 </ol>
172 <ol start="$frame.lineno" class="context-line"><li onclick="toggle('pre$frame.id', 'post$frame.id')">$frame.context_line <span>...</span></li></ol>
173 $if frame.post_context:
70455f2 @anandology fix template in djangoerror
anandology authored
174 <ol start='${frame.lineno + 1}' class="post-context" id="post$frame.id">
175 $for line in frame.post_context:
176 <li onclick="toggle('pre$frame.id', 'post$frame.id')">$line</li>
177 </ol>
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
178 </div>
179
180 $if frame.vars:
181 <div class="commands">
182 <a href='#' onclick="return varToggle(this, '$frame.id')"><span>&#x25b6;</span> Local vars</a>
183 $# $inspect.formatargvalues(*inspect.getargvalues(frame['tb'].tb_frame))
184 </div>
185 $:dicttable(frame.vars, kls='vars', id=('v' + str(frame.id)))
186 </li>
187 </ul>
188 </div>
189
190 <div id="requestinfo">
191 $if ctx.output or ctx.headers:
192 <h2>Response so far</h2>
193 <h3>HEADERS</h3>
7a1ff8f fix debug error
Anand authored
194 $:dicttable_items(ctx.headers)
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
195
196 <h3>BODY</h3>
197 <p class="req" style="padding-bottom: 2em"><code>
198 $ctx.output
199 </code></p>
200
201 <h2>Request information</h2>
202
203 <h3>INPUT</h3>
dea8e77 @anandology don't convert input to unicode when displaying debugerror.
anandology authored
204 $:dicttable(web.input(_unicode=False))
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
205
206 <h3 id="cookie-info">COOKIES</h3>
207 $:dicttable(web.cookies())
208
209 <h3 id="meta-info">META</h3>
7a1ff8f fix debug error
Anand authored
210 $ newctx = [(k, v) for (k, v) in ctx.iteritems() if not k.startswith('_') and not isinstance(v, dict)]
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
211 $:dicttable(dict(newctx))
212
213 <h3 id="meta-info">ENVIRONMENT</h3>
214 $:dicttable(ctx.env)
215 </div>
216
217 <div id="explanation">
218 <p>
7a1ff8f fix debug error
Anand authored
219 You're seeing this error because you have <code>web.config.debug</code>
220 set to <code>True</code>. Set that to <code>False</code> if you don't to see this.
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
221 </p>
222 </div>
223
224 </body>
225 </html>
226 """
227
c015a59 @anandology fix templetor for GAE
anandology authored
228 djangoerror_r = None
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
229
230 def djangoerror():
231 def _get_lines_from_file(filename, lineno, context_lines):
232 """
233 Returns context_lines before and after lineno from file.
234 Returns (pre_context_lineno, pre_context, context_line, post_context).
235 """
236 try:
237 source = open(filename).readlines()
238 lower_bound = max(0, lineno - context_lines)
239 upper_bound = lineno + context_lines
240
241 pre_context = \
242 [line.strip('\n') for line in source[lower_bound:lineno]]
243 context_line = source[lineno].strip('\n')
244 post_context = \
245 [line.strip('\n') for line in source[lineno + 1:upper_bound]]
246
247 return lower_bound, pre_context, context_line, post_context
6561539 @anandology hide unwanted tracebacks in debugerror (idea from py.test)
anandology authored
248 except (OSError, IOError, IndexError):
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
249 return None, [], None, []
250
251 exception_type, exception_value, tback = sys.exc_info()
252 frames = []
253 while tback is not None:
254 filename = tback.tb_frame.f_code.co_filename
255 function = tback.tb_frame.f_code.co_name
256 lineno = tback.tb_lineno - 1
ed4eba1 @anandology hack to display correct template line numbers in debugerror
anandology authored
257
258 # hack to get correct line number for templates
714c129 @anandology fix incorrent line numbers in template errors
anandology authored
259 lineno += tback.tb_frame.f_locals.get("__lineoffset__", 0)
ed4eba1 @anandology hack to display correct template line numbers in debugerror
anandology authored
260
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
261 pre_context_lineno, pre_context, context_line, post_context = \
262 _get_lines_from_file(filename, lineno, 7)
6561539 @anandology hide unwanted tracebacks in debugerror (idea from py.test)
anandology authored
263
264 if '__hidetraceback__' not in tback.tb_frame.f_locals:
265 frames.append(web.storage({
266 'tback': tback,
267 'filename': filename,
268 'function': function,
269 'lineno': lineno,
270 'vars': tback.tb_frame.f_locals,
271 'id': id(tback),
272 'pre_context': pre_context,
273 'context_line': context_line,
274 'post_context': post_context,
275 'pre_context_lineno': pre_context_lineno,
276 }))
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
277 tback = tback.tb_next
278 frames.reverse()
279 urljoin = urlparse.urljoin
280 def prettify(x):
281 try:
282 out = pprint.pformat(x)
283 except Exception, e:
284 out = '[could not display: <' + e.__class__.__name__ + \
285 ': '+str(e)+'>]'
286 return out
c015a59 @anandology fix templetor for GAE
anandology authored
287
288 global djangoerror_r
289 if djangoerror_r is None:
290 djangoerror_r = Template(djangoerror_t, filename=__file__, filter=websafe)
291
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
292 t = djangoerror_r
7a1ff8f fix debug error
Anand authored
293 globals = {'ctx': web.ctx, 'web':web, 'dict':dict, 'str':str, 'prettify': prettify}
294 t.t.func_globals.update(globals)
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
295 return t(exception_type, exception_value, frames)
296
297 def debugerror():
298 """
299 A replacement for `internalerror` that presents a nice page with lots
300 of debug information for the programmer.
301
302 (Based on the beautiful 500 page from [Django](http://djangoproject.com/),
303 designed by [Wilson Miner](http://wilsonminer.com/).)
304 """
f4cf5b2 @anandology use web._InternalError instead of web.internalerror to stop failing w…
anandology authored
305 return web._InternalError(djangoerror())
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
306
103944c @anandology optional from_address argument to web.emailerrors.
anandology authored
307 def emailerrors(to_address, olderror, from_address=None):
77a17f8 New functions: sendmail, emailerrors
aaronsw authored
308 """
309 Wraps the old `internalerror` handler (pass as `olderror`) to
103944c @anandology optional from_address argument to web.emailerrors.
anandology authored
310 additionally email all errors to `to_address`, to aid in
77a17f8 New functions: sendmail, emailerrors
aaronsw authored
311 debugging production websites.
312
313 Emails contain a normal text traceback as well as an
314 attachment containing the nice `debugerror` page.
315 """
103944c @anandology optional from_address argument to web.emailerrors.
anandology authored
316 from_address = from_address or to_address
317
77a17f8 New functions: sendmail, emailerrors
aaronsw authored
318 def emailerrors_internal():
51b438f @anandology fixed debugerror and emailerrors (Bug#179713)
anandology authored
319 error = olderror()
77a17f8 New functions: sendmail, emailerrors
aaronsw authored
320 tb = sys.exc_info()
321 error_name = tb[0]
322 error_value = tb[1]
323 tb_txt = ''.join(traceback.format_exception(*tb))
324 path = web.ctx.path
103944c @anandology optional from_address argument to web.emailerrors.
anandology authored
325 request = web.ctx.method + ' ' + web.ctx.home + web.ctx.fullpath
b7d17b1 @anandology attachment support for web.sendmail (tx gregglind)
anandology authored
326
327 message = "\n%s\n\n%s\n\n" % (request, tb_txt)
328
0a34e17 update debugerror to use new API
aaronsw authored
329 sendmail(
b7d17b1 @anandology attachment support for web.sendmail (tx gregglind)
anandology authored
330 "your buggy site <%s>" % from_address,
331 "the bugfixer <%s>" % to_address,
332 "bug: %(error_name)s: %(error_value)s (%(path)s)" % locals(),
333 message,
334 attachments=[
2194072 @anandology rename payload as content
anandology authored
335 dict(filename="bug.html", content=safestr(djangoerror()))
b7d17b1 @anandology attachment support for web.sendmail (tx gregglind)
anandology authored
336 ],
337 )
51b438f @anandology fixed debugerror and emailerrors (Bug#179713)
anandology authored
338 return error
77a17f8 New functions: sendmail, emailerrors
aaronsw authored
339
340 return emailerrors_internal
341
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
342 if __name__ == "__main__":
343 urls = (
344 '/', 'index'
345 )
35c0702 @anandology let web.debugerror return an error instead error message.
anandology authored
346 from application import application
347 app = application(urls, globals())
348 app.internalerror = debugerror
4249032 move errors into web.py instead of the server; fix bug with ors in te…
aaronsw authored
349
350 class index:
351 def GET(self):
352 thisdoesnotexist
35c0702 @anandology let web.debugerror return an error instead error message.
anandology authored
353
354 app.run()
Something went wrong with that request. Please try again.