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