Package web :: Package web :: Module debugerror'
[hide private]
[frames] | no frames]

Source Code for Module web.web.debugerror'

  1  """ 
  2  pretty debug errors 
  3  (part of web.py) 
  4   
  5  portions adapted from Django <djangoproject.com>  
  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   
 11  __all__ = ["debugerror", "djangoerror", "emailerrors"] 
 12   
 13  import sys, urlparse, pprint, traceback 
 14  from net import websafe 
 15  from template import Template 
 16  from utils import sendmail, safestr 
 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, "\\-"); 
 88          var oRegExp = new RegExp("(^|\\s)" + strClassName + "(\\s|$$)"); 
 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   
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   
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> 
165      $if frame.context_line is not None: 
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: 
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> 
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> 
194      $:dicttable_items(ctx.headers) 
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> 
204  $:dicttable(web.input(_unicode=False)) 
205   
206  <h3 id="cookie-info">COOKIES</h3> 
207  $:dicttable(web.cookies()) 
208   
209  <h3 id="meta-info">META</h3> 
210  $ newctx = [(k, v) for (k, v) in ctx.iteritems() if not k.startswith('_') and not isinstance(v, dict)] 
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> 
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. 
221    </p> 
222  </div> 
223   
224  </body> 
225  </html> 
226  """ 
227   
228  djangoerror_r = None 
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 248 except (OSError, IOError, IndexError): 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 257 258 # hack to get correct line number for templates 259 lineno += tback.tb_frame.f_locals.get("__lineoffset__", 0) 260 261 pre_context_lineno, pre_context, context_line, post_context = \ 262 _get_lines_from_file(filename, lineno, 7) 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 })) 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 287 288 global djangoerror_r 289 if djangoerror_r is None: 290 djangoerror_r = Template(djangoerror_t, filename=__file__, filter=websafe) 291 292 t = djangoerror_r 293 globals = {'ctx': web.ctx, 'web':web, 'dict':dict, 'str':str, 'prettify': prettify} 294 t.t.func_globals.update(globals) 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 """ 305 return web._InternalError(djangoerror())
306
307 -def emailerrors(to_address, olderror, from_address=None):
308 """ 309 Wraps the old `internalerror` handler (pass as `olderror`) to 310 additionally email all errors to `to_address`, to aid in 311 debugging production websites. 312 313 Emails contain a normal text traceback as well as an 314 attachment containing the nice `debugerror` page. 315 """ 316 from_address = from_address or to_address 317 318 def emailerrors_internal(): 319 error = olderror() 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 325 request = web.ctx.method + ' ' + web.ctx.home + web.ctx.fullpath 326 327 message = "\n%s\n\n%s\n\n" % (request, tb_txt) 328 329 sendmail( 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=[ 335 dict(filename="bug.html", content=safestr(djangoerror())) 336 ], 337 ) 338 return error
339 340 return emailerrors_internal 341 342 if __name__ == "__main__": 343 urls = ( 344 '/', 'index' 345 ) 346 from application import application 347 app = application(urls, globals()) 348 app.internalerror = debugerror 349
350 - class index:
351 - def GET(self):
352 thisdoesnotexist
353 354 app.run() 355