##// END OF EJS Templates
Merge pull request #12016 from Carreau/cleanup-cast...
Matthias Bussonnier -
r25336:ad716972 merge
parent child Browse files
Show More
@@ -1,1058 +1,1031 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 ast
16 import ast
17 import inspect
17 import inspect
18 from inspect import signature
18 from inspect import signature
19 import linecache
19 import linecache
20 import warnings
20 import warnings
21 import os
21 import os
22 from textwrap import dedent
22 from textwrap import dedent
23 import types
23 import types
24 import io as stdlib_io
24 import io as stdlib_io
25 from itertools import zip_longest
25 from itertools import zip_longest
26 from typing import Union
26
27
27 # IPython's own
28 # IPython's own
28 from IPython.core import page
29 from IPython.core import page
29 from IPython.lib.pretty import pretty
30 from IPython.lib.pretty import pretty
30 from IPython.testing.skipdoctest import skip_doctest
31 from IPython.testing.skipdoctest import skip_doctest
31 from IPython.utils import PyColorize
32 from IPython.utils import PyColorize
32 from IPython.utils import openpy
33 from IPython.utils import openpy
33 from IPython.utils import py3compat
34 from IPython.utils import py3compat
34 from IPython.utils.dir2 import safe_hasattr
35 from IPython.utils.dir2 import safe_hasattr
35 from IPython.utils.path import compress_user
36 from IPython.utils.path import compress_user
36 from IPython.utils.text import indent
37 from IPython.utils.text import indent
37 from IPython.utils.wildcard import list_namespace
38 from IPython.utils.wildcard import list_namespace
38 from IPython.utils.wildcard import typestr2type
39 from IPython.utils.wildcard import typestr2type
39 from IPython.utils.coloransi import TermColors, ColorScheme, ColorSchemeTable
40 from IPython.utils.coloransi import TermColors, ColorScheme, ColorSchemeTable
40 from IPython.utils.py3compat import cast_unicode
41 from IPython.utils.py3compat import cast_unicode
41 from IPython.utils.colorable import Colorable
42 from IPython.utils.colorable import Colorable
42 from IPython.utils.decorators import undoc
43 from IPython.utils.decorators import undoc
43
44
44 from pygments import highlight
45 from pygments import highlight
45 from pygments.lexers import PythonLexer
46 from pygments.lexers import PythonLexer
46 from pygments.formatters import HtmlFormatter
47 from pygments.formatters import HtmlFormatter
47
48
48 def pylight(code):
49 def pylight(code):
49 return highlight(code, PythonLexer(), HtmlFormatter(noclasses=True))
50 return highlight(code, PythonLexer(), HtmlFormatter(noclasses=True))
50
51
51 # builtin docstrings to ignore
52 # builtin docstrings to ignore
52 _func_call_docstring = types.FunctionType.__call__.__doc__
53 _func_call_docstring = types.FunctionType.__call__.__doc__
53 _object_init_docstring = object.__init__.__doc__
54 _object_init_docstring = object.__init__.__doc__
54 _builtin_type_docstrings = {
55 _builtin_type_docstrings = {
55 inspect.getdoc(t) for t in (types.ModuleType, types.MethodType,
56 inspect.getdoc(t) for t in (types.ModuleType, types.MethodType,
56 types.FunctionType, property)
57 types.FunctionType, property)
57 }
58 }
58
59
59 _builtin_func_type = type(all)
60 _builtin_func_type = type(all)
60 _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
61 #****************************************************************************
62 #****************************************************************************
62 # Builtin color schemes
63 # Builtin color schemes
63
64
64 Colors = TermColors # just a shorthand
65 Colors = TermColors # just a shorthand
65
66
66 InspectColors = PyColorize.ANSICodeColors
67 InspectColors = PyColorize.ANSICodeColors
67
68
68 #****************************************************************************
69 #****************************************************************************
69 # Auxiliary functions and objects
70 # Auxiliary functions and objects
70
71
71 # 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
72 # effectively defines the order of display
73 # effectively defines the order of display
73 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
74 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
74 'length', 'file', 'definition', 'docstring', 'source',
75 'length', 'file', 'definition', 'docstring', 'source',
75 'init_definition', 'class_docstring', 'init_docstring',
76 'init_definition', 'class_docstring', 'init_docstring',
76 'call_def', 'call_docstring',
77 'call_def', 'call_docstring',
77 # 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
78 # format the object
79 # format the object
79 'ismagic', 'isalias', 'isclass', 'found', 'name'
80 'ismagic', 'isalias', 'isclass', 'found', 'name'
80 ]
81 ]
81
82
82
83
83 def object_info(**kw):
84 def object_info(**kw):
84 """Make an object info dict with all fields present."""
85 """Make an object info dict with all fields present."""
85 infodict = dict(zip_longest(info_fields, [None]))
86 infodict = dict(zip_longest(info_fields, [None]))
86 infodict.update(kw)
87 infodict.update(kw)
87 return infodict
88 return infodict
88
89
89
90
90 def get_encoding(obj):
91 def get_encoding(obj):
91 """Get encoding for python source file defining obj
92 """Get encoding for python source file defining obj
92
93
93 Returns None if obj is not defined in a sourcefile.
94 Returns None if obj is not defined in a sourcefile.
94 """
95 """
95 ofile = find_file(obj)
96 ofile = find_file(obj)
96 # 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
97 # 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
98 # filesystem.
99 # filesystem.
99 if ofile is None:
100 if ofile is None:
100 return None
101 return None
101 elif ofile.endswith(('.so', '.dll', '.pyd')):
102 elif ofile.endswith(('.so', '.dll', '.pyd')):
102 return None
103 return None
103 elif not os.path.isfile(ofile):
104 elif not os.path.isfile(ofile):
104 return None
105 return None
105 else:
106 else:
106 # Print only text files, not extension binaries. Note that
107 # Print only text files, not extension binaries. Note that
107 # getsourcelines returns lineno with 1-offset and page() uses
108 # getsourcelines returns lineno with 1-offset and page() uses
108 # 0-offset, so we must adjust.
109 # 0-offset, so we must adjust.
109 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
110 encoding, lines = openpy.detect_encoding(buffer.readline)
111 encoding, lines = openpy.detect_encoding(buffer.readline)
111 return encoding
112 return encoding
112
113
113 def getdoc(obj):
114 def getdoc(obj) -> Union[str,None]:
114 """Stable wrapper around inspect.getdoc.
115 """Stable wrapper around inspect.getdoc.
115
116
116 This can't crash because of attribute problems.
117 This can't crash because of attribute problems.
117
118
118 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
119 allows objects which provide their docstrings via non-standard mechanisms
120 allows objects which provide their docstrings via non-standard mechanisms
120 (like Pyro proxies) to still be inspected by ipython's ? system.
121 (like Pyro proxies) to still be inspected by ipython's ? system.
121 """
122 """
122 # Allow objects to offer customized documentation via a getdoc method:
123 # Allow objects to offer customized documentation via a getdoc method:
123 try:
124 try:
124 ds = obj.getdoc()
125 ds = obj.getdoc()
125 except Exception:
126 except Exception:
126 pass
127 pass
127 else:
128 else:
128 if isinstance(ds, str):
129 if isinstance(ds, str):
129 return inspect.cleandoc(ds)
130 return inspect.cleandoc(ds)
130 docstr = inspect.getdoc(obj)
131 docstr = inspect.getdoc(obj)
131 encoding = get_encoding(obj)
132 return docstr
132 return py3compat.cast_unicode(docstr, encoding=encoding)
133
133
134
134
135 def getsource(obj, oname=''):
135 def getsource(obj, oname='') -> Union[str,None]:
136 """Wrapper around inspect.getsource.
136 """Wrapper around inspect.getsource.
137
137
138 This can be modified by other projects to provide customized source
138 This can be modified by other projects to provide customized source
139 extraction.
139 extraction.
140
140
141 Parameters
141 Parameters
142 ----------
142 ----------
143 obj : object
143 obj : object
144 an object whose source code we will attempt to extract
144 an object whose source code we will attempt to extract
145 oname : str
145 oname : str
146 (optional) a name under which the object is known
146 (optional) a name under which the object is known
147
147
148 Returns
148 Returns
149 -------
149 -------
150 src : unicode or None
150 src : unicode or None
151
151
152 """
152 """
153
153
154 if isinstance(obj, property):
154 if isinstance(obj, property):
155 sources = []
155 sources = []
156 for attrname in ['fget', 'fset', 'fdel']:
156 for attrname in ['fget', 'fset', 'fdel']:
157 fn = getattr(obj, attrname)
157 fn = getattr(obj, attrname)
158 if fn is not None:
158 if fn is not None:
159 encoding = get_encoding(fn)
159 encoding = get_encoding(fn)
160 oname_prefix = ('%s.' % oname) if oname else ''
160 oname_prefix = ('%s.' % oname) if oname else ''
161 sources.append(cast_unicode(
161 sources.append(''.join(('# ', oname_prefix, attrname)))
162 ''.join(('# ', oname_prefix, attrname)),
163 encoding=encoding))
164 if inspect.isfunction(fn):
162 if inspect.isfunction(fn):
165 sources.append(dedent(getsource(fn)))
163 sources.append(dedent(getsource(fn)))
166 else:
164 else:
167 # Default str/repr only prints function name,
165 # Default str/repr only prints function name,
168 # pretty.pretty prints module name too.
166 # pretty.pretty prints module name too.
169 sources.append(cast_unicode(
167 sources.append(
170 '%s%s = %s\n' % (
168 '%s%s = %s\n' % (oname_prefix, attrname, pretty(fn))
171 oname_prefix, attrname, pretty(fn)),
169 )
172 encoding=encoding))
173 if sources:
170 if sources:
174 return '\n'.join(sources)
171 return '\n'.join(sources)
175 else:
172 else:
176 return None
173 return None
177
174
178 else:
175 else:
179 # Get source for non-property objects.
176 # Get source for non-property objects.
180
177
181 obj = _get_wrapped(obj)
178 obj = _get_wrapped(obj)
182
179
183 try:
180 try:
184 src = inspect.getsource(obj)
181 src = inspect.getsource(obj)
185 except TypeError:
182 except TypeError:
186 # The object itself provided no meaningful source, try looking for
183 # The object itself provided no meaningful source, try looking for
187 # its class definition instead.
184 # its class definition instead.
188 if hasattr(obj, '__class__'):
185 if hasattr(obj, '__class__'):
189 try:
186 try:
190 src = inspect.getsource(obj.__class__)
187 src = inspect.getsource(obj.__class__)
191 except TypeError:
188 except TypeError:
192 return None
189 return None
193
190
194 encoding = get_encoding(obj)
191 return src
195 return cast_unicode(src, encoding=encoding)
196
192
197
193
198 def is_simple_callable(obj):
194 def is_simple_callable(obj):
199 """True if obj is a function ()"""
195 """True if obj is a function ()"""
200 return (inspect.isfunction(obj) or inspect.ismethod(obj) or \
196 return (inspect.isfunction(obj) or inspect.ismethod(obj) or \
201 isinstance(obj, _builtin_func_type) or isinstance(obj, _builtin_meth_type))
197 isinstance(obj, _builtin_func_type) or isinstance(obj, _builtin_meth_type))
202
198
203 @undoc
199 @undoc
204 def getargspec(obj):
200 def getargspec(obj):
205 """Wrapper around :func:`inspect.getfullargspec` on Python 3, and
201 """Wrapper around :func:`inspect.getfullargspec` on Python 3, and
206 :func:inspect.getargspec` on Python 2.
202 :func:inspect.getargspec` on Python 2.
207
203
208 In addition to functions and methods, this can also handle objects with a
204 In addition to functions and methods, this can also handle objects with a
209 ``__call__`` attribute.
205 ``__call__`` attribute.
210
206
211 DEPRECATED: Deprecated since 7.10. Do not use, will be removed.
207 DEPRECATED: Deprecated since 7.10. Do not use, will be removed.
212 """
208 """
213
209
214 warnings.warn('`getargspec` function is deprecated as of IPython 7.10'
210 warnings.warn('`getargspec` function is deprecated as of IPython 7.10'
215 'and will be removed in future versions.', DeprecationWarning, stacklevel=2)
211 'and will be removed in future versions.', DeprecationWarning, stacklevel=2)
216
212
217 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
213 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
218 obj = obj.__call__
214 obj = obj.__call__
219
215
220 return inspect.getfullargspec(obj)
216 return inspect.getfullargspec(obj)
221
217
222 @undoc
218 @undoc
223 def format_argspec(argspec):
219 def format_argspec(argspec):
224 """Format argspect, convenience wrapper around inspect's.
220 """Format argspect, convenience wrapper around inspect's.
225
221
226 This takes a dict instead of ordered arguments and calls
222 This takes a dict instead of ordered arguments and calls
227 inspect.format_argspec with the arguments in the necessary order.
223 inspect.format_argspec with the arguments in the necessary order.
228
224
229 DEPRECATED: Do not use; will be removed in future versions.
225 DEPRECATED: Do not use; will be removed in future versions.
230 """
226 """
231
227
232 warnings.warn('`format_argspec` function is deprecated as of IPython 7.10'
228 warnings.warn('`format_argspec` function is deprecated as of IPython 7.10'
233 'and will be removed in future versions.', DeprecationWarning, stacklevel=2)
229 'and will be removed in future versions.', DeprecationWarning, stacklevel=2)
234
230
235
231
236 return inspect.formatargspec(argspec['args'], argspec['varargs'],
232 return inspect.formatargspec(argspec['args'], argspec['varargs'],
237 argspec['varkw'], argspec['defaults'])
233 argspec['varkw'], argspec['defaults'])
238
234
239 @undoc
235 @undoc
240 def call_tip(oinfo, format_call=True):
236 def call_tip(oinfo, format_call=True):
241 """DEPRECATED. Extract call tip data from an oinfo dict.
237 """DEPRECATED. Extract call tip data from an oinfo dict.
242 """
238 """
243 warnings.warn('`call_tip` function is deprecated as of IPython 6.0'
239 warnings.warn('`call_tip` function is deprecated as of IPython 6.0'
244 'and will be removed in future versions.', DeprecationWarning, stacklevel=2)
240 'and will be removed in future versions.', DeprecationWarning, stacklevel=2)
245 # Get call definition
241 # Get call definition
246 argspec = oinfo.get('argspec')
242 argspec = oinfo.get('argspec')
247 if argspec is None:
243 if argspec is None:
248 call_line = None
244 call_line = None
249 else:
245 else:
250 # Callable objects will have 'self' as their first argument, prune
246 # Callable objects will have 'self' as their first argument, prune
251 # 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
252 # extra first argument explicitly).
248 # extra first argument explicitly).
253 try:
249 try:
254 has_self = argspec['args'][0] == 'self'
250 has_self = argspec['args'][0] == 'self'
255 except (KeyError, IndexError):
251 except (KeyError, IndexError):
256 pass
252 pass
257 else:
253 else:
258 if has_self:
254 if has_self:
259 argspec['args'] = argspec['args'][1:]
255 argspec['args'] = argspec['args'][1:]
260
256
261 call_line = oinfo['name']+format_argspec(argspec)
257 call_line = oinfo['name']+format_argspec(argspec)
262
258
263 # Now get docstring.
259 # Now get docstring.
264 # The priority is: call docstring, constructor docstring, main one.
260 # The priority is: call docstring, constructor docstring, main one.
265 doc = oinfo.get('call_docstring')
261 doc = oinfo.get('call_docstring')
266 if doc is None:
262 if doc is None:
267 doc = oinfo.get('init_docstring')
263 doc = oinfo.get('init_docstring')
268 if doc is None:
264 if doc is None:
269 doc = oinfo.get('docstring','')
265 doc = oinfo.get('docstring','')
270
266
271 return call_line, doc
267 return call_line, doc
272
268
273
269
274 def _get_wrapped(obj):
270 def _get_wrapped(obj):
275 """Get the original object if wrapped in one or more @decorators
271 """Get the original object if wrapped in one or more @decorators
276
272
277 Some objects automatically construct similar objects on any unrecognised
273 Some objects automatically construct similar objects on any unrecognised
278 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,
279 this will arbitrarily cut off after 100 levels of obj.__wrapped__
275 this will arbitrarily cut off after 100 levels of obj.__wrapped__
280 attribute access. --TK, Jan 2016
276 attribute access. --TK, Jan 2016
281 """
277 """
282 orig_obj = obj
278 orig_obj = obj
283 i = 0
279 i = 0
284 while safe_hasattr(obj, '__wrapped__'):
280 while safe_hasattr(obj, '__wrapped__'):
285 obj = obj.__wrapped__
281 obj = obj.__wrapped__
286 i += 1
282 i += 1
287 if i > 100:
283 if i > 100:
288 # __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
289 return orig_obj
285 return orig_obj
290 return obj
286 return obj
291
287
292 def find_file(obj):
288 def find_file(obj) -> str:
293 """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.
294
290
295 This is essentially a robust wrapper around `inspect.getabsfile`.
291 This is essentially a robust wrapper around `inspect.getabsfile`.
296
292
297 Returns None if no file can be found.
293 Returns None if no file can be found.
298
294
299 Parameters
295 Parameters
300 ----------
296 ----------
301 obj : any Python object
297 obj : any Python object
302
298
303 Returns
299 Returns
304 -------
300 -------
305 fname : str
301 fname : str
306 The absolute path to the file where the object was defined.
302 The absolute path to the file where the object was defined.
307 """
303 """
308 obj = _get_wrapped(obj)
304 obj = _get_wrapped(obj)
309
305
310 fname = None
306 fname = None
311 try:
307 try:
312 fname = inspect.getabsfile(obj)
308 fname = inspect.getabsfile(obj)
313 except TypeError:
309 except TypeError:
314 # 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
315 # declared.
311 # declared.
316 if hasattr(obj, '__class__'):
312 if hasattr(obj, '__class__'):
317 try:
313 try:
318 fname = inspect.getabsfile(obj.__class__)
314 fname = inspect.getabsfile(obj.__class__)
319 except TypeError:
315 except TypeError:
320 # Can happen for builtins
316 # Can happen for builtins
321 pass
317 pass
322 except:
318 except:
323 pass
319 pass
324 return cast_unicode(fname)
320 return cast_unicode(fname)
325
321
326
322
327 def find_source_lines(obj):
323 def find_source_lines(obj):
328 """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.
329
325
330 This is essentially a robust wrapper around `inspect.getsourcelines`.
326 This is essentially a robust wrapper around `inspect.getsourcelines`.
331
327
332 Returns None if no file can be found.
328 Returns None if no file can be found.
333
329
334 Parameters
330 Parameters
335 ----------
331 ----------
336 obj : any Python object
332 obj : any Python object
337
333
338 Returns
334 Returns
339 -------
335 -------
340 lineno : int
336 lineno : int
341 The line number where the object definition starts.
337 The line number where the object definition starts.
342 """
338 """
343 obj = _get_wrapped(obj)
339 obj = _get_wrapped(obj)
344
340
345 try:
341 try:
346 try:
342 try:
347 lineno = inspect.getsourcelines(obj)[1]
343 lineno = inspect.getsourcelines(obj)[1]
348 except TypeError:
344 except TypeError:
349 # For instances, try the class object like getsource() does
345 # For instances, try the class object like getsource() does
350 if hasattr(obj, '__class__'):
346 if hasattr(obj, '__class__'):
351 lineno = inspect.getsourcelines(obj.__class__)[1]
347 lineno = inspect.getsourcelines(obj.__class__)[1]
352 else:
348 else:
353 lineno = None
349 lineno = None
354 except:
350 except:
355 return None
351 return None
356
352
357 return lineno
353 return lineno
358
354
359 class Inspector(Colorable):
355 class Inspector(Colorable):
360
356
361 def __init__(self, color_table=InspectColors,
357 def __init__(self, color_table=InspectColors,
362 code_color_table=PyColorize.ANSICodeColors,
358 code_color_table=PyColorize.ANSICodeColors,
363 scheme=None,
359 scheme=None,
364 str_detail_level=0,
360 str_detail_level=0,
365 parent=None, config=None):
361 parent=None, config=None):
366 super(Inspector, self).__init__(parent=parent, config=config)
362 super(Inspector, self).__init__(parent=parent, config=config)
367 self.color_table = color_table
363 self.color_table = color_table
368 self.parser = PyColorize.Parser(out='str', parent=self, style=scheme)
364 self.parser = PyColorize.Parser(out='str', parent=self, style=scheme)
369 self.format = self.parser.format
365 self.format = self.parser.format
370 self.str_detail_level = str_detail_level
366 self.str_detail_level = str_detail_level
371 self.set_active_scheme(scheme)
367 self.set_active_scheme(scheme)
372
368
373 def _getdef(self,obj,oname=''):
369 def _getdef(self,obj,oname='') -> Union[str,None]:
374 """Return the call signature for any callable object.
370 """Return the call signature for any callable object.
375
371
376 If any exception is generated, None is returned instead and the
372 If any exception is generated, None is returned instead and the
377 exception is suppressed."""
373 exception is suppressed."""
378 try:
374 try:
379 hdef = _render_signature(signature(obj), oname)
375 return _render_signature(signature(obj), oname)
380 return cast_unicode(hdef)
381 except:
376 except:
382 return None
377 return None
383
378
384 def __head(self,h):
379 def __head(self,h) -> str:
385 """Return a header string with proper colors."""
380 """Return a header string with proper colors."""
386 return '%s%s%s' % (self.color_table.active_colors.header,h,
381 return '%s%s%s' % (self.color_table.active_colors.header,h,
387 self.color_table.active_colors.normal)
382 self.color_table.active_colors.normal)
388
383
389 def set_active_scheme(self, scheme):
384 def set_active_scheme(self, scheme):
390 if scheme is not None:
385 if scheme is not None:
391 self.color_table.set_active_scheme(scheme)
386 self.color_table.set_active_scheme(scheme)
392 self.parser.color_table.set_active_scheme(scheme)
387 self.parser.color_table.set_active_scheme(scheme)
393
388
394 def noinfo(self, msg, oname):
389 def noinfo(self, msg, oname):
395 """Generic message when no information is found."""
390 """Generic message when no information is found."""
396 print('No %s found' % msg, end=' ')
391 print('No %s found' % msg, end=' ')
397 if oname:
392 if oname:
398 print('for %s' % oname)
393 print('for %s' % oname)
399 else:
394 else:
400 print()
395 print()
401
396
402 def pdef(self, obj, oname=''):
397 def pdef(self, obj, oname=''):
403 """Print the call signature for any callable object.
398 """Print the call signature for any callable object.
404
399
405 If the object is a class, print the constructor information."""
400 If the object is a class, print the constructor information."""
406
401
407 if not callable(obj):
402 if not callable(obj):
408 print('Object is not callable.')
403 print('Object is not callable.')
409 return
404 return
410
405
411 header = ''
406 header = ''
412
407
413 if inspect.isclass(obj):
408 if inspect.isclass(obj):
414 header = self.__head('Class constructor information:\n')
409 header = self.__head('Class constructor information:\n')
415
410
416
411
417 output = self._getdef(obj,oname)
412 output = self._getdef(obj,oname)
418 if output is None:
413 if output is None:
419 self.noinfo('definition header',oname)
414 self.noinfo('definition header',oname)
420 else:
415 else:
421 print(header,self.format(output), end=' ')
416 print(header,self.format(output), end=' ')
422
417
423 # In Python 3, all classes are new-style, so they all have __init__.
418 # In Python 3, all classes are new-style, so they all have __init__.
424 @skip_doctest
419 @skip_doctest
425 def pdoc(self, obj, oname='', formatter=None):
420 def pdoc(self, obj, oname='', formatter=None):
426 """Print the docstring for any object.
421 """Print the docstring for any object.
427
422
428 Optional:
423 Optional:
429 -formatter: a function to run the docstring through for specially
424 -formatter: a function to run the docstring through for specially
430 formatted docstrings.
425 formatted docstrings.
431
426
432 Examples
427 Examples
433 --------
428 --------
434
429
435 In [1]: class NoInit:
430 In [1]: class NoInit:
436 ...: pass
431 ...: pass
437
432
438 In [2]: class NoDoc:
433 In [2]: class NoDoc:
439 ...: def __init__(self):
434 ...: def __init__(self):
440 ...: pass
435 ...: pass
441
436
442 In [3]: %pdoc NoDoc
437 In [3]: %pdoc NoDoc
443 No documentation found for NoDoc
438 No documentation found for NoDoc
444
439
445 In [4]: %pdoc NoInit
440 In [4]: %pdoc NoInit
446 No documentation found for NoInit
441 No documentation found for NoInit
447
442
448 In [5]: obj = NoInit()
443 In [5]: obj = NoInit()
449
444
450 In [6]: %pdoc obj
445 In [6]: %pdoc obj
451 No documentation found for obj
446 No documentation found for obj
452
447
453 In [5]: obj2 = NoDoc()
448 In [5]: obj2 = NoDoc()
454
449
455 In [6]: %pdoc obj2
450 In [6]: %pdoc obj2
456 No documentation found for obj2
451 No documentation found for obj2
457 """
452 """
458
453
459 head = self.__head # For convenience
454 head = self.__head # For convenience
460 lines = []
455 lines = []
461 ds = getdoc(obj)
456 ds = getdoc(obj)
462 if formatter:
457 if formatter:
463 ds = formatter(ds).get('plain/text', ds)
458 ds = formatter(ds).get('plain/text', ds)
464 if ds:
459 if ds:
465 lines.append(head("Class docstring:"))
460 lines.append(head("Class docstring:"))
466 lines.append(indent(ds))
461 lines.append(indent(ds))
467 if inspect.isclass(obj) and hasattr(obj, '__init__'):
462 if inspect.isclass(obj) and hasattr(obj, '__init__'):
468 init_ds = getdoc(obj.__init__)
463 init_ds = getdoc(obj.__init__)
469 if init_ds is not None:
464 if init_ds is not None:
470 lines.append(head("Init docstring:"))
465 lines.append(head("Init docstring:"))
471 lines.append(indent(init_ds))
466 lines.append(indent(init_ds))
472 elif hasattr(obj,'__call__'):
467 elif hasattr(obj,'__call__'):
473 call_ds = getdoc(obj.__call__)
468 call_ds = getdoc(obj.__call__)
474 if call_ds:
469 if call_ds:
475 lines.append(head("Call docstring:"))
470 lines.append(head("Call docstring:"))
476 lines.append(indent(call_ds))
471 lines.append(indent(call_ds))
477
472
478 if not lines:
473 if not lines:
479 self.noinfo('documentation',oname)
474 self.noinfo('documentation',oname)
480 else:
475 else:
481 page.page('\n'.join(lines))
476 page.page('\n'.join(lines))
482
477
483 def psource(self, obj, oname=''):
478 def psource(self, obj, oname=''):
484 """Print the source code for an object."""
479 """Print the source code for an object."""
485
480
486 # Flush the source cache because inspect can return out-of-date source
481 # Flush the source cache because inspect can return out-of-date source
487 linecache.checkcache()
482 linecache.checkcache()
488 try:
483 try:
489 src = getsource(obj, oname=oname)
484 src = getsource(obj, oname=oname)
490 except Exception:
485 except Exception:
491 src = None
486 src = None
492
487
493 if src is None:
488 if src is None:
494 self.noinfo('source', oname)
489 self.noinfo('source', oname)
495 else:
490 else:
496 page.page(self.format(src))
491 page.page(self.format(src))
497
492
498 def pfile(self, obj, oname=''):
493 def pfile(self, obj, oname=''):
499 """Show the whole file where an object was defined."""
494 """Show the whole file where an object was defined."""
500
495
501 lineno = find_source_lines(obj)
496 lineno = find_source_lines(obj)
502 if lineno is None:
497 if lineno is None:
503 self.noinfo('file', oname)
498 self.noinfo('file', oname)
504 return
499 return
505
500
506 ofile = find_file(obj)
501 ofile = find_file(obj)
507 # run contents of file through pager starting at line where the object
502 # run contents of file through pager starting at line where the object
508 # is defined, as long as the file isn't binary and is actually on the
503 # is defined, as long as the file isn't binary and is actually on the
509 # filesystem.
504 # filesystem.
510 if ofile.endswith(('.so', '.dll', '.pyd')):
505 if ofile.endswith(('.so', '.dll', '.pyd')):
511 print('File %r is binary, not printing.' % ofile)
506 print('File %r is binary, not printing.' % ofile)
512 elif not os.path.isfile(ofile):
507 elif not os.path.isfile(ofile):
513 print('File %r does not exist, not printing.' % ofile)
508 print('File %r does not exist, not printing.' % ofile)
514 else:
509 else:
515 # Print only text files, not extension binaries. Note that
510 # Print only text files, not extension binaries. Note that
516 # getsourcelines returns lineno with 1-offset and page() uses
511 # getsourcelines returns lineno with 1-offset and page() uses
517 # 0-offset, so we must adjust.
512 # 0-offset, so we must adjust.
518 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1)
513 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1)
519
514
520 def _format_fields(self, fields, title_width=0):
521 """Formats a list of fields for display.
522
523 Parameters
524 ----------
525 fields : list
526 A list of 2-tuples: (field_title, field_content)
527 title_width : int
528 How many characters to pad titles to. Default to longest title.
529 """
530 out = []
531 header = self.__head
532 if title_width == 0:
533 title_width = max(len(title) + 2 for title, _ in fields)
534 for title, content in fields:
535 if len(content.splitlines()) > 1:
536 title = header(title + ':') + '\n'
537 else:
538 title = header((title + ':').ljust(title_width))
539 out.append(cast_unicode(title) + cast_unicode(content))
540 return "\n".join(out)
541
542 def _mime_format(self, text, formatter=None):
515 def _mime_format(self, text, formatter=None):
543 """Return a mime bundle representation of the input text.
516 """Return a mime bundle representation of the input text.
544
517
545 - if `formatter` is None, the returned mime bundle has
518 - if `formatter` is None, the returned mime bundle has
546 a `text/plain` field, with the input text.
519 a `text/plain` field, with the input text.
547 a `text/html` field with a `<pre>` tag containing the input text.
520 a `text/html` field with a `<pre>` tag containing the input text.
548
521
549 - if `formatter` is not None, it must be a callable transforming the
522 - if `formatter` is not None, it must be a callable transforming the
550 input text into a mime bundle. Default values for `text/plain` and
523 input text into a mime bundle. Default values for `text/plain` and
551 `text/html` representations are the ones described above.
524 `text/html` representations are the ones described above.
552
525
553 Note:
526 Note:
554
527
555 Formatters returning strings are supported but this behavior is deprecated.
528 Formatters returning strings are supported but this behavior is deprecated.
556
529
557 """
530 """
558 text = cast_unicode(text)
531 text = cast_unicode(text)
559 defaults = {
532 defaults = {
560 'text/plain': text,
533 'text/plain': text,
561 'text/html': '<pre>' + text + '</pre>'
534 'text/html': '<pre>' + text + '</pre>'
562 }
535 }
563
536
564 if formatter is None:
537 if formatter is None:
565 return defaults
538 return defaults
566 else:
539 else:
567 formatted = formatter(text)
540 formatted = formatter(text)
568
541
569 if not isinstance(formatted, dict):
542 if not isinstance(formatted, dict):
570 # Handle the deprecated behavior of a formatter returning
543 # Handle the deprecated behavior of a formatter returning
571 # a string instead of a mime bundle.
544 # a string instead of a mime bundle.
572 return {
545 return {
573 'text/plain': formatted,
546 'text/plain': formatted,
574 'text/html': '<pre>' + formatted + '</pre>'
547 'text/html': '<pre>' + formatted + '</pre>'
575 }
548 }
576
549
577 else:
550 else:
578 return dict(defaults, **formatted)
551 return dict(defaults, **formatted)
579
552
580
553
581 def format_mime(self, bundle):
554 def format_mime(self, bundle):
582
555
583 text_plain = bundle['text/plain']
556 text_plain = bundle['text/plain']
584
557
585 text = ''
558 text = ''
586 heads, bodies = list(zip(*text_plain))
559 heads, bodies = list(zip(*text_plain))
587 _len = max(len(h) for h in heads)
560 _len = max(len(h) for h in heads)
588
561
589 for head, body in zip(heads, bodies):
562 for head, body in zip(heads, bodies):
590 body = body.strip('\n')
563 body = body.strip('\n')
591 delim = '\n' if '\n' in body else ' '
564 delim = '\n' if '\n' in body else ' '
592 text += self.__head(head+':') + (_len - len(head))*' ' +delim + body +'\n'
565 text += self.__head(head+':') + (_len - len(head))*' ' +delim + body +'\n'
593
566
594 bundle['text/plain'] = text
567 bundle['text/plain'] = text
595 return bundle
568 return bundle
596
569
597 def _get_info(self, obj, oname='', formatter=None, info=None, detail_level=0):
570 def _get_info(self, obj, oname='', formatter=None, info=None, detail_level=0):
598 """Retrieve an info dict and format it.
571 """Retrieve an info dict and format it.
599
572
600 Parameters
573 Parameters
601 ==========
574 ==========
602
575
603 obj: any
576 obj: any
604 Object to inspect and return info from
577 Object to inspect and return info from
605 oname: str (default: ''):
578 oname: str (default: ''):
606 Name of the variable pointing to `obj`.
579 Name of the variable pointing to `obj`.
607 formatter: callable
580 formatter: callable
608 info:
581 info:
609 already computed information
582 already computed information
610 detail_level: integer
583 detail_level: integer
611 Granularity of detail level, if set to 1, give more information.
584 Granularity of detail level, if set to 1, give more information.
612 """
585 """
613
586
614 info = self._info(obj, oname=oname, info=info, detail_level=detail_level)
587 info = self._info(obj, oname=oname, info=info, detail_level=detail_level)
615
588
616 _mime = {
589 _mime = {
617 'text/plain': [],
590 'text/plain': [],
618 'text/html': '',
591 'text/html': '',
619 }
592 }
620
593
621 def append_field(bundle, title, key, formatter=None):
594 def append_field(bundle, title, key, formatter=None):
622 field = info[key]
595 field = info[key]
623 if field is not None:
596 if field is not None:
624 formatted_field = self._mime_format(field, formatter)
597 formatted_field = self._mime_format(field, formatter)
625 bundle['text/plain'].append((title, formatted_field['text/plain']))
598 bundle['text/plain'].append((title, formatted_field['text/plain']))
626 bundle['text/html'] += '<h1>' + title + '</h1>\n' + formatted_field['text/html'] + '\n'
599 bundle['text/html'] += '<h1>' + title + '</h1>\n' + formatted_field['text/html'] + '\n'
627
600
628 def code_formatter(text):
601 def code_formatter(text):
629 return {
602 return {
630 'text/plain': self.format(text),
603 'text/plain': self.format(text),
631 'text/html': pylight(text)
604 'text/html': pylight(text)
632 }
605 }
633
606
634 if info['isalias']:
607 if info['isalias']:
635 append_field(_mime, 'Repr', 'string_form')
608 append_field(_mime, 'Repr', 'string_form')
636
609
637 elif info['ismagic']:
610 elif info['ismagic']:
638 if detail_level > 0:
611 if detail_level > 0:
639 append_field(_mime, 'Source', 'source', code_formatter)
612 append_field(_mime, 'Source', 'source', code_formatter)
640 else:
613 else:
641 append_field(_mime, 'Docstring', 'docstring', formatter)
614 append_field(_mime, 'Docstring', 'docstring', formatter)
642 append_field(_mime, 'File', 'file')
615 append_field(_mime, 'File', 'file')
643
616
644 elif info['isclass'] or is_simple_callable(obj):
617 elif info['isclass'] or is_simple_callable(obj):
645 # Functions, methods, classes
618 # Functions, methods, classes
646 append_field(_mime, 'Signature', 'definition', code_formatter)
619 append_field(_mime, 'Signature', 'definition', code_formatter)
647 append_field(_mime, 'Init signature', 'init_definition', code_formatter)
620 append_field(_mime, 'Init signature', 'init_definition', code_formatter)
648 append_field(_mime, 'Docstring', 'docstring', formatter)
621 append_field(_mime, 'Docstring', 'docstring', formatter)
649 if detail_level > 0 and info['source']:
622 if detail_level > 0 and info['source']:
650 append_field(_mime, 'Source', 'source', code_formatter)
623 append_field(_mime, 'Source', 'source', code_formatter)
651 else:
624 else:
652 append_field(_mime, 'Init docstring', 'init_docstring', formatter)
625 append_field(_mime, 'Init docstring', 'init_docstring', formatter)
653
626
654 append_field(_mime, 'File', 'file')
627 append_field(_mime, 'File', 'file')
655 append_field(_mime, 'Type', 'type_name')
628 append_field(_mime, 'Type', 'type_name')
656 append_field(_mime, 'Subclasses', 'subclasses')
629 append_field(_mime, 'Subclasses', 'subclasses')
657
630
658 else:
631 else:
659 # General Python objects
632 # General Python objects
660 append_field(_mime, 'Signature', 'definition', code_formatter)
633 append_field(_mime, 'Signature', 'definition', code_formatter)
661 append_field(_mime, 'Call signature', 'call_def', code_formatter)
634 append_field(_mime, 'Call signature', 'call_def', code_formatter)
662 append_field(_mime, 'Type', 'type_name')
635 append_field(_mime, 'Type', 'type_name')
663 append_field(_mime, 'String form', 'string_form')
636 append_field(_mime, 'String form', 'string_form')
664
637
665 # Namespace
638 # Namespace
666 if info['namespace'] != 'Interactive':
639 if info['namespace'] != 'Interactive':
667 append_field(_mime, 'Namespace', 'namespace')
640 append_field(_mime, 'Namespace', 'namespace')
668
641
669 append_field(_mime, 'Length', 'length')
642 append_field(_mime, 'Length', 'length')
670 append_field(_mime, 'File', 'file')
643 append_field(_mime, 'File', 'file')
671
644
672 # Source or docstring, depending on detail level and whether
645 # Source or docstring, depending on detail level and whether
673 # source found.
646 # source found.
674 if detail_level > 0 and info['source']:
647 if detail_level > 0 and info['source']:
675 append_field(_mime, 'Source', 'source', code_formatter)
648 append_field(_mime, 'Source', 'source', code_formatter)
676 else:
649 else:
677 append_field(_mime, 'Docstring', 'docstring', formatter)
650 append_field(_mime, 'Docstring', 'docstring', formatter)
678
651
679 append_field(_mime, 'Class docstring', 'class_docstring', formatter)
652 append_field(_mime, 'Class docstring', 'class_docstring', formatter)
680 append_field(_mime, 'Init docstring', 'init_docstring', formatter)
653 append_field(_mime, 'Init docstring', 'init_docstring', formatter)
681 append_field(_mime, 'Call docstring', 'call_docstring', formatter)
654 append_field(_mime, 'Call docstring', 'call_docstring', formatter)
682
655
683
656
684 return self.format_mime(_mime)
657 return self.format_mime(_mime)
685
658
686 def pinfo(self, obj, oname='', formatter=None, info=None, detail_level=0, enable_html_pager=True):
659 def pinfo(self, obj, oname='', formatter=None, info=None, detail_level=0, enable_html_pager=True):
687 """Show detailed information about an object.
660 """Show detailed information about an object.
688
661
689 Optional arguments:
662 Optional arguments:
690
663
691 - oname: name of the variable pointing to the object.
664 - oname: name of the variable pointing to the object.
692
665
693 - formatter: callable (optional)
666 - formatter: callable (optional)
694 A special formatter for docstrings.
667 A special formatter for docstrings.
695
668
696 The formatter is a callable that takes a string as an input
669 The formatter is a callable that takes a string as an input
697 and returns either a formatted string or a mime type bundle
670 and returns either a formatted string or a mime type bundle
698 in the form of a dictionary.
671 in the form of a dictionary.
699
672
700 Although the support of custom formatter returning a string
673 Although the support of custom formatter returning a string
701 instead of a mime type bundle is deprecated.
674 instead of a mime type bundle is deprecated.
702
675
703 - info: a structure with some information fields which may have been
676 - info: a structure with some information fields which may have been
704 precomputed already.
677 precomputed already.
705
678
706 - detail_level: if set to 1, more information is given.
679 - detail_level: if set to 1, more information is given.
707 """
680 """
708 info = self._get_info(obj, oname, formatter, info, detail_level)
681 info = self._get_info(obj, oname, formatter, info, detail_level)
709 if not enable_html_pager:
682 if not enable_html_pager:
710 del info['text/html']
683 del info['text/html']
711 page.page(info)
684 page.page(info)
712
685
713 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
686 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
714 """DEPRECATED. Compute a dict with detailed information about an object.
687 """DEPRECATED. Compute a dict with detailed information about an object.
715 """
688 """
716 if formatter is not None:
689 if formatter is not None:
717 warnings.warn('The `formatter` keyword argument to `Inspector.info`'
690 warnings.warn('The `formatter` keyword argument to `Inspector.info`'
718 'is deprecated as of IPython 5.0 and will have no effects.',
691 'is deprecated as of IPython 5.0 and will have no effects.',
719 DeprecationWarning, stacklevel=2)
692 DeprecationWarning, stacklevel=2)
720 return self._info(obj, oname=oname, info=info, detail_level=detail_level)
693 return self._info(obj, oname=oname, info=info, detail_level=detail_level)
721
694
722 def _info(self, obj, oname='', info=None, detail_level=0) -> dict:
695 def _info(self, obj, oname='', info=None, detail_level=0) -> dict:
723 """Compute a dict with detailed information about an object.
696 """Compute a dict with detailed information about an object.
724
697
725 Parameters
698 Parameters
726 ==========
699 ==========
727
700
728 obj: any
701 obj: any
729 An object to find information about
702 An object to find information about
730 oname: str (default: ''):
703 oname: str (default: ''):
731 Name of the variable pointing to `obj`.
704 Name of the variable pointing to `obj`.
732 info: (default: None)
705 info: (default: None)
733 A struct (dict like with attr access) with some information fields
706 A struct (dict like with attr access) with some information fields
734 which may have been precomputed already.
707 which may have been precomputed already.
735 detail_level: int (default:0)
708 detail_level: int (default:0)
736 If set to 1, more information is given.
709 If set to 1, more information is given.
737
710
738 Returns
711 Returns
739 =======
712 =======
740
713
741 An object info dict with known fields from `info_fields`.
714 An object info dict with known fields from `info_fields`.
742 """
715 """
743
716
744 if info is None:
717 if info is None:
745 ismagic = False
718 ismagic = False
746 isalias = False
719 isalias = False
747 ospace = ''
720 ospace = ''
748 else:
721 else:
749 ismagic = info.ismagic
722 ismagic = info.ismagic
750 isalias = info.isalias
723 isalias = info.isalias
751 ospace = info.namespace
724 ospace = info.namespace
752
725
753 # Get docstring, special-casing aliases:
726 # Get docstring, special-casing aliases:
754 if isalias:
727 if isalias:
755 if not callable(obj):
728 if not callable(obj):
756 try:
729 try:
757 ds = "Alias to the system command:\n %s" % obj[1]
730 ds = "Alias to the system command:\n %s" % obj[1]
758 except:
731 except:
759 ds = "Alias: " + str(obj)
732 ds = "Alias: " + str(obj)
760 else:
733 else:
761 ds = "Alias to " + str(obj)
734 ds = "Alias to " + str(obj)
762 if obj.__doc__:
735 if obj.__doc__:
763 ds += "\nDocstring:\n" + obj.__doc__
736 ds += "\nDocstring:\n" + obj.__doc__
764 else:
737 else:
765 ds = getdoc(obj)
738 ds = getdoc(obj)
766 if ds is None:
739 if ds is None:
767 ds = '<no docstring>'
740 ds = '<no docstring>'
768
741
769 # store output in a dict, we initialize it here and fill it as we go
742 # store output in a dict, we initialize it here and fill it as we go
770 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic, subclasses=None)
743 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic, subclasses=None)
771
744
772 string_max = 200 # max size of strings to show (snipped if longer)
745 string_max = 200 # max size of strings to show (snipped if longer)
773 shalf = int((string_max - 5) / 2)
746 shalf = int((string_max - 5) / 2)
774
747
775 if ismagic:
748 if ismagic:
776 out['type_name'] = 'Magic function'
749 out['type_name'] = 'Magic function'
777 elif isalias:
750 elif isalias:
778 out['type_name'] = 'System alias'
751 out['type_name'] = 'System alias'
779 else:
752 else:
780 out['type_name'] = type(obj).__name__
753 out['type_name'] = type(obj).__name__
781
754
782 try:
755 try:
783 bclass = obj.__class__
756 bclass = obj.__class__
784 out['base_class'] = str(bclass)
757 out['base_class'] = str(bclass)
785 except:
758 except:
786 pass
759 pass
787
760
788 # String form, but snip if too long in ? form (full in ??)
761 # String form, but snip if too long in ? form (full in ??)
789 if detail_level >= self.str_detail_level:
762 if detail_level >= self.str_detail_level:
790 try:
763 try:
791 ostr = str(obj)
764 ostr = str(obj)
792 str_head = 'string_form'
765 str_head = 'string_form'
793 if not detail_level and len(ostr)>string_max:
766 if not detail_level and len(ostr)>string_max:
794 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
767 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
795 ostr = ("\n" + " " * len(str_head.expandtabs())).\
768 ostr = ("\n" + " " * len(str_head.expandtabs())).\
796 join(q.strip() for q in ostr.split("\n"))
769 join(q.strip() for q in ostr.split("\n"))
797 out[str_head] = ostr
770 out[str_head] = ostr
798 except:
771 except:
799 pass
772 pass
800
773
801 if ospace:
774 if ospace:
802 out['namespace'] = ospace
775 out['namespace'] = ospace
803
776
804 # Length (for strings and lists)
777 # Length (for strings and lists)
805 try:
778 try:
806 out['length'] = str(len(obj))
779 out['length'] = str(len(obj))
807 except Exception:
780 except Exception:
808 pass
781 pass
809
782
810 # Filename where object was defined
783 # Filename where object was defined
811 binary_file = False
784 binary_file = False
812 fname = find_file(obj)
785 fname = find_file(obj)
813 if fname is None:
786 if fname is None:
814 # if anything goes wrong, we don't want to show source, so it's as
787 # if anything goes wrong, we don't want to show source, so it's as
815 # if the file was binary
788 # if the file was binary
816 binary_file = True
789 binary_file = True
817 else:
790 else:
818 if fname.endswith(('.so', '.dll', '.pyd')):
791 if fname.endswith(('.so', '.dll', '.pyd')):
819 binary_file = True
792 binary_file = True
820 elif fname.endswith('<string>'):
793 elif fname.endswith('<string>'):
821 fname = 'Dynamically generated function. No source code available.'
794 fname = 'Dynamically generated function. No source code available.'
822 out['file'] = compress_user(fname)
795 out['file'] = compress_user(fname)
823
796
824 # Original source code for a callable, class or property.
797 # Original source code for a callable, class or property.
825 if detail_level:
798 if detail_level:
826 # Flush the source cache because inspect can return out-of-date
799 # Flush the source cache because inspect can return out-of-date
827 # source
800 # source
828 linecache.checkcache()
801 linecache.checkcache()
829 try:
802 try:
830 if isinstance(obj, property) or not binary_file:
803 if isinstance(obj, property) or not binary_file:
831 src = getsource(obj, oname)
804 src = getsource(obj, oname)
832 if src is not None:
805 if src is not None:
833 src = src.rstrip()
806 src = src.rstrip()
834 out['source'] = src
807 out['source'] = src
835
808
836 except Exception:
809 except Exception:
837 pass
810 pass
838
811
839 # Add docstring only if no source is to be shown (avoid repetitions).
812 # Add docstring only if no source is to be shown (avoid repetitions).
840 if ds and not self._source_contains_docstring(out.get('source'), ds):
813 if ds and not self._source_contains_docstring(out.get('source'), ds):
841 out['docstring'] = ds
814 out['docstring'] = ds
842
815
843 # Constructor docstring for classes
816 # Constructor docstring for classes
844 if inspect.isclass(obj):
817 if inspect.isclass(obj):
845 out['isclass'] = True
818 out['isclass'] = True
846
819
847 # get the init signature:
820 # get the init signature:
848 try:
821 try:
849 init_def = self._getdef(obj, oname)
822 init_def = self._getdef(obj, oname)
850 except AttributeError:
823 except AttributeError:
851 init_def = None
824 init_def = None
852
825
853 # get the __init__ docstring
826 # get the __init__ docstring
854 try:
827 try:
855 obj_init = obj.__init__
828 obj_init = obj.__init__
856 except AttributeError:
829 except AttributeError:
857 init_ds = None
830 init_ds = None
858 else:
831 else:
859 if init_def is None:
832 if init_def is None:
860 # Get signature from init if top-level sig failed.
833 # Get signature from init if top-level sig failed.
861 # Can happen for built-in types (list, etc.).
834 # Can happen for built-in types (list, etc.).
862 try:
835 try:
863 init_def = self._getdef(obj_init, oname)
836 init_def = self._getdef(obj_init, oname)
864 except AttributeError:
837 except AttributeError:
865 pass
838 pass
866 init_ds = getdoc(obj_init)
839 init_ds = getdoc(obj_init)
867 # Skip Python's auto-generated docstrings
840 # Skip Python's auto-generated docstrings
868 if init_ds == _object_init_docstring:
841 if init_ds == _object_init_docstring:
869 init_ds = None
842 init_ds = None
870
843
871 if init_def:
844 if init_def:
872 out['init_definition'] = init_def
845 out['init_definition'] = init_def
873
846
874 if init_ds:
847 if init_ds:
875 out['init_docstring'] = init_ds
848 out['init_docstring'] = init_ds
876
849
877 names = [sub.__name__ for sub in type.__subclasses__(obj)]
850 names = [sub.__name__ for sub in type.__subclasses__(obj)]
878 if len(names) < 10:
851 if len(names) < 10:
879 all_names = ', '.join(names)
852 all_names = ', '.join(names)
880 else:
853 else:
881 all_names = ', '.join(names[:10]+['...'])
854 all_names = ', '.join(names[:10]+['...'])
882 out['subclasses'] = all_names
855 out['subclasses'] = all_names
883 # and class docstring for instances:
856 # and class docstring for instances:
884 else:
857 else:
885 # reconstruct the function definition and print it:
858 # reconstruct the function definition and print it:
886 defln = self._getdef(obj, oname)
859 defln = self._getdef(obj, oname)
887 if defln:
860 if defln:
888 out['definition'] = defln
861 out['definition'] = defln
889
862
890 # First, check whether the instance docstring is identical to the
863 # First, check whether the instance docstring is identical to the
891 # 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
892 # 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
893 # objects which use instance-customized docstrings.
866 # objects which use instance-customized docstrings.
894 if ds:
867 if ds:
895 try:
868 try:
896 cls = getattr(obj,'__class__')
869 cls = getattr(obj,'__class__')
897 except:
870 except:
898 class_ds = None
871 class_ds = None
899 else:
872 else:
900 class_ds = getdoc(cls)
873 class_ds = getdoc(cls)
901 # Skip Python's auto-generated docstrings
874 # Skip Python's auto-generated docstrings
902 if class_ds in _builtin_type_docstrings:
875 if class_ds in _builtin_type_docstrings:
903 class_ds = None
876 class_ds = None
904 if class_ds and ds != class_ds:
877 if class_ds and ds != class_ds:
905 out['class_docstring'] = class_ds
878 out['class_docstring'] = class_ds
906
879
907 # Next, try to show constructor docstrings
880 # Next, try to show constructor docstrings
908 try:
881 try:
909 init_ds = getdoc(obj.__init__)
882 init_ds = getdoc(obj.__init__)
910 # Skip Python's auto-generated docstrings
883 # Skip Python's auto-generated docstrings
911 if init_ds == _object_init_docstring:
884 if init_ds == _object_init_docstring:
912 init_ds = None
885 init_ds = None
913 except AttributeError:
886 except AttributeError:
914 init_ds = None
887 init_ds = None
915 if init_ds:
888 if init_ds:
916 out['init_docstring'] = init_ds
889 out['init_docstring'] = init_ds
917
890
918 # Call form docstring for callable instances
891 # Call form docstring for callable instances
919 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
892 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
920 call_def = self._getdef(obj.__call__, oname)
893 call_def = self._getdef(obj.__call__, oname)
921 if call_def and (call_def != out.get('definition')):
894 if call_def and (call_def != out.get('definition')):
922 # 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,
923 # but don't include the same signature twice
896 # but don't include the same signature twice
924 out['call_def'] = call_def
897 out['call_def'] = call_def
925 call_ds = getdoc(obj.__call__)
898 call_ds = getdoc(obj.__call__)
926 # Skip Python's auto-generated docstrings
899 # Skip Python's auto-generated docstrings
927 if call_ds == _func_call_docstring:
900 if call_ds == _func_call_docstring:
928 call_ds = None
901 call_ds = None
929 if call_ds:
902 if call_ds:
930 out['call_docstring'] = call_ds
903 out['call_docstring'] = call_ds
931
904
932 return object_info(**out)
905 return object_info(**out)
933
906
934 @staticmethod
907 @staticmethod
935 def _source_contains_docstring(src, doc):
908 def _source_contains_docstring(src, doc):
936 """
909 """
937 Check whether the source *src* contains the docstring *doc*.
910 Check whether the source *src* contains the docstring *doc*.
938
911
939 This is is helper function to skip displaying the docstring if the
912 This is is helper function to skip displaying the docstring if the
940 source already contains it, avoiding repetition of information.
913 source already contains it, avoiding repetition of information.
941 """
914 """
942 try:
915 try:
943 def_node, = ast.parse(dedent(src)).body
916 def_node, = ast.parse(dedent(src)).body
944 return ast.get_docstring(def_node) == doc
917 return ast.get_docstring(def_node) == doc
945 except Exception:
918 except Exception:
946 # The source can become invalid or even non-existent (because it
919 # The source can become invalid or even non-existent (because it
947 # is re-fetched from the source file) so the above code fail in
920 # is re-fetched from the source file) so the above code fail in
948 # arbitrary ways.
921 # arbitrary ways.
949 return False
922 return False
950
923
951 def psearch(self,pattern,ns_table,ns_search=[],
924 def psearch(self,pattern,ns_table,ns_search=[],
952 ignore_case=False,show_all=False, *, list_types=False):
925 ignore_case=False,show_all=False, *, list_types=False):
953 """Search namespaces with wildcards for objects.
926 """Search namespaces with wildcards for objects.
954
927
955 Arguments:
928 Arguments:
956
929
957 - pattern: string containing shell-like wildcards to use in namespace
930 - pattern: string containing shell-like wildcards to use in namespace
958 searches and optionally a type specification to narrow the search to
931 searches and optionally a type specification to narrow the search to
959 objects of that type.
932 objects of that type.
960
933
961 - ns_table: dict of name->namespaces for search.
934 - ns_table: dict of name->namespaces for search.
962
935
963 Optional arguments:
936 Optional arguments:
964
937
965 - ns_search: list of namespace names to include in search.
938 - ns_search: list of namespace names to include in search.
966
939
967 - ignore_case(False): make the search case-insensitive.
940 - ignore_case(False): make the search case-insensitive.
968
941
969 - show_all(False): show all names, including those starting with
942 - show_all(False): show all names, including those starting with
970 underscores.
943 underscores.
971
944
972 - list_types(False): list all available object types for object matching.
945 - list_types(False): list all available object types for object matching.
973 """
946 """
974 #print 'ps pattern:<%r>' % pattern # dbg
947 #print 'ps pattern:<%r>' % pattern # dbg
975
948
976 # defaults
949 # defaults
977 type_pattern = 'all'
950 type_pattern = 'all'
978 filter = ''
951 filter = ''
979
952
980 # list all object types
953 # list all object types
981 if list_types:
954 if list_types:
982 page.page('\n'.join(sorted(typestr2type)))
955 page.page('\n'.join(sorted(typestr2type)))
983 return
956 return
984
957
985 cmds = pattern.split()
958 cmds = pattern.split()
986 len_cmds = len(cmds)
959 len_cmds = len(cmds)
987 if len_cmds == 1:
960 if len_cmds == 1:
988 # Only filter pattern given
961 # Only filter pattern given
989 filter = cmds[0]
962 filter = cmds[0]
990 elif len_cmds == 2:
963 elif len_cmds == 2:
991 # Both filter and type specified
964 # Both filter and type specified
992 filter,type_pattern = cmds
965 filter,type_pattern = cmds
993 else:
966 else:
994 raise ValueError('invalid argument string for psearch: <%s>' %
967 raise ValueError('invalid argument string for psearch: <%s>' %
995 pattern)
968 pattern)
996
969
997 # filter search namespaces
970 # filter search namespaces
998 for name in ns_search:
971 for name in ns_search:
999 if name not in ns_table:
972 if name not in ns_table:
1000 raise ValueError('invalid namespace <%s>. Valid names: %s' %
973 raise ValueError('invalid namespace <%s>. Valid names: %s' %
1001 (name,ns_table.keys()))
974 (name,ns_table.keys()))
1002
975
1003 #print 'type_pattern:',type_pattern # dbg
976 #print 'type_pattern:',type_pattern # dbg
1004 search_result, namespaces_seen = set(), set()
977 search_result, namespaces_seen = set(), set()
1005 for ns_name in ns_search:
978 for ns_name in ns_search:
1006 ns = ns_table[ns_name]
979 ns = ns_table[ns_name]
1007 # Normally, locals and globals are the same, so we just check one.
980 # Normally, locals and globals are the same, so we just check one.
1008 if id(ns) in namespaces_seen:
981 if id(ns) in namespaces_seen:
1009 continue
982 continue
1010 namespaces_seen.add(id(ns))
983 namespaces_seen.add(id(ns))
1011 tmp_res = list_namespace(ns, type_pattern, filter,
984 tmp_res = list_namespace(ns, type_pattern, filter,
1012 ignore_case=ignore_case, show_all=show_all)
985 ignore_case=ignore_case, show_all=show_all)
1013 search_result.update(tmp_res)
986 search_result.update(tmp_res)
1014
987
1015 page.page('\n'.join(sorted(search_result)))
988 page.page('\n'.join(sorted(search_result)))
1016
989
1017
990
1018 def _render_signature(obj_signature, obj_name):
991 def _render_signature(obj_signature, obj_name) -> str:
1019 """
992 """
1020 This was mostly taken from inspect.Signature.__str__.
993 This was mostly taken from inspect.Signature.__str__.
1021 Look there for the comments.
994 Look there for the comments.
1022 The only change is to add linebreaks when this gets too long.
995 The only change is to add linebreaks when this gets too long.
1023 """
996 """
1024 result = []
997 result = []
1025 pos_only = False
998 pos_only = False
1026 kw_only = True
999 kw_only = True
1027 for param in obj_signature.parameters.values():
1000 for param in obj_signature.parameters.values():
1028 if param.kind == inspect._POSITIONAL_ONLY:
1001 if param.kind == inspect._POSITIONAL_ONLY:
1029 pos_only = True
1002 pos_only = True
1030 elif pos_only:
1003 elif pos_only:
1031 result.append('/')
1004 result.append('/')
1032 pos_only = False
1005 pos_only = False
1033
1006
1034 if param.kind == inspect._VAR_POSITIONAL:
1007 if param.kind == inspect._VAR_POSITIONAL:
1035 kw_only = False
1008 kw_only = False
1036 elif param.kind == inspect._KEYWORD_ONLY and kw_only:
1009 elif param.kind == inspect._KEYWORD_ONLY and kw_only:
1037 result.append('*')
1010 result.append('*')
1038 kw_only = False
1011 kw_only = False
1039
1012
1040 result.append(str(param))
1013 result.append(str(param))
1041
1014
1042 if pos_only:
1015 if pos_only:
1043 result.append('/')
1016 result.append('/')
1044
1017
1045 # add up name, parameters, braces (2), and commas
1018 # add up name, parameters, braces (2), and commas
1046 if len(obj_name) + sum(len(r) + 2 for r in result) > 75:
1019 if len(obj_name) + sum(len(r) + 2 for r in result) > 75:
1047 # This doesn’t fit behind “Signature: ” in an inspect window.
1020 # This doesn’t fit behind “Signature: ” in an inspect window.
1048 rendered = '{}(\n{})'.format(obj_name, ''.join(
1021 rendered = '{}(\n{})'.format(obj_name, ''.join(
1049 ' {},\n'.format(r) for r in result)
1022 ' {},\n'.format(r) for r in result)
1050 )
1023 )
1051 else:
1024 else:
1052 rendered = '{}({})'.format(obj_name, ', '.join(result))
1025 rendered = '{}({})'.format(obj_name, ', '.join(result))
1053
1026
1054 if obj_signature.return_annotation is not inspect._empty:
1027 if obj_signature.return_annotation is not inspect._empty:
1055 anno = inspect.formatannotation(obj_signature.return_annotation)
1028 anno = inspect.formatannotation(obj_signature.return_annotation)
1056 rendered += ' -> {}'.format(anno)
1029 rendered += ' -> {}'.format(anno)
1057
1030
1058 return rendered
1031 return rendered
General Comments 0
You need to be logged in to leave comments. Login now