##// END OF EJS Templates
pinfo magic return mime bundle
Sylvain Corlay -
Show More

The requested changes are too big and content was truncated. Show full diff

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