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