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