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