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