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