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