##// END OF EJS Templates
Deduplicate code
Matthias Bussonnier -
Show More
@@ -1,930 +1,909 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
45
46 # builtin docstrings to ignore
46 # builtin docstrings to ignore
47 _func_call_docstring = types.FunctionType.__call__.__doc__
47 _func_call_docstring = types.FunctionType.__call__.__doc__
48 _object_init_docstring = object.__init__.__doc__
48 _object_init_docstring = object.__init__.__doc__
49 _builtin_type_docstrings = {
49 _builtin_type_docstrings = {
50 inspect.getdoc(t) for t in (types.ModuleType, types.MethodType,
50 inspect.getdoc(t) for t in (types.ModuleType, types.MethodType,
51 types.FunctionType, property)
51 types.FunctionType, property)
52 }
52 }
53
53
54 _builtin_func_type = type(all)
54 _builtin_func_type = type(all)
55 _builtin_meth_type = type(str.upper) # Bound methods have the same type as builtin functions
55 _builtin_meth_type = type(str.upper) # Bound methods have the same type as builtin functions
56 #****************************************************************************
56 #****************************************************************************
57 # Builtin color schemes
57 # Builtin color schemes
58
58
59 Colors = TermColors # just a shorthand
59 Colors = TermColors # just a shorthand
60
60
61 # Build a few color schemes
61 InspectColors = PyColorize.ANSICodeColors
62 NoColor = ColorScheme(
63 'NoColor',{
64 'header' : Colors.NoColor,
65 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
66 } )
67
68 LinuxColors = ColorScheme(
69 'Linux',{
70 'header' : Colors.LightRed,
71 'normal' : Colors.Normal # color off (usu. Colors.Normal)
72 } )
73
74 LightBGColors = ColorScheme(
75 'LightBG',{
76 'header' : Colors.Red,
77 'normal' : Colors.Normal # color off (usu. Colors.Normal)
78 } )
79
80 # Build table of color schemes (needed by the parser)
81 InspectColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
82 'Linux')
83
62
84 #****************************************************************************
63 #****************************************************************************
85 # Auxiliary functions and objects
64 # Auxiliary functions and objects
86
65
87 # See the messaging spec for the definition of all these fields. This list
66 # See the messaging spec for the definition of all these fields. This list
88 # effectively defines the order of display
67 # effectively defines the order of display
89 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
68 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
90 'length', 'file', 'definition', 'docstring', 'source',
69 'length', 'file', 'definition', 'docstring', 'source',
91 'init_definition', 'class_docstring', 'init_docstring',
70 'init_definition', 'class_docstring', 'init_docstring',
92 'call_def', 'call_docstring',
71 'call_def', 'call_docstring',
93 # These won't be printed but will be used to determine how to
72 # These won't be printed but will be used to determine how to
94 # format the object
73 # format the object
95 'ismagic', 'isalias', 'isclass', 'argspec', 'found', 'name'
74 'ismagic', 'isalias', 'isclass', 'argspec', 'found', 'name'
96 ]
75 ]
97
76
98
77
99 def object_info(**kw):
78 def object_info(**kw):
100 """Make an object info dict with all fields present."""
79 """Make an object info dict with all fields present."""
101 infodict = dict(izip_longest(info_fields, [None]))
80 infodict = dict(izip_longest(info_fields, [None]))
102 infodict.update(kw)
81 infodict.update(kw)
103 return infodict
82 return infodict
104
83
105
84
106 def get_encoding(obj):
85 def get_encoding(obj):
107 """Get encoding for python source file defining obj
86 """Get encoding for python source file defining obj
108
87
109 Returns None if obj is not defined in a sourcefile.
88 Returns None if obj is not defined in a sourcefile.
110 """
89 """
111 ofile = find_file(obj)
90 ofile = find_file(obj)
112 # run contents of file through pager starting at line where the object
91 # run contents of file through pager starting at line where the object
113 # is defined, as long as the file isn't binary and is actually on the
92 # is defined, as long as the file isn't binary and is actually on the
114 # filesystem.
93 # filesystem.
115 if ofile is None:
94 if ofile is None:
116 return None
95 return None
117 elif ofile.endswith(('.so', '.dll', '.pyd')):
96 elif ofile.endswith(('.so', '.dll', '.pyd')):
118 return None
97 return None
119 elif not os.path.isfile(ofile):
98 elif not os.path.isfile(ofile):
120 return None
99 return None
121 else:
100 else:
122 # Print only text files, not extension binaries. Note that
101 # Print only text files, not extension binaries. Note that
123 # getsourcelines returns lineno with 1-offset and page() uses
102 # getsourcelines returns lineno with 1-offset and page() uses
124 # 0-offset, so we must adjust.
103 # 0-offset, so we must adjust.
125 with stdlib_io.open(ofile, 'rb') as buffer: # Tweaked to use io.open for Python 2
104 with stdlib_io.open(ofile, 'rb') as buffer: # Tweaked to use io.open for Python 2
126 encoding, lines = openpy.detect_encoding(buffer.readline)
105 encoding, lines = openpy.detect_encoding(buffer.readline)
127 return encoding
106 return encoding
128
107
129 def getdoc(obj):
108 def getdoc(obj):
130 """Stable wrapper around inspect.getdoc.
109 """Stable wrapper around inspect.getdoc.
131
110
132 This can't crash because of attribute problems.
111 This can't crash because of attribute problems.
133
112
134 It also attempts to call a getdoc() method on the given object. This
113 It also attempts to call a getdoc() method on the given object. This
135 allows objects which provide their docstrings via non-standard mechanisms
114 allows objects which provide their docstrings via non-standard mechanisms
136 (like Pyro proxies) to still be inspected by ipython's ? system."""
115 (like Pyro proxies) to still be inspected by ipython's ? system."""
137 # Allow objects to offer customized documentation via a getdoc method:
116 # Allow objects to offer customized documentation via a getdoc method:
138 try:
117 try:
139 ds = obj.getdoc()
118 ds = obj.getdoc()
140 except Exception:
119 except Exception:
141 pass
120 pass
142 else:
121 else:
143 # if we get extra info, we add it to the normal docstring.
122 # if we get extra info, we add it to the normal docstring.
144 if isinstance(ds, string_types):
123 if isinstance(ds, string_types):
145 return inspect.cleandoc(ds)
124 return inspect.cleandoc(ds)
146
125
147 try:
126 try:
148 docstr = inspect.getdoc(obj)
127 docstr = inspect.getdoc(obj)
149 encoding = get_encoding(obj)
128 encoding = get_encoding(obj)
150 return py3compat.cast_unicode(docstr, encoding=encoding)
129 return py3compat.cast_unicode(docstr, encoding=encoding)
151 except Exception:
130 except Exception:
152 # Harden against an inspect failure, which can occur with
131 # Harden against an inspect failure, which can occur with
153 # SWIG-wrapped extensions.
132 # SWIG-wrapped extensions.
154 raise
133 raise
155 return None
134 return None
156
135
157
136
158 def getsource(obj, oname=''):
137 def getsource(obj, oname=''):
159 """Wrapper around inspect.getsource.
138 """Wrapper around inspect.getsource.
160
139
161 This can be modified by other projects to provide customized source
140 This can be modified by other projects to provide customized source
162 extraction.
141 extraction.
163
142
164 Parameters
143 Parameters
165 ----------
144 ----------
166 obj : object
145 obj : object
167 an object whose source code we will attempt to extract
146 an object whose source code we will attempt to extract
168 oname : str
147 oname : str
169 (optional) a name under which the object is known
148 (optional) a name under which the object is known
170
149
171 Returns
150 Returns
172 -------
151 -------
173 src : unicode or None
152 src : unicode or None
174
153
175 """
154 """
176
155
177 if isinstance(obj, property):
156 if isinstance(obj, property):
178 sources = []
157 sources = []
179 for attrname in ['fget', 'fset', 'fdel']:
158 for attrname in ['fget', 'fset', 'fdel']:
180 fn = getattr(obj, attrname)
159 fn = getattr(obj, attrname)
181 if fn is not None:
160 if fn is not None:
182 encoding = get_encoding(fn)
161 encoding = get_encoding(fn)
183 oname_prefix = ('%s.' % oname) if oname else ''
162 oname_prefix = ('%s.' % oname) if oname else ''
184 sources.append(cast_unicode(
163 sources.append(cast_unicode(
185 ''.join(('# ', oname_prefix, attrname)),
164 ''.join(('# ', oname_prefix, attrname)),
186 encoding=encoding))
165 encoding=encoding))
187 if inspect.isfunction(fn):
166 if inspect.isfunction(fn):
188 sources.append(dedent(getsource(fn)))
167 sources.append(dedent(getsource(fn)))
189 else:
168 else:
190 # Default str/repr only prints function name,
169 # Default str/repr only prints function name,
191 # pretty.pretty prints module name too.
170 # pretty.pretty prints module name too.
192 sources.append(cast_unicode(
171 sources.append(cast_unicode(
193 '%s%s = %s\n' % (
172 '%s%s = %s\n' % (
194 oname_prefix, attrname, pretty(fn)),
173 oname_prefix, attrname, pretty(fn)),
195 encoding=encoding))
174 encoding=encoding))
196 if sources:
175 if sources:
197 return '\n'.join(sources)
176 return '\n'.join(sources)
198 else:
177 else:
199 return None
178 return None
200
179
201 else:
180 else:
202 # Get source for non-property objects.
181 # Get source for non-property objects.
203
182
204 obj = _get_wrapped(obj)
183 obj = _get_wrapped(obj)
205
184
206 try:
185 try:
207 src = inspect.getsource(obj)
186 src = inspect.getsource(obj)
208 except TypeError:
187 except TypeError:
209 # The object itself provided no meaningful source, try looking for
188 # The object itself provided no meaningful source, try looking for
210 # its class definition instead.
189 # its class definition instead.
211 if hasattr(obj, '__class__'):
190 if hasattr(obj, '__class__'):
212 try:
191 try:
213 src = inspect.getsource(obj.__class__)
192 src = inspect.getsource(obj.__class__)
214 except TypeError:
193 except TypeError:
215 return None
194 return None
216
195
217 encoding = get_encoding(obj)
196 encoding = get_encoding(obj)
218 return cast_unicode(src, encoding=encoding)
197 return cast_unicode(src, encoding=encoding)
219
198
220
199
221 def is_simple_callable(obj):
200 def is_simple_callable(obj):
222 """True if obj is a function ()"""
201 """True if obj is a function ()"""
223 return (inspect.isfunction(obj) or inspect.ismethod(obj) or \
202 return (inspect.isfunction(obj) or inspect.ismethod(obj) or \
224 isinstance(obj, _builtin_func_type) or isinstance(obj, _builtin_meth_type))
203 isinstance(obj, _builtin_func_type) or isinstance(obj, _builtin_meth_type))
225
204
226
205
227 def getargspec(obj):
206 def getargspec(obj):
228 """Wrapper around :func:`inspect.getfullargspec` on Python 3, and
207 """Wrapper around :func:`inspect.getfullargspec` on Python 3, and
229 :func:inspect.getargspec` on Python 2.
208 :func:inspect.getargspec` on Python 2.
230
209
231 In addition to functions and methods, this can also handle objects with a
210 In addition to functions and methods, this can also handle objects with a
232 ``__call__`` attribute.
211 ``__call__`` attribute.
233 """
212 """
234 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
213 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
235 obj = obj.__call__
214 obj = obj.__call__
236
215
237 return inspect.getfullargspec(obj) if PY3 else inspect.getargspec(obj)
216 return inspect.getfullargspec(obj) if PY3 else inspect.getargspec(obj)
238
217
239
218
240 def format_argspec(argspec):
219 def format_argspec(argspec):
241 """Format argspect, convenience wrapper around inspect's.
220 """Format argspect, convenience wrapper around inspect's.
242
221
243 This takes a dict instead of ordered arguments and calls
222 This takes a dict instead of ordered arguments and calls
244 inspect.format_argspec with the arguments in the necessary order.
223 inspect.format_argspec with the arguments in the necessary order.
245 """
224 """
246 return inspect.formatargspec(argspec['args'], argspec['varargs'],
225 return inspect.formatargspec(argspec['args'], argspec['varargs'],
247 argspec['varkw'], argspec['defaults'])
226 argspec['varkw'], argspec['defaults'])
248
227
249
228
250 def call_tip(oinfo, format_call=True):
229 def call_tip(oinfo, format_call=True):
251 """Extract call tip data from an oinfo dict.
230 """Extract call tip data from an oinfo dict.
252
231
253 Parameters
232 Parameters
254 ----------
233 ----------
255 oinfo : dict
234 oinfo : dict
256
235
257 format_call : bool, optional
236 format_call : bool, optional
258 If True, the call line is formatted and returned as a string. If not, a
237 If True, the call line is formatted and returned as a string. If not, a
259 tuple of (name, argspec) is returned.
238 tuple of (name, argspec) is returned.
260
239
261 Returns
240 Returns
262 -------
241 -------
263 call_info : None, str or (str, dict) tuple.
242 call_info : None, str or (str, dict) tuple.
264 When format_call is True, the whole call information is formattted as a
243 When format_call is True, the whole call information is formattted as a
265 single string. Otherwise, the object's name and its argspec dict are
244 single string. Otherwise, the object's name and its argspec dict are
266 returned. If no call information is available, None is returned.
245 returned. If no call information is available, None is returned.
267
246
268 docstring : str or None
247 docstring : str or None
269 The most relevant docstring for calling purposes is returned, if
248 The most relevant docstring for calling purposes is returned, if
270 available. The priority is: call docstring for callable instances, then
249 available. The priority is: call docstring for callable instances, then
271 constructor docstring for classes, then main object's docstring otherwise
250 constructor docstring for classes, then main object's docstring otherwise
272 (regular functions).
251 (regular functions).
273 """
252 """
274 # Get call definition
253 # Get call definition
275 argspec = oinfo.get('argspec')
254 argspec = oinfo.get('argspec')
276 if argspec is None:
255 if argspec is None:
277 call_line = None
256 call_line = None
278 else:
257 else:
279 # Callable objects will have 'self' as their first argument, prune
258 # Callable objects will have 'self' as their first argument, prune
280 # it out if it's there for clarity (since users do *not* pass an
259 # it out if it's there for clarity (since users do *not* pass an
281 # extra first argument explicitly).
260 # extra first argument explicitly).
282 try:
261 try:
283 has_self = argspec['args'][0] == 'self'
262 has_self = argspec['args'][0] == 'self'
284 except (KeyError, IndexError):
263 except (KeyError, IndexError):
285 pass
264 pass
286 else:
265 else:
287 if has_self:
266 if has_self:
288 argspec['args'] = argspec['args'][1:]
267 argspec['args'] = argspec['args'][1:]
289
268
290 call_line = oinfo['name']+format_argspec(argspec)
269 call_line = oinfo['name']+format_argspec(argspec)
291
270
292 # Now get docstring.
271 # Now get docstring.
293 # The priority is: call docstring, constructor docstring, main one.
272 # The priority is: call docstring, constructor docstring, main one.
294 doc = oinfo.get('call_docstring')
273 doc = oinfo.get('call_docstring')
295 if doc is None:
274 if doc is None:
296 doc = oinfo.get('init_docstring')
275 doc = oinfo.get('init_docstring')
297 if doc is None:
276 if doc is None:
298 doc = oinfo.get('docstring','')
277 doc = oinfo.get('docstring','')
299
278
300 return call_line, doc
279 return call_line, doc
301
280
302
281
303 def _get_wrapped(obj):
282 def _get_wrapped(obj):
304 """Get the original object if wrapped in one or more @decorators"""
283 """Get the original object if wrapped in one or more @decorators"""
305 while safe_hasattr(obj, '__wrapped__'):
284 while safe_hasattr(obj, '__wrapped__'):
306 obj = obj.__wrapped__
285 obj = obj.__wrapped__
307 return obj
286 return obj
308
287
309 def find_file(obj):
288 def find_file(obj):
310 """Find the absolute path to the file where an object was defined.
289 """Find the absolute path to the file where an object was defined.
311
290
312 This is essentially a robust wrapper around `inspect.getabsfile`.
291 This is essentially a robust wrapper around `inspect.getabsfile`.
313
292
314 Returns None if no file can be found.
293 Returns None if no file can be found.
315
294
316 Parameters
295 Parameters
317 ----------
296 ----------
318 obj : any Python object
297 obj : any Python object
319
298
320 Returns
299 Returns
321 -------
300 -------
322 fname : str
301 fname : str
323 The absolute path to the file where the object was defined.
302 The absolute path to the file where the object was defined.
324 """
303 """
325 obj = _get_wrapped(obj)
304 obj = _get_wrapped(obj)
326
305
327 fname = None
306 fname = None
328 try:
307 try:
329 fname = inspect.getabsfile(obj)
308 fname = inspect.getabsfile(obj)
330 except TypeError:
309 except TypeError:
331 # For an instance, the file that matters is where its class was
310 # For an instance, the file that matters is where its class was
332 # declared.
311 # declared.
333 if hasattr(obj, '__class__'):
312 if hasattr(obj, '__class__'):
334 try:
313 try:
335 fname = inspect.getabsfile(obj.__class__)
314 fname = inspect.getabsfile(obj.__class__)
336 except TypeError:
315 except TypeError:
337 # Can happen for builtins
316 # Can happen for builtins
338 pass
317 pass
339 except:
318 except:
340 pass
319 pass
341 return cast_unicode(fname)
320 return cast_unicode(fname)
342
321
343
322
344 def find_source_lines(obj):
323 def find_source_lines(obj):
345 """Find the line number in a file where an object was defined.
324 """Find the line number in a file where an object was defined.
346
325
347 This is essentially a robust wrapper around `inspect.getsourcelines`.
326 This is essentially a robust wrapper around `inspect.getsourcelines`.
348
327
349 Returns None if no file can be found.
328 Returns None if no file can be found.
350
329
351 Parameters
330 Parameters
352 ----------
331 ----------
353 obj : any Python object
332 obj : any Python object
354
333
355 Returns
334 Returns
356 -------
335 -------
357 lineno : int
336 lineno : int
358 The line number where the object definition starts.
337 The line number where the object definition starts.
359 """
338 """
360 obj = _get_wrapped(obj)
339 obj = _get_wrapped(obj)
361
340
362 try:
341 try:
363 try:
342 try:
364 lineno = inspect.getsourcelines(obj)[1]
343 lineno = inspect.getsourcelines(obj)[1]
365 except TypeError:
344 except TypeError:
366 # For instances, try the class object like getsource() does
345 # For instances, try the class object like getsource() does
367 if hasattr(obj, '__class__'):
346 if hasattr(obj, '__class__'):
368 lineno = inspect.getsourcelines(obj.__class__)[1]
347 lineno = inspect.getsourcelines(obj.__class__)[1]
369 else:
348 else:
370 lineno = None
349 lineno = None
371 except:
350 except:
372 return None
351 return None
373
352
374 return lineno
353 return lineno
375
354
376
355
377 class Inspector:
356 class Inspector:
378 def __init__(self, color_table=InspectColors,
357 def __init__(self, color_table=InspectColors,
379 code_color_table=PyColorize.ANSICodeColors,
358 code_color_table=PyColorize.ANSICodeColors,
380 scheme='NoColor',
359 scheme='NoColor',
381 str_detail_level=0):
360 str_detail_level=0):
382 self.color_table = color_table
361 self.color_table = color_table
383 self.parser = PyColorize.Parser(code_color_table,out='str')
362 self.parser = PyColorize.Parser(code_color_table,out='str')
384 self.format = self.parser.format
363 self.format = self.parser.format
385 self.str_detail_level = str_detail_level
364 self.str_detail_level = str_detail_level
386 self.set_active_scheme(scheme)
365 self.set_active_scheme(scheme)
387
366
388 def _getdef(self,obj,oname=''):
367 def _getdef(self,obj,oname=''):
389 """Return the call signature for any callable object.
368 """Return the call signature for any callable object.
390
369
391 If any exception is generated, None is returned instead and the
370 If any exception is generated, None is returned instead and the
392 exception is suppressed."""
371 exception is suppressed."""
393 try:
372 try:
394 hdef = oname + str(signature(obj))
373 hdef = oname + str(signature(obj))
395 return cast_unicode(hdef)
374 return cast_unicode(hdef)
396 except:
375 except:
397 return None
376 return None
398
377
399 def __head(self,h):
378 def __head(self,h):
400 """Return a header string with proper colors."""
379 """Return a header string with proper colors."""
401 return '%s%s%s' % (self.color_table.active_colors.header,h,
380 return '%s%s%s' % (self.color_table.active_colors.header,h,
402 self.color_table.active_colors.normal)
381 self.color_table.active_colors.normal)
403
382
404 def set_active_scheme(self, scheme):
383 def set_active_scheme(self, scheme):
405 self.color_table.set_active_scheme(scheme)
384 self.color_table.set_active_scheme(scheme)
406 self.parser.color_table.set_active_scheme(scheme)
385 self.parser.color_table.set_active_scheme(scheme)
407
386
408 def noinfo(self, msg, oname):
387 def noinfo(self, msg, oname):
409 """Generic message when no information is found."""
388 """Generic message when no information is found."""
410 print('No %s found' % msg, end=' ')
389 print('No %s found' % msg, end=' ')
411 if oname:
390 if oname:
412 print('for %s' % oname)
391 print('for %s' % oname)
413 else:
392 else:
414 print()
393 print()
415
394
416 def pdef(self, obj, oname=''):
395 def pdef(self, obj, oname=''):
417 """Print the call signature for any callable object.
396 """Print the call signature for any callable object.
418
397
419 If the object is a class, print the constructor information."""
398 If the object is a class, print the constructor information."""
420
399
421 if not callable(obj):
400 if not callable(obj):
422 print('Object is not callable.')
401 print('Object is not callable.')
423 return
402 return
424
403
425 header = ''
404 header = ''
426
405
427 if inspect.isclass(obj):
406 if inspect.isclass(obj):
428 header = self.__head('Class constructor information:\n')
407 header = self.__head('Class constructor information:\n')
429 obj = obj.__init__
408 obj = obj.__init__
430 elif (not py3compat.PY3) and type(obj) is types.InstanceType:
409 elif (not py3compat.PY3) and type(obj) is types.InstanceType:
431 obj = obj.__call__
410 obj = obj.__call__
432
411
433 output = self._getdef(obj,oname)
412 output = self._getdef(obj,oname)
434 if output is None:
413 if output is None:
435 self.noinfo('definition header',oname)
414 self.noinfo('definition header',oname)
436 else:
415 else:
437 print(header,self.format(output), end=' ', file=io.stdout)
416 print(header,self.format(output), end=' ', file=io.stdout)
438
417
439 # In Python 3, all classes are new-style, so they all have __init__.
418 # In Python 3, all classes are new-style, so they all have __init__.
440 @skip_doctest_py3
419 @skip_doctest_py3
441 def pdoc(self,obj,oname='',formatter = None):
420 def pdoc(self,obj,oname='',formatter = None):
442 """Print the docstring for any object.
421 """Print the docstring for any object.
443
422
444 Optional:
423 Optional:
445 -formatter: a function to run the docstring through for specially
424 -formatter: a function to run the docstring through for specially
446 formatted docstrings.
425 formatted docstrings.
447
426
448 Examples
427 Examples
449 --------
428 --------
450
429
451 In [1]: class NoInit:
430 In [1]: class NoInit:
452 ...: pass
431 ...: pass
453
432
454 In [2]: class NoDoc:
433 In [2]: class NoDoc:
455 ...: def __init__(self):
434 ...: def __init__(self):
456 ...: pass
435 ...: pass
457
436
458 In [3]: %pdoc NoDoc
437 In [3]: %pdoc NoDoc
459 No documentation found for NoDoc
438 No documentation found for NoDoc
460
439
461 In [4]: %pdoc NoInit
440 In [4]: %pdoc NoInit
462 No documentation found for NoInit
441 No documentation found for NoInit
463
442
464 In [5]: obj = NoInit()
443 In [5]: obj = NoInit()
465
444
466 In [6]: %pdoc obj
445 In [6]: %pdoc obj
467 No documentation found for obj
446 No documentation found for obj
468
447
469 In [5]: obj2 = NoDoc()
448 In [5]: obj2 = NoDoc()
470
449
471 In [6]: %pdoc obj2
450 In [6]: %pdoc obj2
472 No documentation found for obj2
451 No documentation found for obj2
473 """
452 """
474
453
475 head = self.__head # For convenience
454 head = self.__head # For convenience
476 lines = []
455 lines = []
477 ds = getdoc(obj)
456 ds = getdoc(obj)
478 if formatter:
457 if formatter:
479 ds = formatter(ds)
458 ds = formatter(ds)
480 if ds:
459 if ds:
481 lines.append(head("Class docstring:"))
460 lines.append(head("Class docstring:"))
482 lines.append(indent(ds))
461 lines.append(indent(ds))
483 if inspect.isclass(obj) and hasattr(obj, '__init__'):
462 if inspect.isclass(obj) and hasattr(obj, '__init__'):
484 init_ds = getdoc(obj.__init__)
463 init_ds = getdoc(obj.__init__)
485 if init_ds is not None:
464 if init_ds is not None:
486 lines.append(head("Init docstring:"))
465 lines.append(head("Init docstring:"))
487 lines.append(indent(init_ds))
466 lines.append(indent(init_ds))
488 elif hasattr(obj,'__call__'):
467 elif hasattr(obj,'__call__'):
489 call_ds = getdoc(obj.__call__)
468 call_ds = getdoc(obj.__call__)
490 if call_ds:
469 if call_ds:
491 lines.append(head("Call docstring:"))
470 lines.append(head("Call docstring:"))
492 lines.append(indent(call_ds))
471 lines.append(indent(call_ds))
493
472
494 if not lines:
473 if not lines:
495 self.noinfo('documentation',oname)
474 self.noinfo('documentation',oname)
496 else:
475 else:
497 page.page('\n'.join(lines))
476 page.page('\n'.join(lines))
498
477
499 def psource(self, obj, oname=''):
478 def psource(self, obj, oname=''):
500 """Print the source code for an object."""
479 """Print the source code for an object."""
501
480
502 # Flush the source cache because inspect can return out-of-date source
481 # Flush the source cache because inspect can return out-of-date source
503 linecache.checkcache()
482 linecache.checkcache()
504 try:
483 try:
505 src = getsource(obj, oname=oname)
484 src = getsource(obj, oname=oname)
506 except Exception:
485 except Exception:
507 src = None
486 src = None
508
487
509 if src is None:
488 if src is None:
510 self.noinfo('source', oname)
489 self.noinfo('source', oname)
511 else:
490 else:
512 page.page(self.format(src))
491 page.page(self.format(src))
513
492
514 def pfile(self, obj, oname=''):
493 def pfile(self, obj, oname=''):
515 """Show the whole file where an object was defined."""
494 """Show the whole file where an object was defined."""
516
495
517 lineno = find_source_lines(obj)
496 lineno = find_source_lines(obj)
518 if lineno is None:
497 if lineno is None:
519 self.noinfo('file', oname)
498 self.noinfo('file', oname)
520 return
499 return
521
500
522 ofile = find_file(obj)
501 ofile = find_file(obj)
523 # run contents of file through pager starting at line where the object
502 # run contents of file through pager starting at line where the object
524 # is defined, as long as the file isn't binary and is actually on the
503 # is defined, as long as the file isn't binary and is actually on the
525 # filesystem.
504 # filesystem.
526 if ofile.endswith(('.so', '.dll', '.pyd')):
505 if ofile.endswith(('.so', '.dll', '.pyd')):
527 print('File %r is binary, not printing.' % ofile)
506 print('File %r is binary, not printing.' % ofile)
528 elif not os.path.isfile(ofile):
507 elif not os.path.isfile(ofile):
529 print('File %r does not exist, not printing.' % ofile)
508 print('File %r does not exist, not printing.' % ofile)
530 else:
509 else:
531 # Print only text files, not extension binaries. Note that
510 # Print only text files, not extension binaries. Note that
532 # getsourcelines returns lineno with 1-offset and page() uses
511 # getsourcelines returns lineno with 1-offset and page() uses
533 # 0-offset, so we must adjust.
512 # 0-offset, so we must adjust.
534 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1)
513 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1)
535
514
536 def _format_fields(self, fields, title_width=0):
515 def _format_fields(self, fields, title_width=0):
537 """Formats a list of fields for display.
516 """Formats a list of fields for display.
538
517
539 Parameters
518 Parameters
540 ----------
519 ----------
541 fields : list
520 fields : list
542 A list of 2-tuples: (field_title, field_content)
521 A list of 2-tuples: (field_title, field_content)
543 title_width : int
522 title_width : int
544 How many characters to pad titles to. Default to longest title.
523 How many characters to pad titles to. Default to longest title.
545 """
524 """
546 out = []
525 out = []
547 header = self.__head
526 header = self.__head
548 if title_width == 0:
527 if title_width == 0:
549 title_width = max(len(title) + 2 for title, _ in fields)
528 title_width = max(len(title) + 2 for title, _ in fields)
550 for title, content in fields:
529 for title, content in fields:
551 if len(content.splitlines()) > 1:
530 if len(content.splitlines()) > 1:
552 title = header(title + ":") + "\n"
531 title = header(title + ":") + "\n"
553 else:
532 else:
554 title = header((title+":").ljust(title_width))
533 title = header((title+":").ljust(title_width))
555 out.append(cast_unicode(title) + cast_unicode(content))
534 out.append(cast_unicode(title) + cast_unicode(content))
556 return "\n".join(out)
535 return "\n".join(out)
557
536
558 def _format_info(self, obj, oname='', formatter=None, info=None, detail_level=0):
537 def _format_info(self, obj, oname='', formatter=None, info=None, detail_level=0):
559 """Format an info dict as text"""
538 """Format an info dict as text"""
560 info = self.info(obj, oname=oname, formatter=formatter,
539 info = self.info(obj, oname=oname, formatter=formatter,
561 info=info, detail_level=detail_level)
540 info=info, detail_level=detail_level)
562 displayfields = []
541 displayfields = []
563 def add_fields(fields):
542 def add_fields(fields):
564 for title, key in fields:
543 for title, key in fields:
565 field = info[key]
544 field = info[key]
566 if field is not None:
545 if field is not None:
567 if key == "source":
546 if key == "source":
568 displayfields.append((title, self.format(cast_unicode(field.rstrip()))))
547 displayfields.append((title, self.format(cast_unicode(field.rstrip()))))
569 else:
548 else:
570 displayfields.append((title, field.rstrip()))
549 displayfields.append((title, field.rstrip()))
571
550
572 if info['isalias']:
551 if info['isalias']:
573 add_fields([('Repr', "string_form")])
552 add_fields([('Repr', "string_form")])
574
553
575 elif info['ismagic']:
554 elif info['ismagic']:
576 if detail_level > 0 and info['source'] is not None:
555 if detail_level > 0 and info['source'] is not None:
577 add_fields([("Source", "source")])
556 add_fields([("Source", "source")])
578 else:
557 else:
579 add_fields([("Docstring", "docstring")])
558 add_fields([("Docstring", "docstring")])
580
559
581 add_fields([("File", "file"),
560 add_fields([("File", "file"),
582 ])
561 ])
583
562
584 elif info['isclass'] or is_simple_callable(obj):
563 elif info['isclass'] or is_simple_callable(obj):
585 # Functions, methods, classes
564 # Functions, methods, classes
586 add_fields([("Signature", "definition"),
565 add_fields([("Signature", "definition"),
587 ("Init signature", "init_definition"),
566 ("Init signature", "init_definition"),
588 ])
567 ])
589 if detail_level > 0 and info['source'] is not None:
568 if detail_level > 0 and info['source'] is not None:
590 add_fields([("Source", "source")])
569 add_fields([("Source", "source")])
591 else:
570 else:
592 add_fields([("Docstring", "docstring"),
571 add_fields([("Docstring", "docstring"),
593 ("Init docstring", "init_docstring"),
572 ("Init docstring", "init_docstring"),
594 ])
573 ])
595
574
596 add_fields([('File', 'file'),
575 add_fields([('File', 'file'),
597 ('Type', 'type_name'),
576 ('Type', 'type_name'),
598 ])
577 ])
599
578
600 else:
579 else:
601 # General Python objects
580 # General Python objects
602 add_fields([("Type", "type_name")])
581 add_fields([("Type", "type_name")])
603
582
604 # Base class for old-style instances
583 # Base class for old-style instances
605 if (not py3compat.PY3) and isinstance(obj, types.InstanceType) and info['base_class']:
584 if (not py3compat.PY3) and isinstance(obj, types.InstanceType) and info['base_class']:
606 displayfields.append(("Base Class", info['base_class'].rstrip()))
585 displayfields.append(("Base Class", info['base_class'].rstrip()))
607
586
608 add_fields([("String form", "string_form")])
587 add_fields([("String form", "string_form")])
609
588
610 # Namespace
589 # Namespace
611 if info['namespace'] != 'Interactive':
590 if info['namespace'] != 'Interactive':
612 displayfields.append(("Namespace", info['namespace'].rstrip()))
591 displayfields.append(("Namespace", info['namespace'].rstrip()))
613
592
614 add_fields([("Length", "length"),
593 add_fields([("Length", "length"),
615 ("File", "file"),
594 ("File", "file"),
616 ("Signature", "definition"),
595 ("Signature", "definition"),
617 ])
596 ])
618
597
619 # Source or docstring, depending on detail level and whether
598 # Source or docstring, depending on detail level and whether
620 # source found.
599 # source found.
621 if detail_level > 0 and info['source'] is not None:
600 if detail_level > 0 and info['source'] is not None:
622 displayfields.append(("Source",
601 displayfields.append(("Source",
623 self.format(cast_unicode(info['source']))))
602 self.format(cast_unicode(info['source']))))
624 elif info['docstring'] is not None:
603 elif info['docstring'] is not None:
625 displayfields.append(("Docstring", info["docstring"]))
604 displayfields.append(("Docstring", info["docstring"]))
626
605
627 add_fields([("Class docstring", "class_docstring"),
606 add_fields([("Class docstring", "class_docstring"),
628 ("Init docstring", "init_docstring"),
607 ("Init docstring", "init_docstring"),
629 ("Call signature", "call_def"),
608 ("Call signature", "call_def"),
630 ("Call docstring", "call_docstring")])
609 ("Call docstring", "call_docstring")])
631
610
632 if displayfields:
611 if displayfields:
633 return self._format_fields(displayfields)
612 return self._format_fields(displayfields)
634 else:
613 else:
635 return u''
614 return u''
636
615
637 def pinfo(self, obj, oname='', formatter=None, info=None, detail_level=0):
616 def pinfo(self, obj, oname='', formatter=None, info=None, detail_level=0):
638 """Show detailed information about an object.
617 """Show detailed information about an object.
639
618
640 Optional arguments:
619 Optional arguments:
641
620
642 - oname: name of the variable pointing to the object.
621 - oname: name of the variable pointing to the object.
643
622
644 - formatter: special formatter for docstrings (see pdoc)
623 - formatter: special formatter for docstrings (see pdoc)
645
624
646 - info: a structure with some information fields which may have been
625 - info: a structure with some information fields which may have been
647 precomputed already.
626 precomputed already.
648
627
649 - detail_level: if set to 1, more information is given.
628 - detail_level: if set to 1, more information is given.
650 """
629 """
651 text = self._format_info(obj, oname, formatter, info, detail_level)
630 text = self._format_info(obj, oname, formatter, info, detail_level)
652 if text:
631 if text:
653 page.page(text)
632 page.page(text)
654
633
655 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
634 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
656 """Compute a dict with detailed information about an object.
635 """Compute a dict with detailed information about an object.
657
636
658 Optional arguments:
637 Optional arguments:
659
638
660 - oname: name of the variable pointing to the object.
639 - oname: name of the variable pointing to the object.
661
640
662 - formatter: special formatter for docstrings (see pdoc)
641 - formatter: special formatter for docstrings (see pdoc)
663
642
664 - info: a structure with some information fields which may have been
643 - info: a structure with some information fields which may have been
665 precomputed already.
644 precomputed already.
666
645
667 - detail_level: if set to 1, more information is given.
646 - detail_level: if set to 1, more information is given.
668 """
647 """
669
648
670 obj_type = type(obj)
649 obj_type = type(obj)
671
650
672 if info is None:
651 if info is None:
673 ismagic = 0
652 ismagic = 0
674 isalias = 0
653 isalias = 0
675 ospace = ''
654 ospace = ''
676 else:
655 else:
677 ismagic = info.ismagic
656 ismagic = info.ismagic
678 isalias = info.isalias
657 isalias = info.isalias
679 ospace = info.namespace
658 ospace = info.namespace
680
659
681 # Get docstring, special-casing aliases:
660 # Get docstring, special-casing aliases:
682 if isalias:
661 if isalias:
683 if not callable(obj):
662 if not callable(obj):
684 try:
663 try:
685 ds = "Alias to the system command:\n %s" % obj[1]
664 ds = "Alias to the system command:\n %s" % obj[1]
686 except:
665 except:
687 ds = "Alias: " + str(obj)
666 ds = "Alias: " + str(obj)
688 else:
667 else:
689 ds = "Alias to " + str(obj)
668 ds = "Alias to " + str(obj)
690 if obj.__doc__:
669 if obj.__doc__:
691 ds += "\nDocstring:\n" + obj.__doc__
670 ds += "\nDocstring:\n" + obj.__doc__
692 else:
671 else:
693 ds = getdoc(obj)
672 ds = getdoc(obj)
694 if ds is None:
673 if ds is None:
695 ds = '<no docstring>'
674 ds = '<no docstring>'
696 if formatter is not None:
675 if formatter is not None:
697 ds = formatter(ds)
676 ds = formatter(ds)
698
677
699 # store output in a dict, we initialize it here and fill it as we go
678 # store output in a dict, we initialize it here and fill it as we go
700 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic)
679 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic)
701
680
702 string_max = 200 # max size of strings to show (snipped if longer)
681 string_max = 200 # max size of strings to show (snipped if longer)
703 shalf = int((string_max -5)/2)
682 shalf = int((string_max -5)/2)
704
683
705 if ismagic:
684 if ismagic:
706 obj_type_name = 'Magic function'
685 obj_type_name = 'Magic function'
707 elif isalias:
686 elif isalias:
708 obj_type_name = 'System alias'
687 obj_type_name = 'System alias'
709 else:
688 else:
710 obj_type_name = obj_type.__name__
689 obj_type_name = obj_type.__name__
711 out['type_name'] = obj_type_name
690 out['type_name'] = obj_type_name
712
691
713 try:
692 try:
714 bclass = obj.__class__
693 bclass = obj.__class__
715 out['base_class'] = str(bclass)
694 out['base_class'] = str(bclass)
716 except: pass
695 except: pass
717
696
718 # String form, but snip if too long in ? form (full in ??)
697 # String form, but snip if too long in ? form (full in ??)
719 if detail_level >= self.str_detail_level:
698 if detail_level >= self.str_detail_level:
720 try:
699 try:
721 ostr = str(obj)
700 ostr = str(obj)
722 str_head = 'string_form'
701 str_head = 'string_form'
723 if not detail_level and len(ostr)>string_max:
702 if not detail_level and len(ostr)>string_max:
724 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
703 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
725 ostr = ("\n" + " " * len(str_head.expandtabs())).\
704 ostr = ("\n" + " " * len(str_head.expandtabs())).\
726 join(q.strip() for q in ostr.split("\n"))
705 join(q.strip() for q in ostr.split("\n"))
727 out[str_head] = ostr
706 out[str_head] = ostr
728 except:
707 except:
729 pass
708 pass
730
709
731 if ospace:
710 if ospace:
732 out['namespace'] = ospace
711 out['namespace'] = ospace
733
712
734 # Length (for strings and lists)
713 # Length (for strings and lists)
735 try:
714 try:
736 out['length'] = str(len(obj))
715 out['length'] = str(len(obj))
737 except: pass
716 except: pass
738
717
739 # Filename where object was defined
718 # Filename where object was defined
740 binary_file = False
719 binary_file = False
741 fname = find_file(obj)
720 fname = find_file(obj)
742 if fname is None:
721 if fname is None:
743 # if anything goes wrong, we don't want to show source, so it's as
722 # if anything goes wrong, we don't want to show source, so it's as
744 # if the file was binary
723 # if the file was binary
745 binary_file = True
724 binary_file = True
746 else:
725 else:
747 if fname.endswith(('.so', '.dll', '.pyd')):
726 if fname.endswith(('.so', '.dll', '.pyd')):
748 binary_file = True
727 binary_file = True
749 elif fname.endswith('<string>'):
728 elif fname.endswith('<string>'):
750 fname = 'Dynamically generated function. No source code available.'
729 fname = 'Dynamically generated function. No source code available.'
751 out['file'] = compress_user(fname)
730 out['file'] = compress_user(fname)
752
731
753 # Original source code for a callable, class or property.
732 # Original source code for a callable, class or property.
754 if detail_level:
733 if detail_level:
755 # Flush the source cache because inspect can return out-of-date
734 # Flush the source cache because inspect can return out-of-date
756 # source
735 # source
757 linecache.checkcache()
736 linecache.checkcache()
758 try:
737 try:
759 if isinstance(obj, property) or not binary_file:
738 if isinstance(obj, property) or not binary_file:
760 src = getsource(obj, oname)
739 src = getsource(obj, oname)
761 if src is not None:
740 if src is not None:
762 src = src.rstrip()
741 src = src.rstrip()
763 out['source'] = src
742 out['source'] = src
764
743
765 except Exception:
744 except Exception:
766 pass
745 pass
767
746
768 # Add docstring only if no source is to be shown (avoid repetitions).
747 # Add docstring only if no source is to be shown (avoid repetitions).
769 if ds and out.get('source', None) is None:
748 if ds and out.get('source', None) is None:
770 out['docstring'] = ds
749 out['docstring'] = ds
771
750
772 # Constructor docstring for classes
751 # Constructor docstring for classes
773 if inspect.isclass(obj):
752 if inspect.isclass(obj):
774 out['isclass'] = True
753 out['isclass'] = True
775 # reconstruct the function definition and print it:
754 # reconstruct the function definition and print it:
776 try:
755 try:
777 obj_init = obj.__init__
756 obj_init = obj.__init__
778 except AttributeError:
757 except AttributeError:
779 init_def = init_ds = None
758 init_def = init_ds = None
780 else:
759 else:
781 init_def = self._getdef(obj_init,oname)
760 init_def = self._getdef(obj_init,oname)
782 init_ds = getdoc(obj_init)
761 init_ds = getdoc(obj_init)
783 # Skip Python's auto-generated docstrings
762 # Skip Python's auto-generated docstrings
784 if init_ds == _object_init_docstring:
763 if init_ds == _object_init_docstring:
785 init_ds = None
764 init_ds = None
786
765
787 if init_def or init_ds:
766 if init_def or init_ds:
788 if init_def:
767 if init_def:
789 out['init_definition'] = self.format(init_def)
768 out['init_definition'] = self.format(init_def)
790 if init_ds:
769 if init_ds:
791 out['init_docstring'] = init_ds
770 out['init_docstring'] = init_ds
792
771
793 # and class docstring for instances:
772 # and class docstring for instances:
794 else:
773 else:
795 # reconstruct the function definition and print it:
774 # reconstruct the function definition and print it:
796 defln = self._getdef(obj, oname)
775 defln = self._getdef(obj, oname)
797 if defln:
776 if defln:
798 out['definition'] = self.format(defln)
777 out['definition'] = self.format(defln)
799
778
800 # First, check whether the instance docstring is identical to the
779 # First, check whether the instance docstring is identical to the
801 # class one, and print it separately if they don't coincide. In
780 # class one, and print it separately if they don't coincide. In
802 # most cases they will, but it's nice to print all the info for
781 # most cases they will, but it's nice to print all the info for
803 # objects which use instance-customized docstrings.
782 # objects which use instance-customized docstrings.
804 if ds:
783 if ds:
805 try:
784 try:
806 cls = getattr(obj,'__class__')
785 cls = getattr(obj,'__class__')
807 except:
786 except:
808 class_ds = None
787 class_ds = None
809 else:
788 else:
810 class_ds = getdoc(cls)
789 class_ds = getdoc(cls)
811 # Skip Python's auto-generated docstrings
790 # Skip Python's auto-generated docstrings
812 if class_ds in _builtin_type_docstrings:
791 if class_ds in _builtin_type_docstrings:
813 class_ds = None
792 class_ds = None
814 if class_ds and ds != class_ds:
793 if class_ds and ds != class_ds:
815 out['class_docstring'] = class_ds
794 out['class_docstring'] = class_ds
816
795
817 # Next, try to show constructor docstrings
796 # Next, try to show constructor docstrings
818 try:
797 try:
819 init_ds = getdoc(obj.__init__)
798 init_ds = getdoc(obj.__init__)
820 # Skip Python's auto-generated docstrings
799 # Skip Python's auto-generated docstrings
821 if init_ds == _object_init_docstring:
800 if init_ds == _object_init_docstring:
822 init_ds = None
801 init_ds = None
823 except AttributeError:
802 except AttributeError:
824 init_ds = None
803 init_ds = None
825 if init_ds:
804 if init_ds:
826 out['init_docstring'] = init_ds
805 out['init_docstring'] = init_ds
827
806
828 # Call form docstring for callable instances
807 # Call form docstring for callable instances
829 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
808 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
830 call_def = self._getdef(obj.__call__, oname)
809 call_def = self._getdef(obj.__call__, oname)
831 if call_def:
810 if call_def:
832 call_def = self.format(call_def)
811 call_def = self.format(call_def)
833 # it may never be the case that call def and definition differ,
812 # it may never be the case that call def and definition differ,
834 # but don't include the same signature twice
813 # but don't include the same signature twice
835 if call_def != out.get('definition'):
814 if call_def != out.get('definition'):
836 out['call_def'] = call_def
815 out['call_def'] = call_def
837 call_ds = getdoc(obj.__call__)
816 call_ds = getdoc(obj.__call__)
838 # Skip Python's auto-generated docstrings
817 # Skip Python's auto-generated docstrings
839 if call_ds == _func_call_docstring:
818 if call_ds == _func_call_docstring:
840 call_ds = None
819 call_ds = None
841 if call_ds:
820 if call_ds:
842 out['call_docstring'] = call_ds
821 out['call_docstring'] = call_ds
843
822
844 # Compute the object's argspec as a callable. The key is to decide
823 # Compute the object's argspec as a callable. The key is to decide
845 # whether to pull it from the object itself, from its __init__ or
824 # whether to pull it from the object itself, from its __init__ or
846 # from its __call__ method.
825 # from its __call__ method.
847
826
848 if inspect.isclass(obj):
827 if inspect.isclass(obj):
849 # Old-style classes need not have an __init__
828 # Old-style classes need not have an __init__
850 callable_obj = getattr(obj, "__init__", None)
829 callable_obj = getattr(obj, "__init__", None)
851 elif callable(obj):
830 elif callable(obj):
852 callable_obj = obj
831 callable_obj = obj
853 else:
832 else:
854 callable_obj = None
833 callable_obj = None
855
834
856 if callable_obj:
835 if callable_obj:
857 try:
836 try:
858 argspec = getargspec(callable_obj)
837 argspec = getargspec(callable_obj)
859 except (TypeError, AttributeError):
838 except (TypeError, AttributeError):
860 # For extensions/builtins we can't retrieve the argspec
839 # For extensions/builtins we can't retrieve the argspec
861 pass
840 pass
862 else:
841 else:
863 # named tuples' _asdict() method returns an OrderedDict, but we
842 # named tuples' _asdict() method returns an OrderedDict, but we
864 # we want a normal
843 # we want a normal
865 out['argspec'] = argspec_dict = dict(argspec._asdict())
844 out['argspec'] = argspec_dict = dict(argspec._asdict())
866 # We called this varkw before argspec became a named tuple.
845 # We called this varkw before argspec became a named tuple.
867 # With getfullargspec it's also called varkw.
846 # With getfullargspec it's also called varkw.
868 if 'varkw' not in argspec_dict:
847 if 'varkw' not in argspec_dict:
869 argspec_dict['varkw'] = argspec_dict.pop('keywords')
848 argspec_dict['varkw'] = argspec_dict.pop('keywords')
870
849
871 return object_info(**out)
850 return object_info(**out)
872
851
873 def psearch(self,pattern,ns_table,ns_search=[],
852 def psearch(self,pattern,ns_table,ns_search=[],
874 ignore_case=False,show_all=False):
853 ignore_case=False,show_all=False):
875 """Search namespaces with wildcards for objects.
854 """Search namespaces with wildcards for objects.
876
855
877 Arguments:
856 Arguments:
878
857
879 - pattern: string containing shell-like wildcards to use in namespace
858 - pattern: string containing shell-like wildcards to use in namespace
880 searches and optionally a type specification to narrow the search to
859 searches and optionally a type specification to narrow the search to
881 objects of that type.
860 objects of that type.
882
861
883 - ns_table: dict of name->namespaces for search.
862 - ns_table: dict of name->namespaces for search.
884
863
885 Optional arguments:
864 Optional arguments:
886
865
887 - ns_search: list of namespace names to include in search.
866 - ns_search: list of namespace names to include in search.
888
867
889 - ignore_case(False): make the search case-insensitive.
868 - ignore_case(False): make the search case-insensitive.
890
869
891 - show_all(False): show all names, including those starting with
870 - show_all(False): show all names, including those starting with
892 underscores.
871 underscores.
893 """
872 """
894 #print 'ps pattern:<%r>' % pattern # dbg
873 #print 'ps pattern:<%r>' % pattern # dbg
895
874
896 # defaults
875 # defaults
897 type_pattern = 'all'
876 type_pattern = 'all'
898 filter = ''
877 filter = ''
899
878
900 cmds = pattern.split()
879 cmds = pattern.split()
901 len_cmds = len(cmds)
880 len_cmds = len(cmds)
902 if len_cmds == 1:
881 if len_cmds == 1:
903 # Only filter pattern given
882 # Only filter pattern given
904 filter = cmds[0]
883 filter = cmds[0]
905 elif len_cmds == 2:
884 elif len_cmds == 2:
906 # Both filter and type specified
885 # Both filter and type specified
907 filter,type_pattern = cmds
886 filter,type_pattern = cmds
908 else:
887 else:
909 raise ValueError('invalid argument string for psearch: <%s>' %
888 raise ValueError('invalid argument string for psearch: <%s>' %
910 pattern)
889 pattern)
911
890
912 # filter search namespaces
891 # filter search namespaces
913 for name in ns_search:
892 for name in ns_search:
914 if name not in ns_table:
893 if name not in ns_table:
915 raise ValueError('invalid namespace <%s>. Valid names: %s' %
894 raise ValueError('invalid namespace <%s>. Valid names: %s' %
916 (name,ns_table.keys()))
895 (name,ns_table.keys()))
917
896
918 #print 'type_pattern:',type_pattern # dbg
897 #print 'type_pattern:',type_pattern # dbg
919 search_result, namespaces_seen = set(), set()
898 search_result, namespaces_seen = set(), set()
920 for ns_name in ns_search:
899 for ns_name in ns_search:
921 ns = ns_table[ns_name]
900 ns = ns_table[ns_name]
922 # Normally, locals and globals are the same, so we just check one.
901 # Normally, locals and globals are the same, so we just check one.
923 if id(ns) in namespaces_seen:
902 if id(ns) in namespaces_seen:
924 continue
903 continue
925 namespaces_seen.add(id(ns))
904 namespaces_seen.add(id(ns))
926 tmp_res = list_namespace(ns, type_pattern, filter,
905 tmp_res = list_namespace(ns, type_pattern, filter,
927 ignore_case=ignore_case, show_all=show_all)
906 ignore_case=ignore_case, show_all=show_all)
928 search_result.update(tmp_res)
907 search_result.update(tmp_res)
929
908
930 page.page('\n'.join(sorted(search_result)))
909 page.page('\n'.join(sorted(search_result)))
@@ -1,315 +1,318 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 *
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 if PY3:
57 if PY3:
58 from io import StringIO
58 from io import StringIO
59 else:
59 else:
60 from StringIO import StringIO
60 from StringIO import StringIO
61
61
62 #############################################################################
62 #############################################################################
63 ### Python Source Parser (does Hilighting)
63 ### Python Source Parser (does Hilighting)
64 #############################################################################
64 #############################################################################
65
65
66 _KEYWORD = token.NT_OFFSET + 1
66 _KEYWORD = token.NT_OFFSET + 1
67 _TEXT = token.NT_OFFSET + 2
67 _TEXT = token.NT_OFFSET + 2
68
68
69 #****************************************************************************
69 #****************************************************************************
70 # Builtin color schemes
70 # Builtin color schemes
71
71
72 Colors = TermColors # just a shorthand
72 Colors = TermColors # just a shorthand
73
73
74 # Build a few color schemes
74 # Build a few color schemes
75 NoColor = ColorScheme(
75 NoColor = ColorScheme(
76 'NoColor',{
76 'NoColor',{
77 'header' : Colors.NoColor,
77 token.NUMBER : Colors.NoColor,
78 token.NUMBER : Colors.NoColor,
78 token.OP : Colors.NoColor,
79 token.OP : Colors.NoColor,
79 token.STRING : Colors.NoColor,
80 token.STRING : Colors.NoColor,
80 tokenize.COMMENT : Colors.NoColor,
81 tokenize.COMMENT : Colors.NoColor,
81 token.NAME : Colors.NoColor,
82 token.NAME : Colors.NoColor,
82 token.ERRORTOKEN : Colors.NoColor,
83 token.ERRORTOKEN : Colors.NoColor,
83
84
84 _KEYWORD : Colors.NoColor,
85 _KEYWORD : Colors.NoColor,
85 _TEXT : Colors.NoColor,
86 _TEXT : Colors.NoColor,
86
87
87 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
88 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
88 } )
89 } )
89
90
90 LinuxColors = ColorScheme(
91 LinuxColors = ColorScheme(
91 'Linux',{
92 'Linux',{
93 'header' : Colors.LightRed,
92 token.NUMBER : Colors.LightCyan,
94 token.NUMBER : Colors.LightCyan,
93 token.OP : Colors.Yellow,
95 token.OP : Colors.Yellow,
94 token.STRING : Colors.LightBlue,
96 token.STRING : Colors.LightBlue,
95 tokenize.COMMENT : Colors.LightRed,
97 tokenize.COMMENT : Colors.LightRed,
96 token.NAME : Colors.Normal,
98 token.NAME : Colors.Normal,
97 token.ERRORTOKEN : Colors.Red,
99 token.ERRORTOKEN : Colors.Red,
98
100
99 _KEYWORD : Colors.LightGreen,
101 _KEYWORD : Colors.LightGreen,
100 _TEXT : Colors.Yellow,
102 _TEXT : Colors.Yellow,
101
103
102 'normal' : Colors.Normal # color off (usu. Colors.Normal)
104 'normal' : Colors.Normal # color off (usu. Colors.Normal)
103 } )
105 } )
104
106
105 LightBGColors = ColorScheme(
107 LightBGColors = ColorScheme(
106 'LightBG',{
108 'LightBG',{
109 'header' : Colors.Red,
107 token.NUMBER : Colors.Cyan,
110 token.NUMBER : Colors.Cyan,
108 token.OP : Colors.Blue,
111 token.OP : Colors.Blue,
109 token.STRING : Colors.Blue,
112 token.STRING : Colors.Blue,
110 tokenize.COMMENT : Colors.Red,
113 tokenize.COMMENT : Colors.Red,
111 token.NAME : Colors.Normal,
114 token.NAME : Colors.Normal,
112 token.ERRORTOKEN : Colors.Red,
115 token.ERRORTOKEN : Colors.Red,
113
116
114 _KEYWORD : Colors.Green,
117 _KEYWORD : Colors.Green,
115 _TEXT : Colors.Blue,
118 _TEXT : Colors.Blue,
116
119
117 'normal' : Colors.Normal # color off (usu. Colors.Normal)
120 'normal' : Colors.Normal # color off (usu. Colors.Normal)
118 } )
121 } )
119
122
120 # Build table of color schemes (needed by the parser)
123 # Build table of color schemes (needed by the parser)
121 ANSICodeColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
124 ANSICodeColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
122 _scheme_default)
125 _scheme_default)
123
126
124 class Parser:
127 class Parser:
125 """ Format colored Python source.
128 """ Format colored Python source.
126 """
129 """
127
130
128 def __init__(self, color_table=None,out = sys.stdout):
131 def __init__(self, color_table=None,out = sys.stdout):
129 """ Create a parser with a specified color table and output channel.
132 """ Create a parser with a specified color table and output channel.
130
133
131 Call format() to process code.
134 Call format() to process code.
132 """
135 """
133 self.color_table = color_table and color_table or ANSICodeColors
136 self.color_table = color_table and color_table or ANSICodeColors
134 self.out = out
137 self.out = out
135
138
136 def format(self, raw, out = None, scheme = ''):
139 def format(self, raw, out = None, scheme = ''):
137 return self.format2(raw, out, scheme)[0]
140 return self.format2(raw, out, scheme)[0]
138
141
139 def format2(self, raw, out = None, scheme = ''):
142 def format2(self, raw, out = None, scheme = ''):
140 """ Parse and send the colored source.
143 """ Parse and send the colored source.
141
144
142 If out and scheme are not specified, the defaults (given to
145 If out and scheme are not specified, the defaults (given to
143 constructor) are used.
146 constructor) are used.
144
147
145 out should be a file-type object. Optionally, out can be given as the
148 out should be a file-type object. Optionally, out can be given as the
146 string 'str' and the parser will automatically return the output in a
149 string 'str' and the parser will automatically return the output in a
147 string."""
150 string."""
148
151
149 string_output = 0
152 string_output = 0
150 if out == 'str' or self.out == 'str' or \
153 if out == 'str' or self.out == 'str' or \
151 isinstance(self.out,StringIO):
154 isinstance(self.out,StringIO):
152 # XXX - I don't really like this state handling logic, but at this
155 # XXX - I don't really like this state handling logic, but at this
153 # point I don't want to make major changes, so adding the
156 # point I don't want to make major changes, so adding the
154 # isinstance() check is the simplest I can do to ensure correct
157 # isinstance() check is the simplest I can do to ensure correct
155 # behavior.
158 # behavior.
156 out_old = self.out
159 out_old = self.out
157 self.out = StringIO()
160 self.out = StringIO()
158 string_output = 1
161 string_output = 1
159 elif out is not None:
162 elif out is not None:
160 self.out = out
163 self.out = out
161
164
162 # Fast return of the unmodified input for NoColor scheme
165 # Fast return of the unmodified input for NoColor scheme
163 if scheme == 'NoColor':
166 if scheme == 'NoColor':
164 error = False
167 error = False
165 self.out.write(raw)
168 self.out.write(raw)
166 if string_output:
169 if string_output:
167 return raw,error
170 return raw,error
168 else:
171 else:
169 return None,error
172 return None,error
170
173
171 # local shorthands
174 # local shorthands
172 colors = self.color_table[scheme].colors
175 colors = self.color_table[scheme].colors
173 self.colors = colors # put in object so __call__ sees it
176 self.colors = colors # put in object so __call__ sees it
174
177
175 # Remove trailing whitespace and normalize tabs
178 # Remove trailing whitespace and normalize tabs
176 self.raw = raw.expandtabs().rstrip()
179 self.raw = raw.expandtabs().rstrip()
177
180
178 # store line offsets in self.lines
181 # store line offsets in self.lines
179 self.lines = [0, 0]
182 self.lines = [0, 0]
180 pos = 0
183 pos = 0
181 raw_find = self.raw.find
184 raw_find = self.raw.find
182 lines_append = self.lines.append
185 lines_append = self.lines.append
183 while 1:
186 while 1:
184 pos = raw_find('\n', pos) + 1
187 pos = raw_find('\n', pos) + 1
185 if not pos: break
188 if not pos: break
186 lines_append(pos)
189 lines_append(pos)
187 lines_append(len(self.raw))
190 lines_append(len(self.raw))
188
191
189 # parse the source and write it
192 # parse the source and write it
190 self.pos = 0
193 self.pos = 0
191 text = StringIO(self.raw)
194 text = StringIO(self.raw)
192
195
193 error = False
196 error = False
194 try:
197 try:
195 for atoken in generate_tokens(text.readline):
198 for atoken in generate_tokens(text.readline):
196 self(*atoken)
199 self(*atoken)
197 except tokenize.TokenError as ex:
200 except tokenize.TokenError as ex:
198 msg = ex.args[0]
201 msg = ex.args[0]
199 line = ex.args[1][0]
202 line = ex.args[1][0]
200 self.out.write("%s\n\n*** ERROR: %s%s%s\n" %
203 self.out.write("%s\n\n*** ERROR: %s%s%s\n" %
201 (colors[token.ERRORTOKEN],
204 (colors[token.ERRORTOKEN],
202 msg, self.raw[self.lines[line]:],
205 msg, self.raw[self.lines[line]:],
203 colors.normal)
206 colors.normal)
204 )
207 )
205 error = True
208 error = True
206 self.out.write(colors.normal+'\n')
209 self.out.write(colors.normal+'\n')
207 if string_output:
210 if string_output:
208 output = self.out.getvalue()
211 output = self.out.getvalue()
209 self.out = out_old
212 self.out = out_old
210 return (output, error)
213 return (output, error)
211 return (None, error)
214 return (None, error)
212
215
213 def __call__(self, toktype, toktext, start_pos, end_pos, line):
216 def __call__(self, toktype, toktext, start_pos, end_pos, line):
214 """ Token handler, with syntax highlighting."""
217 """ Token handler, with syntax highlighting."""
215 (srow,scol) = start_pos
218 (srow,scol) = start_pos
216 (erow,ecol) = end_pos
219 (erow,ecol) = end_pos
217 colors = self.colors
220 colors = self.colors
218 owrite = self.out.write
221 owrite = self.out.write
219
222
220 # line separator, so this works across platforms
223 # line separator, so this works across platforms
221 linesep = os.linesep
224 linesep = os.linesep
222
225
223 # calculate new positions
226 # calculate new positions
224 oldpos = self.pos
227 oldpos = self.pos
225 newpos = self.lines[srow] + scol
228 newpos = self.lines[srow] + scol
226 self.pos = newpos + len(toktext)
229 self.pos = newpos + len(toktext)
227
230
228 # send the original whitespace, if needed
231 # send the original whitespace, if needed
229 if newpos > oldpos:
232 if newpos > oldpos:
230 owrite(self.raw[oldpos:newpos])
233 owrite(self.raw[oldpos:newpos])
231
234
232 # skip indenting tokens
235 # skip indenting tokens
233 if toktype in [token.INDENT, token.DEDENT]:
236 if toktype in [token.INDENT, token.DEDENT]:
234 self.pos = newpos
237 self.pos = newpos
235 return
238 return
236
239
237 # map token type to a color group
240 # map token type to a color group
238 if token.LPAR <= toktype and toktype <= token.OP:
241 if token.LPAR <= toktype and toktype <= token.OP:
239 toktype = token.OP
242 toktype = token.OP
240 elif toktype == token.NAME and keyword.iskeyword(toktext):
243 elif toktype == token.NAME and keyword.iskeyword(toktext):
241 toktype = _KEYWORD
244 toktype = _KEYWORD
242 color = colors.get(toktype, colors[_TEXT])
245 color = colors.get(toktype, colors[_TEXT])
243
246
244 #print '<%s>' % toktext, # dbg
247 #print '<%s>' % toktext, # dbg
245
248
246 # Triple quoted strings must be handled carefully so that backtracking
249 # Triple quoted strings must be handled carefully so that backtracking
247 # in pagers works correctly. We need color terminators on _each_ line.
250 # in pagers works correctly. We need color terminators on _each_ line.
248 if linesep in toktext:
251 if linesep in toktext:
249 toktext = toktext.replace(linesep, '%s%s%s' %
252 toktext = toktext.replace(linesep, '%s%s%s' %
250 (colors.normal,linesep,color))
253 (colors.normal,linesep,color))
251
254
252 # send text
255 # send text
253 owrite('%s%s%s' % (color,toktext,colors.normal))
256 owrite('%s%s%s' % (color,toktext,colors.normal))
254
257
255 def main(argv=None):
258 def main(argv=None):
256 """Run as a command-line script: colorize a python file or stdin using ANSI
259 """Run as a command-line script: colorize a python file or stdin using ANSI
257 color escapes and print to stdout.
260 color escapes and print to stdout.
258
261
259 Inputs:
262 Inputs:
260
263
261 - argv(None): a list of strings like sys.argv[1:] giving the command-line
264 - argv(None): a list of strings like sys.argv[1:] giving the command-line
262 arguments. If None, use sys.argv[1:].
265 arguments. If None, use sys.argv[1:].
263 """
266 """
264
267
265 usage_msg = """%prog [options] [filename]
268 usage_msg = """%prog [options] [filename]
266
269
267 Colorize a python file or stdin using ANSI color escapes and print to stdout.
270 Colorize a python file or stdin using ANSI color escapes and print to stdout.
268 If no filename is given, or if filename is -, read standard input."""
271 If no filename is given, or if filename is -, read standard input."""
269
272
270 import optparse
273 import optparse
271 parser = optparse.OptionParser(usage=usage_msg)
274 parser = optparse.OptionParser(usage=usage_msg)
272 newopt = parser.add_option
275 newopt = parser.add_option
273 newopt('-s','--scheme',metavar='NAME',dest='scheme_name',action='store',
276 newopt('-s','--scheme',metavar='NAME',dest='scheme_name',action='store',
274 choices=['Linux','LightBG','NoColor'],default=_scheme_default,
277 choices=['Linux','LightBG','NoColor'],default=_scheme_default,
275 help="give the color scheme to use. Currently only 'Linux'\
278 help="give the color scheme to use. Currently only 'Linux'\
276 (default) and 'LightBG' and 'NoColor' are implemented (give without\
279 (default) and 'LightBG' and 'NoColor' are implemented (give without\
277 quotes)")
280 quotes)")
278
281
279 opts,args = parser.parse_args(argv)
282 opts,args = parser.parse_args(argv)
280
283
281 if len(args) > 1:
284 if len(args) > 1:
282 parser.error("you must give at most one filename.")
285 parser.error("you must give at most one filename.")
283
286
284 if len(args) == 0:
287 if len(args) == 0:
285 fname = '-' # no filename given; setup to read from stdin
288 fname = '-' # no filename given; setup to read from stdin
286 else:
289 else:
287 fname = args[0]
290 fname = args[0]
288
291
289 if fname == '-':
292 if fname == '-':
290 stream = sys.stdin
293 stream = sys.stdin
291 else:
294 else:
292 try:
295 try:
293 stream = open(fname)
296 stream = open(fname)
294 except IOError as msg:
297 except IOError as msg:
295 print(msg, file=sys.stderr)
298 print(msg, file=sys.stderr)
296 sys.exit(1)
299 sys.exit(1)
297
300
298 parser = Parser()
301 parser = Parser()
299
302
300 # we need nested try blocks because pre-2.5 python doesn't support unified
303 # we need nested try blocks because pre-2.5 python doesn't support unified
301 # try-except-finally
304 # try-except-finally
302 try:
305 try:
303 try:
306 try:
304 # write colorized version to stdout
307 # write colorized version to stdout
305 parser.format(stream.read(),scheme=opts.scheme_name)
308 parser.format(stream.read(),scheme=opts.scheme_name)
306 except IOError as msg:
309 except IOError as msg:
307 # if user reads through a pager and quits, don't print traceback
310 # if user reads through a pager and quits, don't print traceback
308 if msg.args != (32,'Broken pipe'):
311 if msg.args != (32,'Broken pipe'):
309 raise
312 raise
310 finally:
313 finally:
311 if stream is not sys.stdin:
314 if stream is not sys.stdin:
312 stream.close() # in case a non-handled exception happened above
315 stream.close() # in case a non-handled exception happened above
313
316
314 if __name__ == "__main__":
317 if __name__ == "__main__":
315 main()
318 main()
General Comments 0
You need to be logged in to leave comments. Login now