Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | """Extract, format and print information about Python stack traces.""" |
2 | ||
3 | import linecache | |
4 | import sys | |
5 | import types | |
6 | ||
7 | __all__ = ['extract_stack', 'extract_tb', 'format_exception', | |
8 | 'format_exception_only', 'format_list', 'format_stack', | |
9 | 'format_tb', 'print_exc', 'format_exc', 'print_exception', | |
10 | 'print_last', 'print_stack', 'print_tb', 'tb_lineno'] | |
11 | ||
12 | def _print(file, str='', terminator='\n'): | |
13 | file.write(str+terminator) | |
14 | ||
15 | ||
16 | def print_list(extracted_list, file=None): | |
17 | """Print the list of tuples as returned by extract_tb() or | |
18 | extract_stack() as a formatted stack trace to the given file.""" | |
19 | if file is None: | |
20 | file = sys.stderr | |
21 | for filename, lineno, name, line in extracted_list: | |
22 | _print(file, | |
23 | ' File "%s", line %d, in %s' % (filename,lineno,name)) | |
24 | if line: | |
25 | _print(file, ' %s' % line.strip()) | |
26 | ||
27 | def format_list(extracted_list): | |
28 | """Format a list of traceback entry tuples for printing. | |
29 | ||
30 | Given a list of tuples as returned by extract_tb() or | |
31 | extract_stack(), return a list of strings ready for printing. | |
32 | Each string in the resulting list corresponds to the item with the | |
33 | same index in the argument list. Each string ends in a newline; | |
34 | the strings may contain internal newlines as well, for those items | |
35 | whose source text line is not None. | |
36 | """ | |
37 | list = [] | |
38 | for filename, lineno, name, line in extracted_list: | |
39 | item = ' File "%s", line %d, in %s\n' % (filename,lineno,name) | |
40 | if line: | |
41 | item = item + ' %s\n' % line.strip() | |
42 | list.append(item) | |
43 | return list | |
44 | ||
45 | ||
46 | def print_tb(tb, limit=None, file=None): | |
47 | """Print up to 'limit' stack trace entries from the traceback 'tb'. | |
48 | ||
49 | If 'limit' is omitted or None, all entries are printed. If 'file' | |
50 | is omitted or None, the output goes to sys.stderr; otherwise | |
51 | 'file' should be an open file or file-like object with a write() | |
52 | method. | |
53 | """ | |
54 | if file is None: | |
55 | file = sys.stderr | |
56 | if limit is None: | |
57 | if hasattr(sys, 'tracebacklimit'): | |
58 | limit = sys.tracebacklimit | |
59 | n = 0 | |
60 | while tb is not None and (limit is None or n < limit): | |
61 | f = tb.tb_frame | |
62 | lineno = tb.tb_lineno | |
63 | co = f.f_code | |
64 | filename = co.co_filename | |
65 | name = co.co_name | |
66 | _print(file, | |
67 | ' File "%s", line %d, in %s' % (filename,lineno,name)) | |
68 | linecache.checkcache(filename) | |
69 | line = linecache.getline(filename, lineno) | |
70 | if line: _print(file, ' ' + line.strip()) | |
71 | tb = tb.tb_next | |
72 | n = n+1 | |
73 | ||
74 | def format_tb(tb, limit = None): | |
75 | """A shorthand for 'format_list(extract_stack(f, limit)).""" | |
76 | return format_list(extract_tb(tb, limit)) | |
77 | ||
78 | def extract_tb(tb, limit = None): | |
79 | """Return list of up to limit pre-processed entries from traceback. | |
80 | ||
81 | This is useful for alternate formatting of stack traces. If | |
82 | 'limit' is omitted or None, all entries are extracted. A | |
83 | pre-processed stack trace entry is a quadruple (filename, line | |
84 | number, function name, text) representing the information that is | |
85 | usually printed for a stack trace. The text is a string with | |
86 | leading and trailing whitespace stripped; if the source is not | |
87 | available it is None. | |
88 | """ | |
89 | if limit is None: | |
90 | if hasattr(sys, 'tracebacklimit'): | |
91 | limit = sys.tracebacklimit | |
92 | list = [] | |
93 | n = 0 | |
94 | while tb is not None and (limit is None or n < limit): | |
95 | f = tb.tb_frame | |
96 | lineno = tb.tb_lineno | |
97 | co = f.f_code | |
98 | filename = co.co_filename | |
99 | name = co.co_name | |
100 | linecache.checkcache(filename) | |
101 | line = linecache.getline(filename, lineno) | |
102 | if line: line = line.strip() | |
103 | else: line = None | |
104 | list.append((filename, lineno, name, line)) | |
105 | tb = tb.tb_next | |
106 | n = n+1 | |
107 | return list | |
108 | ||
109 | ||
110 | def print_exception(etype, value, tb, limit=None, file=None): | |
111 | """Print exception up to 'limit' stack trace entries from 'tb' to 'file'. | |
112 | ||
113 | This differs from print_tb() in the following ways: (1) if | |
114 | traceback is not None, it prints a header "Traceback (most recent | |
115 | call last):"; (2) it prints the exception type and value after the | |
116 | stack trace; (3) if type is SyntaxError and value has the | |
117 | appropriate format, it prints the line where the syntax error | |
118 | occurred with a caret on the next line indicating the approximate | |
119 | position of the error. | |
120 | """ | |
121 | if file is None: | |
122 | file = sys.stderr | |
123 | if tb: | |
124 | _print(file, 'Traceback (most recent call last):') | |
125 | print_tb(tb, limit, file) | |
126 | lines = format_exception_only(etype, value) | |
127 | for line in lines[:-1]: | |
128 | _print(file, line, ' ') | |
129 | _print(file, lines[-1], '') | |
130 | ||
131 | def format_exception(etype, value, tb, limit = None): | |
132 | """Format a stack trace and the exception information. | |
133 | ||
134 | The arguments have the same meaning as the corresponding arguments | |
135 | to print_exception(). The return value is a list of strings, each | |
136 | ending in a newline and some containing internal newlines. When | |
137 | these lines are concatenated and printed, exactly the same text is | |
138 | printed as does print_exception(). | |
139 | """ | |
140 | if tb: | |
141 | list = ['Traceback (most recent call last):\n'] | |
142 | list = list + format_tb(tb, limit) | |
143 | else: | |
144 | list = [] | |
145 | list = list + format_exception_only(etype, value) | |
146 | return list | |
147 | ||
148 | def format_exception_only(etype, value): | |
149 | """Format the exception part of a traceback. | |
150 | ||
151 | The arguments are the exception type and value such as given by | |
152 | sys.last_type and sys.last_value. The return value is a list of | |
153 | strings, each ending in a newline. Normally, the list contains a | |
154 | single string; however, for SyntaxError exceptions, it contains | |
155 | several lines that (when printed) display detailed information | |
156 | about where the syntax error occurred. The message indicating | |
157 | which exception occurred is the always last string in the list. | |
158 | """ | |
159 | list = [] | |
160 | if type(etype) == types.ClassType: | |
161 | stype = etype.__name__ | |
162 | else: | |
163 | stype = etype | |
164 | if value is None: | |
165 | list.append(str(stype) + '\n') | |
166 | else: | |
167 | if etype is SyntaxError: | |
168 | try: | |
169 | msg, (filename, lineno, offset, line) = value | |
170 | except: | |
171 | pass | |
172 | else: | |
173 | if not filename: filename = "<string>" | |
174 | list.append(' File "%s", line %d\n' % | |
175 | (filename, lineno)) | |
176 | if line is not None: | |
177 | i = 0 | |
178 | while i < len(line) and line[i].isspace(): | |
179 | i = i+1 | |
180 | list.append(' %s\n' % line.strip()) | |
181 | if offset is not None: | |
182 | s = ' ' | |
183 | for c in line[i:offset-1]: | |
184 | if c.isspace(): | |
185 | s = s + c | |
186 | else: | |
187 | s = s + ' ' | |
188 | list.append('%s^\n' % s) | |
189 | value = msg | |
190 | s = _some_str(value) | |
191 | if s: | |
192 | list.append('%s: %s\n' % (str(stype), s)) | |
193 | else: | |
194 | list.append('%s\n' % str(stype)) | |
195 | return list | |
196 | ||
197 | def _some_str(value): | |
198 | try: | |
199 | return str(value) | |
200 | except: | |
201 | return '<unprintable %s object>' % type(value).__name__ | |
202 | ||
203 | ||
204 | def print_exc(limit=None, file=None): | |
205 | """Shorthand for 'print_exception(sys.exc_type, sys.exc_value, sys.exc_traceback, limit, file)'. | |
206 | (In fact, it uses sys.exc_info() to retrieve the same information | |
207 | in a thread-safe way.)""" | |
208 | if file is None: | |
209 | file = sys.stderr | |
210 | try: | |
211 | etype, value, tb = sys.exc_info() | |
212 | print_exception(etype, value, tb, limit, file) | |
213 | finally: | |
214 | etype = value = tb = None | |
215 | ||
216 | ||
217 | def format_exc(limit=None): | |
218 | """Like print_exc() but return a string.""" | |
219 | try: | |
220 | etype, value, tb = sys.exc_info() | |
221 | return ''.join(format_exception(etype, value, tb, limit)) | |
222 | finally: | |
223 | etype = value = tb = None | |
224 | ||
225 | ||
226 | def print_last(limit=None, file=None): | |
227 | """This is a shorthand for 'print_exception(sys.last_type, | |
228 | sys.last_value, sys.last_traceback, limit, file)'.""" | |
229 | if file is None: | |
230 | file = sys.stderr | |
231 | print_exception(sys.last_type, sys.last_value, sys.last_traceback, | |
232 | limit, file) | |
233 | ||
234 | ||
235 | def print_stack(f=None, limit=None, file=None): | |
236 | """Print a stack trace from its invocation point. | |
237 | ||
238 | The optional 'f' argument can be used to specify an alternate | |
239 | stack frame at which to start. The optional 'limit' and 'file' | |
240 | arguments have the same meaning as for print_exception(). | |
241 | """ | |
242 | if f is None: | |
243 | try: | |
244 | raise ZeroDivisionError | |
245 | except ZeroDivisionError: | |
246 | f = sys.exc_info()[2].tb_frame.f_back | |
247 | print_list(extract_stack(f, limit), file) | |
248 | ||
249 | def format_stack(f=None, limit=None): | |
250 | """Shorthand for 'format_list(extract_stack(f, limit))'.""" | |
251 | if f is None: | |
252 | try: | |
253 | raise ZeroDivisionError | |
254 | except ZeroDivisionError: | |
255 | f = sys.exc_info()[2].tb_frame.f_back | |
256 | return format_list(extract_stack(f, limit)) | |
257 | ||
258 | def extract_stack(f=None, limit = None): | |
259 | """Extract the raw traceback from the current stack frame. | |
260 | ||
261 | The return value has the same format as for extract_tb(). The | |
262 | optional 'f' and 'limit' arguments have the same meaning as for | |
263 | print_stack(). Each item in the list is a quadruple (filename, | |
264 | line number, function name, text), and the entries are in order | |
265 | from oldest to newest stack frame. | |
266 | """ | |
267 | if f is None: | |
268 | try: | |
269 | raise ZeroDivisionError | |
270 | except ZeroDivisionError: | |
271 | f = sys.exc_info()[2].tb_frame.f_back | |
272 | if limit is None: | |
273 | if hasattr(sys, 'tracebacklimit'): | |
274 | limit = sys.tracebacklimit | |
275 | list = [] | |
276 | n = 0 | |
277 | while f is not None and (limit is None or n < limit): | |
278 | lineno = f.f_lineno | |
279 | co = f.f_code | |
280 | filename = co.co_filename | |
281 | name = co.co_name | |
282 | linecache.checkcache(filename) | |
283 | line = linecache.getline(filename, lineno) | |
284 | if line: line = line.strip() | |
285 | else: line = None | |
286 | list.append((filename, lineno, name, line)) | |
287 | f = f.f_back | |
288 | n = n+1 | |
289 | list.reverse() | |
290 | return list | |
291 | ||
292 | def tb_lineno(tb): | |
293 | """Calculate correct line number of traceback given in tb. | |
294 | ||
295 | Obsolete in 2.3. | |
296 | """ | |
297 | return tb.tb_lineno |