~ubuntu-branches/ubuntu/natty/moin/natty-updates

« back to all changes in this revision

Viewing changes to MoinMoin/support/cgitb.py

  • Committer: Bazaar Package Importer
  • Author(s): Jonas Smedegaard
  • Date: 2008-06-22 21:17:13 UTC
  • mfrom: (0.9.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20080622211713-fpo2zrq3s5dfecxg
Tags: 1.7.0-3
Simplify /etc/moin/wikilist format: "USER URL" (drop unneeded middle
CONFIG_DIR that was wrongly advertised as DATA_DIR).  Make
moin-mass-migrate handle both formats and warn about deprecation of
the old one.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
By default, tracebacks are displayed but not saved, the context is 5 lines
18
18
and the output format is 'html' (for backwards compatibility with the
19
 
original use of this module)
 
19
original use of this module).
20
20
 
21
21
Alternatively, if you have caught an exception and want cgitb to display it
22
22
for you, call cgitb.handler().  The optional argument to handler() is a
30
30
 - Refactor html and text functions to View class, HTMLFormatter and
31
31
   TextFormatter. No more duplicate formating code.
32
32
 - Layout is done with minimal html and css, in a way it can't be
33
 
   effected by souranding code.
34
 
 - Built to be easy to subclass and modify without duplicating code
 
33
   affected by surrounding code.
 
34
 - Built to be easy to subclass and modify without duplicating code.
35
35
 - Change layout, important details come first.
36
 
 - Factor frame analaizing and formatting into separate class
 
36
 - Factor frame analyzing and formatting into separate class.
37
37
 - Add debug argument, can be used to change error display e.g. user
38
 
   error view, developer error view
39
 
 - Add viewClass argument, make it easy to customize the traceback view
40
 
 - Easy to customize system details and application details
 
38
   error view, developer error view.
 
39
 - Add viewClass argument, make it easy to customize the traceback view.
 
40
 - Easy to customize system details and application details.
41
41
 
42
42
The main goal of this rewrite was to have a traceback that can render
43
 
few tracebacks combined. Its needed when you wrap an expection and want
 
43
few tracebacks combined. It's needed when you wrap an expection and want
44
44
to print both the traceback up to the wrapper exception, and the
45
 
original traceback. There is no code to support this here, but its easy
 
45
original traceback. There is no code to support this here, but it's easy
46
46
to add by using your own View sub class.
47
47
"""
48
48
 
58
58
    Return a string that resets the CGI and browser to a known state.
59
59
    TODO: probably some of this is not needed any more.
60
60
    """
61
 
    return '''<!--: spam
 
61
    return """<!--: spam
62
62
Content-Type: text/html
63
63
 
64
64
<body><font style="color: white; font-size: 1px"> -->
65
65
<body><font style="color: white; font-size: 1px"> --> -->
66
66
</font> </font> </font> </script> </object> </blockquote> </pre>
67
67
</table> </table> </table> </table> </table> </font> </font> </font>
68
 
'''
 
68
"""
69
69
 
70
70
__UNDEF__ = [] # a special sentinel object
71
71
 
72
72
 
 
73
class HiddenObject:
 
74
    def __repr__(self):
 
75
        return "<HIDDEN>"
 
76
HiddenObject = HiddenObject()
 
77
 
73
78
class HTMLFormatter:
74
79
    """ Minimal html formatter """
75
 
    
 
80
 
76
81
    def attributes(self, attributes=None):
77
82
        if attributes:
78
 
            result = [' %s="%s"' % (k, v) for k, v in attributes.items()]           
 
83
            result = [' %s="%s"' % (k, v) for k, v in attributes.items()]
79
84
            return ''.join(result)
80
85
        return ''
81
 
    
 
86
 
82
87
    def tag(self, name, text, attributes=None):
83
 
        return '<%s%s>%s</%s>\n' % (name, self.attributes(attributes), 
84
 
                                    text, name)
85
 
    
 
88
        return '<%s%s>%s</%s>\n' % (name, self.attributes(attributes), text, name)
 
89
 
86
90
    def section(self, text, attributes=None):
87
91
        return self.tag('div', text, attributes)
88
92
 
109
113
        if isinstance(items, (list, tuple)):
110
114
            items = '\n' + ''.join([self.listItem(i) for i in items])
111
115
        return self.tag(name, items, attributes)
112
 
    
 
116
 
113
117
    def listItem(self, text, attributes=None):
114
 
        return self.tag('li', text, attributes)        
 
118
        return self.tag('li', text, attributes)
115
119
 
116
120
    def link(self, href, text, attributes=None):
117
121
        if attributes is None:
120
124
        return self.tag('a', text, attributes)
121
125
 
122
126
    def strong(self, text, attributes=None):
123
 
        return self.tag('strong', text, attributes)        
 
127
        return self.tag('strong', text, attributes)
124
128
 
125
129
    def em(self, text, attributes=None):
126
 
        return self.tag('em', text, attributes)        
 
130
        return self.tag('em', text, attributes)
127
131
 
128
132
    def repr(self, object):
129
133
        return pydoc.html.repr(object)
130
 
        
 
134
 
131
135
 
132
136
class TextFormatter:
133
137
    """ Plain text formatter """
159
163
    def orderedList(self, items, attributes=None):
160
164
        if isinstance(items, (list, tuple)):
161
165
            result = []
162
 
            for i in rage(items):
 
166
            for i in range(items):
163
167
                result.append(' %d. %s\n' % (i, items[i]))
164
168
            return ''.join(result) + '\n'
165
169
        return items
166
170
 
167
171
    def listItem(self, text, attributes=None):
168
 
        return ' * %s\n' % text       
 
172
        return ' * %s\n' % text
169
173
 
170
174
    def link(self, href, text, attributes=None):
171
175
        return '[[%s]]' % text
172
176
 
173
177
    def strong(self, text, attributes=None):
174
178
        return text
175
 
   
 
179
 
176
180
    def em(self, text, attributes=None):
177
181
        return text
178
 
   
 
182
 
179
183
    def repr(self, object):
180
184
        return repr(object)
181
 
        
 
185
 
182
186
 
183
187
class Frame:
184
188
    """ Analyze and format single frame in a traceback """
202
206
 
203
207
    # -----------------------------------------------------------------
204
208
    # Private - formatting
205
 
        
 
209
 
206
210
    def formatCall(self):
207
211
        call = '%s in %s%s' % (self.formatFile(),
208
212
                               self.formatter.strong(self.func),
209
213
                               self.formatArguments(),)
210
214
        return self.formatter.paragraph(call, {'class': 'call'})
211
 
    
 
215
 
212
216
    def formatFile(self):
213
217
        """ Return formatted file link """
214
218
        if not self.file:
215
219
            return '?'
216
220
        file = pydoc.html.escape(os.path.abspath(self.file))
217
 
        return self.formatter.link('file://' + file, file)        
 
221
        return self.formatter.link('file://' + file, file)
218
222
 
219
223
    def formatArguments(self):
220
224
        """ Return formated arguments list """
245
249
        return self.formatter.orderedList(context, {'class': 'context'})
246
250
 
247
251
    def formatVariables(self, vars):
248
 
        """ Return formatted variables """ 
 
252
        """ Return formatted variables """
249
253
        done = {}
250
254
        dump = []
251
255
        for name, where, value in vars:
252
 
            if name in done: 
 
256
            if name in done:
253
257
                continue
254
258
            done[name] = 1
255
259
            if value is __UNDEF__:
275
279
    def scan(self):
276
280
        """ Scan frame for vars while setting highlight line """
277
281
        highlight = {}
278
 
        
 
282
 
279
283
        def reader(lnum=[self.lnum]):
280
284
            highlight[lnum[0]] = 1
281
 
            try: 
 
285
            try:
282
286
                return linecache.getline(self.file, lnum[0])
283
 
            finally: 
 
287
            finally:
284
288
                lnum[0] += 1
285
289
 
286
290
        vars = self.scanVariables(reader)
290
294
        """ Lookup variables in one logical Python line """
291
295
        vars, lasttoken, parent, prefix, value = [], None, None, '', __UNDEF__
292
296
        for ttype, token, start, end, line in tokenize.generate_tokens(reader):
293
 
            if ttype == tokenize.NEWLINE: 
 
297
            if ttype == tokenize.NEWLINE:
294
298
                break
295
299
            if ttype == tokenize.NAME and token not in keyword.kwlist:
296
300
                if lasttoken == '.':
297
301
                    if parent is not __UNDEF__:
298
 
                        value = getattr(parent, token, __UNDEF__)
 
302
                        if self.unsafe_name(token):
 
303
                            value = HiddenObject
 
304
                        else:
 
305
                            value = getattr(parent, token, __UNDEF__)
299
306
                        vars.append((prefix + token, prefix, value))
300
307
                else:
301
308
                    where, value = self.lookup(token)
324
331
                value = builtins.get(name, __UNDEF__)
325
332
            else:
326
333
                value = getattr(builtins, name, __UNDEF__)
 
334
        if self.unsafe_name(name):
 
335
            value = HiddenObject
327
336
        return scope, value
328
337
 
 
338
    def unsafe_name(self, name):
 
339
        return name in self.frame.f_globals.get("unsafe_names", ())
329
340
 
330
341
class View:
331
342
    """ Traceback view """
332
 
    
 
343
 
333
344
    frameClass = Frame # analyze and format a frame
334
 
    
 
345
 
335
346
    def __init__(self, info=None, debug=0):
336
347
        """ Save starting info or current exception info """
337
348
        self.info = info or sys.exc_info()
338
349
        self.debug = debug
339
 
        
 
350
 
340
351
    def format(self, formatter, context=5):
341
352
        self.formatter = formatter
342
353
        self.context = context
399
410
 
400
411
    # -----------------------------------------------------------------
401
412
    # Head
402
 
    
 
413
 
403
414
    def formatTitle(self):
404
415
        return self.formatter.title(self.exceptionTitle(self.info))
405
 
        
 
416
 
406
417
    def formatMessage(self):
407
418
        return self.formatter.paragraph(self.exceptionMessage(self.info))
408
 
        
 
419
 
409
420
    # -----------------------------------------------------------------
410
421
    # Traceback
411
422
 
412
423
    def formatTraceback(self):
413
424
        """ Return formatted traceback """
414
425
        return self.formatOneTraceback(self.info)
415
 
    
 
426
 
416
427
    def formatOneTraceback(self, info):
417
428
        """ Format one traceback
418
429
        
423
434
                  self.formatter.orderedList(self.tracebackFrames(info),
424
435
                                            {'class': 'frames'}),
425
436
                  self.formatter.section(self.formatException(info),
426
 
                                         {'class': 'exception'}),]
 
437
                                         {'class': 'exception'}), ]
427
438
        return self.formatter.section(''.join(output), {'class': 'traceback'})
428
439
 
429
440
    def tracebackFrames(self, info):
446
457
    def formatException(self, info):
447
458
        items = [self.formatExceptionTitle(info),
448
459
                 self.formatExceptionMessage(info),
449
 
                 self.formatExceptionAttributes(info),]
 
460
                 self.formatExceptionAttributes(info), ]
450
461
        return ''.join(items)
451
462
 
452
463
    def formatExceptionTitle(self, info):
453
464
        return self.formatter.subSubTitle(self.exceptionTitle(info))
454
 
        
 
465
 
455
466
    def formatExceptionMessage(self, info):
456
467
        return self.formatter.paragraph(self.exceptionMessage(info))
457
468
 
459
470
        attribtues = []
460
471
        for name, value in self.exceptionAttributes(info):
461
472
            value = self.formatter.repr(value)
462
 
            attribtues.append('%s = %s' % (name, value))           
 
473
            attribtues.append('%s = %s' % (name, value))
463
474
        return self.formatter.list(attribtues)
464
475
 
465
476
    def exceptionAttributes(self, info):
476
487
    def exceptionTitle(self, info):
477
488
        type = info[0]
478
489
        return getattr(type, '__name__', str(type))
479
 
        
 
490
 
480
491
    def exceptionMessage(self, info):
481
492
        instance = info[1]
482
493
        return pydoc.html.escape(str(instance))
488
499
    def formatSystemDetails(self):
489
500
        details = ['Date: %s' % self.date(),
490
501
                   'Platform: %s' % self.platform(),
491
 
                   'Python: %s' % self.python(),]
 
502
                   'Python: %s' % self.python(), ]
492
503
        details += self.applicationDetails()
493
504
        return (self.formatter.subTitle('System Details') +
494
505
                self.formatter.list(details, {'class': 'system'}))
495
506
 
496
507
    def date(self):
497
508
        import time
498
 
        rfc2822Date = time.strftime("%a, %d %b %Y %H:%M:%S +0000",
499
 
                                    time.gmtime())
 
509
        rfc2822Date = time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime())
500
510
        return rfc2822Date
501
511
 
502
512
    def platform(self):
580
590
            self.file.write('<p>A problem occurred in a Python script.\n')
581
591
 
582
592
        if self.logdir is not None:
583
 
            import os, tempfile
584
 
            suffix = ['.txt', '.html'][self.format=="html"]
 
593
            import tempfile
 
594
            suffix = ['.txt', '.html'][self.format == "html"]
585
595
            (fd, path) = tempfile.mkstemp(suffix=suffix, dir=self.logdir)
586
596
            try:
587
597
                file = os.fdopen(fd, 'w')
598
608
 
599
609
handler = Hook().handle
600
610
 
601
 
def enable(display=1, logdir=None, context=5, format="html",
602
 
           viewClass=View, debug=0):
 
611
def enable(display=1, logdir=None, context=5, format="html", viewClass=View, debug=0):
603
612
    """Install an exception handler that formats tracebacks as HTML.
604
613
 
605
614
    The optional argument 'display' can be set to 0 to suppress sending the
607
616
    tracebacks to be written to files there."""
608
617
    sys.excepthook = Hook(display=display, logdir=logdir, context=context,
609
618
                          format=format, viewClass=viewClass, debug=debug)
 
619