##// END OF EJS Templates
Don't introspect __call__ for simple callables...
Thomas Kluyver -
Show More
@@ -1,868 +1,877 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 #*****************************************************************************
10 #*****************************************************************************
11 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
11 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
12 #
12 #
13 # Distributed under the terms of the BSD License. The full license is in
13 # Distributed under the terms of the BSD License. The full license is in
14 # the file COPYING, distributed as part of this software.
14 # the file COPYING, distributed as part of this software.
15 #*****************************************************************************
15 #*****************************************************************************
16 from __future__ import print_function
16 from __future__ import print_function
17
17
18 __all__ = ['Inspector','InspectColors']
18 __all__ = ['Inspector','InspectColors']
19
19
20 # stdlib modules
20 # stdlib modules
21 import inspect
21 import inspect
22 import linecache
22 import linecache
23 import os
23 import os
24 import types
24 import types
25 import io as stdlib_io
25 import io as stdlib_io
26
26
27 try:
27 try:
28 from itertools import izip_longest
28 from itertools import izip_longest
29 except ImportError:
29 except ImportError:
30 from itertools import zip_longest as izip_longest
30 from itertools import zip_longest as izip_longest
31
31
32 # IPython's own
32 # IPython's own
33 from IPython.core import page
33 from IPython.core import page
34 from IPython.testing.skipdoctest import skip_doctest_py3
34 from IPython.testing.skipdoctest import skip_doctest_py3
35 from IPython.utils import PyColorize
35 from IPython.utils import PyColorize
36 from IPython.utils import io
36 from IPython.utils import io
37 from IPython.utils import openpy
37 from IPython.utils import openpy
38 from IPython.utils import py3compat
38 from IPython.utils import py3compat
39 from IPython.utils.dir2 import safe_hasattr
39 from IPython.utils.dir2 import safe_hasattr
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
44
45 # builtin docstrings to ignore
45 # builtin docstrings to ignore
46 _func_call_docstring = types.FunctionType.__call__.__doc__
46 _func_call_docstring = types.FunctionType.__call__.__doc__
47 _object_init_docstring = object.__init__.__doc__
47 _object_init_docstring = object.__init__.__doc__
48 _builtin_type_docstrings = {
48 _builtin_type_docstrings = {
49 t.__doc__ for t in (types.ModuleType, types.MethodType, types.FunctionType)
49 t.__doc__ for t in (types.ModuleType, types.MethodType, types.FunctionType)
50 }
50 }
51
52 _builtin_func_type = type(all)
53 _builtin_meth_type = type(str.upper) # Bound methods have the same type as builtin functions
51 #****************************************************************************
54 #****************************************************************************
52 # Builtin color schemes
55 # Builtin color schemes
53
56
54 Colors = TermColors # just a shorthand
57 Colors = TermColors # just a shorthand
55
58
56 # Build a few color schemes
59 # Build a few color schemes
57 NoColor = ColorScheme(
60 NoColor = ColorScheme(
58 'NoColor',{
61 'NoColor',{
59 'header' : Colors.NoColor,
62 'header' : Colors.NoColor,
60 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
63 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
61 } )
64 } )
62
65
63 LinuxColors = ColorScheme(
66 LinuxColors = ColorScheme(
64 'Linux',{
67 'Linux',{
65 'header' : Colors.LightRed,
68 'header' : Colors.LightRed,
66 'normal' : Colors.Normal # color off (usu. Colors.Normal)
69 'normal' : Colors.Normal # color off (usu. Colors.Normal)
67 } )
70 } )
68
71
69 LightBGColors = ColorScheme(
72 LightBGColors = ColorScheme(
70 'LightBG',{
73 'LightBG',{
71 'header' : Colors.Red,
74 'header' : Colors.Red,
72 'normal' : Colors.Normal # color off (usu. Colors.Normal)
75 'normal' : Colors.Normal # color off (usu. Colors.Normal)
73 } )
76 } )
74
77
75 # Build table of color schemes (needed by the parser)
78 # Build table of color schemes (needed by the parser)
76 InspectColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
79 InspectColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
77 'Linux')
80 'Linux')
78
81
79 #****************************************************************************
82 #****************************************************************************
80 # Auxiliary functions and objects
83 # Auxiliary functions and objects
81
84
82 # See the messaging spec for the definition of all these fields. This list
85 # See the messaging spec for the definition of all these fields. This list
83 # effectively defines the order of display
86 # effectively defines the order of display
84 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
87 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
85 'length', 'file', 'definition', 'docstring', 'source',
88 'length', 'file', 'definition', 'docstring', 'source',
86 'init_definition', 'class_docstring', 'init_docstring',
89 'init_definition', 'class_docstring', 'init_docstring',
87 'call_def', 'call_docstring',
90 'call_def', 'call_docstring',
88 # These won't be printed but will be used to determine how to
91 # These won't be printed but will be used to determine how to
89 # format the object
92 # format the object
90 'ismagic', 'isalias', 'isclass', 'argspec', 'found', 'name'
93 'ismagic', 'isalias', 'isclass', 'argspec', 'found', 'name'
91 ]
94 ]
92
95
93
96
94 def object_info(**kw):
97 def object_info(**kw):
95 """Make an object info dict with all fields present."""
98 """Make an object info dict with all fields present."""
96 infodict = dict(izip_longest(info_fields, [None]))
99 infodict = dict(izip_longest(info_fields, [None]))
97 infodict.update(kw)
100 infodict.update(kw)
98 return infodict
101 return infodict
99
102
100
103
101 def get_encoding(obj):
104 def get_encoding(obj):
102 """Get encoding for python source file defining obj
105 """Get encoding for python source file defining obj
103
106
104 Returns None if obj is not defined in a sourcefile.
107 Returns None if obj is not defined in a sourcefile.
105 """
108 """
106 ofile = find_file(obj)
109 ofile = find_file(obj)
107 # run contents of file through pager starting at line where the object
110 # run contents of file through pager starting at line where the object
108 # is defined, as long as the file isn't binary and is actually on the
111 # is defined, as long as the file isn't binary and is actually on the
109 # filesystem.
112 # filesystem.
110 if ofile is None:
113 if ofile is None:
111 return None
114 return None
112 elif ofile.endswith(('.so', '.dll', '.pyd')):
115 elif ofile.endswith(('.so', '.dll', '.pyd')):
113 return None
116 return None
114 elif not os.path.isfile(ofile):
117 elif not os.path.isfile(ofile):
115 return None
118 return None
116 else:
119 else:
117 # Print only text files, not extension binaries. Note that
120 # Print only text files, not extension binaries. Note that
118 # getsourcelines returns lineno with 1-offset and page() uses
121 # getsourcelines returns lineno with 1-offset and page() uses
119 # 0-offset, so we must adjust.
122 # 0-offset, so we must adjust.
120 buffer = stdlib_io.open(ofile, 'rb') # Tweaked to use io.open for Python 2
123 buffer = stdlib_io.open(ofile, 'rb') # Tweaked to use io.open for Python 2
121 encoding, lines = openpy.detect_encoding(buffer.readline)
124 encoding, lines = openpy.detect_encoding(buffer.readline)
122 return encoding
125 return encoding
123
126
124 def getdoc(obj):
127 def getdoc(obj):
125 """Stable wrapper around inspect.getdoc.
128 """Stable wrapper around inspect.getdoc.
126
129
127 This can't crash because of attribute problems.
130 This can't crash because of attribute problems.
128
131
129 It also attempts to call a getdoc() method on the given object. This
132 It also attempts to call a getdoc() method on the given object. This
130 allows objects which provide their docstrings via non-standard mechanisms
133 allows objects which provide their docstrings via non-standard mechanisms
131 (like Pyro proxies) to still be inspected by ipython's ? system."""
134 (like Pyro proxies) to still be inspected by ipython's ? system."""
132 # Allow objects to offer customized documentation via a getdoc method:
135 # Allow objects to offer customized documentation via a getdoc method:
133 try:
136 try:
134 ds = obj.getdoc()
137 ds = obj.getdoc()
135 except Exception:
138 except Exception:
136 pass
139 pass
137 else:
140 else:
138 # if we get extra info, we add it to the normal docstring.
141 # if we get extra info, we add it to the normal docstring.
139 if isinstance(ds, string_types):
142 if isinstance(ds, string_types):
140 return inspect.cleandoc(ds)
143 return inspect.cleandoc(ds)
141
144
142 try:
145 try:
143 docstr = inspect.getdoc(obj)
146 docstr = inspect.getdoc(obj)
144 encoding = get_encoding(obj)
147 encoding = get_encoding(obj)
145 return py3compat.cast_unicode(docstr, encoding=encoding)
148 return py3compat.cast_unicode(docstr, encoding=encoding)
146 except Exception:
149 except Exception:
147 # Harden against an inspect failure, which can occur with
150 # Harden against an inspect failure, which can occur with
148 # SWIG-wrapped extensions.
151 # SWIG-wrapped extensions.
149 raise
152 raise
150 return None
153 return None
151
154
152
155
153 def getsource(obj,is_binary=False):
156 def getsource(obj,is_binary=False):
154 """Wrapper around inspect.getsource.
157 """Wrapper around inspect.getsource.
155
158
156 This can be modified by other projects to provide customized source
159 This can be modified by other projects to provide customized source
157 extraction.
160 extraction.
158
161
159 Inputs:
162 Inputs:
160
163
161 - obj: an object whose source code we will attempt to extract.
164 - obj: an object whose source code we will attempt to extract.
162
165
163 Optional inputs:
166 Optional inputs:
164
167
165 - is_binary: whether the object is known to come from a binary source.
168 - is_binary: whether the object is known to come from a binary source.
166 This implementation will skip returning any output for binary objects, but
169 This implementation will skip returning any output for binary objects, but
167 custom extractors may know how to meaningfully process them."""
170 custom extractors may know how to meaningfully process them."""
168
171
169 if is_binary:
172 if is_binary:
170 return None
173 return None
171 else:
174 else:
172 # get source if obj was decorated with @decorator
175 # get source if obj was decorated with @decorator
173 if hasattr(obj,"__wrapped__"):
176 if hasattr(obj,"__wrapped__"):
174 obj = obj.__wrapped__
177 obj = obj.__wrapped__
175 try:
178 try:
176 src = inspect.getsource(obj)
179 src = inspect.getsource(obj)
177 except TypeError:
180 except TypeError:
178 if hasattr(obj,'__class__'):
181 if hasattr(obj,'__class__'):
179 src = inspect.getsource(obj.__class__)
182 src = inspect.getsource(obj.__class__)
180 encoding = get_encoding(obj)
183 encoding = get_encoding(obj)
181 return cast_unicode(src, encoding=encoding)
184 return cast_unicode(src, encoding=encoding)
182
185
186
187 def is_simple_callable(obj):
188 """True if obj is a function ()"""
189 return (inspect.isfunction(obj) or inspect.ismethod(obj) or \
190 isinstance(obj, _builtin_func_type) or isinstance(obj, _builtin_meth_type))
191
192
183 def getargspec(obj):
193 def getargspec(obj):
184 """Wrapper around :func:`inspect.getfullargspec` on Python 3, and
194 """Wrapper around :func:`inspect.getfullargspec` on Python 3, and
185 :func:inspect.getargspec` on Python 2.
195 :func:inspect.getargspec` on Python 2.
186
196
187 In addition to functions and methods, this can also handle objects with a
197 In addition to functions and methods, this can also handle objects with a
188 ``__call__`` attribute.
198 ``__call__`` attribute.
189 """
199 """
190 if not (inspect.isfunction(obj) or inspect.ismethod(obj)) \
200 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
191 and safe_hasattr(obj, '__call__'):
192 obj = obj.__call__
201 obj = obj.__call__
193
202
194 return inspect.getfullargspec(obj) if PY3 else inspect.getargspec(obj)
203 return inspect.getfullargspec(obj) if PY3 else inspect.getargspec(obj)
195
204
196
205
197 def format_argspec(argspec):
206 def format_argspec(argspec):
198 """Format argspect, convenience wrapper around inspect's.
207 """Format argspect, convenience wrapper around inspect's.
199
208
200 This takes a dict instead of ordered arguments and calls
209 This takes a dict instead of ordered arguments and calls
201 inspect.format_argspec with the arguments in the necessary order.
210 inspect.format_argspec with the arguments in the necessary order.
202 """
211 """
203 return inspect.formatargspec(argspec['args'], argspec['varargs'],
212 return inspect.formatargspec(argspec['args'], argspec['varargs'],
204 argspec['varkw'], argspec['defaults'])
213 argspec['varkw'], argspec['defaults'])
205
214
206
215
207 def call_tip(oinfo, format_call=True):
216 def call_tip(oinfo, format_call=True):
208 """Extract call tip data from an oinfo dict.
217 """Extract call tip data from an oinfo dict.
209
218
210 Parameters
219 Parameters
211 ----------
220 ----------
212 oinfo : dict
221 oinfo : dict
213
222
214 format_call : bool, optional
223 format_call : bool, optional
215 If True, the call line is formatted and returned as a string. If not, a
224 If True, the call line is formatted and returned as a string. If not, a
216 tuple of (name, argspec) is returned.
225 tuple of (name, argspec) is returned.
217
226
218 Returns
227 Returns
219 -------
228 -------
220 call_info : None, str or (str, dict) tuple.
229 call_info : None, str or (str, dict) tuple.
221 When format_call is True, the whole call information is formattted as a
230 When format_call is True, the whole call information is formattted as a
222 single string. Otherwise, the object's name and its argspec dict are
231 single string. Otherwise, the object's name and its argspec dict are
223 returned. If no call information is available, None is returned.
232 returned. If no call information is available, None is returned.
224
233
225 docstring : str or None
234 docstring : str or None
226 The most relevant docstring for calling purposes is returned, if
235 The most relevant docstring for calling purposes is returned, if
227 available. The priority is: call docstring for callable instances, then
236 available. The priority is: call docstring for callable instances, then
228 constructor docstring for classes, then main object's docstring otherwise
237 constructor docstring for classes, then main object's docstring otherwise
229 (regular functions).
238 (regular functions).
230 """
239 """
231 # Get call definition
240 # Get call definition
232 argspec = oinfo.get('argspec')
241 argspec = oinfo.get('argspec')
233 if argspec is None:
242 if argspec is None:
234 call_line = None
243 call_line = None
235 else:
244 else:
236 # Callable objects will have 'self' as their first argument, prune
245 # Callable objects will have 'self' as their first argument, prune
237 # it out if it's there for clarity (since users do *not* pass an
246 # it out if it's there for clarity (since users do *not* pass an
238 # extra first argument explicitly).
247 # extra first argument explicitly).
239 try:
248 try:
240 has_self = argspec['args'][0] == 'self'
249 has_self = argspec['args'][0] == 'self'
241 except (KeyError, IndexError):
250 except (KeyError, IndexError):
242 pass
251 pass
243 else:
252 else:
244 if has_self:
253 if has_self:
245 argspec['args'] = argspec['args'][1:]
254 argspec['args'] = argspec['args'][1:]
246
255
247 call_line = oinfo['name']+format_argspec(argspec)
256 call_line = oinfo['name']+format_argspec(argspec)
248
257
249 # Now get docstring.
258 # Now get docstring.
250 # The priority is: call docstring, constructor docstring, main one.
259 # The priority is: call docstring, constructor docstring, main one.
251 doc = oinfo.get('call_docstring')
260 doc = oinfo.get('call_docstring')
252 if doc is None:
261 if doc is None:
253 doc = oinfo.get('init_docstring')
262 doc = oinfo.get('init_docstring')
254 if doc is None:
263 if doc is None:
255 doc = oinfo.get('docstring','')
264 doc = oinfo.get('docstring','')
256
265
257 return call_line, doc
266 return call_line, doc
258
267
259
268
260 def find_file(obj):
269 def find_file(obj):
261 """Find the absolute path to the file where an object was defined.
270 """Find the absolute path to the file where an object was defined.
262
271
263 This is essentially a robust wrapper around `inspect.getabsfile`.
272 This is essentially a robust wrapper around `inspect.getabsfile`.
264
273
265 Returns None if no file can be found.
274 Returns None if no file can be found.
266
275
267 Parameters
276 Parameters
268 ----------
277 ----------
269 obj : any Python object
278 obj : any Python object
270
279
271 Returns
280 Returns
272 -------
281 -------
273 fname : str
282 fname : str
274 The absolute path to the file where the object was defined.
283 The absolute path to the file where the object was defined.
275 """
284 """
276 # get source if obj was decorated with @decorator
285 # get source if obj was decorated with @decorator
277 if safe_hasattr(obj, '__wrapped__'):
286 if safe_hasattr(obj, '__wrapped__'):
278 obj = obj.__wrapped__
287 obj = obj.__wrapped__
279
288
280 fname = None
289 fname = None
281 try:
290 try:
282 fname = inspect.getabsfile(obj)
291 fname = inspect.getabsfile(obj)
283 except TypeError:
292 except TypeError:
284 # For an instance, the file that matters is where its class was
293 # For an instance, the file that matters is where its class was
285 # declared.
294 # declared.
286 if hasattr(obj, '__class__'):
295 if hasattr(obj, '__class__'):
287 try:
296 try:
288 fname = inspect.getabsfile(obj.__class__)
297 fname = inspect.getabsfile(obj.__class__)
289 except TypeError:
298 except TypeError:
290 # Can happen for builtins
299 # Can happen for builtins
291 pass
300 pass
292 except:
301 except:
293 pass
302 pass
294 return cast_unicode(fname)
303 return cast_unicode(fname)
295
304
296
305
297 def find_source_lines(obj):
306 def find_source_lines(obj):
298 """Find the line number in a file where an object was defined.
307 """Find the line number in a file where an object was defined.
299
308
300 This is essentially a robust wrapper around `inspect.getsourcelines`.
309 This is essentially a robust wrapper around `inspect.getsourcelines`.
301
310
302 Returns None if no file can be found.
311 Returns None if no file can be found.
303
312
304 Parameters
313 Parameters
305 ----------
314 ----------
306 obj : any Python object
315 obj : any Python object
307
316
308 Returns
317 Returns
309 -------
318 -------
310 lineno : int
319 lineno : int
311 The line number where the object definition starts.
320 The line number where the object definition starts.
312 """
321 """
313 # get source if obj was decorated with @decorator
322 # get source if obj was decorated with @decorator
314 if safe_hasattr(obj, '__wrapped__'):
323 if safe_hasattr(obj, '__wrapped__'):
315 obj = obj.__wrapped__
324 obj = obj.__wrapped__
316
325
317 try:
326 try:
318 try:
327 try:
319 lineno = inspect.getsourcelines(obj)[1]
328 lineno = inspect.getsourcelines(obj)[1]
320 except TypeError:
329 except TypeError:
321 # For instances, try the class object like getsource() does
330 # For instances, try the class object like getsource() does
322 if hasattr(obj, '__class__'):
331 if hasattr(obj, '__class__'):
323 lineno = inspect.getsourcelines(obj.__class__)[1]
332 lineno = inspect.getsourcelines(obj.__class__)[1]
324 else:
333 else:
325 lineno = None
334 lineno = None
326 except:
335 except:
327 return None
336 return None
328
337
329 return lineno
338 return lineno
330
339
331
340
332 class Inspector:
341 class Inspector:
333 def __init__(self, color_table=InspectColors,
342 def __init__(self, color_table=InspectColors,
334 code_color_table=PyColorize.ANSICodeColors,
343 code_color_table=PyColorize.ANSICodeColors,
335 scheme='NoColor',
344 scheme='NoColor',
336 str_detail_level=0):
345 str_detail_level=0):
337 self.color_table = color_table
346 self.color_table = color_table
338 self.parser = PyColorize.Parser(code_color_table,out='str')
347 self.parser = PyColorize.Parser(code_color_table,out='str')
339 self.format = self.parser.format
348 self.format = self.parser.format
340 self.str_detail_level = str_detail_level
349 self.str_detail_level = str_detail_level
341 self.set_active_scheme(scheme)
350 self.set_active_scheme(scheme)
342
351
343 def _getdef(self,obj,oname=''):
352 def _getdef(self,obj,oname=''):
344 """Return the call signature for any callable object.
353 """Return the call signature for any callable object.
345
354
346 If any exception is generated, None is returned instead and the
355 If any exception is generated, None is returned instead and the
347 exception is suppressed."""
356 exception is suppressed."""
348 try:
357 try:
349 hdef = oname + inspect.formatargspec(*getargspec(obj))
358 hdef = oname + inspect.formatargspec(*getargspec(obj))
350 return cast_unicode(hdef)
359 return cast_unicode(hdef)
351 except:
360 except:
352 return None
361 return None
353
362
354 def __head(self,h):
363 def __head(self,h):
355 """Return a header string with proper colors."""
364 """Return a header string with proper colors."""
356 return '%s%s%s' % (self.color_table.active_colors.header,h,
365 return '%s%s%s' % (self.color_table.active_colors.header,h,
357 self.color_table.active_colors.normal)
366 self.color_table.active_colors.normal)
358
367
359 def set_active_scheme(self, scheme):
368 def set_active_scheme(self, scheme):
360 self.color_table.set_active_scheme(scheme)
369 self.color_table.set_active_scheme(scheme)
361 self.parser.color_table.set_active_scheme(scheme)
370 self.parser.color_table.set_active_scheme(scheme)
362
371
363 def noinfo(self, msg, oname):
372 def noinfo(self, msg, oname):
364 """Generic message when no information is found."""
373 """Generic message when no information is found."""
365 print('No %s found' % msg, end=' ')
374 print('No %s found' % msg, end=' ')
366 if oname:
375 if oname:
367 print('for %s' % oname)
376 print('for %s' % oname)
368 else:
377 else:
369 print()
378 print()
370
379
371 def pdef(self, obj, oname=''):
380 def pdef(self, obj, oname=''):
372 """Print the call signature for any callable object.
381 """Print the call signature for any callable object.
373
382
374 If the object is a class, print the constructor information."""
383 If the object is a class, print the constructor information."""
375
384
376 if not callable(obj):
385 if not callable(obj):
377 print('Object is not callable.')
386 print('Object is not callable.')
378 return
387 return
379
388
380 header = ''
389 header = ''
381
390
382 if inspect.isclass(obj):
391 if inspect.isclass(obj):
383 header = self.__head('Class constructor information:\n')
392 header = self.__head('Class constructor information:\n')
384 obj = obj.__init__
393 obj = obj.__init__
385 elif (not py3compat.PY3) and type(obj) is types.InstanceType:
394 elif (not py3compat.PY3) and type(obj) is types.InstanceType:
386 obj = obj.__call__
395 obj = obj.__call__
387
396
388 output = self._getdef(obj,oname)
397 output = self._getdef(obj,oname)
389 if output is None:
398 if output is None:
390 self.noinfo('definition header',oname)
399 self.noinfo('definition header',oname)
391 else:
400 else:
392 print(header,self.format(output), end=' ', file=io.stdout)
401 print(header,self.format(output), end=' ', file=io.stdout)
393
402
394 # In Python 3, all classes are new-style, so they all have __init__.
403 # In Python 3, all classes are new-style, so they all have __init__.
395 @skip_doctest_py3
404 @skip_doctest_py3
396 def pdoc(self,obj,oname='',formatter = None):
405 def pdoc(self,obj,oname='',formatter = None):
397 """Print the docstring for any object.
406 """Print the docstring for any object.
398
407
399 Optional:
408 Optional:
400 -formatter: a function to run the docstring through for specially
409 -formatter: a function to run the docstring through for specially
401 formatted docstrings.
410 formatted docstrings.
402
411
403 Examples
412 Examples
404 --------
413 --------
405
414
406 In [1]: class NoInit:
415 In [1]: class NoInit:
407 ...: pass
416 ...: pass
408
417
409 In [2]: class NoDoc:
418 In [2]: class NoDoc:
410 ...: def __init__(self):
419 ...: def __init__(self):
411 ...: pass
420 ...: pass
412
421
413 In [3]: %pdoc NoDoc
422 In [3]: %pdoc NoDoc
414 No documentation found for NoDoc
423 No documentation found for NoDoc
415
424
416 In [4]: %pdoc NoInit
425 In [4]: %pdoc NoInit
417 No documentation found for NoInit
426 No documentation found for NoInit
418
427
419 In [5]: obj = NoInit()
428 In [5]: obj = NoInit()
420
429
421 In [6]: %pdoc obj
430 In [6]: %pdoc obj
422 No documentation found for obj
431 No documentation found for obj
423
432
424 In [5]: obj2 = NoDoc()
433 In [5]: obj2 = NoDoc()
425
434
426 In [6]: %pdoc obj2
435 In [6]: %pdoc obj2
427 No documentation found for obj2
436 No documentation found for obj2
428 """
437 """
429
438
430 head = self.__head # For convenience
439 head = self.__head # For convenience
431 lines = []
440 lines = []
432 ds = getdoc(obj)
441 ds = getdoc(obj)
433 if formatter:
442 if formatter:
434 ds = formatter(ds)
443 ds = formatter(ds)
435 if ds:
444 if ds:
436 lines.append(head("Class Docstring:"))
445 lines.append(head("Class Docstring:"))
437 lines.append(indent(ds))
446 lines.append(indent(ds))
438 if inspect.isclass(obj) and hasattr(obj, '__init__'):
447 if inspect.isclass(obj) and hasattr(obj, '__init__'):
439 init_ds = getdoc(obj.__init__)
448 init_ds = getdoc(obj.__init__)
440 if init_ds is not None:
449 if init_ds is not None:
441 lines.append(head("Constructor Docstring:"))
450 lines.append(head("Constructor Docstring:"))
442 lines.append(indent(init_ds))
451 lines.append(indent(init_ds))
443 elif hasattr(obj,'__call__'):
452 elif hasattr(obj,'__call__'):
444 call_ds = getdoc(obj.__call__)
453 call_ds = getdoc(obj.__call__)
445 if call_ds:
454 if call_ds:
446 lines.append(head("Calling Docstring:"))
455 lines.append(head("Calling Docstring:"))
447 lines.append(indent(call_ds))
456 lines.append(indent(call_ds))
448
457
449 if not lines:
458 if not lines:
450 self.noinfo('documentation',oname)
459 self.noinfo('documentation',oname)
451 else:
460 else:
452 page.page('\n'.join(lines))
461 page.page('\n'.join(lines))
453
462
454 def psource(self,obj,oname=''):
463 def psource(self,obj,oname=''):
455 """Print the source code for an object."""
464 """Print the source code for an object."""
456
465
457 # Flush the source cache because inspect can return out-of-date source
466 # Flush the source cache because inspect can return out-of-date source
458 linecache.checkcache()
467 linecache.checkcache()
459 try:
468 try:
460 src = getsource(obj)
469 src = getsource(obj)
461 except:
470 except:
462 self.noinfo('source',oname)
471 self.noinfo('source',oname)
463 else:
472 else:
464 page.page(self.format(src))
473 page.page(self.format(src))
465
474
466 def pfile(self, obj, oname=''):
475 def pfile(self, obj, oname=''):
467 """Show the whole file where an object was defined."""
476 """Show the whole file where an object was defined."""
468
477
469 lineno = find_source_lines(obj)
478 lineno = find_source_lines(obj)
470 if lineno is None:
479 if lineno is None:
471 self.noinfo('file', oname)
480 self.noinfo('file', oname)
472 return
481 return
473
482
474 ofile = find_file(obj)
483 ofile = find_file(obj)
475 # run contents of file through pager starting at line where the object
484 # run contents of file through pager starting at line where the object
476 # is defined, as long as the file isn't binary and is actually on the
485 # is defined, as long as the file isn't binary and is actually on the
477 # filesystem.
486 # filesystem.
478 if ofile.endswith(('.so', '.dll', '.pyd')):
487 if ofile.endswith(('.so', '.dll', '.pyd')):
479 print('File %r is binary, not printing.' % ofile)
488 print('File %r is binary, not printing.' % ofile)
480 elif not os.path.isfile(ofile):
489 elif not os.path.isfile(ofile):
481 print('File %r does not exist, not printing.' % ofile)
490 print('File %r does not exist, not printing.' % ofile)
482 else:
491 else:
483 # Print only text files, not extension binaries. Note that
492 # Print only text files, not extension binaries. Note that
484 # getsourcelines returns lineno with 1-offset and page() uses
493 # getsourcelines returns lineno with 1-offset and page() uses
485 # 0-offset, so we must adjust.
494 # 0-offset, so we must adjust.
486 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1)
495 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1)
487
496
488 def _format_fields(self, fields, title_width=12):
497 def _format_fields(self, fields, title_width=12):
489 """Formats a list of fields for display.
498 """Formats a list of fields for display.
490
499
491 Parameters
500 Parameters
492 ----------
501 ----------
493 fields : list
502 fields : list
494 A list of 2-tuples: (field_title, field_content)
503 A list of 2-tuples: (field_title, field_content)
495 title_width : int
504 title_width : int
496 How many characters to pad titles to. Default 12.
505 How many characters to pad titles to. Default 12.
497 """
506 """
498 out = []
507 out = []
499 header = self.__head
508 header = self.__head
500 for title, content in fields:
509 for title, content in fields:
501 if len(content.splitlines()) > 1:
510 if len(content.splitlines()) > 1:
502 title = header(title + ":") + "\n"
511 title = header(title + ":") + "\n"
503 else:
512 else:
504 title = header((title+":").ljust(title_width))
513 title = header((title+":").ljust(title_width))
505 out.append(cast_unicode(title) + cast_unicode(content))
514 out.append(cast_unicode(title) + cast_unicode(content))
506 return "\n".join(out)
515 return "\n".join(out)
507
516
508 # The fields to be displayed by pinfo: (fancy_name, key_in_info_dict)
517 # The fields to be displayed by pinfo: (fancy_name, key_in_info_dict)
509 pinfo_fields1 = [("Type", "type_name"),
518 pinfo_fields1 = [("Type", "type_name"),
510 ]
519 ]
511
520
512 pinfo_fields2 = [("String Form", "string_form"),
521 pinfo_fields2 = [("String Form", "string_form"),
513 ]
522 ]
514
523
515 pinfo_fields3 = [("Length", "length"),
524 pinfo_fields3 = [("Length", "length"),
516 ("File", "file"),
525 ("File", "file"),
517 ("Definition", "definition"),
526 ("Definition", "definition"),
518 ]
527 ]
519
528
520 pinfo_fields_obj = [("Class Docstring", "class_docstring"),
529 pinfo_fields_obj = [("Class Docstring", "class_docstring"),
521 ("Constructor Docstring","init_docstring"),
530 ("Constructor Docstring","init_docstring"),
522 ("Call def", "call_def"),
531 ("Call def", "call_def"),
523 ("Call docstring", "call_docstring")]
532 ("Call docstring", "call_docstring")]
524
533
525 def pinfo(self,obj,oname='',formatter=None,info=None,detail_level=0):
534 def pinfo(self,obj,oname='',formatter=None,info=None,detail_level=0):
526 """Show detailed information about an object.
535 """Show detailed information about an object.
527
536
528 Optional arguments:
537 Optional arguments:
529
538
530 - oname: name of the variable pointing to the object.
539 - oname: name of the variable pointing to the object.
531
540
532 - formatter: special formatter for docstrings (see pdoc)
541 - formatter: special formatter for docstrings (see pdoc)
533
542
534 - info: a structure with some information fields which may have been
543 - info: a structure with some information fields which may have been
535 precomputed already.
544 precomputed already.
536
545
537 - detail_level: if set to 1, more information is given.
546 - detail_level: if set to 1, more information is given.
538 """
547 """
539 info = self.info(obj, oname=oname, formatter=formatter,
548 info = self.info(obj, oname=oname, formatter=formatter,
540 info=info, detail_level=detail_level)
549 info=info, detail_level=detail_level)
541 displayfields = []
550 displayfields = []
542 def add_fields(fields):
551 def add_fields(fields):
543 for title, key in fields:
552 for title, key in fields:
544 field = info[key]
553 field = info[key]
545 if field is not None:
554 if field is not None:
546 displayfields.append((title, field.rstrip()))
555 displayfields.append((title, field.rstrip()))
547
556
548 add_fields(self.pinfo_fields1)
557 add_fields(self.pinfo_fields1)
549
558
550 # Base class for old-style instances
559 # Base class for old-style instances
551 if (not py3compat.PY3) and isinstance(obj, types.InstanceType) and info['base_class']:
560 if (not py3compat.PY3) and isinstance(obj, types.InstanceType) and info['base_class']:
552 displayfields.append(("Base Class", info['base_class'].rstrip()))
561 displayfields.append(("Base Class", info['base_class'].rstrip()))
553
562
554 add_fields(self.pinfo_fields2)
563 add_fields(self.pinfo_fields2)
555
564
556 # Namespace
565 # Namespace
557 if info['namespace'] != 'Interactive':
566 if info['namespace'] != 'Interactive':
558 displayfields.append(("Namespace", info['namespace'].rstrip()))
567 displayfields.append(("Namespace", info['namespace'].rstrip()))
559
568
560 add_fields(self.pinfo_fields3)
569 add_fields(self.pinfo_fields3)
561
570
562 # Source or docstring, depending on detail level and whether
571 # Source or docstring, depending on detail level and whether
563 # source found.
572 # source found.
564 if detail_level > 0 and info['source'] is not None:
573 if detail_level > 0 and info['source'] is not None:
565 displayfields.append(("Source",
574 displayfields.append(("Source",
566 self.format(cast_unicode(info['source']))))
575 self.format(cast_unicode(info['source']))))
567 elif info['docstring'] is not None:
576 elif info['docstring'] is not None:
568 displayfields.append(("Docstring", info["docstring"]))
577 displayfields.append(("Docstring", info["docstring"]))
569
578
570 # Constructor info for classes
579 # Constructor info for classes
571 if info['isclass']:
580 if info['isclass']:
572 if info['init_definition'] or info['init_docstring']:
581 if info['init_definition'] or info['init_docstring']:
573 displayfields.append(("Constructor information", ""))
582 displayfields.append(("Constructor information", ""))
574 if info['init_definition'] is not None:
583 if info['init_definition'] is not None:
575 displayfields.append((" Definition",
584 displayfields.append((" Definition",
576 info['init_definition'].rstrip()))
585 info['init_definition'].rstrip()))
577 if info['init_docstring'] is not None:
586 if info['init_docstring'] is not None:
578 displayfields.append((" Docstring",
587 displayfields.append((" Docstring",
579 indent(info['init_docstring'])))
588 indent(info['init_docstring'])))
580
589
581 # Info for objects:
590 # Info for objects:
582 else:
591 else:
583 add_fields(self.pinfo_fields_obj)
592 add_fields(self.pinfo_fields_obj)
584
593
585 # Finally send to printer/pager:
594 # Finally send to printer/pager:
586 if displayfields:
595 if displayfields:
587 page.page(self._format_fields(displayfields))
596 page.page(self._format_fields(displayfields))
588
597
589 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
598 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
590 """Compute a dict with detailed information about an object.
599 """Compute a dict with detailed information about an object.
591
600
592 Optional arguments:
601 Optional arguments:
593
602
594 - oname: name of the variable pointing to the object.
603 - oname: name of the variable pointing to the object.
595
604
596 - formatter: special formatter for docstrings (see pdoc)
605 - formatter: special formatter for docstrings (see pdoc)
597
606
598 - info: a structure with some information fields which may have been
607 - info: a structure with some information fields which may have been
599 precomputed already.
608 precomputed already.
600
609
601 - detail_level: if set to 1, more information is given.
610 - detail_level: if set to 1, more information is given.
602 """
611 """
603
612
604 obj_type = type(obj)
613 obj_type = type(obj)
605
614
606 if info is None:
615 if info is None:
607 ismagic = 0
616 ismagic = 0
608 isalias = 0
617 isalias = 0
609 ospace = ''
618 ospace = ''
610 else:
619 else:
611 ismagic = info.ismagic
620 ismagic = info.ismagic
612 isalias = info.isalias
621 isalias = info.isalias
613 ospace = info.namespace
622 ospace = info.namespace
614
623
615 # Get docstring, special-casing aliases:
624 # Get docstring, special-casing aliases:
616 if isalias:
625 if isalias:
617 if not callable(obj):
626 if not callable(obj):
618 try:
627 try:
619 ds = "Alias to the system command:\n %s" % obj[1]
628 ds = "Alias to the system command:\n %s" % obj[1]
620 except:
629 except:
621 ds = "Alias: " + str(obj)
630 ds = "Alias: " + str(obj)
622 else:
631 else:
623 ds = "Alias to " + str(obj)
632 ds = "Alias to " + str(obj)
624 if obj.__doc__:
633 if obj.__doc__:
625 ds += "\nDocstring:\n" + obj.__doc__
634 ds += "\nDocstring:\n" + obj.__doc__
626 else:
635 else:
627 ds = getdoc(obj)
636 ds = getdoc(obj)
628 if ds is None:
637 if ds is None:
629 ds = '<no docstring>'
638 ds = '<no docstring>'
630 if formatter is not None:
639 if formatter is not None:
631 ds = formatter(ds)
640 ds = formatter(ds)
632
641
633 # store output in a dict, we initialize it here and fill it as we go
642 # store output in a dict, we initialize it here and fill it as we go
634 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic)
643 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic)
635
644
636 string_max = 200 # max size of strings to show (snipped if longer)
645 string_max = 200 # max size of strings to show (snipped if longer)
637 shalf = int((string_max -5)/2)
646 shalf = int((string_max -5)/2)
638
647
639 if ismagic:
648 if ismagic:
640 obj_type_name = 'Magic function'
649 obj_type_name = 'Magic function'
641 elif isalias:
650 elif isalias:
642 obj_type_name = 'System alias'
651 obj_type_name = 'System alias'
643 else:
652 else:
644 obj_type_name = obj_type.__name__
653 obj_type_name = obj_type.__name__
645 out['type_name'] = obj_type_name
654 out['type_name'] = obj_type_name
646
655
647 try:
656 try:
648 bclass = obj.__class__
657 bclass = obj.__class__
649 out['base_class'] = str(bclass)
658 out['base_class'] = str(bclass)
650 except: pass
659 except: pass
651
660
652 # String form, but snip if too long in ? form (full in ??)
661 # String form, but snip if too long in ? form (full in ??)
653 if detail_level >= self.str_detail_level:
662 if detail_level >= self.str_detail_level:
654 try:
663 try:
655 ostr = str(obj)
664 ostr = str(obj)
656 str_head = 'string_form'
665 str_head = 'string_form'
657 if not detail_level and len(ostr)>string_max:
666 if not detail_level and len(ostr)>string_max:
658 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
667 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
659 ostr = ("\n" + " " * len(str_head.expandtabs())).\
668 ostr = ("\n" + " " * len(str_head.expandtabs())).\
660 join(q.strip() for q in ostr.split("\n"))
669 join(q.strip() for q in ostr.split("\n"))
661 out[str_head] = ostr
670 out[str_head] = ostr
662 except:
671 except:
663 pass
672 pass
664
673
665 if ospace:
674 if ospace:
666 out['namespace'] = ospace
675 out['namespace'] = ospace
667
676
668 # Length (for strings and lists)
677 # Length (for strings and lists)
669 try:
678 try:
670 out['length'] = str(len(obj))
679 out['length'] = str(len(obj))
671 except: pass
680 except: pass
672
681
673 # Filename where object was defined
682 # Filename where object was defined
674 binary_file = False
683 binary_file = False
675 fname = find_file(obj)
684 fname = find_file(obj)
676 if fname is None:
685 if fname is None:
677 # if anything goes wrong, we don't want to show source, so it's as
686 # if anything goes wrong, we don't want to show source, so it's as
678 # if the file was binary
687 # if the file was binary
679 binary_file = True
688 binary_file = True
680 else:
689 else:
681 if fname.endswith(('.so', '.dll', '.pyd')):
690 if fname.endswith(('.so', '.dll', '.pyd')):
682 binary_file = True
691 binary_file = True
683 elif fname.endswith('<string>'):
692 elif fname.endswith('<string>'):
684 fname = 'Dynamically generated function. No source code available.'
693 fname = 'Dynamically generated function. No source code available.'
685 out['file'] = fname
694 out['file'] = fname
686
695
687 # reconstruct the function definition and print it:
696 # reconstruct the function definition and print it:
688 defln = self._getdef(obj, oname)
697 defln = self._getdef(obj, oname)
689 if defln:
698 if defln:
690 out['definition'] = self.format(defln)
699 out['definition'] = self.format(defln)
691
700
692 # Docstrings only in detail 0 mode, since source contains them (we
701 # Docstrings only in detail 0 mode, since source contains them (we
693 # avoid repetitions). If source fails, we add them back, see below.
702 # avoid repetitions). If source fails, we add them back, see below.
694 if ds and detail_level == 0:
703 if ds and detail_level == 0:
695 out['docstring'] = ds
704 out['docstring'] = ds
696
705
697 # Original source code for any callable
706 # Original source code for any callable
698 if detail_level:
707 if detail_level:
699 # Flush the source cache because inspect can return out-of-date
708 # Flush the source cache because inspect can return out-of-date
700 # source
709 # source
701 linecache.checkcache()
710 linecache.checkcache()
702 source = None
711 source = None
703 try:
712 try:
704 try:
713 try:
705 source = getsource(obj, binary_file)
714 source = getsource(obj, binary_file)
706 except TypeError:
715 except TypeError:
707 if hasattr(obj, '__class__'):
716 if hasattr(obj, '__class__'):
708 source = getsource(obj.__class__, binary_file)
717 source = getsource(obj.__class__, binary_file)
709 if source is not None:
718 if source is not None:
710 out['source'] = source.rstrip()
719 out['source'] = source.rstrip()
711 except Exception:
720 except Exception:
712 pass
721 pass
713
722
714 if ds and source is None:
723 if ds and source is None:
715 out['docstring'] = ds
724 out['docstring'] = ds
716
725
717
726
718 # Constructor docstring for classes
727 # Constructor docstring for classes
719 if inspect.isclass(obj):
728 if inspect.isclass(obj):
720 out['isclass'] = True
729 out['isclass'] = True
721 # reconstruct the function definition and print it:
730 # reconstruct the function definition and print it:
722 try:
731 try:
723 obj_init = obj.__init__
732 obj_init = obj.__init__
724 except AttributeError:
733 except AttributeError:
725 init_def = init_ds = None
734 init_def = init_ds = None
726 else:
735 else:
727 init_def = self._getdef(obj_init,oname)
736 init_def = self._getdef(obj_init,oname)
728 init_ds = getdoc(obj_init)
737 init_ds = getdoc(obj_init)
729 # Skip Python's auto-generated docstrings
738 # Skip Python's auto-generated docstrings
730 if init_ds == _object_init_docstring:
739 if init_ds == _object_init_docstring:
731 init_ds = None
740 init_ds = None
732
741
733 if init_def or init_ds:
742 if init_def or init_ds:
734 if init_def:
743 if init_def:
735 out['init_definition'] = self.format(init_def)
744 out['init_definition'] = self.format(init_def)
736 if init_ds:
745 if init_ds:
737 out['init_docstring'] = init_ds
746 out['init_docstring'] = init_ds
738
747
739 # and class docstring for instances:
748 # and class docstring for instances:
740 else:
749 else:
741 # First, check whether the instance docstring is identical to the
750 # First, check whether the instance docstring is identical to the
742 # class one, and print it separately if they don't coincide. In
751 # class one, and print it separately if they don't coincide. In
743 # most cases they will, but it's nice to print all the info for
752 # most cases they will, but it's nice to print all the info for
744 # objects which use instance-customized docstrings.
753 # objects which use instance-customized docstrings.
745 if ds:
754 if ds:
746 try:
755 try:
747 cls = getattr(obj,'__class__')
756 cls = getattr(obj,'__class__')
748 except:
757 except:
749 class_ds = None
758 class_ds = None
750 else:
759 else:
751 class_ds = getdoc(cls)
760 class_ds = getdoc(cls)
752 # Skip Python's auto-generated docstrings
761 # Skip Python's auto-generated docstrings
753 if class_ds in _builtin_type_docstrings:
762 if class_ds in _builtin_type_docstrings:
754 class_ds = None
763 class_ds = None
755 if class_ds and ds != class_ds:
764 if class_ds and ds != class_ds:
756 out['class_docstring'] = class_ds
765 out['class_docstring'] = class_ds
757
766
758 # Next, try to show constructor docstrings
767 # Next, try to show constructor docstrings
759 try:
768 try:
760 init_ds = getdoc(obj.__init__)
769 init_ds = getdoc(obj.__init__)
761 # Skip Python's auto-generated docstrings
770 # Skip Python's auto-generated docstrings
762 if init_ds == _object_init_docstring:
771 if init_ds == _object_init_docstring:
763 init_ds = None
772 init_ds = None
764 except AttributeError:
773 except AttributeError:
765 init_ds = None
774 init_ds = None
766 if init_ds:
775 if init_ds:
767 out['init_docstring'] = init_ds
776 out['init_docstring'] = init_ds
768
777
769 # Call form docstring for callable instances
778 # Call form docstring for callable instances
770 if safe_hasattr(obj, '__call__'):
779 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
771 call_def = self._getdef(obj.__call__, oname)
780 call_def = self._getdef(obj.__call__, oname)
772 if call_def is not None:
781 if call_def is not None:
773 out['call_def'] = self.format(call_def)
782 out['call_def'] = self.format(call_def)
774 call_ds = getdoc(obj.__call__)
783 call_ds = getdoc(obj.__call__)
775 # Skip Python's auto-generated docstrings
784 # Skip Python's auto-generated docstrings
776 if call_ds == _func_call_docstring:
785 if call_ds == _func_call_docstring:
777 call_ds = None
786 call_ds = None
778 if call_ds:
787 if call_ds:
779 out['call_docstring'] = call_ds
788 out['call_docstring'] = call_ds
780
789
781 # Compute the object's argspec as a callable. The key is to decide
790 # Compute the object's argspec as a callable. The key is to decide
782 # whether to pull it from the object itself, from its __init__ or
791 # whether to pull it from the object itself, from its __init__ or
783 # from its __call__ method.
792 # from its __call__ method.
784
793
785 if inspect.isclass(obj):
794 if inspect.isclass(obj):
786 # Old-style classes need not have an __init__
795 # Old-style classes need not have an __init__
787 callable_obj = getattr(obj, "__init__", None)
796 callable_obj = getattr(obj, "__init__", None)
788 elif callable(obj):
797 elif callable(obj):
789 callable_obj = obj
798 callable_obj = obj
790 else:
799 else:
791 callable_obj = None
800 callable_obj = None
792
801
793 if callable_obj:
802 if callable_obj:
794 try:
803 try:
795 argspec = getargspec(callable_obj)
804 argspec = getargspec(callable_obj)
796 except (TypeError, AttributeError):
805 except (TypeError, AttributeError):
797 # For extensions/builtins we can't retrieve the argspec
806 # For extensions/builtins we can't retrieve the argspec
798 pass
807 pass
799 else:
808 else:
800 # named tuples' _asdict() method returns an OrderedDict, but we
809 # named tuples' _asdict() method returns an OrderedDict, but we
801 # we want a normal
810 # we want a normal
802 out['argspec'] = argspec_dict = dict(argspec._asdict())
811 out['argspec'] = argspec_dict = dict(argspec._asdict())
803 # We called this varkw before argspec became a named tuple.
812 # We called this varkw before argspec became a named tuple.
804 # With getfullargspec it's also called varkw.
813 # With getfullargspec it's also called varkw.
805 if 'varkw' not in argspec_dict:
814 if 'varkw' not in argspec_dict:
806 argspec_dict['varkw'] = argspec_dict.pop('keywords')
815 argspec_dict['varkw'] = argspec_dict.pop('keywords')
807
816
808 return object_info(**out)
817 return object_info(**out)
809
818
810
819
811 def psearch(self,pattern,ns_table,ns_search=[],
820 def psearch(self,pattern,ns_table,ns_search=[],
812 ignore_case=False,show_all=False):
821 ignore_case=False,show_all=False):
813 """Search namespaces with wildcards for objects.
822 """Search namespaces with wildcards for objects.
814
823
815 Arguments:
824 Arguments:
816
825
817 - pattern: string containing shell-like wildcards to use in namespace
826 - pattern: string containing shell-like wildcards to use in namespace
818 searches and optionally a type specification to narrow the search to
827 searches and optionally a type specification to narrow the search to
819 objects of that type.
828 objects of that type.
820
829
821 - ns_table: dict of name->namespaces for search.
830 - ns_table: dict of name->namespaces for search.
822
831
823 Optional arguments:
832 Optional arguments:
824
833
825 - ns_search: list of namespace names to include in search.
834 - ns_search: list of namespace names to include in search.
826
835
827 - ignore_case(False): make the search case-insensitive.
836 - ignore_case(False): make the search case-insensitive.
828
837
829 - show_all(False): show all names, including those starting with
838 - show_all(False): show all names, including those starting with
830 underscores.
839 underscores.
831 """
840 """
832 #print 'ps pattern:<%r>' % pattern # dbg
841 #print 'ps pattern:<%r>' % pattern # dbg
833
842
834 # defaults
843 # defaults
835 type_pattern = 'all'
844 type_pattern = 'all'
836 filter = ''
845 filter = ''
837
846
838 cmds = pattern.split()
847 cmds = pattern.split()
839 len_cmds = len(cmds)
848 len_cmds = len(cmds)
840 if len_cmds == 1:
849 if len_cmds == 1:
841 # Only filter pattern given
850 # Only filter pattern given
842 filter = cmds[0]
851 filter = cmds[0]
843 elif len_cmds == 2:
852 elif len_cmds == 2:
844 # Both filter and type specified
853 # Both filter and type specified
845 filter,type_pattern = cmds
854 filter,type_pattern = cmds
846 else:
855 else:
847 raise ValueError('invalid argument string for psearch: <%s>' %
856 raise ValueError('invalid argument string for psearch: <%s>' %
848 pattern)
857 pattern)
849
858
850 # filter search namespaces
859 # filter search namespaces
851 for name in ns_search:
860 for name in ns_search:
852 if name not in ns_table:
861 if name not in ns_table:
853 raise ValueError('invalid namespace <%s>. Valid names: %s' %
862 raise ValueError('invalid namespace <%s>. Valid names: %s' %
854 (name,ns_table.keys()))
863 (name,ns_table.keys()))
855
864
856 #print 'type_pattern:',type_pattern # dbg
865 #print 'type_pattern:',type_pattern # dbg
857 search_result, namespaces_seen = set(), set()
866 search_result, namespaces_seen = set(), set()
858 for ns_name in ns_search:
867 for ns_name in ns_search:
859 ns = ns_table[ns_name]
868 ns = ns_table[ns_name]
860 # Normally, locals and globals are the same, so we just check one.
869 # Normally, locals and globals are the same, so we just check one.
861 if id(ns) in namespaces_seen:
870 if id(ns) in namespaces_seen:
862 continue
871 continue
863 namespaces_seen.add(id(ns))
872 namespaces_seen.add(id(ns))
864 tmp_res = list_namespace(ns, type_pattern, filter,
873 tmp_res = list_namespace(ns, type_pattern, filter,
865 ignore_case=ignore_case, show_all=show_all)
874 ignore_case=ignore_case, show_all=show_all)
866 search_result.update(tmp_res)
875 search_result.update(tmp_res)
867
876
868 page.page('\n'.join(sorted(search_result)))
877 page.page('\n'.join(sorted(search_result)))
@@ -1,314 +1,325 b''
1 """Tests for the object inspection functionality.
1 """Tests for the object inspection functionality.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2010-2011 The IPython Development Team.
4 # Copyright (C) 2010-2011 The IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the BSD License.
6 # Distributed under the terms of the BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 from __future__ import print_function
14 from __future__ import print_function
15
15
16 # Stdlib imports
16 # Stdlib imports
17 import os
17 import os
18 import re
18 import re
19
19
20 # Third-party imports
20 # Third-party imports
21 import nose.tools as nt
21 import nose.tools as nt
22
22
23 # Our own imports
23 # Our own imports
24 from .. import oinspect
24 from .. import oinspect
25 from IPython.core.magic import (Magics, magics_class, line_magic,
25 from IPython.core.magic import (Magics, magics_class, line_magic,
26 cell_magic, line_cell_magic,
26 cell_magic, line_cell_magic,
27 register_line_magic, register_cell_magic,
27 register_line_magic, register_cell_magic,
28 register_line_cell_magic)
28 register_line_cell_magic)
29 from IPython.external.decorator import decorator
29 from IPython.external.decorator import decorator
30 from IPython.testing.decorators import skipif
30 from IPython.testing.decorators import skipif
31 from IPython.utils import py3compat
31 from IPython.utils import py3compat
32
32
33
33
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35 # Globals and constants
35 # Globals and constants
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37
37
38 inspector = oinspect.Inspector()
38 inspector = oinspect.Inspector()
39 ip = get_ipython()
39 ip = get_ipython()
40
40
41 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
42 # Local utilities
42 # Local utilities
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44
44
45 # WARNING: since this test checks the line number where a function is
45 # WARNING: since this test checks the line number where a function is
46 # defined, if any code is inserted above, the following line will need to be
46 # defined, if any code is inserted above, the following line will need to be
47 # updated. Do NOT insert any whitespace between the next line and the function
47 # updated. Do NOT insert any whitespace between the next line and the function
48 # definition below.
48 # definition below.
49 THIS_LINE_NUMBER = 49 # Put here the actual number of this line
49 THIS_LINE_NUMBER = 49 # Put here the actual number of this line
50 def test_find_source_lines():
50 def test_find_source_lines():
51 nt.assert_equal(oinspect.find_source_lines(test_find_source_lines),
51 nt.assert_equal(oinspect.find_source_lines(test_find_source_lines),
52 THIS_LINE_NUMBER+1)
52 THIS_LINE_NUMBER+1)
53
53
54
54
55 # A couple of utilities to ensure these tests work the same from a source or a
55 # A couple of utilities to ensure these tests work the same from a source or a
56 # binary install
56 # binary install
57 def pyfile(fname):
57 def pyfile(fname):
58 return os.path.normcase(re.sub('.py[co]$', '.py', fname))
58 return os.path.normcase(re.sub('.py[co]$', '.py', fname))
59
59
60
60
61 def match_pyfiles(f1, f2):
61 def match_pyfiles(f1, f2):
62 nt.assert_equal(pyfile(f1), pyfile(f2))
62 nt.assert_equal(pyfile(f1), pyfile(f2))
63
63
64
64
65 def test_find_file():
65 def test_find_file():
66 match_pyfiles(oinspect.find_file(test_find_file), os.path.abspath(__file__))
66 match_pyfiles(oinspect.find_file(test_find_file), os.path.abspath(__file__))
67
67
68
68
69 def test_find_file_decorated1():
69 def test_find_file_decorated1():
70
70
71 @decorator
71 @decorator
72 def noop1(f):
72 def noop1(f):
73 def wrapper():
73 def wrapper():
74 return f(*a, **kw)
74 return f(*a, **kw)
75 return wrapper
75 return wrapper
76
76
77 @noop1
77 @noop1
78 def f(x):
78 def f(x):
79 "My docstring"
79 "My docstring"
80
80
81 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
81 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
82 nt.assert_equal(f.__doc__, "My docstring")
82 nt.assert_equal(f.__doc__, "My docstring")
83
83
84
84
85 def test_find_file_decorated2():
85 def test_find_file_decorated2():
86
86
87 @decorator
87 @decorator
88 def noop2(f, *a, **kw):
88 def noop2(f, *a, **kw):
89 return f(*a, **kw)
89 return f(*a, **kw)
90
90
91 @noop2
91 @noop2
92 def f(x):
92 def f(x):
93 "My docstring 2"
93 "My docstring 2"
94
94
95 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
95 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
96 nt.assert_equal(f.__doc__, "My docstring 2")
96 nt.assert_equal(f.__doc__, "My docstring 2")
97
97
98
98
99 def test_find_file_magic():
99 def test_find_file_magic():
100 run = ip.find_line_magic('run')
100 run = ip.find_line_magic('run')
101 nt.assert_not_equal(oinspect.find_file(run), None)
101 nt.assert_not_equal(oinspect.find_file(run), None)
102
102
103
103
104 # A few generic objects we can then inspect in the tests below
104 # A few generic objects we can then inspect in the tests below
105
105
106 class Call(object):
106 class Call(object):
107 """This is the class docstring."""
107 """This is the class docstring."""
108
108
109 def __init__(self, x, y=1):
109 def __init__(self, x, y=1):
110 """This is the constructor docstring."""
110 """This is the constructor docstring."""
111
111
112 def __call__(self, *a, **kw):
112 def __call__(self, *a, **kw):
113 """This is the call docstring."""
113 """This is the call docstring."""
114
114
115 def method(self, x, z=2):
115 def method(self, x, z=2):
116 """Some method's docstring"""
116 """Some method's docstring"""
117
117
118 class SimpleClass(object):
119 def method(self, x, z=2):
120 """Some method's docstring"""
121
118
122
119 class OldStyle:
123 class OldStyle:
120 """An old-style class for testing."""
124 """An old-style class for testing."""
121 pass
125 pass
122
126
123
127
124 def f(x, y=2, *a, **kw):
128 def f(x, y=2, *a, **kw):
125 """A simple function."""
129 """A simple function."""
126
130
127
131
128 def g(y, z=3, *a, **kw):
132 def g(y, z=3, *a, **kw):
129 pass # no docstring
133 pass # no docstring
130
134
131
135
132 @register_line_magic
136 @register_line_magic
133 def lmagic(line):
137 def lmagic(line):
134 "A line magic"
138 "A line magic"
135
139
136
140
137 @register_cell_magic
141 @register_cell_magic
138 def cmagic(line, cell):
142 def cmagic(line, cell):
139 "A cell magic"
143 "A cell magic"
140
144
141
145
142 @register_line_cell_magic
146 @register_line_cell_magic
143 def lcmagic(line, cell=None):
147 def lcmagic(line, cell=None):
144 "A line/cell magic"
148 "A line/cell magic"
145
149
146
150
147 @magics_class
151 @magics_class
148 class SimpleMagics(Magics):
152 class SimpleMagics(Magics):
149 @line_magic
153 @line_magic
150 def Clmagic(self, cline):
154 def Clmagic(self, cline):
151 "A class-based line magic"
155 "A class-based line magic"
152
156
153 @cell_magic
157 @cell_magic
154 def Ccmagic(self, cline, ccell):
158 def Ccmagic(self, cline, ccell):
155 "A class-based cell magic"
159 "A class-based cell magic"
156
160
157 @line_cell_magic
161 @line_cell_magic
158 def Clcmagic(self, cline, ccell=None):
162 def Clcmagic(self, cline, ccell=None):
159 "A class-based line/cell magic"
163 "A class-based line/cell magic"
160
164
161
165
162 class Awkward(object):
166 class Awkward(object):
163 def __getattr__(self, name):
167 def __getattr__(self, name):
164 raise Exception(name)
168 raise Exception(name)
165
169
166
170
167 def check_calltip(obj, name, call, docstring):
171 def check_calltip(obj, name, call, docstring):
168 """Generic check pattern all calltip tests will use"""
172 """Generic check pattern all calltip tests will use"""
169 info = inspector.info(obj, name)
173 info = inspector.info(obj, name)
170 call_line, ds = oinspect.call_tip(info)
174 call_line, ds = oinspect.call_tip(info)
171 nt.assert_equal(call_line, call)
175 nt.assert_equal(call_line, call)
172 nt.assert_equal(ds, docstring)
176 nt.assert_equal(ds, docstring)
173
177
174 #-----------------------------------------------------------------------------
178 #-----------------------------------------------------------------------------
175 # Tests
179 # Tests
176 #-----------------------------------------------------------------------------
180 #-----------------------------------------------------------------------------
177
181
178 def test_calltip_class():
182 def test_calltip_class():
179 check_calltip(Call, 'Call', 'Call(x, y=1)', Call.__init__.__doc__)
183 check_calltip(Call, 'Call', 'Call(x, y=1)', Call.__init__.__doc__)
180
184
181
185
182 def test_calltip_instance():
186 def test_calltip_instance():
183 c = Call(1)
187 c = Call(1)
184 check_calltip(c, 'c', 'c(*a, **kw)', c.__call__.__doc__)
188 check_calltip(c, 'c', 'c(*a, **kw)', c.__call__.__doc__)
185
189
186
190
187 def test_calltip_method():
191 def test_calltip_method():
188 c = Call(1)
192 c = Call(1)
189 check_calltip(c.method, 'c.method', 'c.method(x, z=2)', c.method.__doc__)
193 check_calltip(c.method, 'c.method', 'c.method(x, z=2)', c.method.__doc__)
190
194
191
195
192 def test_calltip_function():
196 def test_calltip_function():
193 check_calltip(f, 'f', 'f(x, y=2, *a, **kw)', f.__doc__)
197 check_calltip(f, 'f', 'f(x, y=2, *a, **kw)', f.__doc__)
194
198
195
199
196 def test_calltip_function2():
200 def test_calltip_function2():
197 check_calltip(g, 'g', 'g(y, z=3, *a, **kw)', '<no docstring>')
201 check_calltip(g, 'g', 'g(y, z=3, *a, **kw)', '<no docstring>')
198
202
199
203
200 def test_calltip_builtin():
204 def test_calltip_builtin():
201 check_calltip(sum, 'sum', None, sum.__doc__)
205 check_calltip(sum, 'sum', None, sum.__doc__)
202
206
203
207
204 def test_calltip_line_magic():
208 def test_calltip_line_magic():
205 check_calltip(lmagic, 'lmagic', 'lmagic(line)', "A line magic")
209 check_calltip(lmagic, 'lmagic', 'lmagic(line)', "A line magic")
206
210
207
211
208 def test_calltip_cell_magic():
212 def test_calltip_cell_magic():
209 check_calltip(cmagic, 'cmagic', 'cmagic(line, cell)', "A cell magic")
213 check_calltip(cmagic, 'cmagic', 'cmagic(line, cell)', "A cell magic")
210
214
211
215
212 def test_calltip_line_cell_magic():
216 def test_calltip_line_cell_magic():
213 check_calltip(lcmagic, 'lcmagic', 'lcmagic(line, cell=None)',
217 check_calltip(lcmagic, 'lcmagic', 'lcmagic(line, cell=None)',
214 "A line/cell magic")
218 "A line/cell magic")
215
219
216
220
217 def test_class_magics():
221 def test_class_magics():
218 cm = SimpleMagics(ip)
222 cm = SimpleMagics(ip)
219 ip.register_magics(cm)
223 ip.register_magics(cm)
220 check_calltip(cm.Clmagic, 'Clmagic', 'Clmagic(cline)',
224 check_calltip(cm.Clmagic, 'Clmagic', 'Clmagic(cline)',
221 "A class-based line magic")
225 "A class-based line magic")
222 check_calltip(cm.Ccmagic, 'Ccmagic', 'Ccmagic(cline, ccell)',
226 check_calltip(cm.Ccmagic, 'Ccmagic', 'Ccmagic(cline, ccell)',
223 "A class-based cell magic")
227 "A class-based cell magic")
224 check_calltip(cm.Clcmagic, 'Clcmagic', 'Clcmagic(cline, ccell=None)',
228 check_calltip(cm.Clcmagic, 'Clcmagic', 'Clcmagic(cline, ccell=None)',
225 "A class-based line/cell magic")
229 "A class-based line/cell magic")
226
230
227
231
228 def test_info():
232 def test_info():
229 "Check that Inspector.info fills out various fields as expected."
233 "Check that Inspector.info fills out various fields as expected."
230 i = inspector.info(Call, oname='Call')
234 i = inspector.info(Call, oname='Call')
231 nt.assert_equal(i['type_name'], 'type')
235 nt.assert_equal(i['type_name'], 'type')
232 expted_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'>
236 expted_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'>
233 nt.assert_equal(i['base_class'], expted_class)
237 nt.assert_equal(i['base_class'], expted_class)
234 nt.assert_equal(i['string_form'], "<class 'IPython.core.tests.test_oinspect.Call'>")
238 nt.assert_equal(i['string_form'], "<class 'IPython.core.tests.test_oinspect.Call'>")
235 fname = __file__
239 fname = __file__
236 if fname.endswith(".pyc"):
240 if fname.endswith(".pyc"):
237 fname = fname[:-1]
241 fname = fname[:-1]
238 # case-insensitive comparison needed on some filesystems
242 # case-insensitive comparison needed on some filesystems
239 # e.g. Windows:
243 # e.g. Windows:
240 nt.assert_equal(i['file'].lower(), fname.lower())
244 nt.assert_equal(i['file'].lower(), fname.lower())
241 nt.assert_equal(i['definition'], 'Call(self, *a, **kw)\n')
245 nt.assert_equal(i['definition'], 'Call(self, *a, **kw)\n')
242 nt.assert_equal(i['docstring'], Call.__doc__)
246 nt.assert_equal(i['docstring'], Call.__doc__)
243 nt.assert_equal(i['source'], None)
247 nt.assert_equal(i['source'], None)
244 nt.assert_true(i['isclass'])
248 nt.assert_true(i['isclass'])
245 nt.assert_equal(i['init_definition'], "Call(self, x, y=1)\n")
249 nt.assert_equal(i['init_definition'], "Call(self, x, y=1)\n")
246 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
250 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
247
251
248 i = inspector.info(Call, detail_level=1)
252 i = inspector.info(Call, detail_level=1)
249 nt.assert_not_equal(i['source'], None)
253 nt.assert_not_equal(i['source'], None)
250 nt.assert_equal(i['docstring'], None)
254 nt.assert_equal(i['docstring'], None)
251
255
252 c = Call(1)
256 c = Call(1)
253 c.__doc__ = "Modified instance docstring"
257 c.__doc__ = "Modified instance docstring"
254 i = inspector.info(c)
258 i = inspector.info(c)
255 nt.assert_equal(i['type_name'], 'Call')
259 nt.assert_equal(i['type_name'], 'Call')
256 nt.assert_equal(i['docstring'], "Modified instance docstring")
260 nt.assert_equal(i['docstring'], "Modified instance docstring")
257 nt.assert_equal(i['class_docstring'], Call.__doc__)
261 nt.assert_equal(i['class_docstring'], Call.__doc__)
258 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
262 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
259 nt.assert_equal(i['call_docstring'], c.__call__.__doc__)
263 nt.assert_equal(i['call_docstring'], c.__call__.__doc__)
260
264
261 # Test old-style classes, which for example may not have an __init__ method.
265 # Test old-style classes, which for example may not have an __init__ method.
262 if not py3compat.PY3:
266 if not py3compat.PY3:
263 i = inspector.info(OldStyle)
267 i = inspector.info(OldStyle)
264 nt.assert_equal(i['type_name'], 'classobj')
268 nt.assert_equal(i['type_name'], 'classobj')
265
269
266 i = inspector.info(OldStyle())
270 i = inspector.info(OldStyle())
267 nt.assert_equal(i['type_name'], 'instance')
271 nt.assert_equal(i['type_name'], 'instance')
268 nt.assert_equal(i['docstring'], OldStyle.__doc__)
272 nt.assert_equal(i['docstring'], OldStyle.__doc__)
269
273
270 def test_info_awkward():
274 def test_info_awkward():
271 # Just test that this doesn't throw an error.
275 # Just test that this doesn't throw an error.
272 i = inspector.info(Awkward())
276 i = inspector.info(Awkward())
273
277
278 def test_calldef_none():
279 # We should ignore __call__ for all of these.
280 for obj in [f, SimpleClass().method, any, str.upper]:
281 print(obj)
282 i = inspector.info(obj)
283 nt.assert_is(i['call_def'], None)
284
274 if py3compat.PY3:
285 if py3compat.PY3:
275 exec("def f_kwarg(pos, *, kwonly): pass")
286 exec("def f_kwarg(pos, *, kwonly): pass")
276
287
277 @skipif(not py3compat.PY3)
288 @skipif(not py3compat.PY3)
278 def test_definition_kwonlyargs():
289 def test_definition_kwonlyargs():
279 i = inspector.info(f_kwarg, oname='f_kwarg') # analysis:ignore
290 i = inspector.info(f_kwarg, oname='f_kwarg') # analysis:ignore
280 nt.assert_equal(i['definition'], "f_kwarg(pos, *, kwonly)\n")
291 nt.assert_equal(i['definition'], "f_kwarg(pos, *, kwonly)\n")
281
292
282 def test_getdoc():
293 def test_getdoc():
283 class A(object):
294 class A(object):
284 """standard docstring"""
295 """standard docstring"""
285 pass
296 pass
286
297
287 class B(object):
298 class B(object):
288 """standard docstring"""
299 """standard docstring"""
289 def getdoc(self):
300 def getdoc(self):
290 return "custom docstring"
301 return "custom docstring"
291
302
292 class C(object):
303 class C(object):
293 """standard docstring"""
304 """standard docstring"""
294 def getdoc(self):
305 def getdoc(self):
295 return None
306 return None
296
307
297 a = A()
308 a = A()
298 b = B()
309 b = B()
299 c = C()
310 c = C()
300
311
301 nt.assert_equal(oinspect.getdoc(a), "standard docstring")
312 nt.assert_equal(oinspect.getdoc(a), "standard docstring")
302 nt.assert_equal(oinspect.getdoc(b), "custom docstring")
313 nt.assert_equal(oinspect.getdoc(b), "custom docstring")
303 nt.assert_equal(oinspect.getdoc(c), "standard docstring")
314 nt.assert_equal(oinspect.getdoc(c), "standard docstring")
304
315
305 def test_pdef():
316 def test_pdef():
306 # See gh-1914
317 # See gh-1914
307 def foo(): pass
318 def foo(): pass
308 inspector.pdef(foo, 'foo')
319 inspector.pdef(foo, 'foo')
309
320
310 def test_pinfo_nonascii():
321 def test_pinfo_nonascii():
311 # See gh-1177
322 # See gh-1177
312 from . import nonascii2
323 from . import nonascii2
313 ip.user_ns['nonascii2'] = nonascii2
324 ip.user_ns['nonascii2'] = nonascii2
314 ip._inspect('pinfo', 'nonascii2', detail_level=1)
325 ip._inspect('pinfo', 'nonascii2', detail_level=1)
General Comments 0
You need to be logged in to leave comments. Login now