##// END OF EJS Templates
Merge pull request #9250 from Carreau/pygpartial-1...
Matthias Bussonnier -
r22111:f31e6001 merge
parent child Browse files
Show More
@@ -0,0 +1,26 b''
1 #*****************************************************************************
2 # Copyright (C) 2016 The IPython Team <ipython-dev@scipy.org>
3 #
4 # Distributed under the terms of the BSD License. The full license is in
5 # the file COPYING, distributed as part of this software.
6 #*****************************************************************************
7 from __future__ import absolute_import
8
9 """
10 Color managing related utilities
11 """
12
13 import pygments
14
15 from traitlets.config import Configurable
16 from traitlets import Unicode
17
18
19 available_themes = lambda : [s for s in pygments.styles.get_all_styles()]+['NoColor','LightBG','Linux']
20
21 class Colorable(Configurable):
22 """
23 A subclass of configurable for all the classes that have a `default_scheme`
24 """
25 default_style=Unicode('lightbg', config=True)
26
@@ -1,921 +1,924 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Tools for inspecting Python objects.
2 """Tools for inspecting Python objects.
3
3
4 Uses syntax highlighting for presenting the various information elements.
4 Uses syntax highlighting for presenting the various information elements.
5
5
6 Similar in spirit to the inspect module, but all calls take a name argument to
6 Similar in spirit to the inspect module, but all calls take a name argument to
7 reference the name under which an object is being read.
7 reference the name under which an object is being read.
8 """
8 """
9
9
10 # Copyright (c) IPython Development Team.
10 # Copyright (c) IPython Development Team.
11 # Distributed under the terms of the Modified BSD License.
11 # Distributed under the terms of the Modified BSD License.
12
12
13 from __future__ import print_function
13 from __future__ import print_function
14
14
15 __all__ = ['Inspector','InspectColors']
15 __all__ = ['Inspector','InspectColors']
16
16
17 # stdlib modules
17 # stdlib modules
18 import inspect
18 import inspect
19 import linecache
19 import linecache
20 import os
20 import os
21 from textwrap import dedent
21 from textwrap import dedent
22 import types
22 import types
23 import io as stdlib_io
23 import io as stdlib_io
24
24
25 try:
25 try:
26 from itertools import izip_longest
26 from itertools import izip_longest
27 except ImportError:
27 except ImportError:
28 from itertools import zip_longest as izip_longest
28 from itertools import zip_longest as izip_longest
29
29
30 # IPython's own
30 # IPython's own
31 from IPython.core import page
31 from IPython.core import page
32 from IPython.lib.pretty import pretty
32 from IPython.lib.pretty import pretty
33 from IPython.testing.skipdoctest import skip_doctest_py3
33 from IPython.testing.skipdoctest import skip_doctest_py3
34 from IPython.utils import PyColorize
34 from IPython.utils import PyColorize
35 from IPython.utils import io
35 from IPython.utils import io
36 from IPython.utils import openpy
36 from IPython.utils import openpy
37 from IPython.utils import py3compat
37 from IPython.utils import py3compat
38 from IPython.utils.dir2 import safe_hasattr
38 from IPython.utils.dir2 import safe_hasattr
39 from IPython.utils.path import compress_user
39 from IPython.utils.path import compress_user
40 from IPython.utils.text import indent
40 from IPython.utils.text import indent
41 from IPython.utils.wildcard import list_namespace
41 from IPython.utils.wildcard import list_namespace
42 from IPython.utils.coloransi import TermColors, ColorScheme, ColorSchemeTable
42 from IPython.utils.coloransi import TermColors, ColorScheme, ColorSchemeTable
43 from IPython.utils.py3compat import cast_unicode, string_types, PY3
43 from IPython.utils.py3compat import cast_unicode, string_types, PY3
44 from IPython.utils.signatures import signature
44 from IPython.utils.signatures import signature
45 from IPython.utils.colorable import Colorable
45
46
46 # builtin docstrings to ignore
47 # builtin docstrings to ignore
47 _func_call_docstring = types.FunctionType.__call__.__doc__
48 _func_call_docstring = types.FunctionType.__call__.__doc__
48 _object_init_docstring = object.__init__.__doc__
49 _object_init_docstring = object.__init__.__doc__
49 _builtin_type_docstrings = {
50 _builtin_type_docstrings = {
50 inspect.getdoc(t) for t in (types.ModuleType, types.MethodType,
51 inspect.getdoc(t) for t in (types.ModuleType, types.MethodType,
51 types.FunctionType, property)
52 types.FunctionType, property)
52 }
53 }
53
54
54 _builtin_func_type = type(all)
55 _builtin_func_type = type(all)
55 _builtin_meth_type = type(str.upper) # Bound methods have the same type as builtin functions
56 _builtin_meth_type = type(str.upper) # Bound methods have the same type as builtin functions
56 #****************************************************************************
57 #****************************************************************************
57 # Builtin color schemes
58 # Builtin color schemes
58
59
59 Colors = TermColors # just a shorthand
60 Colors = TermColors # just a shorthand
60
61
61 InspectColors = PyColorize.ANSICodeColors
62 InspectColors = PyColorize.ANSICodeColors
62
63
63 #****************************************************************************
64 #****************************************************************************
64 # Auxiliary functions and objects
65 # Auxiliary functions and objects
65
66
66 # See the messaging spec for the definition of all these fields. This list
67 # See the messaging spec for the definition of all these fields. This list
67 # effectively defines the order of display
68 # effectively defines the order of display
68 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
69 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
69 'length', 'file', 'definition', 'docstring', 'source',
70 'length', 'file', 'definition', 'docstring', 'source',
70 'init_definition', 'class_docstring', 'init_docstring',
71 'init_definition', 'class_docstring', 'init_docstring',
71 'call_def', 'call_docstring',
72 'call_def', 'call_docstring',
72 # These won't be printed but will be used to determine how to
73 # These won't be printed but will be used to determine how to
73 # format the object
74 # format the object
74 'ismagic', 'isalias', 'isclass', 'argspec', 'found', 'name'
75 'ismagic', 'isalias', 'isclass', 'argspec', 'found', 'name'
75 ]
76 ]
76
77
77
78
78 def object_info(**kw):
79 def object_info(**kw):
79 """Make an object info dict with all fields present."""
80 """Make an object info dict with all fields present."""
80 infodict = dict(izip_longest(info_fields, [None]))
81 infodict = dict(izip_longest(info_fields, [None]))
81 infodict.update(kw)
82 infodict.update(kw)
82 return infodict
83 return infodict
83
84
84
85
85 def get_encoding(obj):
86 def get_encoding(obj):
86 """Get encoding for python source file defining obj
87 """Get encoding for python source file defining obj
87
88
88 Returns None if obj is not defined in a sourcefile.
89 Returns None if obj is not defined in a sourcefile.
89 """
90 """
90 ofile = find_file(obj)
91 ofile = find_file(obj)
91 # run contents of file through pager starting at line where the object
92 # run contents of file through pager starting at line where the object
92 # is defined, as long as the file isn't binary and is actually on the
93 # is defined, as long as the file isn't binary and is actually on the
93 # filesystem.
94 # filesystem.
94 if ofile is None:
95 if ofile is None:
95 return None
96 return None
96 elif ofile.endswith(('.so', '.dll', '.pyd')):
97 elif ofile.endswith(('.so', '.dll', '.pyd')):
97 return None
98 return None
98 elif not os.path.isfile(ofile):
99 elif not os.path.isfile(ofile):
99 return None
100 return None
100 else:
101 else:
101 # Print only text files, not extension binaries. Note that
102 # Print only text files, not extension binaries. Note that
102 # getsourcelines returns lineno with 1-offset and page() uses
103 # getsourcelines returns lineno with 1-offset and page() uses
103 # 0-offset, so we must adjust.
104 # 0-offset, so we must adjust.
104 with stdlib_io.open(ofile, 'rb') as buffer: # Tweaked to use io.open for Python 2
105 with stdlib_io.open(ofile, 'rb') as buffer: # Tweaked to use io.open for Python 2
105 encoding, lines = openpy.detect_encoding(buffer.readline)
106 encoding, lines = openpy.detect_encoding(buffer.readline)
106 return encoding
107 return encoding
107
108
108 def getdoc(obj):
109 def getdoc(obj):
109 """Stable wrapper around inspect.getdoc.
110 """Stable wrapper around inspect.getdoc.
110
111
111 This can't crash because of attribute problems.
112 This can't crash because of attribute problems.
112
113
113 It also attempts to call a getdoc() method on the given object. This
114 It also attempts to call a getdoc() method on the given object. This
114 allows objects which provide their docstrings via non-standard mechanisms
115 allows objects which provide their docstrings via non-standard mechanisms
115 (like Pyro proxies) to still be inspected by ipython's ? system."""
116 (like Pyro proxies) to still be inspected by ipython's ? system."""
116 # Allow objects to offer customized documentation via a getdoc method:
117 # Allow objects to offer customized documentation via a getdoc method:
117 try:
118 try:
118 ds = obj.getdoc()
119 ds = obj.getdoc()
119 except Exception:
120 except Exception:
120 pass
121 pass
121 else:
122 else:
122 # if we get extra info, we add it to the normal docstring.
123 # if we get extra info, we add it to the normal docstring.
123 if isinstance(ds, string_types):
124 if isinstance(ds, string_types):
124 return inspect.cleandoc(ds)
125 return inspect.cleandoc(ds)
125
126
126 try:
127 try:
127 docstr = inspect.getdoc(obj)
128 docstr = inspect.getdoc(obj)
128 encoding = get_encoding(obj)
129 encoding = get_encoding(obj)
129 return py3compat.cast_unicode(docstr, encoding=encoding)
130 return py3compat.cast_unicode(docstr, encoding=encoding)
130 except Exception:
131 except Exception:
131 # Harden against an inspect failure, which can occur with
132 # Harden against an inspect failure, which can occur with
132 # SWIG-wrapped extensions.
133 # SWIG-wrapped extensions.
133 raise
134 raise
134 return None
135 return None
135
136
136
137
137 def getsource(obj, oname=''):
138 def getsource(obj, oname=''):
138 """Wrapper around inspect.getsource.
139 """Wrapper around inspect.getsource.
139
140
140 This can be modified by other projects to provide customized source
141 This can be modified by other projects to provide customized source
141 extraction.
142 extraction.
142
143
143 Parameters
144 Parameters
144 ----------
145 ----------
145 obj : object
146 obj : object
146 an object whose source code we will attempt to extract
147 an object whose source code we will attempt to extract
147 oname : str
148 oname : str
148 (optional) a name under which the object is known
149 (optional) a name under which the object is known
149
150
150 Returns
151 Returns
151 -------
152 -------
152 src : unicode or None
153 src : unicode or None
153
154
154 """
155 """
155
156
156 if isinstance(obj, property):
157 if isinstance(obj, property):
157 sources = []
158 sources = []
158 for attrname in ['fget', 'fset', 'fdel']:
159 for attrname in ['fget', 'fset', 'fdel']:
159 fn = getattr(obj, attrname)
160 fn = getattr(obj, attrname)
160 if fn is not None:
161 if fn is not None:
161 encoding = get_encoding(fn)
162 encoding = get_encoding(fn)
162 oname_prefix = ('%s.' % oname) if oname else ''
163 oname_prefix = ('%s.' % oname) if oname else ''
163 sources.append(cast_unicode(
164 sources.append(cast_unicode(
164 ''.join(('# ', oname_prefix, attrname)),
165 ''.join(('# ', oname_prefix, attrname)),
165 encoding=encoding))
166 encoding=encoding))
166 if inspect.isfunction(fn):
167 if inspect.isfunction(fn):
167 sources.append(dedent(getsource(fn)))
168 sources.append(dedent(getsource(fn)))
168 else:
169 else:
169 # Default str/repr only prints function name,
170 # Default str/repr only prints function name,
170 # pretty.pretty prints module name too.
171 # pretty.pretty prints module name too.
171 sources.append(cast_unicode(
172 sources.append(cast_unicode(
172 '%s%s = %s\n' % (
173 '%s%s = %s\n' % (
173 oname_prefix, attrname, pretty(fn)),
174 oname_prefix, attrname, pretty(fn)),
174 encoding=encoding))
175 encoding=encoding))
175 if sources:
176 if sources:
176 return '\n'.join(sources)
177 return '\n'.join(sources)
177 else:
178 else:
178 return None
179 return None
179
180
180 else:
181 else:
181 # Get source for non-property objects.
182 # Get source for non-property objects.
182
183
183 obj = _get_wrapped(obj)
184 obj = _get_wrapped(obj)
184
185
185 try:
186 try:
186 src = inspect.getsource(obj)
187 src = inspect.getsource(obj)
187 except TypeError:
188 except TypeError:
188 # The object itself provided no meaningful source, try looking for
189 # The object itself provided no meaningful source, try looking for
189 # its class definition instead.
190 # its class definition instead.
190 if hasattr(obj, '__class__'):
191 if hasattr(obj, '__class__'):
191 try:
192 try:
192 src = inspect.getsource(obj.__class__)
193 src = inspect.getsource(obj.__class__)
193 except TypeError:
194 except TypeError:
194 return None
195 return None
195
196
196 encoding = get_encoding(obj)
197 encoding = get_encoding(obj)
197 return cast_unicode(src, encoding=encoding)
198 return cast_unicode(src, encoding=encoding)
198
199
199
200
200 def is_simple_callable(obj):
201 def is_simple_callable(obj):
201 """True if obj is a function ()"""
202 """True if obj is a function ()"""
202 return (inspect.isfunction(obj) or inspect.ismethod(obj) or \
203 return (inspect.isfunction(obj) or inspect.ismethod(obj) or \
203 isinstance(obj, _builtin_func_type) or isinstance(obj, _builtin_meth_type))
204 isinstance(obj, _builtin_func_type) or isinstance(obj, _builtin_meth_type))
204
205
205
206
206 def getargspec(obj):
207 def getargspec(obj):
207 """Wrapper around :func:`inspect.getfullargspec` on Python 3, and
208 """Wrapper around :func:`inspect.getfullargspec` on Python 3, and
208 :func:inspect.getargspec` on Python 2.
209 :func:inspect.getargspec` on Python 2.
209
210
210 In addition to functions and methods, this can also handle objects with a
211 In addition to functions and methods, this can also handle objects with a
211 ``__call__`` attribute.
212 ``__call__`` attribute.
212 """
213 """
213 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
214 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
214 obj = obj.__call__
215 obj = obj.__call__
215
216
216 return inspect.getfullargspec(obj) if PY3 else inspect.getargspec(obj)
217 return inspect.getfullargspec(obj) if PY3 else inspect.getargspec(obj)
217
218
218
219
219 def format_argspec(argspec):
220 def format_argspec(argspec):
220 """Format argspect, convenience wrapper around inspect's.
221 """Format argspect, convenience wrapper around inspect's.
221
222
222 This takes a dict instead of ordered arguments and calls
223 This takes a dict instead of ordered arguments and calls
223 inspect.format_argspec with the arguments in the necessary order.
224 inspect.format_argspec with the arguments in the necessary order.
224 """
225 """
225 return inspect.formatargspec(argspec['args'], argspec['varargs'],
226 return inspect.formatargspec(argspec['args'], argspec['varargs'],
226 argspec['varkw'], argspec['defaults'])
227 argspec['varkw'], argspec['defaults'])
227
228
228
229
229 def call_tip(oinfo, format_call=True):
230 def call_tip(oinfo, format_call=True):
230 """Extract call tip data from an oinfo dict.
231 """Extract call tip data from an oinfo dict.
231
232
232 Parameters
233 Parameters
233 ----------
234 ----------
234 oinfo : dict
235 oinfo : dict
235
236
236 format_call : bool, optional
237 format_call : bool, optional
237 If True, the call line is formatted and returned as a string. If not, a
238 If True, the call line is formatted and returned as a string. If not, a
238 tuple of (name, argspec) is returned.
239 tuple of (name, argspec) is returned.
239
240
240 Returns
241 Returns
241 -------
242 -------
242 call_info : None, str or (str, dict) tuple.
243 call_info : None, str or (str, dict) tuple.
243 When format_call is True, the whole call information is formattted as a
244 When format_call is True, the whole call information is formattted as a
244 single string. Otherwise, the object's name and its argspec dict are
245 single string. Otherwise, the object's name and its argspec dict are
245 returned. If no call information is available, None is returned.
246 returned. If no call information is available, None is returned.
246
247
247 docstring : str or None
248 docstring : str or None
248 The most relevant docstring for calling purposes is returned, if
249 The most relevant docstring for calling purposes is returned, if
249 available. The priority is: call docstring for callable instances, then
250 available. The priority is: call docstring for callable instances, then
250 constructor docstring for classes, then main object's docstring otherwise
251 constructor docstring for classes, then main object's docstring otherwise
251 (regular functions).
252 (regular functions).
252 """
253 """
253 # Get call definition
254 # Get call definition
254 argspec = oinfo.get('argspec')
255 argspec = oinfo.get('argspec')
255 if argspec is None:
256 if argspec is None:
256 call_line = None
257 call_line = None
257 else:
258 else:
258 # Callable objects will have 'self' as their first argument, prune
259 # Callable objects will have 'self' as their first argument, prune
259 # it out if it's there for clarity (since users do *not* pass an
260 # it out if it's there for clarity (since users do *not* pass an
260 # extra first argument explicitly).
261 # extra first argument explicitly).
261 try:
262 try:
262 has_self = argspec['args'][0] == 'self'
263 has_self = argspec['args'][0] == 'self'
263 except (KeyError, IndexError):
264 except (KeyError, IndexError):
264 pass
265 pass
265 else:
266 else:
266 if has_self:
267 if has_self:
267 argspec['args'] = argspec['args'][1:]
268 argspec['args'] = argspec['args'][1:]
268
269
269 call_line = oinfo['name']+format_argspec(argspec)
270 call_line = oinfo['name']+format_argspec(argspec)
270
271
271 # Now get docstring.
272 # Now get docstring.
272 # The priority is: call docstring, constructor docstring, main one.
273 # The priority is: call docstring, constructor docstring, main one.
273 doc = oinfo.get('call_docstring')
274 doc = oinfo.get('call_docstring')
274 if doc is None:
275 if doc is None:
275 doc = oinfo.get('init_docstring')
276 doc = oinfo.get('init_docstring')
276 if doc is None:
277 if doc is None:
277 doc = oinfo.get('docstring','')
278 doc = oinfo.get('docstring','')
278
279
279 return call_line, doc
280 return call_line, doc
280
281
281
282
282 def _get_wrapped(obj):
283 def _get_wrapped(obj):
283 """Get the original object if wrapped in one or more @decorators
284 """Get the original object if wrapped in one or more @decorators
284
285
285 Some objects automatically construct similar objects on any unrecognised
286 Some objects automatically construct similar objects on any unrecognised
286 attribute access (e.g. unittest.mock.call). To protect against infinite loops,
287 attribute access (e.g. unittest.mock.call). To protect against infinite loops,
287 this will arbitrarily cut off after 100 levels of obj.__wrapped__
288 this will arbitrarily cut off after 100 levels of obj.__wrapped__
288 attribute access. --TK, Jan 2016
289 attribute access. --TK, Jan 2016
289 """
290 """
290 orig_obj = obj
291 orig_obj = obj
291 i = 0
292 i = 0
292 while safe_hasattr(obj, '__wrapped__'):
293 while safe_hasattr(obj, '__wrapped__'):
293 obj = obj.__wrapped__
294 obj = obj.__wrapped__
294 i += 1
295 i += 1
295 if i > 100:
296 if i > 100:
296 # __wrapped__ is probably a lie, so return the thing we started with
297 # __wrapped__ is probably a lie, so return the thing we started with
297 return orig_obj
298 return orig_obj
298 return obj
299 return obj
299
300
300 def find_file(obj):
301 def find_file(obj):
301 """Find the absolute path to the file where an object was defined.
302 """Find the absolute path to the file where an object was defined.
302
303
303 This is essentially a robust wrapper around `inspect.getabsfile`.
304 This is essentially a robust wrapper around `inspect.getabsfile`.
304
305
305 Returns None if no file can be found.
306 Returns None if no file can be found.
306
307
307 Parameters
308 Parameters
308 ----------
309 ----------
309 obj : any Python object
310 obj : any Python object
310
311
311 Returns
312 Returns
312 -------
313 -------
313 fname : str
314 fname : str
314 The absolute path to the file where the object was defined.
315 The absolute path to the file where the object was defined.
315 """
316 """
316 obj = _get_wrapped(obj)
317 obj = _get_wrapped(obj)
317
318
318 fname = None
319 fname = None
319 try:
320 try:
320 fname = inspect.getabsfile(obj)
321 fname = inspect.getabsfile(obj)
321 except TypeError:
322 except TypeError:
322 # For an instance, the file that matters is where its class was
323 # For an instance, the file that matters is where its class was
323 # declared.
324 # declared.
324 if hasattr(obj, '__class__'):
325 if hasattr(obj, '__class__'):
325 try:
326 try:
326 fname = inspect.getabsfile(obj.__class__)
327 fname = inspect.getabsfile(obj.__class__)
327 except TypeError:
328 except TypeError:
328 # Can happen for builtins
329 # Can happen for builtins
329 pass
330 pass
330 except:
331 except:
331 pass
332 pass
332 return cast_unicode(fname)
333 return cast_unicode(fname)
333
334
334
335
335 def find_source_lines(obj):
336 def find_source_lines(obj):
336 """Find the line number in a file where an object was defined.
337 """Find the line number in a file where an object was defined.
337
338
338 This is essentially a robust wrapper around `inspect.getsourcelines`.
339 This is essentially a robust wrapper around `inspect.getsourcelines`.
339
340
340 Returns None if no file can be found.
341 Returns None if no file can be found.
341
342
342 Parameters
343 Parameters
343 ----------
344 ----------
344 obj : any Python object
345 obj : any Python object
345
346
346 Returns
347 Returns
347 -------
348 -------
348 lineno : int
349 lineno : int
349 The line number where the object definition starts.
350 The line number where the object definition starts.
350 """
351 """
351 obj = _get_wrapped(obj)
352 obj = _get_wrapped(obj)
352
353
353 try:
354 try:
354 try:
355 try:
355 lineno = inspect.getsourcelines(obj)[1]
356 lineno = inspect.getsourcelines(obj)[1]
356 except TypeError:
357 except TypeError:
357 # For instances, try the class object like getsource() does
358 # For instances, try the class object like getsource() does
358 if hasattr(obj, '__class__'):
359 if hasattr(obj, '__class__'):
359 lineno = inspect.getsourcelines(obj.__class__)[1]
360 lineno = inspect.getsourcelines(obj.__class__)[1]
360 else:
361 else:
361 lineno = None
362 lineno = None
362 except:
363 except:
363 return None
364 return None
364
365
365 return lineno
366 return lineno
366
367
367
368
368 class Inspector:
369 class Inspector(Colorable):
369 def __init__(self, color_table=InspectColors,
370 def __init__(self, color_table=InspectColors,
370 code_color_table=PyColorize.ANSICodeColors,
371 code_color_table=PyColorize.ANSICodeColors,
371 scheme='NoColor',
372 scheme='NoColor',
372 str_detail_level=0):
373 str_detail_level=0,
374 parent=None, config=None):
375 super(Inspector, self).__init__(parent=parent, config=config)
373 self.color_table = color_table
376 self.color_table = color_table
374 self.parser = PyColorize.Parser(code_color_table,out='str')
377 self.parser = PyColorize.Parser(out='str', parent=self, style=scheme)
375 self.format = self.parser.format
378 self.format = self.parser.format
376 self.str_detail_level = str_detail_level
379 self.str_detail_level = str_detail_level
377 self.set_active_scheme(scheme)
380 self.set_active_scheme(scheme)
378
381
379 def _getdef(self,obj,oname=''):
382 def _getdef(self,obj,oname=''):
380 """Return the call signature for any callable object.
383 """Return the call signature for any callable object.
381
384
382 If any exception is generated, None is returned instead and the
385 If any exception is generated, None is returned instead and the
383 exception is suppressed."""
386 exception is suppressed."""
384 try:
387 try:
385 hdef = oname + str(signature(obj))
388 hdef = oname + str(signature(obj))
386 return cast_unicode(hdef)
389 return cast_unicode(hdef)
387 except:
390 except:
388 return None
391 return None
389
392
390 def __head(self,h):
393 def __head(self,h):
391 """Return a header string with proper colors."""
394 """Return a header string with proper colors."""
392 return '%s%s%s' % (self.color_table.active_colors.header,h,
395 return '%s%s%s' % (self.color_table.active_colors.header,h,
393 self.color_table.active_colors.normal)
396 self.color_table.active_colors.normal)
394
397
395 def set_active_scheme(self, scheme):
398 def set_active_scheme(self, scheme):
396 self.color_table.set_active_scheme(scheme)
399 self.color_table.set_active_scheme(scheme)
397 self.parser.color_table.set_active_scheme(scheme)
400 self.parser.color_table.set_active_scheme(scheme)
398
401
399 def noinfo(self, msg, oname):
402 def noinfo(self, msg, oname):
400 """Generic message when no information is found."""
403 """Generic message when no information is found."""
401 print('No %s found' % msg, end=' ')
404 print('No %s found' % msg, end=' ')
402 if oname:
405 if oname:
403 print('for %s' % oname)
406 print('for %s' % oname)
404 else:
407 else:
405 print()
408 print()
406
409
407 def pdef(self, obj, oname=''):
410 def pdef(self, obj, oname=''):
408 """Print the call signature for any callable object.
411 """Print the call signature for any callable object.
409
412
410 If the object is a class, print the constructor information."""
413 If the object is a class, print the constructor information."""
411
414
412 if not callable(obj):
415 if not callable(obj):
413 print('Object is not callable.')
416 print('Object is not callable.')
414 return
417 return
415
418
416 header = ''
419 header = ''
417
420
418 if inspect.isclass(obj):
421 if inspect.isclass(obj):
419 header = self.__head('Class constructor information:\n')
422 header = self.__head('Class constructor information:\n')
420 obj = obj.__init__
423 obj = obj.__init__
421 elif (not py3compat.PY3) and type(obj) is types.InstanceType:
424 elif (not py3compat.PY3) and type(obj) is types.InstanceType:
422 obj = obj.__call__
425 obj = obj.__call__
423
426
424 output = self._getdef(obj,oname)
427 output = self._getdef(obj,oname)
425 if output is None:
428 if output is None:
426 self.noinfo('definition header',oname)
429 self.noinfo('definition header',oname)
427 else:
430 else:
428 print(header,self.format(output), end=' ', file=io.stdout)
431 print(header,self.format(output), end=' ', file=io.stdout)
429
432
430 # In Python 3, all classes are new-style, so they all have __init__.
433 # In Python 3, all classes are new-style, so they all have __init__.
431 @skip_doctest_py3
434 @skip_doctest_py3
432 def pdoc(self,obj,oname='',formatter = None):
435 def pdoc(self,obj,oname='',formatter = None):
433 """Print the docstring for any object.
436 """Print the docstring for any object.
434
437
435 Optional:
438 Optional:
436 -formatter: a function to run the docstring through for specially
439 -formatter: a function to run the docstring through for specially
437 formatted docstrings.
440 formatted docstrings.
438
441
439 Examples
442 Examples
440 --------
443 --------
441
444
442 In [1]: class NoInit:
445 In [1]: class NoInit:
443 ...: pass
446 ...: pass
444
447
445 In [2]: class NoDoc:
448 In [2]: class NoDoc:
446 ...: def __init__(self):
449 ...: def __init__(self):
447 ...: pass
450 ...: pass
448
451
449 In [3]: %pdoc NoDoc
452 In [3]: %pdoc NoDoc
450 No documentation found for NoDoc
453 No documentation found for NoDoc
451
454
452 In [4]: %pdoc NoInit
455 In [4]: %pdoc NoInit
453 No documentation found for NoInit
456 No documentation found for NoInit
454
457
455 In [5]: obj = NoInit()
458 In [5]: obj = NoInit()
456
459
457 In [6]: %pdoc obj
460 In [6]: %pdoc obj
458 No documentation found for obj
461 No documentation found for obj
459
462
460 In [5]: obj2 = NoDoc()
463 In [5]: obj2 = NoDoc()
461
464
462 In [6]: %pdoc obj2
465 In [6]: %pdoc obj2
463 No documentation found for obj2
466 No documentation found for obj2
464 """
467 """
465
468
466 head = self.__head # For convenience
469 head = self.__head # For convenience
467 lines = []
470 lines = []
468 ds = getdoc(obj)
471 ds = getdoc(obj)
469 if formatter:
472 if formatter:
470 ds = formatter(ds)
473 ds = formatter(ds)
471 if ds:
474 if ds:
472 lines.append(head("Class docstring:"))
475 lines.append(head("Class docstring:"))
473 lines.append(indent(ds))
476 lines.append(indent(ds))
474 if inspect.isclass(obj) and hasattr(obj, '__init__'):
477 if inspect.isclass(obj) and hasattr(obj, '__init__'):
475 init_ds = getdoc(obj.__init__)
478 init_ds = getdoc(obj.__init__)
476 if init_ds is not None:
479 if init_ds is not None:
477 lines.append(head("Init docstring:"))
480 lines.append(head("Init docstring:"))
478 lines.append(indent(init_ds))
481 lines.append(indent(init_ds))
479 elif hasattr(obj,'__call__'):
482 elif hasattr(obj,'__call__'):
480 call_ds = getdoc(obj.__call__)
483 call_ds = getdoc(obj.__call__)
481 if call_ds:
484 if call_ds:
482 lines.append(head("Call docstring:"))
485 lines.append(head("Call docstring:"))
483 lines.append(indent(call_ds))
486 lines.append(indent(call_ds))
484
487
485 if not lines:
488 if not lines:
486 self.noinfo('documentation',oname)
489 self.noinfo('documentation',oname)
487 else:
490 else:
488 page.page('\n'.join(lines))
491 page.page('\n'.join(lines))
489
492
490 def psource(self, obj, oname=''):
493 def psource(self, obj, oname=''):
491 """Print the source code for an object."""
494 """Print the source code for an object."""
492
495
493 # Flush the source cache because inspect can return out-of-date source
496 # Flush the source cache because inspect can return out-of-date source
494 linecache.checkcache()
497 linecache.checkcache()
495 try:
498 try:
496 src = getsource(obj, oname=oname)
499 src = getsource(obj, oname=oname)
497 except Exception:
500 except Exception:
498 src = None
501 src = None
499
502
500 if src is None:
503 if src is None:
501 self.noinfo('source', oname)
504 self.noinfo('source', oname)
502 else:
505 else:
503 page.page(self.format(src))
506 page.page(self.format(src))
504
507
505 def pfile(self, obj, oname=''):
508 def pfile(self, obj, oname=''):
506 """Show the whole file where an object was defined."""
509 """Show the whole file where an object was defined."""
507
510
508 lineno = find_source_lines(obj)
511 lineno = find_source_lines(obj)
509 if lineno is None:
512 if lineno is None:
510 self.noinfo('file', oname)
513 self.noinfo('file', oname)
511 return
514 return
512
515
513 ofile = find_file(obj)
516 ofile = find_file(obj)
514 # run contents of file through pager starting at line where the object
517 # run contents of file through pager starting at line where the object
515 # is defined, as long as the file isn't binary and is actually on the
518 # is defined, as long as the file isn't binary and is actually on the
516 # filesystem.
519 # filesystem.
517 if ofile.endswith(('.so', '.dll', '.pyd')):
520 if ofile.endswith(('.so', '.dll', '.pyd')):
518 print('File %r is binary, not printing.' % ofile)
521 print('File %r is binary, not printing.' % ofile)
519 elif not os.path.isfile(ofile):
522 elif not os.path.isfile(ofile):
520 print('File %r does not exist, not printing.' % ofile)
523 print('File %r does not exist, not printing.' % ofile)
521 else:
524 else:
522 # Print only text files, not extension binaries. Note that
525 # Print only text files, not extension binaries. Note that
523 # getsourcelines returns lineno with 1-offset and page() uses
526 # getsourcelines returns lineno with 1-offset and page() uses
524 # 0-offset, so we must adjust.
527 # 0-offset, so we must adjust.
525 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1)
528 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1)
526
529
527 def _format_fields(self, fields, title_width=0):
530 def _format_fields(self, fields, title_width=0):
528 """Formats a list of fields for display.
531 """Formats a list of fields for display.
529
532
530 Parameters
533 Parameters
531 ----------
534 ----------
532 fields : list
535 fields : list
533 A list of 2-tuples: (field_title, field_content)
536 A list of 2-tuples: (field_title, field_content)
534 title_width : int
537 title_width : int
535 How many characters to pad titles to. Default to longest title.
538 How many characters to pad titles to. Default to longest title.
536 """
539 """
537 out = []
540 out = []
538 header = self.__head
541 header = self.__head
539 if title_width == 0:
542 if title_width == 0:
540 title_width = max(len(title) + 2 for title, _ in fields)
543 title_width = max(len(title) + 2 for title, _ in fields)
541 for title, content in fields:
544 for title, content in fields:
542 if len(content.splitlines()) > 1:
545 if len(content.splitlines()) > 1:
543 title = header(title + ":") + "\n"
546 title = header(title + ":") + "\n"
544 else:
547 else:
545 title = header((title+":").ljust(title_width))
548 title = header((title+":").ljust(title_width))
546 out.append(cast_unicode(title) + cast_unicode(content))
549 out.append(cast_unicode(title) + cast_unicode(content))
547 return "\n".join(out)
550 return "\n".join(out)
548
551
549 def _format_info(self, obj, oname='', formatter=None, info=None, detail_level=0):
552 def _format_info(self, obj, oname='', formatter=None, info=None, detail_level=0):
550 """Format an info dict as text"""
553 """Format an info dict as text"""
551 info = self.info(obj, oname=oname, formatter=formatter,
554 info = self.info(obj, oname=oname, formatter=formatter,
552 info=info, detail_level=detail_level)
555 info=info, detail_level=detail_level)
553 displayfields = []
556 displayfields = []
554 def add_fields(fields):
557 def add_fields(fields):
555 for title, key in fields:
558 for title, key in fields:
556 field = info[key]
559 field = info[key]
557 if field is not None:
560 if field is not None:
558 if key == "source":
561 if key == "source":
559 displayfields.append((title, self.format(cast_unicode(field.rstrip()))))
562 displayfields.append((title, self.format(cast_unicode(field.rstrip()))))
560 else:
563 else:
561 displayfields.append((title, field.rstrip()))
564 displayfields.append((title, field.rstrip()))
562
565
563 if info['isalias']:
566 if info['isalias']:
564 add_fields([('Repr', "string_form")])
567 add_fields([('Repr', "string_form")])
565
568
566 elif info['ismagic']:
569 elif info['ismagic']:
567 if detail_level > 0 and info['source'] is not None:
570 if detail_level > 0 and info['source'] is not None:
568 add_fields([("Source", "source")])
571 add_fields([("Source", "source")])
569 else:
572 else:
570 add_fields([("Docstring", "docstring")])
573 add_fields([("Docstring", "docstring")])
571
574
572 add_fields([("File", "file"),
575 add_fields([("File", "file"),
573 ])
576 ])
574
577
575 elif info['isclass'] or is_simple_callable(obj):
578 elif info['isclass'] or is_simple_callable(obj):
576 # Functions, methods, classes
579 # Functions, methods, classes
577 add_fields([("Signature", "definition"),
580 add_fields([("Signature", "definition"),
578 ("Init signature", "init_definition"),
581 ("Init signature", "init_definition"),
579 ])
582 ])
580 if detail_level > 0 and info['source'] is not None:
583 if detail_level > 0 and info['source'] is not None:
581 add_fields([("Source", "source")])
584 add_fields([("Source", "source")])
582 else:
585 else:
583 add_fields([("Docstring", "docstring"),
586 add_fields([("Docstring", "docstring"),
584 ("Init docstring", "init_docstring"),
587 ("Init docstring", "init_docstring"),
585 ])
588 ])
586
589
587 add_fields([('File', 'file'),
590 add_fields([('File', 'file'),
588 ('Type', 'type_name'),
591 ('Type', 'type_name'),
589 ])
592 ])
590
593
591 else:
594 else:
592 # General Python objects
595 # General Python objects
593 add_fields([("Type", "type_name")])
596 add_fields([("Type", "type_name")])
594
597
595 # Base class for old-style instances
598 # Base class for old-style instances
596 if (not py3compat.PY3) and isinstance(obj, types.InstanceType) and info['base_class']:
599 if (not py3compat.PY3) and isinstance(obj, types.InstanceType) and info['base_class']:
597 displayfields.append(("Base Class", info['base_class'].rstrip()))
600 displayfields.append(("Base Class", info['base_class'].rstrip()))
598
601
599 add_fields([("String form", "string_form")])
602 add_fields([("String form", "string_form")])
600
603
601 # Namespace
604 # Namespace
602 if info['namespace'] != 'Interactive':
605 if info['namespace'] != 'Interactive':
603 displayfields.append(("Namespace", info['namespace'].rstrip()))
606 displayfields.append(("Namespace", info['namespace'].rstrip()))
604
607
605 add_fields([("Length", "length"),
608 add_fields([("Length", "length"),
606 ("File", "file"),
609 ("File", "file"),
607 ("Signature", "definition"),
610 ("Signature", "definition"),
608 ])
611 ])
609
612
610 # Source or docstring, depending on detail level and whether
613 # Source or docstring, depending on detail level and whether
611 # source found.
614 # source found.
612 if detail_level > 0 and info['source'] is not None:
615 if detail_level > 0 and info['source'] is not None:
613 displayfields.append(("Source",
616 displayfields.append(("Source",
614 self.format(cast_unicode(info['source']))))
617 self.format(cast_unicode(info['source']))))
615 elif info['docstring'] is not None:
618 elif info['docstring'] is not None:
616 displayfields.append(("Docstring", info["docstring"]))
619 displayfields.append(("Docstring", info["docstring"]))
617
620
618 add_fields([("Class docstring", "class_docstring"),
621 add_fields([("Class docstring", "class_docstring"),
619 ("Init docstring", "init_docstring"),
622 ("Init docstring", "init_docstring"),
620 ("Call signature", "call_def"),
623 ("Call signature", "call_def"),
621 ("Call docstring", "call_docstring")])
624 ("Call docstring", "call_docstring")])
622
625
623 if displayfields:
626 if displayfields:
624 return self._format_fields(displayfields)
627 return self._format_fields(displayfields)
625 else:
628 else:
626 return u''
629 return u''
627
630
628 def pinfo(self, obj, oname='', formatter=None, info=None, detail_level=0):
631 def pinfo(self, obj, oname='', formatter=None, info=None, detail_level=0):
629 """Show detailed information about an object.
632 """Show detailed information about an object.
630
633
631 Optional arguments:
634 Optional arguments:
632
635
633 - oname: name of the variable pointing to the object.
636 - oname: name of the variable pointing to the object.
634
637
635 - formatter: special formatter for docstrings (see pdoc)
638 - formatter: special formatter for docstrings (see pdoc)
636
639
637 - info: a structure with some information fields which may have been
640 - info: a structure with some information fields which may have been
638 precomputed already.
641 precomputed already.
639
642
640 - detail_level: if set to 1, more information is given.
643 - detail_level: if set to 1, more information is given.
641 """
644 """
642 text = self._format_info(obj, oname, formatter, info, detail_level)
645 text = self._format_info(obj, oname, formatter, info, detail_level)
643 if text:
646 if text:
644 page.page(text)
647 page.page(text)
645
648
646 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
649 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
647 """Compute a dict with detailed information about an object.
650 """Compute a dict with detailed information about an object.
648
651
649 Optional arguments:
652 Optional arguments:
650
653
651 - oname: name of the variable pointing to the object.
654 - oname: name of the variable pointing to the object.
652
655
653 - formatter: special formatter for docstrings (see pdoc)
656 - formatter: special formatter for docstrings (see pdoc)
654
657
655 - info: a structure with some information fields which may have been
658 - info: a structure with some information fields which may have been
656 precomputed already.
659 precomputed already.
657
660
658 - detail_level: if set to 1, more information is given.
661 - detail_level: if set to 1, more information is given.
659 """
662 """
660
663
661 obj_type = type(obj)
664 obj_type = type(obj)
662
665
663 if info is None:
666 if info is None:
664 ismagic = 0
667 ismagic = 0
665 isalias = 0
668 isalias = 0
666 ospace = ''
669 ospace = ''
667 else:
670 else:
668 ismagic = info.ismagic
671 ismagic = info.ismagic
669 isalias = info.isalias
672 isalias = info.isalias
670 ospace = info.namespace
673 ospace = info.namespace
671
674
672 # Get docstring, special-casing aliases:
675 # Get docstring, special-casing aliases:
673 if isalias:
676 if isalias:
674 if not callable(obj):
677 if not callable(obj):
675 try:
678 try:
676 ds = "Alias to the system command:\n %s" % obj[1]
679 ds = "Alias to the system command:\n %s" % obj[1]
677 except:
680 except:
678 ds = "Alias: " + str(obj)
681 ds = "Alias: " + str(obj)
679 else:
682 else:
680 ds = "Alias to " + str(obj)
683 ds = "Alias to " + str(obj)
681 if obj.__doc__:
684 if obj.__doc__:
682 ds += "\nDocstring:\n" + obj.__doc__
685 ds += "\nDocstring:\n" + obj.__doc__
683 else:
686 else:
684 ds = getdoc(obj)
687 ds = getdoc(obj)
685 if ds is None:
688 if ds is None:
686 ds = '<no docstring>'
689 ds = '<no docstring>'
687 if formatter is not None:
690 if formatter is not None:
688 ds = formatter(ds)
691 ds = formatter(ds)
689
692
690 # store output in a dict, we initialize it here and fill it as we go
693 # store output in a dict, we initialize it here and fill it as we go
691 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic)
694 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic)
692
695
693 string_max = 200 # max size of strings to show (snipped if longer)
696 string_max = 200 # max size of strings to show (snipped if longer)
694 shalf = int((string_max -5)/2)
697 shalf = int((string_max -5)/2)
695
698
696 if ismagic:
699 if ismagic:
697 obj_type_name = 'Magic function'
700 obj_type_name = 'Magic function'
698 elif isalias:
701 elif isalias:
699 obj_type_name = 'System alias'
702 obj_type_name = 'System alias'
700 else:
703 else:
701 obj_type_name = obj_type.__name__
704 obj_type_name = obj_type.__name__
702 out['type_name'] = obj_type_name
705 out['type_name'] = obj_type_name
703
706
704 try:
707 try:
705 bclass = obj.__class__
708 bclass = obj.__class__
706 out['base_class'] = str(bclass)
709 out['base_class'] = str(bclass)
707 except: pass
710 except: pass
708
711
709 # String form, but snip if too long in ? form (full in ??)
712 # String form, but snip if too long in ? form (full in ??)
710 if detail_level >= self.str_detail_level:
713 if detail_level >= self.str_detail_level:
711 try:
714 try:
712 ostr = str(obj)
715 ostr = str(obj)
713 str_head = 'string_form'
716 str_head = 'string_form'
714 if not detail_level and len(ostr)>string_max:
717 if not detail_level and len(ostr)>string_max:
715 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
718 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
716 ostr = ("\n" + " " * len(str_head.expandtabs())).\
719 ostr = ("\n" + " " * len(str_head.expandtabs())).\
717 join(q.strip() for q in ostr.split("\n"))
720 join(q.strip() for q in ostr.split("\n"))
718 out[str_head] = ostr
721 out[str_head] = ostr
719 except:
722 except:
720 pass
723 pass
721
724
722 if ospace:
725 if ospace:
723 out['namespace'] = ospace
726 out['namespace'] = ospace
724
727
725 # Length (for strings and lists)
728 # Length (for strings and lists)
726 try:
729 try:
727 out['length'] = str(len(obj))
730 out['length'] = str(len(obj))
728 except: pass
731 except: pass
729
732
730 # Filename where object was defined
733 # Filename where object was defined
731 binary_file = False
734 binary_file = False
732 fname = find_file(obj)
735 fname = find_file(obj)
733 if fname is None:
736 if fname is None:
734 # if anything goes wrong, we don't want to show source, so it's as
737 # if anything goes wrong, we don't want to show source, so it's as
735 # if the file was binary
738 # if the file was binary
736 binary_file = True
739 binary_file = True
737 else:
740 else:
738 if fname.endswith(('.so', '.dll', '.pyd')):
741 if fname.endswith(('.so', '.dll', '.pyd')):
739 binary_file = True
742 binary_file = True
740 elif fname.endswith('<string>'):
743 elif fname.endswith('<string>'):
741 fname = 'Dynamically generated function. No source code available.'
744 fname = 'Dynamically generated function. No source code available.'
742 out['file'] = compress_user(fname)
745 out['file'] = compress_user(fname)
743
746
744 # Original source code for a callable, class or property.
747 # Original source code for a callable, class or property.
745 if detail_level:
748 if detail_level:
746 # Flush the source cache because inspect can return out-of-date
749 # Flush the source cache because inspect can return out-of-date
747 # source
750 # source
748 linecache.checkcache()
751 linecache.checkcache()
749 try:
752 try:
750 if isinstance(obj, property) or not binary_file:
753 if isinstance(obj, property) or not binary_file:
751 src = getsource(obj, oname)
754 src = getsource(obj, oname)
752 if src is not None:
755 if src is not None:
753 src = src.rstrip()
756 src = src.rstrip()
754 out['source'] = src
757 out['source'] = src
755
758
756 except Exception:
759 except Exception:
757 pass
760 pass
758
761
759 # Add docstring only if no source is to be shown (avoid repetitions).
762 # Add docstring only if no source is to be shown (avoid repetitions).
760 if ds and out.get('source', None) is None:
763 if ds and out.get('source', None) is None:
761 out['docstring'] = ds
764 out['docstring'] = ds
762
765
763 # Constructor docstring for classes
766 # Constructor docstring for classes
764 if inspect.isclass(obj):
767 if inspect.isclass(obj):
765 out['isclass'] = True
768 out['isclass'] = True
766 # reconstruct the function definition and print it:
769 # reconstruct the function definition and print it:
767 try:
770 try:
768 obj_init = obj.__init__
771 obj_init = obj.__init__
769 except AttributeError:
772 except AttributeError:
770 init_def = init_ds = None
773 init_def = init_ds = None
771 else:
774 else:
772 init_def = self._getdef(obj_init,oname)
775 init_def = self._getdef(obj_init,oname)
773 init_ds = getdoc(obj_init)
776 init_ds = getdoc(obj_init)
774 # Skip Python's auto-generated docstrings
777 # Skip Python's auto-generated docstrings
775 if init_ds == _object_init_docstring:
778 if init_ds == _object_init_docstring:
776 init_ds = None
779 init_ds = None
777
780
778 if init_def or init_ds:
781 if init_def or init_ds:
779 if init_def:
782 if init_def:
780 out['init_definition'] = self.format(init_def)
783 out['init_definition'] = self.format(init_def)
781 if init_ds:
784 if init_ds:
782 out['init_docstring'] = init_ds
785 out['init_docstring'] = init_ds
783
786
784 # and class docstring for instances:
787 # and class docstring for instances:
785 else:
788 else:
786 # reconstruct the function definition and print it:
789 # reconstruct the function definition and print it:
787 defln = self._getdef(obj, oname)
790 defln = self._getdef(obj, oname)
788 if defln:
791 if defln:
789 out['definition'] = self.format(defln)
792 out['definition'] = self.format(defln)
790
793
791 # First, check whether the instance docstring is identical to the
794 # First, check whether the instance docstring is identical to the
792 # class one, and print it separately if they don't coincide. In
795 # class one, and print it separately if they don't coincide. In
793 # most cases they will, but it's nice to print all the info for
796 # most cases they will, but it's nice to print all the info for
794 # objects which use instance-customized docstrings.
797 # objects which use instance-customized docstrings.
795 if ds:
798 if ds:
796 try:
799 try:
797 cls = getattr(obj,'__class__')
800 cls = getattr(obj,'__class__')
798 except:
801 except:
799 class_ds = None
802 class_ds = None
800 else:
803 else:
801 class_ds = getdoc(cls)
804 class_ds = getdoc(cls)
802 # Skip Python's auto-generated docstrings
805 # Skip Python's auto-generated docstrings
803 if class_ds in _builtin_type_docstrings:
806 if class_ds in _builtin_type_docstrings:
804 class_ds = None
807 class_ds = None
805 if class_ds and ds != class_ds:
808 if class_ds and ds != class_ds:
806 out['class_docstring'] = class_ds
809 out['class_docstring'] = class_ds
807
810
808 # Next, try to show constructor docstrings
811 # Next, try to show constructor docstrings
809 try:
812 try:
810 init_ds = getdoc(obj.__init__)
813 init_ds = getdoc(obj.__init__)
811 # Skip Python's auto-generated docstrings
814 # Skip Python's auto-generated docstrings
812 if init_ds == _object_init_docstring:
815 if init_ds == _object_init_docstring:
813 init_ds = None
816 init_ds = None
814 except AttributeError:
817 except AttributeError:
815 init_ds = None
818 init_ds = None
816 if init_ds:
819 if init_ds:
817 out['init_docstring'] = init_ds
820 out['init_docstring'] = init_ds
818
821
819 # Call form docstring for callable instances
822 # Call form docstring for callable instances
820 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
823 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
821 call_def = self._getdef(obj.__call__, oname)
824 call_def = self._getdef(obj.__call__, oname)
822 if call_def:
825 if call_def:
823 call_def = self.format(call_def)
826 call_def = self.format(call_def)
824 # it may never be the case that call def and definition differ,
827 # it may never be the case that call def and definition differ,
825 # but don't include the same signature twice
828 # but don't include the same signature twice
826 if call_def != out.get('definition'):
829 if call_def != out.get('definition'):
827 out['call_def'] = call_def
830 out['call_def'] = call_def
828 call_ds = getdoc(obj.__call__)
831 call_ds = getdoc(obj.__call__)
829 # Skip Python's auto-generated docstrings
832 # Skip Python's auto-generated docstrings
830 if call_ds == _func_call_docstring:
833 if call_ds == _func_call_docstring:
831 call_ds = None
834 call_ds = None
832 if call_ds:
835 if call_ds:
833 out['call_docstring'] = call_ds
836 out['call_docstring'] = call_ds
834
837
835 # Compute the object's argspec as a callable. The key is to decide
838 # Compute the object's argspec as a callable. The key is to decide
836 # whether to pull it from the object itself, from its __init__ or
839 # whether to pull it from the object itself, from its __init__ or
837 # from its __call__ method.
840 # from its __call__ method.
838
841
839 if inspect.isclass(obj):
842 if inspect.isclass(obj):
840 # Old-style classes need not have an __init__
843 # Old-style classes need not have an __init__
841 callable_obj = getattr(obj, "__init__", None)
844 callable_obj = getattr(obj, "__init__", None)
842 elif callable(obj):
845 elif callable(obj):
843 callable_obj = obj
846 callable_obj = obj
844 else:
847 else:
845 callable_obj = None
848 callable_obj = None
846
849
847 if callable_obj is not None:
850 if callable_obj is not None:
848 try:
851 try:
849 argspec = getargspec(callable_obj)
852 argspec = getargspec(callable_obj)
850 except (TypeError, AttributeError):
853 except (TypeError, AttributeError):
851 # For extensions/builtins we can't retrieve the argspec
854 # For extensions/builtins we can't retrieve the argspec
852 pass
855 pass
853 else:
856 else:
854 # named tuples' _asdict() method returns an OrderedDict, but we
857 # named tuples' _asdict() method returns an OrderedDict, but we
855 # we want a normal
858 # we want a normal
856 out['argspec'] = argspec_dict = dict(argspec._asdict())
859 out['argspec'] = argspec_dict = dict(argspec._asdict())
857 # We called this varkw before argspec became a named tuple.
860 # We called this varkw before argspec became a named tuple.
858 # With getfullargspec it's also called varkw.
861 # With getfullargspec it's also called varkw.
859 if 'varkw' not in argspec_dict:
862 if 'varkw' not in argspec_dict:
860 argspec_dict['varkw'] = argspec_dict.pop('keywords')
863 argspec_dict['varkw'] = argspec_dict.pop('keywords')
861
864
862 return object_info(**out)
865 return object_info(**out)
863
866
864 def psearch(self,pattern,ns_table,ns_search=[],
867 def psearch(self,pattern,ns_table,ns_search=[],
865 ignore_case=False,show_all=False):
868 ignore_case=False,show_all=False):
866 """Search namespaces with wildcards for objects.
869 """Search namespaces with wildcards for objects.
867
870
868 Arguments:
871 Arguments:
869
872
870 - pattern: string containing shell-like wildcards to use in namespace
873 - pattern: string containing shell-like wildcards to use in namespace
871 searches and optionally a type specification to narrow the search to
874 searches and optionally a type specification to narrow the search to
872 objects of that type.
875 objects of that type.
873
876
874 - ns_table: dict of name->namespaces for search.
877 - ns_table: dict of name->namespaces for search.
875
878
876 Optional arguments:
879 Optional arguments:
877
880
878 - ns_search: list of namespace names to include in search.
881 - ns_search: list of namespace names to include in search.
879
882
880 - ignore_case(False): make the search case-insensitive.
883 - ignore_case(False): make the search case-insensitive.
881
884
882 - show_all(False): show all names, including those starting with
885 - show_all(False): show all names, including those starting with
883 underscores.
886 underscores.
884 """
887 """
885 #print 'ps pattern:<%r>' % pattern # dbg
888 #print 'ps pattern:<%r>' % pattern # dbg
886
889
887 # defaults
890 # defaults
888 type_pattern = 'all'
891 type_pattern = 'all'
889 filter = ''
892 filter = ''
890
893
891 cmds = pattern.split()
894 cmds = pattern.split()
892 len_cmds = len(cmds)
895 len_cmds = len(cmds)
893 if len_cmds == 1:
896 if len_cmds == 1:
894 # Only filter pattern given
897 # Only filter pattern given
895 filter = cmds[0]
898 filter = cmds[0]
896 elif len_cmds == 2:
899 elif len_cmds == 2:
897 # Both filter and type specified
900 # Both filter and type specified
898 filter,type_pattern = cmds
901 filter,type_pattern = cmds
899 else:
902 else:
900 raise ValueError('invalid argument string for psearch: <%s>' %
903 raise ValueError('invalid argument string for psearch: <%s>' %
901 pattern)
904 pattern)
902
905
903 # filter search namespaces
906 # filter search namespaces
904 for name in ns_search:
907 for name in ns_search:
905 if name not in ns_table:
908 if name not in ns_table:
906 raise ValueError('invalid namespace <%s>. Valid names: %s' %
909 raise ValueError('invalid namespace <%s>. Valid names: %s' %
907 (name,ns_table.keys()))
910 (name,ns_table.keys()))
908
911
909 #print 'type_pattern:',type_pattern # dbg
912 #print 'type_pattern:',type_pattern # dbg
910 search_result, namespaces_seen = set(), set()
913 search_result, namespaces_seen = set(), set()
911 for ns_name in ns_search:
914 for ns_name in ns_search:
912 ns = ns_table[ns_name]
915 ns = ns_table[ns_name]
913 # Normally, locals and globals are the same, so we just check one.
916 # Normally, locals and globals are the same, so we just check one.
914 if id(ns) in namespaces_seen:
917 if id(ns) in namespaces_seen:
915 continue
918 continue
916 namespaces_seen.add(id(ns))
919 namespaces_seen.add(id(ns))
917 tmp_res = list_namespace(ns, type_pattern, filter,
920 tmp_res = list_namespace(ns, type_pattern, filter,
918 ignore_case=ignore_case, show_all=show_all)
921 ignore_case=ignore_case, show_all=show_all)
919 search_result.update(tmp_res)
922 search_result.update(tmp_res)
920
923
921 page.page('\n'.join(sorted(search_result)))
924 page.page('\n'.join(sorted(search_result)))
@@ -1,1479 +1,1483 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Verbose and colourful traceback formatting.
3 Verbose and colourful traceback formatting.
4
4
5 **ColorTB**
5 **ColorTB**
6
6
7 I've always found it a bit hard to visually parse tracebacks in Python. The
7 I've always found it a bit hard to visually parse tracebacks in Python. The
8 ColorTB class is a solution to that problem. It colors the different parts of a
8 ColorTB class is a solution to that problem. It colors the different parts of a
9 traceback in a manner similar to what you would expect from a syntax-highlighting
9 traceback in a manner similar to what you would expect from a syntax-highlighting
10 text editor.
10 text editor.
11
11
12 Installation instructions for ColorTB::
12 Installation instructions for ColorTB::
13
13
14 import sys,ultratb
14 import sys,ultratb
15 sys.excepthook = ultratb.ColorTB()
15 sys.excepthook = ultratb.ColorTB()
16
16
17 **VerboseTB**
17 **VerboseTB**
18
18
19 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
19 I've also included a port of Ka-Ping Yee's "cgitb.py" that produces all kinds
20 of useful info when a traceback occurs. Ping originally had it spit out HTML
20 of useful info when a traceback occurs. Ping originally had it spit out HTML
21 and intended it for CGI programmers, but why should they have all the fun? I
21 and intended it for CGI programmers, but why should they have all the fun? I
22 altered it to spit out colored text to the terminal. It's a bit overwhelming,
22 altered it to spit out colored text to the terminal. It's a bit overwhelming,
23 but kind of neat, and maybe useful for long-running programs that you believe
23 but kind of neat, and maybe useful for long-running programs that you believe
24 are bug-free. If a crash *does* occur in that type of program you want details.
24 are bug-free. If a crash *does* occur in that type of program you want details.
25 Give it a shot--you'll love it or you'll hate it.
25 Give it a shot--you'll love it or you'll hate it.
26
26
27 .. note::
27 .. note::
28
28
29 The Verbose mode prints the variables currently visible where the exception
29 The Verbose mode prints the variables currently visible where the exception
30 happened (shortening their strings if too long). This can potentially be
30 happened (shortening their strings if too long). This can potentially be
31 very slow, if you happen to have a huge data structure whose string
31 very slow, if you happen to have a huge data structure whose string
32 representation is complex to compute. Your computer may appear to freeze for
32 representation is complex to compute. Your computer may appear to freeze for
33 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
33 a while with cpu usage at 100%. If this occurs, you can cancel the traceback
34 with Ctrl-C (maybe hitting it more than once).
34 with Ctrl-C (maybe hitting it more than once).
35
35
36 If you encounter this kind of situation often, you may want to use the
36 If you encounter this kind of situation often, you may want to use the
37 Verbose_novars mode instead of the regular Verbose, which avoids formatting
37 Verbose_novars mode instead of the regular Verbose, which avoids formatting
38 variables (but otherwise includes the information and context given by
38 variables (but otherwise includes the information and context given by
39 Verbose).
39 Verbose).
40
40
41 .. note::
41 .. note::
42
42
43 The verbose mode print all variables in the stack, which means it can
43 The verbose mode print all variables in the stack, which means it can
44 potentially leak sensitive information like access keys, or unencryted
44 potentially leak sensitive information like access keys, or unencryted
45 password.
45 password.
46
46
47 Installation instructions for VerboseTB::
47 Installation instructions for VerboseTB::
48
48
49 import sys,ultratb
49 import sys,ultratb
50 sys.excepthook = ultratb.VerboseTB()
50 sys.excepthook = ultratb.VerboseTB()
51
51
52 Note: Much of the code in this module was lifted verbatim from the standard
52 Note: Much of the code in this module was lifted verbatim from the standard
53 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
53 library module 'traceback.py' and Ka-Ping Yee's 'cgitb.py'.
54
54
55 Color schemes
55 Color schemes
56 -------------
56 -------------
57
57
58 The colors are defined in the class TBTools through the use of the
58 The colors are defined in the class TBTools through the use of the
59 ColorSchemeTable class. Currently the following exist:
59 ColorSchemeTable class. Currently the following exist:
60
60
61 - NoColor: allows all of this module to be used in any terminal (the color
61 - NoColor: allows all of this module to be used in any terminal (the color
62 escapes are just dummy blank strings).
62 escapes are just dummy blank strings).
63
63
64 - Linux: is meant to look good in a terminal like the Linux console (black
64 - Linux: is meant to look good in a terminal like the Linux console (black
65 or very dark background).
65 or very dark background).
66
66
67 - LightBG: similar to Linux but swaps dark/light colors to be more readable
67 - LightBG: similar to Linux but swaps dark/light colors to be more readable
68 in light background terminals.
68 in light background terminals.
69
69
70 You can implement other color schemes easily, the syntax is fairly
70 You can implement other color schemes easily, the syntax is fairly
71 self-explanatory. Please send back new schemes you develop to the author for
71 self-explanatory. Please send back new schemes you develop to the author for
72 possible inclusion in future releases.
72 possible inclusion in future releases.
73
73
74 Inheritance diagram:
74 Inheritance diagram:
75
75
76 .. inheritance-diagram:: IPython.core.ultratb
76 .. inheritance-diagram:: IPython.core.ultratb
77 :parts: 3
77 :parts: 3
78 """
78 """
79
79
80 #*****************************************************************************
80 #*****************************************************************************
81 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
81 # Copyright (C) 2001 Nathaniel Gray <n8gray@caltech.edu>
82 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
82 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
83 #
83 #
84 # Distributed under the terms of the BSD License. The full license is in
84 # Distributed under the terms of the BSD License. The full license is in
85 # the file COPYING, distributed as part of this software.
85 # the file COPYING, distributed as part of this software.
86 #*****************************************************************************
86 #*****************************************************************************
87
87
88 from __future__ import absolute_import
88 from __future__ import unicode_literals
89 from __future__ import unicode_literals
89 from __future__ import print_function
90 from __future__ import print_function
90
91
91 import dis
92 import dis
92 import inspect
93 import inspect
93 import keyword
94 import keyword
94 import linecache
95 import linecache
95 import os
96 import os
96 import pydoc
97 import pydoc
97 import re
98 import re
98 import sys
99 import sys
99 import time
100 import time
100 import tokenize
101 import tokenize
101 import traceback
102 import traceback
102 import types
103 import types
103
104
104 try: # Python 2
105 try: # Python 2
105 generate_tokens = tokenize.generate_tokens
106 generate_tokens = tokenize.generate_tokens
106 except AttributeError: # Python 3
107 except AttributeError: # Python 3
107 generate_tokens = tokenize.tokenize
108 generate_tokens = tokenize.tokenize
108
109
109 # For purposes of monkeypatching inspect to fix a bug in it.
110 # For purposes of monkeypatching inspect to fix a bug in it.
110 from inspect import getsourcefile, getfile, getmodule, \
111 from inspect import getsourcefile, getfile, getmodule, \
111 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
112 ismodule, isclass, ismethod, isfunction, istraceback, isframe, iscode
112
113
113 # IPython's own modules
114 # IPython's own modules
114 # Modified pdb which doesn't damage IPython's readline handling
115 # Modified pdb which doesn't damage IPython's readline handling
115 from IPython import get_ipython
116 from IPython import get_ipython
116 from IPython.core import debugger
117 from IPython.core import debugger
117 from IPython.core.display_trap import DisplayTrap
118 from IPython.core.display_trap import DisplayTrap
118 from IPython.core.excolors import exception_colors
119 from IPython.core.excolors import exception_colors
119 from IPython.utils import PyColorize
120 from IPython.utils import PyColorize
120 from IPython.utils import io
121 from IPython.utils import io
121 from IPython.utils import openpy
122 from IPython.utils import openpy
122 from IPython.utils import path as util_path
123 from IPython.utils import path as util_path
123 from IPython.utils import py3compat
124 from IPython.utils import py3compat
124 from IPython.utils import ulinecache
125 from IPython.utils import ulinecache
125 from IPython.utils.data import uniq_stable
126 from IPython.utils.data import uniq_stable
126 from logging import info, error
127 from logging import info, error
127
128
129 import IPython.utils.colorable as colorable
130
128 # Globals
131 # Globals
129 # amount of space to put line numbers before verbose tracebacks
132 # amount of space to put line numbers before verbose tracebacks
130 INDENT_SIZE = 8
133 INDENT_SIZE = 8
131
134
132 # Default color scheme. This is used, for example, by the traceback
135 # Default color scheme. This is used, for example, by the traceback
133 # formatter. When running in an actual IPython instance, the user's rc.colors
136 # formatter. When running in an actual IPython instance, the user's rc.colors
134 # value is used, but having a module global makes this functionality available
137 # value is used, but having a module global makes this functionality available
135 # to users of ultratb who are NOT running inside ipython.
138 # to users of ultratb who are NOT running inside ipython.
136 DEFAULT_SCHEME = 'NoColor'
139 DEFAULT_SCHEME = 'NoColor'
137
140
138 # ---------------------------------------------------------------------------
141 # ---------------------------------------------------------------------------
139 # Code begins
142 # Code begins
140
143
141 # Utility functions
144 # Utility functions
142 def inspect_error():
145 def inspect_error():
143 """Print a message about internal inspect errors.
146 """Print a message about internal inspect errors.
144
147
145 These are unfortunately quite common."""
148 These are unfortunately quite common."""
146
149
147 error('Internal Python error in the inspect module.\n'
150 error('Internal Python error in the inspect module.\n'
148 'Below is the traceback from this internal error.\n')
151 'Below is the traceback from this internal error.\n')
149
152
150
153
151 # This function is a monkeypatch we apply to the Python inspect module. We have
154 # This function is a monkeypatch we apply to the Python inspect module. We have
152 # now found when it's needed (see discussion on issue gh-1456), and we have a
155 # now found when it's needed (see discussion on issue gh-1456), and we have a
153 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
156 # test case (IPython.core.tests.test_ultratb.ChangedPyFileTest) that fails if
154 # the monkeypatch is not applied. TK, Aug 2012.
157 # the monkeypatch is not applied. TK, Aug 2012.
155 def findsource(object):
158 def findsource(object):
156 """Return the entire source file and starting line number for an object.
159 """Return the entire source file and starting line number for an object.
157
160
158 The argument may be a module, class, method, function, traceback, frame,
161 The argument may be a module, class, method, function, traceback, frame,
159 or code object. The source code is returned as a list of all the lines
162 or code object. The source code is returned as a list of all the lines
160 in the file and the line number indexes a line in that list. An IOError
163 in the file and the line number indexes a line in that list. An IOError
161 is raised if the source code cannot be retrieved.
164 is raised if the source code cannot be retrieved.
162
165
163 FIXED version with which we monkeypatch the stdlib to work around a bug."""
166 FIXED version with which we monkeypatch the stdlib to work around a bug."""
164
167
165 file = getsourcefile(object) or getfile(object)
168 file = getsourcefile(object) or getfile(object)
166 # If the object is a frame, then trying to get the globals dict from its
169 # If the object is a frame, then trying to get the globals dict from its
167 # module won't work. Instead, the frame object itself has the globals
170 # module won't work. Instead, the frame object itself has the globals
168 # dictionary.
171 # dictionary.
169 globals_dict = None
172 globals_dict = None
170 if inspect.isframe(object):
173 if inspect.isframe(object):
171 # XXX: can this ever be false?
174 # XXX: can this ever be false?
172 globals_dict = object.f_globals
175 globals_dict = object.f_globals
173 else:
176 else:
174 module = getmodule(object, file)
177 module = getmodule(object, file)
175 if module:
178 if module:
176 globals_dict = module.__dict__
179 globals_dict = module.__dict__
177 lines = linecache.getlines(file, globals_dict)
180 lines = linecache.getlines(file, globals_dict)
178 if not lines:
181 if not lines:
179 raise IOError('could not get source code')
182 raise IOError('could not get source code')
180
183
181 if ismodule(object):
184 if ismodule(object):
182 return lines, 0
185 return lines, 0
183
186
184 if isclass(object):
187 if isclass(object):
185 name = object.__name__
188 name = object.__name__
186 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
189 pat = re.compile(r'^(\s*)class\s*' + name + r'\b')
187 # make some effort to find the best matching class definition:
190 # make some effort to find the best matching class definition:
188 # use the one with the least indentation, which is the one
191 # use the one with the least indentation, which is the one
189 # that's most probably not inside a function definition.
192 # that's most probably not inside a function definition.
190 candidates = []
193 candidates = []
191 for i in range(len(lines)):
194 for i in range(len(lines)):
192 match = pat.match(lines[i])
195 match = pat.match(lines[i])
193 if match:
196 if match:
194 # if it's at toplevel, it's already the best one
197 # if it's at toplevel, it's already the best one
195 if lines[i][0] == 'c':
198 if lines[i][0] == 'c':
196 return lines, i
199 return lines, i
197 # else add whitespace to candidate list
200 # else add whitespace to candidate list
198 candidates.append((match.group(1), i))
201 candidates.append((match.group(1), i))
199 if candidates:
202 if candidates:
200 # this will sort by whitespace, and by line number,
203 # this will sort by whitespace, and by line number,
201 # less whitespace first
204 # less whitespace first
202 candidates.sort()
205 candidates.sort()
203 return lines, candidates[0][1]
206 return lines, candidates[0][1]
204 else:
207 else:
205 raise IOError('could not find class definition')
208 raise IOError('could not find class definition')
206
209
207 if ismethod(object):
210 if ismethod(object):
208 object = object.__func__
211 object = object.__func__
209 if isfunction(object):
212 if isfunction(object):
210 object = object.__code__
213 object = object.__code__
211 if istraceback(object):
214 if istraceback(object):
212 object = object.tb_frame
215 object = object.tb_frame
213 if isframe(object):
216 if isframe(object):
214 object = object.f_code
217 object = object.f_code
215 if iscode(object):
218 if iscode(object):
216 if not hasattr(object, 'co_firstlineno'):
219 if not hasattr(object, 'co_firstlineno'):
217 raise IOError('could not find function definition')
220 raise IOError('could not find function definition')
218 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
221 pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)')
219 pmatch = pat.match
222 pmatch = pat.match
220 # fperez - fix: sometimes, co_firstlineno can give a number larger than
223 # fperez - fix: sometimes, co_firstlineno can give a number larger than
221 # the length of lines, which causes an error. Safeguard against that.
224 # the length of lines, which causes an error. Safeguard against that.
222 lnum = min(object.co_firstlineno, len(lines)) - 1
225 lnum = min(object.co_firstlineno, len(lines)) - 1
223 while lnum > 0:
226 while lnum > 0:
224 if pmatch(lines[lnum]):
227 if pmatch(lines[lnum]):
225 break
228 break
226 lnum -= 1
229 lnum -= 1
227
230
228 return lines, lnum
231 return lines, lnum
229 raise IOError('could not find code object')
232 raise IOError('could not find code object')
230
233
231
234
232 # This is a patched version of inspect.getargs that applies the (unmerged)
235 # This is a patched version of inspect.getargs that applies the (unmerged)
233 # patch for http://bugs.python.org/issue14611 by Stefano Taschini. This fixes
236 # patch for http://bugs.python.org/issue14611 by Stefano Taschini. This fixes
234 # https://github.com/ipython/ipython/issues/8205 and
237 # https://github.com/ipython/ipython/issues/8205 and
235 # https://github.com/ipython/ipython/issues/8293
238 # https://github.com/ipython/ipython/issues/8293
236 def getargs(co):
239 def getargs(co):
237 """Get information about the arguments accepted by a code object.
240 """Get information about the arguments accepted by a code object.
238
241
239 Three things are returned: (args, varargs, varkw), where 'args' is
242 Three things are returned: (args, varargs, varkw), where 'args' is
240 a list of argument names (possibly containing nested lists), and
243 a list of argument names (possibly containing nested lists), and
241 'varargs' and 'varkw' are the names of the * and ** arguments or None."""
244 'varargs' and 'varkw' are the names of the * and ** arguments or None."""
242 if not iscode(co):
245 if not iscode(co):
243 raise TypeError('{!r} is not a code object'.format(co))
246 raise TypeError('{!r} is not a code object'.format(co))
244
247
245 nargs = co.co_argcount
248 nargs = co.co_argcount
246 names = co.co_varnames
249 names = co.co_varnames
247 args = list(names[:nargs])
250 args = list(names[:nargs])
248 step = 0
251 step = 0
249
252
250 # The following acrobatics are for anonymous (tuple) arguments.
253 # The following acrobatics are for anonymous (tuple) arguments.
251 for i in range(nargs):
254 for i in range(nargs):
252 if args[i][:1] in ('', '.'):
255 if args[i][:1] in ('', '.'):
253 stack, remain, count = [], [], []
256 stack, remain, count = [], [], []
254 while step < len(co.co_code):
257 while step < len(co.co_code):
255 op = ord(co.co_code[step])
258 op = ord(co.co_code[step])
256 step = step + 1
259 step = step + 1
257 if op >= dis.HAVE_ARGUMENT:
260 if op >= dis.HAVE_ARGUMENT:
258 opname = dis.opname[op]
261 opname = dis.opname[op]
259 value = ord(co.co_code[step]) + ord(co.co_code[step+1])*256
262 value = ord(co.co_code[step]) + ord(co.co_code[step+1])*256
260 step = step + 2
263 step = step + 2
261 if opname in ('UNPACK_TUPLE', 'UNPACK_SEQUENCE'):
264 if opname in ('UNPACK_TUPLE', 'UNPACK_SEQUENCE'):
262 remain.append(value)
265 remain.append(value)
263 count.append(value)
266 count.append(value)
264 elif opname in ('STORE_FAST', 'STORE_DEREF'):
267 elif opname in ('STORE_FAST', 'STORE_DEREF'):
265 if op in dis.haslocal:
268 if op in dis.haslocal:
266 stack.append(co.co_varnames[value])
269 stack.append(co.co_varnames[value])
267 elif op in dis.hasfree:
270 elif op in dis.hasfree:
268 stack.append((co.co_cellvars + co.co_freevars)[value])
271 stack.append((co.co_cellvars + co.co_freevars)[value])
269 # Special case for sublists of length 1: def foo((bar))
272 # Special case for sublists of length 1: def foo((bar))
270 # doesn't generate the UNPACK_TUPLE bytecode, so if
273 # doesn't generate the UNPACK_TUPLE bytecode, so if
271 # `remain` is empty here, we have such a sublist.
274 # `remain` is empty here, we have such a sublist.
272 if not remain:
275 if not remain:
273 stack[0] = [stack[0]]
276 stack[0] = [stack[0]]
274 break
277 break
275 else:
278 else:
276 remain[-1] = remain[-1] - 1
279 remain[-1] = remain[-1] - 1
277 while remain[-1] == 0:
280 while remain[-1] == 0:
278 remain.pop()
281 remain.pop()
279 size = count.pop()
282 size = count.pop()
280 stack[-size:] = [stack[-size:]]
283 stack[-size:] = [stack[-size:]]
281 if not remain:
284 if not remain:
282 break
285 break
283 remain[-1] = remain[-1] - 1
286 remain[-1] = remain[-1] - 1
284 if not remain:
287 if not remain:
285 break
288 break
286 args[i] = stack[0]
289 args[i] = stack[0]
287
290
288 varargs = None
291 varargs = None
289 if co.co_flags & inspect.CO_VARARGS:
292 if co.co_flags & inspect.CO_VARARGS:
290 varargs = co.co_varnames[nargs]
293 varargs = co.co_varnames[nargs]
291 nargs = nargs + 1
294 nargs = nargs + 1
292 varkw = None
295 varkw = None
293 if co.co_flags & inspect.CO_VARKEYWORDS:
296 if co.co_flags & inspect.CO_VARKEYWORDS:
294 varkw = co.co_varnames[nargs]
297 varkw = co.co_varnames[nargs]
295 return inspect.Arguments(args, varargs, varkw)
298 return inspect.Arguments(args, varargs, varkw)
296
299
297
300
298 # Monkeypatch inspect to apply our bugfix.
301 # Monkeypatch inspect to apply our bugfix.
299 def with_patch_inspect(f):
302 def with_patch_inspect(f):
300 """decorator for monkeypatching inspect.findsource"""
303 """decorator for monkeypatching inspect.findsource"""
301
304
302 def wrapped(*args, **kwargs):
305 def wrapped(*args, **kwargs):
303 save_findsource = inspect.findsource
306 save_findsource = inspect.findsource
304 save_getargs = inspect.getargs
307 save_getargs = inspect.getargs
305 inspect.findsource = findsource
308 inspect.findsource = findsource
306 inspect.getargs = getargs
309 inspect.getargs = getargs
307 try:
310 try:
308 return f(*args, **kwargs)
311 return f(*args, **kwargs)
309 finally:
312 finally:
310 inspect.findsource = save_findsource
313 inspect.findsource = save_findsource
311 inspect.getargs = save_getargs
314 inspect.getargs = save_getargs
312
315
313 return wrapped
316 return wrapped
314
317
315
318
316 if py3compat.PY3:
319 if py3compat.PY3:
317 fixed_getargvalues = inspect.getargvalues
320 fixed_getargvalues = inspect.getargvalues
318 else:
321 else:
319 # Fixes for https://github.com/ipython/ipython/issues/8293
322 # Fixes for https://github.com/ipython/ipython/issues/8293
320 # and https://github.com/ipython/ipython/issues/8205.
323 # and https://github.com/ipython/ipython/issues/8205.
321 # The relevant bug is caused by failure to correctly handle anonymous tuple
324 # The relevant bug is caused by failure to correctly handle anonymous tuple
322 # unpacking, which only exists in Python 2.
325 # unpacking, which only exists in Python 2.
323 fixed_getargvalues = with_patch_inspect(inspect.getargvalues)
326 fixed_getargvalues = with_patch_inspect(inspect.getargvalues)
324
327
325
328
326 def fix_frame_records_filenames(records):
329 def fix_frame_records_filenames(records):
327 """Try to fix the filenames in each record from inspect.getinnerframes().
330 """Try to fix the filenames in each record from inspect.getinnerframes().
328
331
329 Particularly, modules loaded from within zip files have useless filenames
332 Particularly, modules loaded from within zip files have useless filenames
330 attached to their code object, and inspect.getinnerframes() just uses it.
333 attached to their code object, and inspect.getinnerframes() just uses it.
331 """
334 """
332 fixed_records = []
335 fixed_records = []
333 for frame, filename, line_no, func_name, lines, index in records:
336 for frame, filename, line_no, func_name, lines, index in records:
334 # Look inside the frame's globals dictionary for __file__,
337 # Look inside the frame's globals dictionary for __file__,
335 # which should be better. However, keep Cython filenames since
338 # which should be better. However, keep Cython filenames since
336 # we prefer the source filenames over the compiled .so file.
339 # we prefer the source filenames over the compiled .so file.
337 filename = py3compat.cast_unicode_py2(filename, "utf-8")
340 filename = py3compat.cast_unicode_py2(filename, "utf-8")
338 if not filename.endswith(('.pyx', '.pxd', '.pxi')):
341 if not filename.endswith(('.pyx', '.pxd', '.pxi')):
339 better_fn = frame.f_globals.get('__file__', None)
342 better_fn = frame.f_globals.get('__file__', None)
340 if isinstance(better_fn, str):
343 if isinstance(better_fn, str):
341 # Check the type just in case someone did something weird with
344 # Check the type just in case someone did something weird with
342 # __file__. It might also be None if the error occurred during
345 # __file__. It might also be None if the error occurred during
343 # import.
346 # import.
344 filename = better_fn
347 filename = better_fn
345 fixed_records.append((frame, filename, line_no, func_name, lines, index))
348 fixed_records.append((frame, filename, line_no, func_name, lines, index))
346 return fixed_records
349 return fixed_records
347
350
348
351
349 @with_patch_inspect
352 @with_patch_inspect
350 def _fixed_getinnerframes(etb, context=1, tb_offset=0):
353 def _fixed_getinnerframes(etb, context=1, tb_offset=0):
351 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
354 LNUM_POS, LINES_POS, INDEX_POS = 2, 4, 5
352
355
353 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
356 records = fix_frame_records_filenames(inspect.getinnerframes(etb, context))
354 # If the error is at the console, don't build any context, since it would
357 # If the error is at the console, don't build any context, since it would
355 # otherwise produce 5 blank lines printed out (there is no file at the
358 # otherwise produce 5 blank lines printed out (there is no file at the
356 # console)
359 # console)
357 rec_check = records[tb_offset:]
360 rec_check = records[tb_offset:]
358 try:
361 try:
359 rname = rec_check[0][1]
362 rname = rec_check[0][1]
360 if rname == '<ipython console>' or rname.endswith('<string>'):
363 if rname == '<ipython console>' or rname.endswith('<string>'):
361 return rec_check
364 return rec_check
362 except IndexError:
365 except IndexError:
363 pass
366 pass
364
367
365 aux = traceback.extract_tb(etb)
368 aux = traceback.extract_tb(etb)
366 assert len(records) == len(aux)
369 assert len(records) == len(aux)
367 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
370 for i, (file, lnum, _, _) in zip(range(len(records)), aux):
368 maybeStart = lnum - 1 - context // 2
371 maybeStart = lnum - 1 - context // 2
369 start = max(maybeStart, 0)
372 start = max(maybeStart, 0)
370 end = start + context
373 end = start + context
371 lines = ulinecache.getlines(file)[start:end]
374 lines = ulinecache.getlines(file)[start:end]
372 buf = list(records[i])
375 buf = list(records[i])
373 buf[LNUM_POS] = lnum
376 buf[LNUM_POS] = lnum
374 buf[INDEX_POS] = lnum - 1 - start
377 buf[INDEX_POS] = lnum - 1 - start
375 buf[LINES_POS] = lines
378 buf[LINES_POS] = lines
376 records[i] = tuple(buf)
379 records[i] = tuple(buf)
377 return records[tb_offset:]
380 return records[tb_offset:]
378
381
379 # Helper function -- largely belongs to VerboseTB, but we need the same
382 # Helper function -- largely belongs to VerboseTB, but we need the same
380 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
383 # functionality to produce a pseudo verbose TB for SyntaxErrors, so that they
381 # can be recognized properly by ipython.el's py-traceback-line-re
384 # can be recognized properly by ipython.el's py-traceback-line-re
382 # (SyntaxErrors have to be treated specially because they have no traceback)
385 # (SyntaxErrors have to be treated specially because they have no traceback)
383
386
384 _parser = PyColorize.Parser()
387 _parser = PyColorize.Parser()
385
388
386
389
387 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None, scheme=None):
390 def _format_traceback_lines(lnum, index, lines, Colors, lvals=None, scheme=None):
388 numbers_width = INDENT_SIZE - 1
391 numbers_width = INDENT_SIZE - 1
389 res = []
392 res = []
390 i = lnum - index
393 i = lnum - index
391
394
392 # This lets us get fully syntax-highlighted tracebacks.
395 # This lets us get fully syntax-highlighted tracebacks.
393 if scheme is None:
396 if scheme is None:
394 ipinst = get_ipython()
397 ipinst = get_ipython()
395 if ipinst is not None:
398 if ipinst is not None:
396 scheme = ipinst.colors
399 scheme = ipinst.colors
397 else:
400 else:
398 scheme = DEFAULT_SCHEME
401 scheme = DEFAULT_SCHEME
399
402
400 _line_format = _parser.format2
403 _line_format = _parser.format2
401
404
402 for line in lines:
405 for line in lines:
403 line = py3compat.cast_unicode(line)
406 line = py3compat.cast_unicode(line)
404
407
405 new_line, err = _line_format(line, 'str', scheme)
408 new_line, err = _line_format(line, 'str', scheme)
406 if not err: line = new_line
409 if not err: line = new_line
407
410
408 if i == lnum:
411 if i == lnum:
409 # This is the line with the error
412 # This is the line with the error
410 pad = numbers_width - len(str(i))
413 pad = numbers_width - len(str(i))
411 num = '%s%s' % (debugger.make_arrow(pad), str(lnum))
414 num = '%s%s' % (debugger.make_arrow(pad), str(lnum))
412 line = '%s%s%s %s%s' % (Colors.linenoEm, num,
415 line = '%s%s%s %s%s' % (Colors.linenoEm, num,
413 Colors.line, line, Colors.Normal)
416 Colors.line, line, Colors.Normal)
414 else:
417 else:
415 num = '%*s' % (numbers_width, i)
418 num = '%*s' % (numbers_width, i)
416 line = '%s%s%s %s' % (Colors.lineno, num,
419 line = '%s%s%s %s' % (Colors.lineno, num,
417 Colors.Normal, line)
420 Colors.Normal, line)
418
421
419 res.append(line)
422 res.append(line)
420 if lvals and i == lnum:
423 if lvals and i == lnum:
421 res.append(lvals + '\n')
424 res.append(lvals + '\n')
422 i = i + 1
425 i = i + 1
423 return res
426 return res
424
427
425 def is_recursion_error(etype, value, records):
428 def is_recursion_error(etype, value, records):
426 try:
429 try:
427 # RecursionError is new in Python 3.5
430 # RecursionError is new in Python 3.5
428 recursion_error_type = RecursionError
431 recursion_error_type = RecursionError
429 except NameError:
432 except NameError:
430 recursion_error_type = RuntimeError
433 recursion_error_type = RuntimeError
431
434
432 # The default recursion limit is 1000, but some of that will be taken up
435 # The default recursion limit is 1000, but some of that will be taken up
433 # by stack frames in IPython itself. >500 frames probably indicates
436 # by stack frames in IPython itself. >500 frames probably indicates
434 # a recursion error.
437 # a recursion error.
435 return (etype is recursion_error_type) \
438 return (etype is recursion_error_type) \
436 and "recursion" in str(value).lower() \
439 and "recursion" in str(value).lower() \
437 and len(records) > 500
440 and len(records) > 500
438
441
439 def find_recursion(etype, value, records):
442 def find_recursion(etype, value, records):
440 """Identify the repeating stack frames from a RecursionError traceback
443 """Identify the repeating stack frames from a RecursionError traceback
441
444
442 'records' is a list as returned by VerboseTB.get_records()
445 'records' is a list as returned by VerboseTB.get_records()
443
446
444 Returns (last_unique, repeat_length)
447 Returns (last_unique, repeat_length)
445 """
448 """
446 # This involves a bit of guesswork - we want to show enough of the traceback
449 # This involves a bit of guesswork - we want to show enough of the traceback
447 # to indicate where the recursion is occurring. We guess that the innermost
450 # to indicate where the recursion is occurring. We guess that the innermost
448 # quarter of the traceback (250 frames by default) is repeats, and find the
451 # quarter of the traceback (250 frames by default) is repeats, and find the
449 # first frame (from in to out) that looks different.
452 # first frame (from in to out) that looks different.
450 if not is_recursion_error(etype, value, records):
453 if not is_recursion_error(etype, value, records):
451 return len(records), 0
454 return len(records), 0
452
455
453 # Select filename, lineno, func_name to track frames with
456 # Select filename, lineno, func_name to track frames with
454 records = [r[1:4] for r in records]
457 records = [r[1:4] for r in records]
455 inner_frames = records[-(len(records)//4):]
458 inner_frames = records[-(len(records)//4):]
456 frames_repeated = set(inner_frames)
459 frames_repeated = set(inner_frames)
457
460
458 last_seen_at = {}
461 last_seen_at = {}
459 longest_repeat = 0
462 longest_repeat = 0
460 i = len(records)
463 i = len(records)
461 for frame in reversed(records):
464 for frame in reversed(records):
462 i -= 1
465 i -= 1
463 if frame not in frames_repeated:
466 if frame not in frames_repeated:
464 last_unique = i
467 last_unique = i
465 break
468 break
466
469
467 if frame in last_seen_at:
470 if frame in last_seen_at:
468 distance = last_seen_at[frame] - i
471 distance = last_seen_at[frame] - i
469 longest_repeat = max(longest_repeat, distance)
472 longest_repeat = max(longest_repeat, distance)
470
473
471 last_seen_at[frame] = i
474 last_seen_at[frame] = i
472 else:
475 else:
473 last_unique = 0 # The whole traceback was recursion
476 last_unique = 0 # The whole traceback was recursion
474
477
475 return last_unique, longest_repeat
478 return last_unique, longest_repeat
476
479
477 #---------------------------------------------------------------------------
480 #---------------------------------------------------------------------------
478 # Module classes
481 # Module classes
479 class TBTools(object):
482 class TBTools(colorable.Colorable):
480 """Basic tools used by all traceback printer classes."""
483 """Basic tools used by all traceback printer classes."""
481
484
482 # Number of frames to skip when reporting tracebacks
485 # Number of frames to skip when reporting tracebacks
483 tb_offset = 0
486 tb_offset = 0
484
487
485 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None):
488 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None, config=None):
486 # Whether to call the interactive pdb debugger after printing
489 # Whether to call the interactive pdb debugger after printing
487 # tracebacks or not
490 # tracebacks or not
491 super(TBTools, self).__init__(parent=parent, config=config)
488 self.call_pdb = call_pdb
492 self.call_pdb = call_pdb
489
493
490 # Output stream to write to. Note that we store the original value in
494 # Output stream to write to. Note that we store the original value in
491 # a private attribute and then make the public ostream a property, so
495 # a private attribute and then make the public ostream a property, so
492 # that we can delay accessing io.stdout until runtime. The way
496 # that we can delay accessing io.stdout until runtime. The way
493 # things are written now, the io.stdout object is dynamically managed
497 # things are written now, the io.stdout object is dynamically managed
494 # so a reference to it should NEVER be stored statically. This
498 # so a reference to it should NEVER be stored statically. This
495 # property approach confines this detail to a single location, and all
499 # property approach confines this detail to a single location, and all
496 # subclasses can simply access self.ostream for writing.
500 # subclasses can simply access self.ostream for writing.
497 self._ostream = ostream
501 self._ostream = ostream
498
502
499 # Create color table
503 # Create color table
500 self.color_scheme_table = exception_colors()
504 self.color_scheme_table = exception_colors()
501
505
502 self.set_colors(color_scheme)
506 self.set_colors(color_scheme)
503 self.old_scheme = color_scheme # save initial value for toggles
507 self.old_scheme = color_scheme # save initial value for toggles
504
508
505 if call_pdb:
509 if call_pdb:
506 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
510 self.pdb = debugger.Pdb(self.color_scheme_table.active_scheme_name)
507 else:
511 else:
508 self.pdb = None
512 self.pdb = None
509
513
510 def _get_ostream(self):
514 def _get_ostream(self):
511 """Output stream that exceptions are written to.
515 """Output stream that exceptions are written to.
512
516
513 Valid values are:
517 Valid values are:
514
518
515 - None: the default, which means that IPython will dynamically resolve
519 - None: the default, which means that IPython will dynamically resolve
516 to io.stdout. This ensures compatibility with most tools, including
520 to io.stdout. This ensures compatibility with most tools, including
517 Windows (where plain stdout doesn't recognize ANSI escapes).
521 Windows (where plain stdout doesn't recognize ANSI escapes).
518
522
519 - Any object with 'write' and 'flush' attributes.
523 - Any object with 'write' and 'flush' attributes.
520 """
524 """
521 return io.stdout if self._ostream is None else self._ostream
525 return io.stdout if self._ostream is None else self._ostream
522
526
523 def _set_ostream(self, val):
527 def _set_ostream(self, val):
524 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
528 assert val is None or (hasattr(val, 'write') and hasattr(val, 'flush'))
525 self._ostream = val
529 self._ostream = val
526
530
527 ostream = property(_get_ostream, _set_ostream)
531 ostream = property(_get_ostream, _set_ostream)
528
532
529 def set_colors(self, *args, **kw):
533 def set_colors(self, *args, **kw):
530 """Shorthand access to the color table scheme selector method."""
534 """Shorthand access to the color table scheme selector method."""
531
535
532 # Set own color table
536 # Set own color table
533 self.color_scheme_table.set_active_scheme(*args, **kw)
537 self.color_scheme_table.set_active_scheme(*args, **kw)
534 # for convenience, set Colors to the active scheme
538 # for convenience, set Colors to the active scheme
535 self.Colors = self.color_scheme_table.active_colors
539 self.Colors = self.color_scheme_table.active_colors
536 # Also set colors of debugger
540 # Also set colors of debugger
537 if hasattr(self, 'pdb') and self.pdb is not None:
541 if hasattr(self, 'pdb') and self.pdb is not None:
538 self.pdb.set_colors(*args, **kw)
542 self.pdb.set_colors(*args, **kw)
539
543
540 def color_toggle(self):
544 def color_toggle(self):
541 """Toggle between the currently active color scheme and NoColor."""
545 """Toggle between the currently active color scheme and NoColor."""
542
546
543 if self.color_scheme_table.active_scheme_name == 'NoColor':
547 if self.color_scheme_table.active_scheme_name == 'NoColor':
544 self.color_scheme_table.set_active_scheme(self.old_scheme)
548 self.color_scheme_table.set_active_scheme(self.old_scheme)
545 self.Colors = self.color_scheme_table.active_colors
549 self.Colors = self.color_scheme_table.active_colors
546 else:
550 else:
547 self.old_scheme = self.color_scheme_table.active_scheme_name
551 self.old_scheme = self.color_scheme_table.active_scheme_name
548 self.color_scheme_table.set_active_scheme('NoColor')
552 self.color_scheme_table.set_active_scheme('NoColor')
549 self.Colors = self.color_scheme_table.active_colors
553 self.Colors = self.color_scheme_table.active_colors
550
554
551 def stb2text(self, stb):
555 def stb2text(self, stb):
552 """Convert a structured traceback (a list) to a string."""
556 """Convert a structured traceback (a list) to a string."""
553 return '\n'.join(stb)
557 return '\n'.join(stb)
554
558
555 def text(self, etype, value, tb, tb_offset=None, context=5):
559 def text(self, etype, value, tb, tb_offset=None, context=5):
556 """Return formatted traceback.
560 """Return formatted traceback.
557
561
558 Subclasses may override this if they add extra arguments.
562 Subclasses may override this if they add extra arguments.
559 """
563 """
560 tb_list = self.structured_traceback(etype, value, tb,
564 tb_list = self.structured_traceback(etype, value, tb,
561 tb_offset, context)
565 tb_offset, context)
562 return self.stb2text(tb_list)
566 return self.stb2text(tb_list)
563
567
564 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
568 def structured_traceback(self, etype, evalue, tb, tb_offset=None,
565 context=5, mode=None):
569 context=5, mode=None):
566 """Return a list of traceback frames.
570 """Return a list of traceback frames.
567
571
568 Must be implemented by each class.
572 Must be implemented by each class.
569 """
573 """
570 raise NotImplementedError()
574 raise NotImplementedError()
571
575
572
576
573 #---------------------------------------------------------------------------
577 #---------------------------------------------------------------------------
574 class ListTB(TBTools):
578 class ListTB(TBTools):
575 """Print traceback information from a traceback list, with optional color.
579 """Print traceback information from a traceback list, with optional color.
576
580
577 Calling requires 3 arguments: (etype, evalue, elist)
581 Calling requires 3 arguments: (etype, evalue, elist)
578 as would be obtained by::
582 as would be obtained by::
579
583
580 etype, evalue, tb = sys.exc_info()
584 etype, evalue, tb = sys.exc_info()
581 if tb:
585 if tb:
582 elist = traceback.extract_tb(tb)
586 elist = traceback.extract_tb(tb)
583 else:
587 else:
584 elist = None
588 elist = None
585
589
586 It can thus be used by programs which need to process the traceback before
590 It can thus be used by programs which need to process the traceback before
587 printing (such as console replacements based on the code module from the
591 printing (such as console replacements based on the code module from the
588 standard library).
592 standard library).
589
593
590 Because they are meant to be called without a full traceback (only a
594 Because they are meant to be called without a full traceback (only a
591 list), instances of this class can't call the interactive pdb debugger."""
595 list), instances of this class can't call the interactive pdb debugger."""
592
596
593 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None):
597 def __init__(self, color_scheme='NoColor', call_pdb=False, ostream=None, parent=None):
594 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
598 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
595 ostream=ostream)
599 ostream=ostream, parent=parent)
596
600
597 def __call__(self, etype, value, elist):
601 def __call__(self, etype, value, elist):
598 self.ostream.flush()
602 self.ostream.flush()
599 self.ostream.write(self.text(etype, value, elist))
603 self.ostream.write(self.text(etype, value, elist))
600 self.ostream.write('\n')
604 self.ostream.write('\n')
601
605
602 def structured_traceback(self, etype, value, elist, tb_offset=None,
606 def structured_traceback(self, etype, value, elist, tb_offset=None,
603 context=5):
607 context=5):
604 """Return a color formatted string with the traceback info.
608 """Return a color formatted string with the traceback info.
605
609
606 Parameters
610 Parameters
607 ----------
611 ----------
608 etype : exception type
612 etype : exception type
609 Type of the exception raised.
613 Type of the exception raised.
610
614
611 value : object
615 value : object
612 Data stored in the exception
616 Data stored in the exception
613
617
614 elist : list
618 elist : list
615 List of frames, see class docstring for details.
619 List of frames, see class docstring for details.
616
620
617 tb_offset : int, optional
621 tb_offset : int, optional
618 Number of frames in the traceback to skip. If not given, the
622 Number of frames in the traceback to skip. If not given, the
619 instance value is used (set in constructor).
623 instance value is used (set in constructor).
620
624
621 context : int, optional
625 context : int, optional
622 Number of lines of context information to print.
626 Number of lines of context information to print.
623
627
624 Returns
628 Returns
625 -------
629 -------
626 String with formatted exception.
630 String with formatted exception.
627 """
631 """
628 tb_offset = self.tb_offset if tb_offset is None else tb_offset
632 tb_offset = self.tb_offset if tb_offset is None else tb_offset
629 Colors = self.Colors
633 Colors = self.Colors
630 out_list = []
634 out_list = []
631 if elist:
635 if elist:
632
636
633 if tb_offset and len(elist) > tb_offset:
637 if tb_offset and len(elist) > tb_offset:
634 elist = elist[tb_offset:]
638 elist = elist[tb_offset:]
635
639
636 out_list.append('Traceback %s(most recent call last)%s:' %
640 out_list.append('Traceback %s(most recent call last)%s:' %
637 (Colors.normalEm, Colors.Normal) + '\n')
641 (Colors.normalEm, Colors.Normal) + '\n')
638 out_list.extend(self._format_list(elist))
642 out_list.extend(self._format_list(elist))
639 # The exception info should be a single entry in the list.
643 # The exception info should be a single entry in the list.
640 lines = ''.join(self._format_exception_only(etype, value))
644 lines = ''.join(self._format_exception_only(etype, value))
641 out_list.append(lines)
645 out_list.append(lines)
642
646
643 # Note: this code originally read:
647 # Note: this code originally read:
644
648
645 ## for line in lines[:-1]:
649 ## for line in lines[:-1]:
646 ## out_list.append(" "+line)
650 ## out_list.append(" "+line)
647 ## out_list.append(lines[-1])
651 ## out_list.append(lines[-1])
648
652
649 # This means it was indenting everything but the last line by a little
653 # This means it was indenting everything but the last line by a little
650 # bit. I've disabled this for now, but if we see ugliness somewhere we
654 # bit. I've disabled this for now, but if we see ugliness somewhere we
651 # can restore it.
655 # can restore it.
652
656
653 return out_list
657 return out_list
654
658
655 def _format_list(self, extracted_list):
659 def _format_list(self, extracted_list):
656 """Format a list of traceback entry tuples for printing.
660 """Format a list of traceback entry tuples for printing.
657
661
658 Given a list of tuples as returned by extract_tb() or
662 Given a list of tuples as returned by extract_tb() or
659 extract_stack(), return a list of strings ready for printing.
663 extract_stack(), return a list of strings ready for printing.
660 Each string in the resulting list corresponds to the item with the
664 Each string in the resulting list corresponds to the item with the
661 same index in the argument list. Each string ends in a newline;
665 same index in the argument list. Each string ends in a newline;
662 the strings may contain internal newlines as well, for those items
666 the strings may contain internal newlines as well, for those items
663 whose source text line is not None.
667 whose source text line is not None.
664
668
665 Lifted almost verbatim from traceback.py
669 Lifted almost verbatim from traceback.py
666 """
670 """
667
671
668 Colors = self.Colors
672 Colors = self.Colors
669 list = []
673 list = []
670 for filename, lineno, name, line in extracted_list[:-1]:
674 for filename, lineno, name, line in extracted_list[:-1]:
671 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
675 item = ' File %s"%s"%s, line %s%d%s, in %s%s%s\n' % \
672 (Colors.filename, py3compat.cast_unicode_py2(filename, "utf-8"), Colors.Normal,
676 (Colors.filename, py3compat.cast_unicode_py2(filename, "utf-8"), Colors.Normal,
673 Colors.lineno, lineno, Colors.Normal,
677 Colors.lineno, lineno, Colors.Normal,
674 Colors.name, py3compat.cast_unicode_py2(name, "utf-8"), Colors.Normal)
678 Colors.name, py3compat.cast_unicode_py2(name, "utf-8"), Colors.Normal)
675 if line:
679 if line:
676 item += ' %s\n' % line.strip()
680 item += ' %s\n' % line.strip()
677 list.append(item)
681 list.append(item)
678 # Emphasize the last entry
682 # Emphasize the last entry
679 filename, lineno, name, line = extracted_list[-1]
683 filename, lineno, name, line = extracted_list[-1]
680 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
684 item = '%s File %s"%s"%s, line %s%d%s, in %s%s%s%s\n' % \
681 (Colors.normalEm,
685 (Colors.normalEm,
682 Colors.filenameEm, py3compat.cast_unicode_py2(filename, "utf-8"), Colors.normalEm,
686 Colors.filenameEm, py3compat.cast_unicode_py2(filename, "utf-8"), Colors.normalEm,
683 Colors.linenoEm, lineno, Colors.normalEm,
687 Colors.linenoEm, lineno, Colors.normalEm,
684 Colors.nameEm, py3compat.cast_unicode_py2(name, "utf-8"), Colors.normalEm,
688 Colors.nameEm, py3compat.cast_unicode_py2(name, "utf-8"), Colors.normalEm,
685 Colors.Normal)
689 Colors.Normal)
686 if line:
690 if line:
687 item += '%s %s%s\n' % (Colors.line, line.strip(),
691 item += '%s %s%s\n' % (Colors.line, line.strip(),
688 Colors.Normal)
692 Colors.Normal)
689 list.append(item)
693 list.append(item)
690 return list
694 return list
691
695
692 def _format_exception_only(self, etype, value):
696 def _format_exception_only(self, etype, value):
693 """Format the exception part of a traceback.
697 """Format the exception part of a traceback.
694
698
695 The arguments are the exception type and value such as given by
699 The arguments are the exception type and value such as given by
696 sys.exc_info()[:2]. The return value is a list of strings, each ending
700 sys.exc_info()[:2]. The return value is a list of strings, each ending
697 in a newline. Normally, the list contains a single string; however,
701 in a newline. Normally, the list contains a single string; however,
698 for SyntaxError exceptions, it contains several lines that (when
702 for SyntaxError exceptions, it contains several lines that (when
699 printed) display detailed information about where the syntax error
703 printed) display detailed information about where the syntax error
700 occurred. The message indicating which exception occurred is the
704 occurred. The message indicating which exception occurred is the
701 always last string in the list.
705 always last string in the list.
702
706
703 Also lifted nearly verbatim from traceback.py
707 Also lifted nearly verbatim from traceback.py
704 """
708 """
705 have_filedata = False
709 have_filedata = False
706 Colors = self.Colors
710 Colors = self.Colors
707 list = []
711 list = []
708 stype = Colors.excName + etype.__name__ + Colors.Normal
712 stype = Colors.excName + etype.__name__ + Colors.Normal
709 if value is None:
713 if value is None:
710 # Not sure if this can still happen in Python 2.6 and above
714 # Not sure if this can still happen in Python 2.6 and above
711 list.append(py3compat.cast_unicode(stype) + '\n')
715 list.append(py3compat.cast_unicode(stype) + '\n')
712 else:
716 else:
713 if issubclass(etype, SyntaxError):
717 if issubclass(etype, SyntaxError):
714 have_filedata = True
718 have_filedata = True
715 if not value.filename: value.filename = "<string>"
719 if not value.filename: value.filename = "<string>"
716 if value.lineno:
720 if value.lineno:
717 lineno = value.lineno
721 lineno = value.lineno
718 textline = ulinecache.getline(value.filename, value.lineno)
722 textline = ulinecache.getline(value.filename, value.lineno)
719 else:
723 else:
720 lineno = 'unknown'
724 lineno = 'unknown'
721 textline = ''
725 textline = ''
722 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
726 list.append('%s File %s"%s"%s, line %s%s%s\n' % \
723 (Colors.normalEm,
727 (Colors.normalEm,
724 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
728 Colors.filenameEm, py3compat.cast_unicode(value.filename), Colors.normalEm,
725 Colors.linenoEm, lineno, Colors.Normal ))
729 Colors.linenoEm, lineno, Colors.Normal ))
726 if textline == '':
730 if textline == '':
727 textline = py3compat.cast_unicode(value.text, "utf-8")
731 textline = py3compat.cast_unicode(value.text, "utf-8")
728
732
729 if textline is not None:
733 if textline is not None:
730 i = 0
734 i = 0
731 while i < len(textline) and textline[i].isspace():
735 while i < len(textline) and textline[i].isspace():
732 i += 1
736 i += 1
733 list.append('%s %s%s\n' % (Colors.line,
737 list.append('%s %s%s\n' % (Colors.line,
734 textline.strip(),
738 textline.strip(),
735 Colors.Normal))
739 Colors.Normal))
736 if value.offset is not None:
740 if value.offset is not None:
737 s = ' '
741 s = ' '
738 for c in textline[i:value.offset - 1]:
742 for c in textline[i:value.offset - 1]:
739 if c.isspace():
743 if c.isspace():
740 s += c
744 s += c
741 else:
745 else:
742 s += ' '
746 s += ' '
743 list.append('%s%s^%s\n' % (Colors.caret, s,
747 list.append('%s%s^%s\n' % (Colors.caret, s,
744 Colors.Normal))
748 Colors.Normal))
745
749
746 try:
750 try:
747 s = value.msg
751 s = value.msg
748 except Exception:
752 except Exception:
749 s = self._some_str(value)
753 s = self._some_str(value)
750 if s:
754 if s:
751 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
755 list.append('%s%s:%s %s\n' % (str(stype), Colors.excName,
752 Colors.Normal, s))
756 Colors.Normal, s))
753 else:
757 else:
754 list.append('%s\n' % str(stype))
758 list.append('%s\n' % str(stype))
755
759
756 # sync with user hooks
760 # sync with user hooks
757 if have_filedata:
761 if have_filedata:
758 ipinst = get_ipython()
762 ipinst = get_ipython()
759 if ipinst is not None:
763 if ipinst is not None:
760 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
764 ipinst.hooks.synchronize_with_editor(value.filename, value.lineno, 0)
761
765
762 return list
766 return list
763
767
764 def get_exception_only(self, etype, value):
768 def get_exception_only(self, etype, value):
765 """Only print the exception type and message, without a traceback.
769 """Only print the exception type and message, without a traceback.
766
770
767 Parameters
771 Parameters
768 ----------
772 ----------
769 etype : exception type
773 etype : exception type
770 value : exception value
774 value : exception value
771 """
775 """
772 return ListTB.structured_traceback(self, etype, value, [])
776 return ListTB.structured_traceback(self, etype, value, [])
773
777
774 def show_exception_only(self, etype, evalue):
778 def show_exception_only(self, etype, evalue):
775 """Only print the exception type and message, without a traceback.
779 """Only print the exception type and message, without a traceback.
776
780
777 Parameters
781 Parameters
778 ----------
782 ----------
779 etype : exception type
783 etype : exception type
780 value : exception value
784 value : exception value
781 """
785 """
782 # This method needs to use __call__ from *this* class, not the one from
786 # This method needs to use __call__ from *this* class, not the one from
783 # a subclass whose signature or behavior may be different
787 # a subclass whose signature or behavior may be different
784 ostream = self.ostream
788 ostream = self.ostream
785 ostream.flush()
789 ostream.flush()
786 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
790 ostream.write('\n'.join(self.get_exception_only(etype, evalue)))
787 ostream.flush()
791 ostream.flush()
788
792
789 def _some_str(self, value):
793 def _some_str(self, value):
790 # Lifted from traceback.py
794 # Lifted from traceback.py
791 try:
795 try:
792 return str(value)
796 return str(value)
793 except:
797 except:
794 return '<unprintable %s object>' % type(value).__name__
798 return '<unprintable %s object>' % type(value).__name__
795
799
796
800
797 #----------------------------------------------------------------------------
801 #----------------------------------------------------------------------------
798 class VerboseTB(TBTools):
802 class VerboseTB(TBTools):
799 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
803 """A port of Ka-Ping Yee's cgitb.py module that outputs color text instead
800 of HTML. Requires inspect and pydoc. Crazy, man.
804 of HTML. Requires inspect and pydoc. Crazy, man.
801
805
802 Modified version which optionally strips the topmost entries from the
806 Modified version which optionally strips the topmost entries from the
803 traceback, to be used with alternate interpreters (because their own code
807 traceback, to be used with alternate interpreters (because their own code
804 would appear in the traceback)."""
808 would appear in the traceback)."""
805
809
806 def __init__(self, color_scheme='Linux', call_pdb=False, ostream=None,
810 def __init__(self, color_scheme='Linux', call_pdb=False, ostream=None,
807 tb_offset=0, long_header=False, include_vars=True,
811 tb_offset=0, long_header=False, include_vars=True,
808 check_cache=None):
812 check_cache=None):
809 """Specify traceback offset, headers and color scheme.
813 """Specify traceback offset, headers and color scheme.
810
814
811 Define how many frames to drop from the tracebacks. Calling it with
815 Define how many frames to drop from the tracebacks. Calling it with
812 tb_offset=1 allows use of this handler in interpreters which will have
816 tb_offset=1 allows use of this handler in interpreters which will have
813 their own code at the top of the traceback (VerboseTB will first
817 their own code at the top of the traceback (VerboseTB will first
814 remove that frame before printing the traceback info)."""
818 remove that frame before printing the traceback info)."""
815 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
819 TBTools.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
816 ostream=ostream)
820 ostream=ostream)
817 self.tb_offset = tb_offset
821 self.tb_offset = tb_offset
818 self.long_header = long_header
822 self.long_header = long_header
819 self.include_vars = include_vars
823 self.include_vars = include_vars
820 # By default we use linecache.checkcache, but the user can provide a
824 # By default we use linecache.checkcache, but the user can provide a
821 # different check_cache implementation. This is used by the IPython
825 # different check_cache implementation. This is used by the IPython
822 # kernel to provide tracebacks for interactive code that is cached,
826 # kernel to provide tracebacks for interactive code that is cached,
823 # by a compiler instance that flushes the linecache but preserves its
827 # by a compiler instance that flushes the linecache but preserves its
824 # own code cache.
828 # own code cache.
825 if check_cache is None:
829 if check_cache is None:
826 check_cache = linecache.checkcache
830 check_cache = linecache.checkcache
827 self.check_cache = check_cache
831 self.check_cache = check_cache
828
832
829 def format_records(self, records, last_unique, recursion_repeat):
833 def format_records(self, records, last_unique, recursion_repeat):
830 """Format the stack frames of the traceback"""
834 """Format the stack frames of the traceback"""
831 frames = []
835 frames = []
832 for r in records[:last_unique+recursion_repeat+1]:
836 for r in records[:last_unique+recursion_repeat+1]:
833 #print '*** record:',file,lnum,func,lines,index # dbg
837 #print '*** record:',file,lnum,func,lines,index # dbg
834 frames.append(self.format_record(*r))
838 frames.append(self.format_record(*r))
835
839
836 if recursion_repeat:
840 if recursion_repeat:
837 frames.append('... last %d frames repeated, from the frame below ...\n' % recursion_repeat)
841 frames.append('... last %d frames repeated, from the frame below ...\n' % recursion_repeat)
838 frames.append(self.format_record(*records[last_unique+recursion_repeat+1]))
842 frames.append(self.format_record(*records[last_unique+recursion_repeat+1]))
839
843
840 return frames
844 return frames
841
845
842 def format_record(self, frame, file, lnum, func, lines, index):
846 def format_record(self, frame, file, lnum, func, lines, index):
843 """Format a single stack frame"""
847 """Format a single stack frame"""
844 Colors = self.Colors # just a shorthand + quicker name lookup
848 Colors = self.Colors # just a shorthand + quicker name lookup
845 ColorsNormal = Colors.Normal # used a lot
849 ColorsNormal = Colors.Normal # used a lot
846 col_scheme = self.color_scheme_table.active_scheme_name
850 col_scheme = self.color_scheme_table.active_scheme_name
847 indent = ' ' * INDENT_SIZE
851 indent = ' ' * INDENT_SIZE
848 em_normal = '%s\n%s%s' % (Colors.valEm, indent, ColorsNormal)
852 em_normal = '%s\n%s%s' % (Colors.valEm, indent, ColorsNormal)
849 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
853 undefined = '%sundefined%s' % (Colors.em, ColorsNormal)
850 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
854 tpl_link = '%s%%s%s' % (Colors.filenameEm, ColorsNormal)
851 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
855 tpl_call = 'in %s%%s%s%%s%s' % (Colors.vName, Colors.valEm,
852 ColorsNormal)
856 ColorsNormal)
853 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
857 tpl_call_fail = 'in %s%%s%s(***failed resolving arguments***)%s' % \
854 (Colors.vName, Colors.valEm, ColorsNormal)
858 (Colors.vName, Colors.valEm, ColorsNormal)
855 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
859 tpl_local_var = '%s%%s%s' % (Colors.vName, ColorsNormal)
856 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
860 tpl_global_var = '%sglobal%s %s%%s%s' % (Colors.em, ColorsNormal,
857 Colors.vName, ColorsNormal)
861 Colors.vName, ColorsNormal)
858 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
862 tpl_name_val = '%%s %s= %%s%s' % (Colors.valEm, ColorsNormal)
859
863
860 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
864 tpl_line = '%s%%s%s %%s' % (Colors.lineno, ColorsNormal)
861 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm, Colors.line,
865 tpl_line_em = '%s%%s%s %%s%s' % (Colors.linenoEm, Colors.line,
862 ColorsNormal)
866 ColorsNormal)
863
867
864 abspath = os.path.abspath
868 abspath = os.path.abspath
865
869
866
870
867 if not file:
871 if not file:
868 file = '?'
872 file = '?'
869 elif file.startswith(str("<")) and file.endswith(str(">")):
873 elif file.startswith(str("<")) and file.endswith(str(">")):
870 # Not a real filename, no problem...
874 # Not a real filename, no problem...
871 pass
875 pass
872 elif not os.path.isabs(file):
876 elif not os.path.isabs(file):
873 # Try to make the filename absolute by trying all
877 # Try to make the filename absolute by trying all
874 # sys.path entries (which is also what linecache does)
878 # sys.path entries (which is also what linecache does)
875 for dirname in sys.path:
879 for dirname in sys.path:
876 try:
880 try:
877 fullname = os.path.join(dirname, file)
881 fullname = os.path.join(dirname, file)
878 if os.path.isfile(fullname):
882 if os.path.isfile(fullname):
879 file = os.path.abspath(fullname)
883 file = os.path.abspath(fullname)
880 break
884 break
881 except Exception:
885 except Exception:
882 # Just in case that sys.path contains very
886 # Just in case that sys.path contains very
883 # strange entries...
887 # strange entries...
884 pass
888 pass
885
889
886 file = py3compat.cast_unicode(file, util_path.fs_encoding)
890 file = py3compat.cast_unicode(file, util_path.fs_encoding)
887 link = tpl_link % file
891 link = tpl_link % file
888 args, varargs, varkw, locals = fixed_getargvalues(frame)
892 args, varargs, varkw, locals = fixed_getargvalues(frame)
889
893
890 if func == '?':
894 if func == '?':
891 call = ''
895 call = ''
892 else:
896 else:
893 # Decide whether to include variable details or not
897 # Decide whether to include variable details or not
894 var_repr = self.include_vars and eqrepr or nullrepr
898 var_repr = self.include_vars and eqrepr or nullrepr
895 try:
899 try:
896 call = tpl_call % (func, inspect.formatargvalues(args,
900 call = tpl_call % (func, inspect.formatargvalues(args,
897 varargs, varkw,
901 varargs, varkw,
898 locals, formatvalue=var_repr))
902 locals, formatvalue=var_repr))
899 except KeyError:
903 except KeyError:
900 # This happens in situations like errors inside generator
904 # This happens in situations like errors inside generator
901 # expressions, where local variables are listed in the
905 # expressions, where local variables are listed in the
902 # line, but can't be extracted from the frame. I'm not
906 # line, but can't be extracted from the frame. I'm not
903 # 100% sure this isn't actually a bug in inspect itself,
907 # 100% sure this isn't actually a bug in inspect itself,
904 # but since there's no info for us to compute with, the
908 # but since there's no info for us to compute with, the
905 # best we can do is report the failure and move on. Here
909 # best we can do is report the failure and move on. Here
906 # we must *not* call any traceback construction again,
910 # we must *not* call any traceback construction again,
907 # because that would mess up use of %debug later on. So we
911 # because that would mess up use of %debug later on. So we
908 # simply report the failure and move on. The only
912 # simply report the failure and move on. The only
909 # limitation will be that this frame won't have locals
913 # limitation will be that this frame won't have locals
910 # listed in the call signature. Quite subtle problem...
914 # listed in the call signature. Quite subtle problem...
911 # I can't think of a good way to validate this in a unit
915 # I can't think of a good way to validate this in a unit
912 # test, but running a script consisting of:
916 # test, but running a script consisting of:
913 # dict( (k,v.strip()) for (k,v) in range(10) )
917 # dict( (k,v.strip()) for (k,v) in range(10) )
914 # will illustrate the error, if this exception catch is
918 # will illustrate the error, if this exception catch is
915 # disabled.
919 # disabled.
916 call = tpl_call_fail % func
920 call = tpl_call_fail % func
917
921
918 # Don't attempt to tokenize binary files.
922 # Don't attempt to tokenize binary files.
919 if file.endswith(('.so', '.pyd', '.dll')):
923 if file.endswith(('.so', '.pyd', '.dll')):
920 return '%s %s\n' % (link, call)
924 return '%s %s\n' % (link, call)
921
925
922 elif file.endswith(('.pyc', '.pyo')):
926 elif file.endswith(('.pyc', '.pyo')):
923 # Look up the corresponding source file.
927 # Look up the corresponding source file.
924 file = openpy.source_from_cache(file)
928 file = openpy.source_from_cache(file)
925
929
926 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
930 def linereader(file=file, lnum=[lnum], getline=ulinecache.getline):
927 line = getline(file, lnum[0])
931 line = getline(file, lnum[0])
928 lnum[0] += 1
932 lnum[0] += 1
929 return line
933 return line
930
934
931 # Build the list of names on this line of code where the exception
935 # Build the list of names on this line of code where the exception
932 # occurred.
936 # occurred.
933 try:
937 try:
934 names = []
938 names = []
935 name_cont = False
939 name_cont = False
936
940
937 for token_type, token, start, end, line in generate_tokens(linereader):
941 for token_type, token, start, end, line in generate_tokens(linereader):
938 # build composite names
942 # build composite names
939 if token_type == tokenize.NAME and token not in keyword.kwlist:
943 if token_type == tokenize.NAME and token not in keyword.kwlist:
940 if name_cont:
944 if name_cont:
941 # Continuation of a dotted name
945 # Continuation of a dotted name
942 try:
946 try:
943 names[-1].append(token)
947 names[-1].append(token)
944 except IndexError:
948 except IndexError:
945 names.append([token])
949 names.append([token])
946 name_cont = False
950 name_cont = False
947 else:
951 else:
948 # Regular new names. We append everything, the caller
952 # Regular new names. We append everything, the caller
949 # will be responsible for pruning the list later. It's
953 # will be responsible for pruning the list later. It's
950 # very tricky to try to prune as we go, b/c composite
954 # very tricky to try to prune as we go, b/c composite
951 # names can fool us. The pruning at the end is easy
955 # names can fool us. The pruning at the end is easy
952 # to do (or the caller can print a list with repeated
956 # to do (or the caller can print a list with repeated
953 # names if so desired.
957 # names if so desired.
954 names.append([token])
958 names.append([token])
955 elif token == '.':
959 elif token == '.':
956 name_cont = True
960 name_cont = True
957 elif token_type == tokenize.NEWLINE:
961 elif token_type == tokenize.NEWLINE:
958 break
962 break
959
963
960 except (IndexError, UnicodeDecodeError, SyntaxError):
964 except (IndexError, UnicodeDecodeError, SyntaxError):
961 # signals exit of tokenizer
965 # signals exit of tokenizer
962 # SyntaxError can occur if the file is not actually Python
966 # SyntaxError can occur if the file is not actually Python
963 # - see gh-6300
967 # - see gh-6300
964 pass
968 pass
965 except tokenize.TokenError as msg:
969 except tokenize.TokenError as msg:
966 _m = ("An unexpected error occurred while tokenizing input\n"
970 _m = ("An unexpected error occurred while tokenizing input\n"
967 "The following traceback may be corrupted or invalid\n"
971 "The following traceback may be corrupted or invalid\n"
968 "The error message is: %s\n" % msg)
972 "The error message is: %s\n" % msg)
969 error(_m)
973 error(_m)
970
974
971 # Join composite names (e.g. "dict.fromkeys")
975 # Join composite names (e.g. "dict.fromkeys")
972 names = ['.'.join(n) for n in names]
976 names = ['.'.join(n) for n in names]
973 # prune names list of duplicates, but keep the right order
977 # prune names list of duplicates, but keep the right order
974 unique_names = uniq_stable(names)
978 unique_names = uniq_stable(names)
975
979
976 # Start loop over vars
980 # Start loop over vars
977 lvals = []
981 lvals = []
978 if self.include_vars:
982 if self.include_vars:
979 for name_full in unique_names:
983 for name_full in unique_names:
980 name_base = name_full.split('.', 1)[0]
984 name_base = name_full.split('.', 1)[0]
981 if name_base in frame.f_code.co_varnames:
985 if name_base in frame.f_code.co_varnames:
982 if name_base in locals:
986 if name_base in locals:
983 try:
987 try:
984 value = repr(eval(name_full, locals))
988 value = repr(eval(name_full, locals))
985 except:
989 except:
986 value = undefined
990 value = undefined
987 else:
991 else:
988 value = undefined
992 value = undefined
989 name = tpl_local_var % name_full
993 name = tpl_local_var % name_full
990 else:
994 else:
991 if name_base in frame.f_globals:
995 if name_base in frame.f_globals:
992 try:
996 try:
993 value = repr(eval(name_full, frame.f_globals))
997 value = repr(eval(name_full, frame.f_globals))
994 except:
998 except:
995 value = undefined
999 value = undefined
996 else:
1000 else:
997 value = undefined
1001 value = undefined
998 name = tpl_global_var % name_full
1002 name = tpl_global_var % name_full
999 lvals.append(tpl_name_val % (name, value))
1003 lvals.append(tpl_name_val % (name, value))
1000 if lvals:
1004 if lvals:
1001 lvals = '%s%s' % (indent, em_normal.join(lvals))
1005 lvals = '%s%s' % (indent, em_normal.join(lvals))
1002 else:
1006 else:
1003 lvals = ''
1007 lvals = ''
1004
1008
1005 level = '%s %s\n' % (link, call)
1009 level = '%s %s\n' % (link, call)
1006
1010
1007 if index is None:
1011 if index is None:
1008 return level
1012 return level
1009 else:
1013 else:
1010 return '%s%s' % (level, ''.join(
1014 return '%s%s' % (level, ''.join(
1011 _format_traceback_lines(lnum, index, lines, Colors, lvals,
1015 _format_traceback_lines(lnum, index, lines, Colors, lvals,
1012 col_scheme)))
1016 col_scheme)))
1013
1017
1014 def prepare_chained_exception_message(self, cause):
1018 def prepare_chained_exception_message(self, cause):
1015 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
1019 direct_cause = "\nThe above exception was the direct cause of the following exception:\n"
1016 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
1020 exception_during_handling = "\nDuring handling of the above exception, another exception occurred:\n"
1017
1021
1018 if cause:
1022 if cause:
1019 message = [[direct_cause]]
1023 message = [[direct_cause]]
1020 else:
1024 else:
1021 message = [[exception_during_handling]]
1025 message = [[exception_during_handling]]
1022 return message
1026 return message
1023
1027
1024 def prepare_header(self, etype, long_version=False):
1028 def prepare_header(self, etype, long_version=False):
1025 colors = self.Colors # just a shorthand + quicker name lookup
1029 colors = self.Colors # just a shorthand + quicker name lookup
1026 colorsnormal = colors.Normal # used a lot
1030 colorsnormal = colors.Normal # used a lot
1027 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
1031 exc = '%s%s%s' % (colors.excName, etype, colorsnormal)
1028 if long_version:
1032 if long_version:
1029 # Header with the exception type, python version, and date
1033 # Header with the exception type, python version, and date
1030 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
1034 pyver = 'Python ' + sys.version.split()[0] + ': ' + sys.executable
1031 date = time.ctime(time.time())
1035 date = time.ctime(time.time())
1032
1036
1033 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * 75, colorsnormal,
1037 head = '%s%s%s\n%s%s%s\n%s' % (colors.topline, '-' * 75, colorsnormal,
1034 exc, ' ' * (75 - len(str(etype)) - len(pyver)),
1038 exc, ' ' * (75 - len(str(etype)) - len(pyver)),
1035 pyver, date.rjust(75) )
1039 pyver, date.rjust(75) )
1036 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
1040 head += "\nA problem occurred executing Python code. Here is the sequence of function" \
1037 "\ncalls leading up to the error, with the most recent (innermost) call last."
1041 "\ncalls leading up to the error, with the most recent (innermost) call last."
1038 else:
1042 else:
1039 # Simplified header
1043 # Simplified header
1040 head = '%s%s' % (exc, 'Traceback (most recent call last)'. \
1044 head = '%s%s' % (exc, 'Traceback (most recent call last)'. \
1041 rjust(75 - len(str(etype))) )
1045 rjust(75 - len(str(etype))) )
1042
1046
1043 return head
1047 return head
1044
1048
1045 def format_exception(self, etype, evalue):
1049 def format_exception(self, etype, evalue):
1046 colors = self.Colors # just a shorthand + quicker name lookup
1050 colors = self.Colors # just a shorthand + quicker name lookup
1047 colorsnormal = colors.Normal # used a lot
1051 colorsnormal = colors.Normal # used a lot
1048 indent = ' ' * INDENT_SIZE
1052 indent = ' ' * INDENT_SIZE
1049 # Get (safely) a string form of the exception info
1053 # Get (safely) a string form of the exception info
1050 try:
1054 try:
1051 etype_str, evalue_str = map(str, (etype, evalue))
1055 etype_str, evalue_str = map(str, (etype, evalue))
1052 except:
1056 except:
1053 # User exception is improperly defined.
1057 # User exception is improperly defined.
1054 etype, evalue = str, sys.exc_info()[:2]
1058 etype, evalue = str, sys.exc_info()[:2]
1055 etype_str, evalue_str = map(str, (etype, evalue))
1059 etype_str, evalue_str = map(str, (etype, evalue))
1056 # ... and format it
1060 # ... and format it
1057 exception = ['%s%s%s: %s' % (colors.excName, etype_str,
1061 exception = ['%s%s%s: %s' % (colors.excName, etype_str,
1058 colorsnormal, py3compat.cast_unicode(evalue_str))]
1062 colorsnormal, py3compat.cast_unicode(evalue_str))]
1059
1063
1060 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
1064 if (not py3compat.PY3) and type(evalue) is types.InstanceType:
1061 try:
1065 try:
1062 names = [w for w in dir(evalue) if isinstance(w, py3compat.string_types)]
1066 names = [w for w in dir(evalue) if isinstance(w, py3compat.string_types)]
1063 except:
1067 except:
1064 # Every now and then, an object with funny internals blows up
1068 # Every now and then, an object with funny internals blows up
1065 # when dir() is called on it. We do the best we can to report
1069 # when dir() is called on it. We do the best we can to report
1066 # the problem and continue
1070 # the problem and continue
1067 _m = '%sException reporting error (object with broken dir())%s:'
1071 _m = '%sException reporting error (object with broken dir())%s:'
1068 exception.append(_m % (colors.excName, colorsnormal))
1072 exception.append(_m % (colors.excName, colorsnormal))
1069 etype_str, evalue_str = map(str, sys.exc_info()[:2])
1073 etype_str, evalue_str = map(str, sys.exc_info()[:2])
1070 exception.append('%s%s%s: %s' % (colors.excName, etype_str,
1074 exception.append('%s%s%s: %s' % (colors.excName, etype_str,
1071 colorsnormal, py3compat.cast_unicode(evalue_str)))
1075 colorsnormal, py3compat.cast_unicode(evalue_str)))
1072 names = []
1076 names = []
1073 for name in names:
1077 for name in names:
1074 value = text_repr(getattr(evalue, name))
1078 value = text_repr(getattr(evalue, name))
1075 exception.append('\n%s%s = %s' % (indent, name, value))
1079 exception.append('\n%s%s = %s' % (indent, name, value))
1076
1080
1077 return exception
1081 return exception
1078
1082
1079 def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_context, tb_offset):
1083 def format_exception_as_a_whole(self, etype, evalue, etb, number_of_lines_of_context, tb_offset):
1080 """Formats the header, traceback and exception message for a single exception.
1084 """Formats the header, traceback and exception message for a single exception.
1081
1085
1082 This may be called multiple times by Python 3 exception chaining
1086 This may be called multiple times by Python 3 exception chaining
1083 (PEP 3134).
1087 (PEP 3134).
1084 """
1088 """
1085 # some locals
1089 # some locals
1086 orig_etype = etype
1090 orig_etype = etype
1087 try:
1091 try:
1088 etype = etype.__name__
1092 etype = etype.__name__
1089 except AttributeError:
1093 except AttributeError:
1090 pass
1094 pass
1091
1095
1092 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1096 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1093 head = self.prepare_header(etype, self.long_header)
1097 head = self.prepare_header(etype, self.long_header)
1094 records = self.get_records(etb, number_of_lines_of_context, tb_offset)
1098 records = self.get_records(etb, number_of_lines_of_context, tb_offset)
1095
1099
1096 if records is None:
1100 if records is None:
1097 return ""
1101 return ""
1098
1102
1099 last_unique, recursion_repeat = find_recursion(orig_etype, evalue, records)
1103 last_unique, recursion_repeat = find_recursion(orig_etype, evalue, records)
1100
1104
1101 frames = self.format_records(records, last_unique, recursion_repeat)
1105 frames = self.format_records(records, last_unique, recursion_repeat)
1102
1106
1103 formatted_exception = self.format_exception(etype, evalue)
1107 formatted_exception = self.format_exception(etype, evalue)
1104 if records:
1108 if records:
1105 filepath, lnum = records[-1][1:3]
1109 filepath, lnum = records[-1][1:3]
1106 filepath = os.path.abspath(filepath)
1110 filepath = os.path.abspath(filepath)
1107 ipinst = get_ipython()
1111 ipinst = get_ipython()
1108 if ipinst is not None:
1112 if ipinst is not None:
1109 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
1113 ipinst.hooks.synchronize_with_editor(filepath, lnum, 0)
1110
1114
1111 return [[head] + frames + [''.join(formatted_exception[0])]]
1115 return [[head] + frames + [''.join(formatted_exception[0])]]
1112
1116
1113 def get_records(self, etb, number_of_lines_of_context, tb_offset):
1117 def get_records(self, etb, number_of_lines_of_context, tb_offset):
1114 try:
1118 try:
1115 # Try the default getinnerframes and Alex's: Alex's fixes some
1119 # Try the default getinnerframes and Alex's: Alex's fixes some
1116 # problems, but it generates empty tracebacks for console errors
1120 # problems, but it generates empty tracebacks for console errors
1117 # (5 blanks lines) where none should be returned.
1121 # (5 blanks lines) where none should be returned.
1118 return _fixed_getinnerframes(etb, number_of_lines_of_context, tb_offset)
1122 return _fixed_getinnerframes(etb, number_of_lines_of_context, tb_offset)
1119 except:
1123 except:
1120 # FIXME: I've been getting many crash reports from python 2.3
1124 # FIXME: I've been getting many crash reports from python 2.3
1121 # users, traceable to inspect.py. If I can find a small test-case
1125 # users, traceable to inspect.py. If I can find a small test-case
1122 # to reproduce this, I should either write a better workaround or
1126 # to reproduce this, I should either write a better workaround or
1123 # file a bug report against inspect (if that's the real problem).
1127 # file a bug report against inspect (if that's the real problem).
1124 # So far, I haven't been able to find an isolated example to
1128 # So far, I haven't been able to find an isolated example to
1125 # reproduce the problem.
1129 # reproduce the problem.
1126 inspect_error()
1130 inspect_error()
1127 traceback.print_exc(file=self.ostream)
1131 traceback.print_exc(file=self.ostream)
1128 info('\nUnfortunately, your original traceback can not be constructed.\n')
1132 info('\nUnfortunately, your original traceback can not be constructed.\n')
1129 return None
1133 return None
1130
1134
1131 def get_parts_of_chained_exception(self, evalue):
1135 def get_parts_of_chained_exception(self, evalue):
1132 def get_chained_exception(exception_value):
1136 def get_chained_exception(exception_value):
1133 cause = getattr(exception_value, '__cause__', None)
1137 cause = getattr(exception_value, '__cause__', None)
1134 if cause:
1138 if cause:
1135 return cause
1139 return cause
1136 if getattr(exception_value, '__suppress_context__', False):
1140 if getattr(exception_value, '__suppress_context__', False):
1137 return None
1141 return None
1138 return getattr(exception_value, '__context__', None)
1142 return getattr(exception_value, '__context__', None)
1139
1143
1140 chained_evalue = get_chained_exception(evalue)
1144 chained_evalue = get_chained_exception(evalue)
1141
1145
1142 if chained_evalue:
1146 if chained_evalue:
1143 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
1147 return chained_evalue.__class__, chained_evalue, chained_evalue.__traceback__
1144
1148
1145 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
1149 def structured_traceback(self, etype, evalue, etb, tb_offset=None,
1146 number_of_lines_of_context=5):
1150 number_of_lines_of_context=5):
1147 """Return a nice text document describing the traceback."""
1151 """Return a nice text document describing the traceback."""
1148
1152
1149 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
1153 formatted_exception = self.format_exception_as_a_whole(etype, evalue, etb, number_of_lines_of_context,
1150 tb_offset)
1154 tb_offset)
1151
1155
1152 colors = self.Colors # just a shorthand + quicker name lookup
1156 colors = self.Colors # just a shorthand + quicker name lookup
1153 colorsnormal = colors.Normal # used a lot
1157 colorsnormal = colors.Normal # used a lot
1154 head = '%s%s%s' % (colors.topline, '-' * 75, colorsnormal)
1158 head = '%s%s%s' % (colors.topline, '-' * 75, colorsnormal)
1155 structured_traceback_parts = [head]
1159 structured_traceback_parts = [head]
1156 if py3compat.PY3:
1160 if py3compat.PY3:
1157 chained_exceptions_tb_offset = 0
1161 chained_exceptions_tb_offset = 0
1158 lines_of_context = 3
1162 lines_of_context = 3
1159 formatted_exceptions = formatted_exception
1163 formatted_exceptions = formatted_exception
1160 exception = self.get_parts_of_chained_exception(evalue)
1164 exception = self.get_parts_of_chained_exception(evalue)
1161 if exception:
1165 if exception:
1162 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1166 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1163 etype, evalue, etb = exception
1167 etype, evalue, etb = exception
1164 else:
1168 else:
1165 evalue = None
1169 evalue = None
1166 chained_exc_ids = set()
1170 chained_exc_ids = set()
1167 while evalue:
1171 while evalue:
1168 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
1172 formatted_exceptions += self.format_exception_as_a_whole(etype, evalue, etb, lines_of_context,
1169 chained_exceptions_tb_offset)
1173 chained_exceptions_tb_offset)
1170 exception = self.get_parts_of_chained_exception(evalue)
1174 exception = self.get_parts_of_chained_exception(evalue)
1171
1175
1172 if exception and not id(exception[1]) in chained_exc_ids:
1176 if exception and not id(exception[1]) in chained_exc_ids:
1173 chained_exc_ids.add(id(exception[1])) # trace exception to avoid infinite 'cause' loop
1177 chained_exc_ids.add(id(exception[1])) # trace exception to avoid infinite 'cause' loop
1174 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1178 formatted_exceptions += self.prepare_chained_exception_message(evalue.__cause__)
1175 etype, evalue, etb = exception
1179 etype, evalue, etb = exception
1176 else:
1180 else:
1177 evalue = None
1181 evalue = None
1178
1182
1179 # we want to see exceptions in a reversed order:
1183 # we want to see exceptions in a reversed order:
1180 # the first exception should be on top
1184 # the first exception should be on top
1181 for formatted_exception in reversed(formatted_exceptions):
1185 for formatted_exception in reversed(formatted_exceptions):
1182 structured_traceback_parts += formatted_exception
1186 structured_traceback_parts += formatted_exception
1183 else:
1187 else:
1184 structured_traceback_parts += formatted_exception[0]
1188 structured_traceback_parts += formatted_exception[0]
1185
1189
1186 return structured_traceback_parts
1190 return structured_traceback_parts
1187
1191
1188 def debugger(self, force=False):
1192 def debugger(self, force=False):
1189 """Call up the pdb debugger if desired, always clean up the tb
1193 """Call up the pdb debugger if desired, always clean up the tb
1190 reference.
1194 reference.
1191
1195
1192 Keywords:
1196 Keywords:
1193
1197
1194 - force(False): by default, this routine checks the instance call_pdb
1198 - force(False): by default, this routine checks the instance call_pdb
1195 flag and does not actually invoke the debugger if the flag is false.
1199 flag and does not actually invoke the debugger if the flag is false.
1196 The 'force' option forces the debugger to activate even if the flag
1200 The 'force' option forces the debugger to activate even if the flag
1197 is false.
1201 is false.
1198
1202
1199 If the call_pdb flag is set, the pdb interactive debugger is
1203 If the call_pdb flag is set, the pdb interactive debugger is
1200 invoked. In all cases, the self.tb reference to the current traceback
1204 invoked. In all cases, the self.tb reference to the current traceback
1201 is deleted to prevent lingering references which hamper memory
1205 is deleted to prevent lingering references which hamper memory
1202 management.
1206 management.
1203
1207
1204 Note that each call to pdb() does an 'import readline', so if your app
1208 Note that each call to pdb() does an 'import readline', so if your app
1205 requires a special setup for the readline completers, you'll have to
1209 requires a special setup for the readline completers, you'll have to
1206 fix that by hand after invoking the exception handler."""
1210 fix that by hand after invoking the exception handler."""
1207
1211
1208 if force or self.call_pdb:
1212 if force or self.call_pdb:
1209 if self.pdb is None:
1213 if self.pdb is None:
1210 self.pdb = debugger.Pdb(
1214 self.pdb = debugger.Pdb(
1211 self.color_scheme_table.active_scheme_name)
1215 self.color_scheme_table.active_scheme_name)
1212 # the system displayhook may have changed, restore the original
1216 # the system displayhook may have changed, restore the original
1213 # for pdb
1217 # for pdb
1214 display_trap = DisplayTrap(hook=sys.__displayhook__)
1218 display_trap = DisplayTrap(hook=sys.__displayhook__)
1215 with display_trap:
1219 with display_trap:
1216 self.pdb.reset()
1220 self.pdb.reset()
1217 # Find the right frame so we don't pop up inside ipython itself
1221 # Find the right frame so we don't pop up inside ipython itself
1218 if hasattr(self, 'tb') and self.tb is not None:
1222 if hasattr(self, 'tb') and self.tb is not None:
1219 etb = self.tb
1223 etb = self.tb
1220 else:
1224 else:
1221 etb = self.tb = sys.last_traceback
1225 etb = self.tb = sys.last_traceback
1222 while self.tb is not None and self.tb.tb_next is not None:
1226 while self.tb is not None and self.tb.tb_next is not None:
1223 self.tb = self.tb.tb_next
1227 self.tb = self.tb.tb_next
1224 if etb and etb.tb_next:
1228 if etb and etb.tb_next:
1225 etb = etb.tb_next
1229 etb = etb.tb_next
1226 self.pdb.botframe = etb.tb_frame
1230 self.pdb.botframe = etb.tb_frame
1227 self.pdb.interaction(self.tb.tb_frame, self.tb)
1231 self.pdb.interaction(self.tb.tb_frame, self.tb)
1228
1232
1229 if hasattr(self, 'tb'):
1233 if hasattr(self, 'tb'):
1230 del self.tb
1234 del self.tb
1231
1235
1232 def handler(self, info=None):
1236 def handler(self, info=None):
1233 (etype, evalue, etb) = info or sys.exc_info()
1237 (etype, evalue, etb) = info or sys.exc_info()
1234 self.tb = etb
1238 self.tb = etb
1235 ostream = self.ostream
1239 ostream = self.ostream
1236 ostream.flush()
1240 ostream.flush()
1237 ostream.write(self.text(etype, evalue, etb))
1241 ostream.write(self.text(etype, evalue, etb))
1238 ostream.write('\n')
1242 ostream.write('\n')
1239 ostream.flush()
1243 ostream.flush()
1240
1244
1241 # Changed so an instance can just be called as VerboseTB_inst() and print
1245 # Changed so an instance can just be called as VerboseTB_inst() and print
1242 # out the right info on its own.
1246 # out the right info on its own.
1243 def __call__(self, etype=None, evalue=None, etb=None):
1247 def __call__(self, etype=None, evalue=None, etb=None):
1244 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1248 """This hook can replace sys.excepthook (for Python 2.1 or higher)."""
1245 if etb is None:
1249 if etb is None:
1246 self.handler()
1250 self.handler()
1247 else:
1251 else:
1248 self.handler((etype, evalue, etb))
1252 self.handler((etype, evalue, etb))
1249 try:
1253 try:
1250 self.debugger()
1254 self.debugger()
1251 except KeyboardInterrupt:
1255 except KeyboardInterrupt:
1252 print("\nKeyboardInterrupt")
1256 print("\nKeyboardInterrupt")
1253
1257
1254
1258
1255 #----------------------------------------------------------------------------
1259 #----------------------------------------------------------------------------
1256 class FormattedTB(VerboseTB, ListTB):
1260 class FormattedTB(VerboseTB, ListTB):
1257 """Subclass ListTB but allow calling with a traceback.
1261 """Subclass ListTB but allow calling with a traceback.
1258
1262
1259 It can thus be used as a sys.excepthook for Python > 2.1.
1263 It can thus be used as a sys.excepthook for Python > 2.1.
1260
1264
1261 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1265 Also adds 'Context' and 'Verbose' modes, not available in ListTB.
1262
1266
1263 Allows a tb_offset to be specified. This is useful for situations where
1267 Allows a tb_offset to be specified. This is useful for situations where
1264 one needs to remove a number of topmost frames from the traceback (such as
1268 one needs to remove a number of topmost frames from the traceback (such as
1265 occurs with python programs that themselves execute other python code,
1269 occurs with python programs that themselves execute other python code,
1266 like Python shells). """
1270 like Python shells). """
1267
1271
1268 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1272 def __init__(self, mode='Plain', color_scheme='Linux', call_pdb=False,
1269 ostream=None,
1273 ostream=None,
1270 tb_offset=0, long_header=False, include_vars=False,
1274 tb_offset=0, long_header=False, include_vars=False,
1271 check_cache=None):
1275 check_cache=None):
1272
1276
1273 # NEVER change the order of this list. Put new modes at the end:
1277 # NEVER change the order of this list. Put new modes at the end:
1274 self.valid_modes = ['Plain', 'Context', 'Verbose']
1278 self.valid_modes = ['Plain', 'Context', 'Verbose']
1275 self.verbose_modes = self.valid_modes[1:3]
1279 self.verbose_modes = self.valid_modes[1:3]
1276
1280
1277 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1281 VerboseTB.__init__(self, color_scheme=color_scheme, call_pdb=call_pdb,
1278 ostream=ostream, tb_offset=tb_offset,
1282 ostream=ostream, tb_offset=tb_offset,
1279 long_header=long_header, include_vars=include_vars,
1283 long_header=long_header, include_vars=include_vars,
1280 check_cache=check_cache)
1284 check_cache=check_cache)
1281
1285
1282 # Different types of tracebacks are joined with different separators to
1286 # Different types of tracebacks are joined with different separators to
1283 # form a single string. They are taken from this dict
1287 # form a single string. They are taken from this dict
1284 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1288 self._join_chars = dict(Plain='', Context='\n', Verbose='\n')
1285 # set_mode also sets the tb_join_char attribute
1289 # set_mode also sets the tb_join_char attribute
1286 self.set_mode(mode)
1290 self.set_mode(mode)
1287
1291
1288 def _extract_tb(self, tb):
1292 def _extract_tb(self, tb):
1289 if tb:
1293 if tb:
1290 return traceback.extract_tb(tb)
1294 return traceback.extract_tb(tb)
1291 else:
1295 else:
1292 return None
1296 return None
1293
1297
1294 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
1298 def structured_traceback(self, etype, value, tb, tb_offset=None, number_of_lines_of_context=5):
1295 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1299 tb_offset = self.tb_offset if tb_offset is None else tb_offset
1296 mode = self.mode
1300 mode = self.mode
1297 if mode in self.verbose_modes:
1301 if mode in self.verbose_modes:
1298 # Verbose modes need a full traceback
1302 # Verbose modes need a full traceback
1299 return VerboseTB.structured_traceback(
1303 return VerboseTB.structured_traceback(
1300 self, etype, value, tb, tb_offset, number_of_lines_of_context
1304 self, etype, value, tb, tb_offset, number_of_lines_of_context
1301 )
1305 )
1302 else:
1306 else:
1303 # We must check the source cache because otherwise we can print
1307 # We must check the source cache because otherwise we can print
1304 # out-of-date source code.
1308 # out-of-date source code.
1305 self.check_cache()
1309 self.check_cache()
1306 # Now we can extract and format the exception
1310 # Now we can extract and format the exception
1307 elist = self._extract_tb(tb)
1311 elist = self._extract_tb(tb)
1308 return ListTB.structured_traceback(
1312 return ListTB.structured_traceback(
1309 self, etype, value, elist, tb_offset, number_of_lines_of_context
1313 self, etype, value, elist, tb_offset, number_of_lines_of_context
1310 )
1314 )
1311
1315
1312 def stb2text(self, stb):
1316 def stb2text(self, stb):
1313 """Convert a structured traceback (a list) to a string."""
1317 """Convert a structured traceback (a list) to a string."""
1314 return self.tb_join_char.join(stb)
1318 return self.tb_join_char.join(stb)
1315
1319
1316
1320
1317 def set_mode(self, mode=None):
1321 def set_mode(self, mode=None):
1318 """Switch to the desired mode.
1322 """Switch to the desired mode.
1319
1323
1320 If mode is not specified, cycles through the available modes."""
1324 If mode is not specified, cycles through the available modes."""
1321
1325
1322 if not mode:
1326 if not mode:
1323 new_idx = (self.valid_modes.index(self.mode) + 1 ) % \
1327 new_idx = (self.valid_modes.index(self.mode) + 1 ) % \
1324 len(self.valid_modes)
1328 len(self.valid_modes)
1325 self.mode = self.valid_modes[new_idx]
1329 self.mode = self.valid_modes[new_idx]
1326 elif mode not in self.valid_modes:
1330 elif mode not in self.valid_modes:
1327 raise ValueError('Unrecognized mode in FormattedTB: <' + mode + '>\n'
1331 raise ValueError('Unrecognized mode in FormattedTB: <' + mode + '>\n'
1328 'Valid modes: ' + str(self.valid_modes))
1332 'Valid modes: ' + str(self.valid_modes))
1329 else:
1333 else:
1330 self.mode = mode
1334 self.mode = mode
1331 # include variable details only in 'Verbose' mode
1335 # include variable details only in 'Verbose' mode
1332 self.include_vars = (self.mode == self.valid_modes[2])
1336 self.include_vars = (self.mode == self.valid_modes[2])
1333 # Set the join character for generating text tracebacks
1337 # Set the join character for generating text tracebacks
1334 self.tb_join_char = self._join_chars[self.mode]
1338 self.tb_join_char = self._join_chars[self.mode]
1335
1339
1336 # some convenient shortcuts
1340 # some convenient shortcuts
1337 def plain(self):
1341 def plain(self):
1338 self.set_mode(self.valid_modes[0])
1342 self.set_mode(self.valid_modes[0])
1339
1343
1340 def context(self):
1344 def context(self):
1341 self.set_mode(self.valid_modes[1])
1345 self.set_mode(self.valid_modes[1])
1342
1346
1343 def verbose(self):
1347 def verbose(self):
1344 self.set_mode(self.valid_modes[2])
1348 self.set_mode(self.valid_modes[2])
1345
1349
1346
1350
1347 #----------------------------------------------------------------------------
1351 #----------------------------------------------------------------------------
1348 class AutoFormattedTB(FormattedTB):
1352 class AutoFormattedTB(FormattedTB):
1349 """A traceback printer which can be called on the fly.
1353 """A traceback printer which can be called on the fly.
1350
1354
1351 It will find out about exceptions by itself.
1355 It will find out about exceptions by itself.
1352
1356
1353 A brief example::
1357 A brief example::
1354
1358
1355 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1359 AutoTB = AutoFormattedTB(mode = 'Verbose',color_scheme='Linux')
1356 try:
1360 try:
1357 ...
1361 ...
1358 except:
1362 except:
1359 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1363 AutoTB() # or AutoTB(out=logfile) where logfile is an open file object
1360 """
1364 """
1361
1365
1362 def __call__(self, etype=None, evalue=None, etb=None,
1366 def __call__(self, etype=None, evalue=None, etb=None,
1363 out=None, tb_offset=None):
1367 out=None, tb_offset=None):
1364 """Print out a formatted exception traceback.
1368 """Print out a formatted exception traceback.
1365
1369
1366 Optional arguments:
1370 Optional arguments:
1367 - out: an open file-like object to direct output to.
1371 - out: an open file-like object to direct output to.
1368
1372
1369 - tb_offset: the number of frames to skip over in the stack, on a
1373 - tb_offset: the number of frames to skip over in the stack, on a
1370 per-call basis (this overrides temporarily the instance's tb_offset
1374 per-call basis (this overrides temporarily the instance's tb_offset
1371 given at initialization time. """
1375 given at initialization time. """
1372
1376
1373 if out is None:
1377 if out is None:
1374 out = self.ostream
1378 out = self.ostream
1375 out.flush()
1379 out.flush()
1376 out.write(self.text(etype, evalue, etb, tb_offset))
1380 out.write(self.text(etype, evalue, etb, tb_offset))
1377 out.write('\n')
1381 out.write('\n')
1378 out.flush()
1382 out.flush()
1379 # FIXME: we should remove the auto pdb behavior from here and leave
1383 # FIXME: we should remove the auto pdb behavior from here and leave
1380 # that to the clients.
1384 # that to the clients.
1381 try:
1385 try:
1382 self.debugger()
1386 self.debugger()
1383 except KeyboardInterrupt:
1387 except KeyboardInterrupt:
1384 print("\nKeyboardInterrupt")
1388 print("\nKeyboardInterrupt")
1385
1389
1386 def structured_traceback(self, etype=None, value=None, tb=None,
1390 def structured_traceback(self, etype=None, value=None, tb=None,
1387 tb_offset=None, number_of_lines_of_context=5):
1391 tb_offset=None, number_of_lines_of_context=5):
1388 if etype is None:
1392 if etype is None:
1389 etype, value, tb = sys.exc_info()
1393 etype, value, tb = sys.exc_info()
1390 self.tb = tb
1394 self.tb = tb
1391 return FormattedTB.structured_traceback(
1395 return FormattedTB.structured_traceback(
1392 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1396 self, etype, value, tb, tb_offset, number_of_lines_of_context)
1393
1397
1394
1398
1395 #---------------------------------------------------------------------------
1399 #---------------------------------------------------------------------------
1396
1400
1397 # A simple class to preserve Nathan's original functionality.
1401 # A simple class to preserve Nathan's original functionality.
1398 class ColorTB(FormattedTB):
1402 class ColorTB(FormattedTB):
1399 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1403 """Shorthand to initialize a FormattedTB in Linux colors mode."""
1400
1404
1401 def __init__(self, color_scheme='Linux', call_pdb=0, **kwargs):
1405 def __init__(self, color_scheme='Linux', call_pdb=0, **kwargs):
1402 FormattedTB.__init__(self, color_scheme=color_scheme,
1406 FormattedTB.__init__(self, color_scheme=color_scheme,
1403 call_pdb=call_pdb, **kwargs)
1407 call_pdb=call_pdb, **kwargs)
1404
1408
1405
1409
1406 class SyntaxTB(ListTB):
1410 class SyntaxTB(ListTB):
1407 """Extension which holds some state: the last exception value"""
1411 """Extension which holds some state: the last exception value"""
1408
1412
1409 def __init__(self, color_scheme='NoColor'):
1413 def __init__(self, color_scheme='NoColor'):
1410 ListTB.__init__(self, color_scheme)
1414 ListTB.__init__(self, color_scheme)
1411 self.last_syntax_error = None
1415 self.last_syntax_error = None
1412
1416
1413 def __call__(self, etype, value, elist):
1417 def __call__(self, etype, value, elist):
1414 self.last_syntax_error = value
1418 self.last_syntax_error = value
1415
1419
1416 ListTB.__call__(self, etype, value, elist)
1420 ListTB.__call__(self, etype, value, elist)
1417
1421
1418 def structured_traceback(self, etype, value, elist, tb_offset=None,
1422 def structured_traceback(self, etype, value, elist, tb_offset=None,
1419 context=5):
1423 context=5):
1420 # If the source file has been edited, the line in the syntax error can
1424 # If the source file has been edited, the line in the syntax error can
1421 # be wrong (retrieved from an outdated cache). This replaces it with
1425 # be wrong (retrieved from an outdated cache). This replaces it with
1422 # the current value.
1426 # the current value.
1423 if isinstance(value, SyntaxError) \
1427 if isinstance(value, SyntaxError) \
1424 and isinstance(value.filename, py3compat.string_types) \
1428 and isinstance(value.filename, py3compat.string_types) \
1425 and isinstance(value.lineno, int):
1429 and isinstance(value.lineno, int):
1426 linecache.checkcache(value.filename)
1430 linecache.checkcache(value.filename)
1427 newtext = ulinecache.getline(value.filename, value.lineno)
1431 newtext = ulinecache.getline(value.filename, value.lineno)
1428 if newtext:
1432 if newtext:
1429 value.text = newtext
1433 value.text = newtext
1430 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1434 return super(SyntaxTB, self).structured_traceback(etype, value, elist,
1431 tb_offset=tb_offset, context=context)
1435 tb_offset=tb_offset, context=context)
1432
1436
1433 def clear_err_state(self):
1437 def clear_err_state(self):
1434 """Return the current error state and clear it"""
1438 """Return the current error state and clear it"""
1435 e = self.last_syntax_error
1439 e = self.last_syntax_error
1436 self.last_syntax_error = None
1440 self.last_syntax_error = None
1437 return e
1441 return e
1438
1442
1439 def stb2text(self, stb):
1443 def stb2text(self, stb):
1440 """Convert a structured traceback (a list) to a string."""
1444 """Convert a structured traceback (a list) to a string."""
1441 return ''.join(stb)
1445 return ''.join(stb)
1442
1446
1443
1447
1444 # some internal-use functions
1448 # some internal-use functions
1445 def text_repr(value):
1449 def text_repr(value):
1446 """Hopefully pretty robust repr equivalent."""
1450 """Hopefully pretty robust repr equivalent."""
1447 # this is pretty horrible but should always return *something*
1451 # this is pretty horrible but should always return *something*
1448 try:
1452 try:
1449 return pydoc.text.repr(value)
1453 return pydoc.text.repr(value)
1450 except KeyboardInterrupt:
1454 except KeyboardInterrupt:
1451 raise
1455 raise
1452 except:
1456 except:
1453 try:
1457 try:
1454 return repr(value)
1458 return repr(value)
1455 except KeyboardInterrupt:
1459 except KeyboardInterrupt:
1456 raise
1460 raise
1457 except:
1461 except:
1458 try:
1462 try:
1459 # all still in an except block so we catch
1463 # all still in an except block so we catch
1460 # getattr raising
1464 # getattr raising
1461 name = getattr(value, '__name__', None)
1465 name = getattr(value, '__name__', None)
1462 if name:
1466 if name:
1463 # ick, recursion
1467 # ick, recursion
1464 return text_repr(name)
1468 return text_repr(name)
1465 klass = getattr(value, '__class__', None)
1469 klass = getattr(value, '__class__', None)
1466 if klass:
1470 if klass:
1467 return '%s instance' % text_repr(klass)
1471 return '%s instance' % text_repr(klass)
1468 except KeyboardInterrupt:
1472 except KeyboardInterrupt:
1469 raise
1473 raise
1470 except:
1474 except:
1471 return 'UNRECOVERABLE REPR FAILURE'
1475 return 'UNRECOVERABLE REPR FAILURE'
1472
1476
1473
1477
1474 def eqrepr(value, repr=text_repr):
1478 def eqrepr(value, repr=text_repr):
1475 return '=%s' % repr(value)
1479 return '=%s' % repr(value)
1476
1480
1477
1481
1478 def nullrepr(value, repr=text_repr):
1482 def nullrepr(value, repr=text_repr):
1479 return ''
1483 return ''
@@ -1,342 +1,347 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 Class and program to colorize python source code for ANSI terminals.
3 Class and program to colorize python source code for ANSI terminals.
4
4
5 Based on an HTML code highlighter by Jurgen Hermann found at:
5 Based on an HTML code highlighter by Jurgen Hermann found at:
6 http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52298
6 http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52298
7
7
8 Modifications by Fernando Perez (fperez@colorado.edu).
8 Modifications by Fernando Perez (fperez@colorado.edu).
9
9
10 Information on the original HTML highlighter follows:
10 Information on the original HTML highlighter follows:
11
11
12 MoinMoin - Python Source Parser
12 MoinMoin - Python Source Parser
13
13
14 Title: Colorize Python source using the built-in tokenizer
14 Title: Colorize Python source using the built-in tokenizer
15
15
16 Submitter: Jurgen Hermann
16 Submitter: Jurgen Hermann
17 Last Updated:2001/04/06
17 Last Updated:2001/04/06
18
18
19 Version no:1.2
19 Version no:1.2
20
20
21 Description:
21 Description:
22
22
23 This code is part of MoinMoin (http://moin.sourceforge.net/) and converts
23 This code is part of MoinMoin (http://moin.sourceforge.net/) and converts
24 Python source code to HTML markup, rendering comments, keywords,
24 Python source code to HTML markup, rendering comments, keywords,
25 operators, numeric and string literals in different colors.
25 operators, numeric and string literals in different colors.
26
26
27 It shows how to use the built-in keyword, token and tokenize modules to
27 It shows how to use the built-in keyword, token and tokenize modules to
28 scan Python source code and re-emit it with no changes to its original
28 scan Python source code and re-emit it with no changes to its original
29 formatting (which is the hard part).
29 formatting (which is the hard part).
30 """
30 """
31 from __future__ import print_function
31 from __future__ import print_function
32 from __future__ import absolute_import
32 from __future__ import absolute_import
33 from __future__ import unicode_literals
33 from __future__ import unicode_literals
34
34
35 __all__ = ['ANSICodeColors','Parser']
35 __all__ = ['ANSICodeColors','Parser']
36
36
37 _scheme_default = 'Linux'
37 _scheme_default = 'Linux'
38
38
39
39
40 # Imports
40 # Imports
41 import keyword
41 import keyword
42 import os
42 import os
43 import sys
43 import sys
44 import token
44 import token
45 import tokenize
45 import tokenize
46
46
47 try:
47 try:
48 generate_tokens = tokenize.generate_tokens
48 generate_tokens = tokenize.generate_tokens
49 except AttributeError:
49 except AttributeError:
50 # Python 3. Note that we use the undocumented _tokenize because it expects
50 # Python 3. Note that we use the undocumented _tokenize because it expects
51 # strings, not bytes. See also Python issue #9969.
51 # strings, not bytes. See also Python issue #9969.
52 generate_tokens = tokenize._tokenize
52 generate_tokens = tokenize._tokenize
53
53
54 from IPython.utils.coloransi import TermColors, InputTermColors ,ColorScheme, ColorSchemeTable
54 from IPython.utils.coloransi import TermColors, InputTermColors ,ColorScheme, ColorSchemeTable
55 from IPython.utils.py3compat import PY3
55 from IPython.utils.py3compat import PY3
56
56
57 from .colorable import Colorable
58
57 if PY3:
59 if PY3:
58 from io import StringIO
60 from io import StringIO
59 else:
61 else:
60 from StringIO import StringIO
62 from StringIO import StringIO
61
63
62 #############################################################################
64 #############################################################################
63 ### Python Source Parser (does Hilighting)
65 ### Python Source Parser (does Hilighting)
64 #############################################################################
66 #############################################################################
65
67
66 _KEYWORD = token.NT_OFFSET + 1
68 _KEYWORD = token.NT_OFFSET + 1
67 _TEXT = token.NT_OFFSET + 2
69 _TEXT = token.NT_OFFSET + 2
68
70
69 #****************************************************************************
71 #****************************************************************************
70 # Builtin color schemes
72 # Builtin color schemes
71
73
72 Colors = TermColors # just a shorthand
74 Colors = TermColors # just a shorthand
73
75
74 # Build a few color schemes
76 # Build a few color schemes
75 NoColor = ColorScheme(
77 NoColor = ColorScheme(
76 'NoColor',{
78 'NoColor',{
77 'header' : Colors.NoColor,
79 'header' : Colors.NoColor,
78 token.NUMBER : Colors.NoColor,
80 token.NUMBER : Colors.NoColor,
79 token.OP : Colors.NoColor,
81 token.OP : Colors.NoColor,
80 token.STRING : Colors.NoColor,
82 token.STRING : Colors.NoColor,
81 tokenize.COMMENT : Colors.NoColor,
83 tokenize.COMMENT : Colors.NoColor,
82 token.NAME : Colors.NoColor,
84 token.NAME : Colors.NoColor,
83 token.ERRORTOKEN : Colors.NoColor,
85 token.ERRORTOKEN : Colors.NoColor,
84
86
85 _KEYWORD : Colors.NoColor,
87 _KEYWORD : Colors.NoColor,
86 _TEXT : Colors.NoColor,
88 _TEXT : Colors.NoColor,
87
89
88 'in_prompt' : InputTermColors.NoColor, # Input prompt
90 'in_prompt' : InputTermColors.NoColor, # Input prompt
89 'in_number' : InputTermColors.NoColor, # Input prompt number
91 'in_number' : InputTermColors.NoColor, # Input prompt number
90 'in_prompt2' : InputTermColors.NoColor, # Continuation prompt
92 'in_prompt2' : InputTermColors.NoColor, # Continuation prompt
91 'in_normal' : InputTermColors.NoColor, # color off (usu. Colors.Normal)
93 'in_normal' : InputTermColors.NoColor, # color off (usu. Colors.Normal)
92
94
93 'out_prompt' : Colors.NoColor, # Output prompt
95 'out_prompt' : Colors.NoColor, # Output prompt
94 'out_number' : Colors.NoColor, # Output prompt number
96 'out_number' : Colors.NoColor, # Output prompt number
95
97
96 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
98 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
97 } )
99 } )
98
100
99 LinuxColors = ColorScheme(
101 LinuxColors = ColorScheme(
100 'Linux',{
102 'Linux',{
101 'header' : Colors.LightRed,
103 'header' : Colors.LightRed,
102 token.NUMBER : Colors.LightCyan,
104 token.NUMBER : Colors.LightCyan,
103 token.OP : Colors.Yellow,
105 token.OP : Colors.Yellow,
104 token.STRING : Colors.LightBlue,
106 token.STRING : Colors.LightBlue,
105 tokenize.COMMENT : Colors.LightRed,
107 tokenize.COMMENT : Colors.LightRed,
106 token.NAME : Colors.Normal,
108 token.NAME : Colors.Normal,
107 token.ERRORTOKEN : Colors.Red,
109 token.ERRORTOKEN : Colors.Red,
108
110
109 _KEYWORD : Colors.LightGreen,
111 _KEYWORD : Colors.LightGreen,
110 _TEXT : Colors.Yellow,
112 _TEXT : Colors.Yellow,
111
113
112 'in_prompt' : InputTermColors.Green,
114 'in_prompt' : InputTermColors.Green,
113 'in_number' : InputTermColors.LightGreen,
115 'in_number' : InputTermColors.LightGreen,
114 'in_prompt2' : InputTermColors.Green,
116 'in_prompt2' : InputTermColors.Green,
115 'in_normal' : InputTermColors.Normal, # color off (usu. Colors.Normal)
117 'in_normal' : InputTermColors.Normal, # color off (usu. Colors.Normal)
116
118
117 'out_prompt' : Colors.Red,
119 'out_prompt' : Colors.Red,
118 'out_number' : Colors.LightRed,
120 'out_number' : Colors.LightRed,
119
121
120 'normal' : Colors.Normal # color off (usu. Colors.Normal)
122 'normal' : Colors.Normal # color off (usu. Colors.Normal)
121 } )
123 } )
122
124
123 LightBGColors = ColorScheme(
125 LightBGColors = ColorScheme(
124 'LightBG',{
126 'LightBG',{
125 'header' : Colors.Red,
127 'header' : Colors.Red,
126 token.NUMBER : Colors.Cyan,
128 token.NUMBER : Colors.Cyan,
127 token.OP : Colors.Blue,
129 token.OP : Colors.Blue,
128 token.STRING : Colors.Blue,
130 token.STRING : Colors.Blue,
129 tokenize.COMMENT : Colors.Red,
131 tokenize.COMMENT : Colors.Red,
130 token.NAME : Colors.Normal,
132 token.NAME : Colors.Normal,
131 token.ERRORTOKEN : Colors.Red,
133 token.ERRORTOKEN : Colors.Red,
132
134
133 _KEYWORD : Colors.Green,
135 _KEYWORD : Colors.Green,
134 _TEXT : Colors.Blue,
136 _TEXT : Colors.Blue,
135
137
136 'in_prompt' : InputTermColors.Blue,
138 'in_prompt' : InputTermColors.Blue,
137 'in_number' : InputTermColors.LightBlue,
139 'in_number' : InputTermColors.LightBlue,
138 'in_prompt2' : InputTermColors.Blue,
140 'in_prompt2' : InputTermColors.Blue,
139 'in_normal' : InputTermColors.Normal, # color off (usu. Colors.Normal)
141 'in_normal' : InputTermColors.Normal, # color off (usu. Colors.Normal)
140
142
141 'out_prompt' : Colors.Red,
143 'out_prompt' : Colors.Red,
142 'out_number' : Colors.LightRed,
144 'out_number' : Colors.LightRed,
143
145
144 'normal' : Colors.Normal # color off (usu. Colors.Normal)
146 'normal' : Colors.Normal # color off (usu. Colors.Normal)
145 } )
147 } )
146
148
147 # Build table of color schemes (needed by the parser)
149 # Build table of color schemes (needed by the parser)
148 ANSICodeColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
150 ANSICodeColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
149 _scheme_default)
151 _scheme_default)
150
152
151 class Parser:
153 class Parser(Colorable):
152 """ Format colored Python source.
154 """ Format colored Python source.
153 """
155 """
154
156
155 def __init__(self, color_table=None,out = sys.stdout):
157 def __init__(self, color_table=None, out = sys.stdout, parent=None, style=None):
156 """ Create a parser with a specified color table and output channel.
158 """ Create a parser with a specified color table and output channel.
157
159
158 Call format() to process code.
160 Call format() to process code.
159 """
161 """
162
163 super(Parser, self).__init__(parent=parent)
164
160 self.color_table = color_table and color_table or ANSICodeColors
165 self.color_table = color_table and color_table or ANSICodeColors
161 self.out = out
166 self.out = out
162
167
163 def format(self, raw, out = None, scheme = ''):
168 def format(self, raw, out = None, scheme = ''):
164 return self.format2(raw, out, scheme)[0]
169 return self.format2(raw, out, scheme)[0]
165
170
166 def format2(self, raw, out = None, scheme = ''):
171 def format2(self, raw, out = None, scheme = ''):
167 """ Parse and send the colored source.
172 """ Parse and send the colored source.
168
173
169 If out and scheme are not specified, the defaults (given to
174 If out and scheme are not specified, the defaults (given to
170 constructor) are used.
175 constructor) are used.
171
176
172 out should be a file-type object. Optionally, out can be given as the
177 out should be a file-type object. Optionally, out can be given as the
173 string 'str' and the parser will automatically return the output in a
178 string 'str' and the parser will automatically return the output in a
174 string."""
179 string."""
175
180
176 string_output = 0
181 string_output = 0
177 if out == 'str' or self.out == 'str' or \
182 if out == 'str' or self.out == 'str' or \
178 isinstance(self.out,StringIO):
183 isinstance(self.out,StringIO):
179 # XXX - I don't really like this state handling logic, but at this
184 # XXX - I don't really like this state handling logic, but at this
180 # point I don't want to make major changes, so adding the
185 # point I don't want to make major changes, so adding the
181 # isinstance() check is the simplest I can do to ensure correct
186 # isinstance() check is the simplest I can do to ensure correct
182 # behavior.
187 # behavior.
183 out_old = self.out
188 out_old = self.out
184 self.out = StringIO()
189 self.out = StringIO()
185 string_output = 1
190 string_output = 1
186 elif out is not None:
191 elif out is not None:
187 self.out = out
192 self.out = out
188
193
189 # Fast return of the unmodified input for NoColor scheme
194 # Fast return of the unmodified input for NoColor scheme
190 if scheme == 'NoColor':
195 if scheme == 'NoColor':
191 error = False
196 error = False
192 self.out.write(raw)
197 self.out.write(raw)
193 if string_output:
198 if string_output:
194 return raw,error
199 return raw,error
195 else:
200 else:
196 return None,error
201 return None,error
197
202
198 # local shorthands
203 # local shorthands
199 colors = self.color_table[scheme].colors
204 colors = self.color_table[scheme].colors
200 self.colors = colors # put in object so __call__ sees it
205 self.colors = colors # put in object so __call__ sees it
201
206
202 # Remove trailing whitespace and normalize tabs
207 # Remove trailing whitespace and normalize tabs
203 self.raw = raw.expandtabs().rstrip()
208 self.raw = raw.expandtabs().rstrip()
204
209
205 # store line offsets in self.lines
210 # store line offsets in self.lines
206 self.lines = [0, 0]
211 self.lines = [0, 0]
207 pos = 0
212 pos = 0
208 raw_find = self.raw.find
213 raw_find = self.raw.find
209 lines_append = self.lines.append
214 lines_append = self.lines.append
210 while 1:
215 while 1:
211 pos = raw_find('\n', pos) + 1
216 pos = raw_find('\n', pos) + 1
212 if not pos: break
217 if not pos: break
213 lines_append(pos)
218 lines_append(pos)
214 lines_append(len(self.raw))
219 lines_append(len(self.raw))
215
220
216 # parse the source and write it
221 # parse the source and write it
217 self.pos = 0
222 self.pos = 0
218 text = StringIO(self.raw)
223 text = StringIO(self.raw)
219
224
220 error = False
225 error = False
221 try:
226 try:
222 for atoken in generate_tokens(text.readline):
227 for atoken in generate_tokens(text.readline):
223 self(*atoken)
228 self(*atoken)
224 except tokenize.TokenError as ex:
229 except tokenize.TokenError as ex:
225 msg = ex.args[0]
230 msg = ex.args[0]
226 line = ex.args[1][0]
231 line = ex.args[1][0]
227 self.out.write("%s\n\n*** ERROR: %s%s%s\n" %
232 self.out.write("%s\n\n*** ERROR: %s%s%s\n" %
228 (colors[token.ERRORTOKEN],
233 (colors[token.ERRORTOKEN],
229 msg, self.raw[self.lines[line]:],
234 msg, self.raw[self.lines[line]:],
230 colors.normal)
235 colors.normal)
231 )
236 )
232 error = True
237 error = True
233 self.out.write(colors.normal+'\n')
238 self.out.write(colors.normal+'\n')
234 if string_output:
239 if string_output:
235 output = self.out.getvalue()
240 output = self.out.getvalue()
236 self.out = out_old
241 self.out = out_old
237 return (output, error)
242 return (output, error)
238 return (None, error)
243 return (None, error)
239
244
240 def __call__(self, toktype, toktext, start_pos, end_pos, line):
245 def __call__(self, toktype, toktext, start_pos, end_pos, line):
241 """ Token handler, with syntax highlighting."""
246 """ Token handler, with syntax highlighting."""
242 (srow,scol) = start_pos
247 (srow,scol) = start_pos
243 (erow,ecol) = end_pos
248 (erow,ecol) = end_pos
244 colors = self.colors
249 colors = self.colors
245 owrite = self.out.write
250 owrite = self.out.write
246
251
247 # line separator, so this works across platforms
252 # line separator, so this works across platforms
248 linesep = os.linesep
253 linesep = os.linesep
249
254
250 # calculate new positions
255 # calculate new positions
251 oldpos = self.pos
256 oldpos = self.pos
252 newpos = self.lines[srow] + scol
257 newpos = self.lines[srow] + scol
253 self.pos = newpos + len(toktext)
258 self.pos = newpos + len(toktext)
254
259
255 # send the original whitespace, if needed
260 # send the original whitespace, if needed
256 if newpos > oldpos:
261 if newpos > oldpos:
257 owrite(self.raw[oldpos:newpos])
262 owrite(self.raw[oldpos:newpos])
258
263
259 # skip indenting tokens
264 # skip indenting tokens
260 if toktype in [token.INDENT, token.DEDENT]:
265 if toktype in [token.INDENT, token.DEDENT]:
261 self.pos = newpos
266 self.pos = newpos
262 return
267 return
263
268
264 # map token type to a color group
269 # map token type to a color group
265 if token.LPAR <= toktype <= token.OP:
270 if token.LPAR <= toktype <= token.OP:
266 toktype = token.OP
271 toktype = token.OP
267 elif toktype == token.NAME and keyword.iskeyword(toktext):
272 elif toktype == token.NAME and keyword.iskeyword(toktext):
268 toktype = _KEYWORD
273 toktype = _KEYWORD
269 color = colors.get(toktype, colors[_TEXT])
274 color = colors.get(toktype, colors[_TEXT])
270
275
271 #print '<%s>' % toktext, # dbg
276 #print '<%s>' % toktext, # dbg
272
277
273 # Triple quoted strings must be handled carefully so that backtracking
278 # Triple quoted strings must be handled carefully so that backtracking
274 # in pagers works correctly. We need color terminators on _each_ line.
279 # in pagers works correctly. We need color terminators on _each_ line.
275 if linesep in toktext:
280 if linesep in toktext:
276 toktext = toktext.replace(linesep, '%s%s%s' %
281 toktext = toktext.replace(linesep, '%s%s%s' %
277 (colors.normal,linesep,color))
282 (colors.normal,linesep,color))
278
283
279 # send text
284 # send text
280 owrite('%s%s%s' % (color,toktext,colors.normal))
285 owrite('%s%s%s' % (color,toktext,colors.normal))
281
286
282 def main(argv=None):
287 def main(argv=None):
283 """Run as a command-line script: colorize a python file or stdin using ANSI
288 """Run as a command-line script: colorize a python file or stdin using ANSI
284 color escapes and print to stdout.
289 color escapes and print to stdout.
285
290
286 Inputs:
291 Inputs:
287
292
288 - argv(None): a list of strings like sys.argv[1:] giving the command-line
293 - argv(None): a list of strings like sys.argv[1:] giving the command-line
289 arguments. If None, use sys.argv[1:].
294 arguments. If None, use sys.argv[1:].
290 """
295 """
291
296
292 usage_msg = """%prog [options] [filename]
297 usage_msg = """%prog [options] [filename]
293
298
294 Colorize a python file or stdin using ANSI color escapes and print to stdout.
299 Colorize a python file or stdin using ANSI color escapes and print to stdout.
295 If no filename is given, or if filename is -, read standard input."""
300 If no filename is given, or if filename is -, read standard input."""
296
301
297 import optparse
302 import optparse
298 parser = optparse.OptionParser(usage=usage_msg)
303 parser = optparse.OptionParser(usage=usage_msg)
299 newopt = parser.add_option
304 newopt = parser.add_option
300 newopt('-s','--scheme',metavar='NAME',dest='scheme_name',action='store',
305 newopt('-s','--scheme',metavar='NAME',dest='scheme_name',action='store',
301 choices=['Linux','LightBG','NoColor'],default=_scheme_default,
306 choices=['Linux','LightBG','NoColor'],default=_scheme_default,
302 help="give the color scheme to use. Currently only 'Linux'\
307 help="give the color scheme to use. Currently only 'Linux'\
303 (default) and 'LightBG' and 'NoColor' are implemented (give without\
308 (default) and 'LightBG' and 'NoColor' are implemented (give without\
304 quotes)")
309 quotes)")
305
310
306 opts,args = parser.parse_args(argv)
311 opts,args = parser.parse_args(argv)
307
312
308 if len(args) > 1:
313 if len(args) > 1:
309 parser.error("you must give at most one filename.")
314 parser.error("you must give at most one filename.")
310
315
311 if len(args) == 0:
316 if len(args) == 0:
312 fname = '-' # no filename given; setup to read from stdin
317 fname = '-' # no filename given; setup to read from stdin
313 else:
318 else:
314 fname = args[0]
319 fname = args[0]
315
320
316 if fname == '-':
321 if fname == '-':
317 stream = sys.stdin
322 stream = sys.stdin
318 else:
323 else:
319 try:
324 try:
320 stream = open(fname)
325 stream = open(fname)
321 except IOError as msg:
326 except IOError as msg:
322 print(msg, file=sys.stderr)
327 print(msg, file=sys.stderr)
323 sys.exit(1)
328 sys.exit(1)
324
329
325 parser = Parser()
330 parser = Parser()
326
331
327 # we need nested try blocks because pre-2.5 python doesn't support unified
332 # we need nested try blocks because pre-2.5 python doesn't support unified
328 # try-except-finally
333 # try-except-finally
329 try:
334 try:
330 try:
335 try:
331 # write colorized version to stdout
336 # write colorized version to stdout
332 parser.format(stream.read(),scheme=opts.scheme_name)
337 parser.format(stream.read(),scheme=opts.scheme_name)
333 except IOError as msg:
338 except IOError as msg:
334 # if user reads through a pager and quits, don't print traceback
339 # if user reads through a pager and quits, don't print traceback
335 if msg.args != (32,'Broken pipe'):
340 if msg.args != (32,'Broken pipe'):
336 raise
341 raise
337 finally:
342 finally:
338 if stream is not sys.stdin:
343 if stream is not sys.stdin:
339 stream.close() # in case a non-handled exception happened above
344 stream.close() # in case a non-handled exception happened above
340
345
341 if __name__ == "__main__":
346 if __name__ == "__main__":
342 main()
347 main()
General Comments 0
You need to be logged in to leave comments. Login now