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