~ubuntu-branches/ubuntu/karmic/pypy/karmic

« back to all changes in this revision

Viewing changes to pypy/interpreter/error.py

  • Committer: Bazaar Package Importer
  • Author(s): Alexandre Fayolle
  • Date: 2007-04-13 09:33:09 UTC
  • Revision ID: james.westby@ubuntu.com-20070413093309-yoojh4jcoocu2krz
Tags: upstream-1.0.0
ImportĀ upstreamĀ versionĀ 1.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import os, sys
 
2
from pypy.rlib.objectmodel import we_are_translated
 
3
 
 
4
AUTO_DEBUG = os.getenv('PYPY_DEBUG')
 
5
RECORD_INTERPLEVEL_TRACEBACK = True
 
6
 
 
7
 
 
8
class OperationError(Exception):
 
9
    """Interpreter-level exception that signals an exception that should be
 
10
    sent to the application level.
 
11
 
 
12
    OperationError instances have three public attributes (and no .args),
 
13
    w_type, w_value and application_traceback, which contain the wrapped
 
14
    type and value describing the exception, and a chained list of
 
15
    PyTraceback objects making the application-level traceback.
 
16
    """
 
17
 
 
18
    def __init__(self, w_type, w_value, tb=None):
 
19
        if w_type is None:
 
20
            from pypy.tool.error import FlowingError
 
21
            raise FlowingError(w_value)
 
22
        self.w_type = w_type
 
23
        self.w_value = w_value
 
24
        self.application_traceback = tb
 
25
        if not we_are_translated():
 
26
            self.debug_excs = []
 
27
 
 
28
    def clear(self, space):
 
29
        # for sys.exc_clear()
 
30
        self.w_type = space.w_None
 
31
        self.w_value = space.w_None
 
32
        self.application_traceback = None
 
33
        if not we_are_translated():
 
34
            del self.debug_excs[:]
 
35
 
 
36
    def match(self, space, w_check_class):
 
37
        "Check if this application-level exception matches 'w_check_class'."
 
38
        return space.exception_match(self.w_type, w_check_class)
 
39
 
 
40
    def async(self, space):
 
41
        "Check if this is an exception that should better not be caught."
 
42
        return (self.match(space, space.w_SystemExit) or
 
43
                self.match(space, space.w_KeyboardInterrupt))
 
44
 
 
45
    def __str__(self):
 
46
        "NOT_RPYTHON: Convenience for tracebacks."
 
47
        return '[%s: %s]' % (self.w_type, self.w_value)
 
48
 
 
49
    def errorstr(self, space):
 
50
        "The exception class and value, as a string."
 
51
        if space is None:
 
52
            # this part NOT_RPYTHON
 
53
            exc_typename = str(self.w_type)
 
54
            exc_value    = str(self.w_value)
 
55
        else:
 
56
            w = space.wrap
 
57
            if space.is_w(space.type(self.w_type), space.w_str):
 
58
                exc_typename = space.str_w(self.w_type)
 
59
            else:
 
60
                exc_typename = space.str_w(
 
61
                    space.getattr(self.w_type, w('__name__')))
 
62
            if space.is_w(self.w_value, space.w_None):
 
63
                exc_value = ""
 
64
            else:
 
65
                try:
 
66
                    exc_value = space.str_w(space.str(self.w_value))
 
67
                except OperationError:
 
68
                    # oups, cannot __str__ the exception object
 
69
                    exc_value = "<oups, exception object itself cannot be str'd>"
 
70
        if not exc_value:
 
71
            return exc_typename
 
72
        else:
 
73
            return '%s: %s' % (exc_typename, exc_value)
 
74
 
 
75
    def getframe(self):
 
76
        "The frame this exception was raised in, or None."
 
77
        if self.application_traceback:
 
78
            return self.application_traceback.frame
 
79
        else:
 
80
            return None
 
81
 
 
82
    def record_interpreter_traceback(self):
 
83
        """Records the current traceback inside the interpreter.
 
84
        This traceback is only useful to debug the interpreter, not the
 
85
        application."""
 
86
        if not we_are_translated():
 
87
            if RECORD_INTERPLEVEL_TRACEBACK:
 
88
                self.debug_excs.append(sys.exc_info())
 
89
 
 
90
    def print_application_traceback(self, space, file=None):
 
91
        "NOT_RPYTHON: Dump a standard application-level traceback."
 
92
        if file is None: file = sys.stderr
 
93
        self.print_app_tb_only(file)
 
94
        print >> file, self.errorstr(space)
 
95
 
 
96
    def print_app_tb_only(self, file):
 
97
        "NOT_RPYTHON"
 
98
        tb = self.application_traceback
 
99
        if tb:
 
100
            import linecache
 
101
            print >> file, "Traceback (application-level):"
 
102
            while tb is not None:
 
103
                co = tb.frame.pycode
 
104
                lineno = tb.lineno
 
105
                fname = co.co_filename
 
106
                if fname.startswith('<inline>\n'):
 
107
                    lines = fname.split('\n')
 
108
                    fname = lines[0].strip()
 
109
                    try:
 
110
                        l = lines[lineno]
 
111
                    except IndexError:
 
112
                        l = ''
 
113
                else:
 
114
                    l = linecache.getline(fname, lineno)
 
115
                print >> file, "  File \"%s\"," % fname,
 
116
                print >> file, "line", lineno, "in", co.co_name
 
117
                if l:
 
118
                    if l.endswith('\n'):
 
119
                        l = l[:-1]
 
120
                    l = "    " + l.lstrip()
 
121
                    print >> file, l
 
122
                tb = tb.next
 
123
 
 
124
    def print_detailed_traceback(self, space=None, file=None):
 
125
        """NOT_RPYTHON: Dump a nice detailed interpreter- and
 
126
        application-level traceback, useful to debug the interpreter."""
 
127
        import traceback, cStringIO
 
128
        if file is None: file = sys.stderr
 
129
        f = cStringIO.StringIO()
 
130
        for i in range(len(self.debug_excs)-1, -1, -1):
 
131
            print >> f, "Traceback (interpreter-level):"
 
132
            traceback.print_tb(self.debug_excs[i][2], file=f)
 
133
        f.seek(0)
 
134
        debug_print(''.join(['|| ' + line for line in f.readlines()]), file)
 
135
        if self.debug_excs:
 
136
            from pypy.tool import tb_server
 
137
            tb_server.publish_exc(self.debug_excs[-1])
 
138
        self.print_app_tb_only(file)
 
139
        print >> file, '(application-level)', self.errorstr(space)
 
140
        if AUTO_DEBUG:
 
141
            import debug
 
142
            debug.fire(self)
 
143
 
 
144
    def normalize_exception(self, space):
 
145
        """Normalize the OperationError.  In other words, fix w_type and/or
 
146
        w_value to make sure that the __class__ of w_value is exactly w_type.
 
147
        """
 
148
        w_type  = self.w_type
 
149
        w_value = self.w_value
 
150
        if space.full_exceptions:
 
151
            while space.is_true(space.isinstance(w_type, space.w_tuple)):
 
152
                w_type = space.getitem(w_type, space.wrap(0))
 
153
 
 
154
        if space.is_true(space.abstract_isclass(w_type)):
 
155
            if space.is_w(w_value, space.w_None):
 
156
                # raise Type: we assume we have to instantiate Type
 
157
                w_value = space.call_function(w_type)
 
158
                w_type = space.abstract_getclass(w_value)
 
159
            else:
 
160
                w_valuetype = space.abstract_getclass(w_value)
 
161
                if space.is_true(space.abstract_issubclass(w_valuetype,
 
162
                                                           w_type)):
 
163
                    # raise Type, Instance: let etype be the exact type of value
 
164
                    w_type = w_valuetype
 
165
                else:
 
166
                    if space.full_exceptions and space.is_true(
 
167
                        space.isinstance(w_value, space.w_tuple)):
 
168
                        # raise Type, tuple: assume the tuple contains the
 
169
                        #                    constructor args
 
170
                        w_value = space.call(w_type, w_value)
 
171
                    else:
 
172
                        # raise Type, X: assume X is the constructor argument
 
173
                        w_value = space.call_function(w_type, w_value)
 
174
                    w_type = space.abstract_getclass(w_value)
 
175
 
 
176
        elif space.full_exceptions and space.is_w(space.type(w_type),
 
177
                                                  space.w_str):
 
178
            # XXX warn -- deprecated
 
179
            pass
 
180
        else:
 
181
 
 
182
            # raise X: we assume that X is an already-built instance
 
183
            if not space.is_w(w_value, space.w_None):
 
184
                raise OperationError(space.w_TypeError,
 
185
                                     space.wrap("instance exception may not "
 
186
                                                "have a separate value"))
 
187
            w_value = w_type
 
188
            w_type = space.abstract_getclass(w_value)
 
189
            if space.full_exceptions:
 
190
                # for the sake of language consistency we should not allow
 
191
                # things like 'raise 1', but it is probably fine (i.e.
 
192
                # not ambiguous) to allow them in the explicit form
 
193
                # 'raise int, 1'
 
194
                if (space.findattr(w_value, space.wrap('__dict__')) is None and
 
195
                    space.findattr(w_value, space.wrap('__slots__')) is None):
 
196
                    msg = ("raising built-in objects can be ambiguous, "
 
197
                           "use 'raise type, value' instead")
 
198
                    raise OperationError(space.w_TypeError, space.wrap(msg))
 
199
        self.w_type  = w_type
 
200
        self.w_value = w_value
 
201
 
 
202
    def write_unraisable(self, space, where, w_object=None):
 
203
        if w_object is None:
 
204
            objrepr = ''
 
205
        else:
 
206
            try:
 
207
                objrepr = space.str_w(space.repr(w_object))
 
208
            except OperationError:
 
209
                objrepr = '?'
 
210
        msg = 'Exception "%s" in %s%s ignored\n' % (self.errorstr(space),
 
211
                                                    where, objrepr)
 
212
        try:
 
213
            space.call_method(space.sys.get('stderr'), 'write', space.wrap(msg))
 
214
        except OperationError:
 
215
            pass   # ignored
 
216
 
 
217
 
 
218
# Utilities
 
219
from pypy.tool.ansi_print import ansi_print
 
220
 
 
221
def debug_print(text, file=None, newline=True):
 
222
    # 31: ANSI color code "red"
 
223
    ansi_print(text, esc="31", file=file, newline=newline)
 
224
 
 
225
### installing the excepthook for OperationErrors
 
226
##def operr_excepthook(exctype, value, traceback):
 
227
##    if issubclass(exctype, OperationError):
 
228
##        value.debug_excs.append((exctype, value, traceback))
 
229
##        value.print_detailed_traceback()
 
230
##    else:
 
231
##        old_excepthook(exctype, value, traceback)
 
232
##        from pypy.tool import tb_server
 
233
##        tb_server.publish_exc((exctype, value, traceback))
 
234
 
 
235
##old_excepthook = sys.excepthook
 
236
##sys.excepthook = operr_excepthook