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