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