##// END OF EJS Templates
Unindent custom docstrings of objects.
Thomas Kluyver -
Show More
@@ -1,770 +1,770
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 #*****************************************************************************
10 #*****************************************************************************
11 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
11 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
12 #
12 #
13 # Distributed under the terms of the BSD License. The full license is in
13 # Distributed under the terms of the BSD License. The full license is in
14 # the file COPYING, distributed as part of this software.
14 # the file COPYING, distributed as part of this software.
15 #*****************************************************************************
15 #*****************************************************************************
16
16
17 __all__ = ['Inspector','InspectColors']
17 __all__ = ['Inspector','InspectColors']
18
18
19 # stdlib modules
19 # stdlib modules
20 import __builtin__
20 import __builtin__
21 import inspect
21 import inspect
22 import linecache
22 import linecache
23 import os
23 import os
24 import sys
24 import sys
25 import types
25 import types
26 from collections import namedtuple
26 from collections import namedtuple
27 try:
27 try:
28 from itertools import izip_longest
28 from itertools import izip_longest
29 except ImportError:
29 except ImportError:
30 from itertools import zip_longest as izip_longest
30 from itertools import zip_longest as izip_longest
31
31
32 # IPython's own
32 # IPython's own
33 from IPython.core import page
33 from IPython.core import page
34 from IPython.testing.skipdoctest import skip_doctest_py3
34 from IPython.testing.skipdoctest import skip_doctest_py3
35 from IPython.utils import PyColorize
35 from IPython.utils import PyColorize
36 from IPython.utils import io
36 from IPython.utils import io
37 from IPython.utils import py3compat
37 from IPython.utils import py3compat
38 from IPython.utils.text import indent
38 from IPython.utils.text import indent
39 from IPython.utils.wildcard import list_namespace
39 from IPython.utils.wildcard import list_namespace
40 from IPython.utils.coloransi import *
40 from IPython.utils.coloransi import *
41
41
42 #****************************************************************************
42 #****************************************************************************
43 # Builtin color schemes
43 # Builtin color schemes
44
44
45 Colors = TermColors # just a shorthand
45 Colors = TermColors # just a shorthand
46
46
47 # Build a few color schemes
47 # Build a few color schemes
48 NoColor = ColorScheme(
48 NoColor = ColorScheme(
49 'NoColor',{
49 'NoColor',{
50 'header' : Colors.NoColor,
50 'header' : Colors.NoColor,
51 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
51 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
52 } )
52 } )
53
53
54 LinuxColors = ColorScheme(
54 LinuxColors = ColorScheme(
55 'Linux',{
55 'Linux',{
56 'header' : Colors.LightRed,
56 'header' : Colors.LightRed,
57 'normal' : Colors.Normal # color off (usu. Colors.Normal)
57 'normal' : Colors.Normal # color off (usu. Colors.Normal)
58 } )
58 } )
59
59
60 LightBGColors = ColorScheme(
60 LightBGColors = ColorScheme(
61 'LightBG',{
61 'LightBG',{
62 'header' : Colors.Red,
62 'header' : Colors.Red,
63 'normal' : Colors.Normal # color off (usu. Colors.Normal)
63 'normal' : Colors.Normal # color off (usu. Colors.Normal)
64 } )
64 } )
65
65
66 # Build table of color schemes (needed by the parser)
66 # Build table of color schemes (needed by the parser)
67 InspectColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
67 InspectColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
68 'Linux')
68 'Linux')
69
69
70 #****************************************************************************
70 #****************************************************************************
71 # Auxiliary functions and objects
71 # Auxiliary functions and objects
72
72
73 # See the messaging spec for the definition of all these fields. This list
73 # See the messaging spec for the definition of all these fields. This list
74 # effectively defines the order of display
74 # effectively defines the order of display
75 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
75 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
76 'length', 'file', 'definition', 'docstring', 'source',
76 'length', 'file', 'definition', 'docstring', 'source',
77 'init_definition', 'class_docstring', 'init_docstring',
77 'init_definition', 'class_docstring', 'init_docstring',
78 'call_def', 'call_docstring',
78 'call_def', 'call_docstring',
79 # These won't be printed but will be used to determine how to
79 # These won't be printed but will be used to determine how to
80 # format the object
80 # format the object
81 'ismagic', 'isalias', 'isclass', 'argspec', 'found', 'name'
81 'ismagic', 'isalias', 'isclass', 'argspec', 'found', 'name'
82 ]
82 ]
83
83
84
84
85 def object_info(**kw):
85 def object_info(**kw):
86 """Make an object info dict with all fields present."""
86 """Make an object info dict with all fields present."""
87 infodict = dict(izip_longest(info_fields, [None]))
87 infodict = dict(izip_longest(info_fields, [None]))
88 infodict.update(kw)
88 infodict.update(kw)
89 return infodict
89 return infodict
90
90
91
91
92 def getdoc(obj):
92 def getdoc(obj):
93 """Stable wrapper around inspect.getdoc.
93 """Stable wrapper around inspect.getdoc.
94
94
95 This can't crash because of attribute problems.
95 This can't crash because of attribute problems.
96
96
97 It also attempts to call a getdoc() method on the given object. This
97 It also attempts to call a getdoc() method on the given object. This
98 allows objects which provide their docstrings via non-standard mechanisms
98 allows objects which provide their docstrings via non-standard mechanisms
99 (like Pyro proxies) to still be inspected by ipython's ? system."""
99 (like Pyro proxies) to still be inspected by ipython's ? system."""
100 # Allow objects to offer customized documentation via a getdoc method:
100 # Allow objects to offer customized documentation via a getdoc method:
101 try:
101 try:
102 ds = obj.getdoc()
102 ds = obj.getdoc()
103 except Exception:
103 except Exception:
104 pass
104 pass
105 else:
105 else:
106 # if we get extra info, we add it to the normal docstring.
106 # if we get extra info, we add it to the normal docstring.
107 if isinstance(ds, basestring):
107 if isinstance(ds, basestring):
108 return ds
108 return inspect.cleandoc(ds)
109
109
110 try:
110 try:
111 return inspect.getdoc(obj)
111 return inspect.getdoc(obj)
112 except Exception:
112 except Exception:
113 # Harden against an inspect failure, which can occur with
113 # Harden against an inspect failure, which can occur with
114 # SWIG-wrapped extensions.
114 # SWIG-wrapped extensions.
115 return None
115 return None
116
116
117
117
118 def getsource(obj,is_binary=False):
118 def getsource(obj,is_binary=False):
119 """Wrapper around inspect.getsource.
119 """Wrapper around inspect.getsource.
120
120
121 This can be modified by other projects to provide customized source
121 This can be modified by other projects to provide customized source
122 extraction.
122 extraction.
123
123
124 Inputs:
124 Inputs:
125
125
126 - obj: an object whose source code we will attempt to extract.
126 - obj: an object whose source code we will attempt to extract.
127
127
128 Optional inputs:
128 Optional inputs:
129
129
130 - is_binary: whether the object is known to come from a binary source.
130 - is_binary: whether the object is known to come from a binary source.
131 This implementation will skip returning any output for binary objects, but
131 This implementation will skip returning any output for binary objects, but
132 custom extractors may know how to meaningfully process them."""
132 custom extractors may know how to meaningfully process them."""
133
133
134 if is_binary:
134 if is_binary:
135 return None
135 return None
136 else:
136 else:
137 # get source if obj was decorated with @decorator
137 # get source if obj was decorated with @decorator
138 if hasattr(obj,"__wrapped__"):
138 if hasattr(obj,"__wrapped__"):
139 obj = obj.__wrapped__
139 obj = obj.__wrapped__
140 try:
140 try:
141 src = inspect.getsource(obj)
141 src = inspect.getsource(obj)
142 except TypeError:
142 except TypeError:
143 if hasattr(obj,'__class__'):
143 if hasattr(obj,'__class__'):
144 src = inspect.getsource(obj.__class__)
144 src = inspect.getsource(obj.__class__)
145 return src
145 return src
146
146
147 def getargspec(obj):
147 def getargspec(obj):
148 """Get the names and default values of a function's arguments.
148 """Get the names and default values of a function's arguments.
149
149
150 A tuple of four things is returned: (args, varargs, varkw, defaults).
150 A tuple of four things is returned: (args, varargs, varkw, defaults).
151 'args' is a list of the argument names (it may contain nested lists).
151 'args' is a list of the argument names (it may contain nested lists).
152 'varargs' and 'varkw' are the names of the * and ** arguments or None.
152 'varargs' and 'varkw' are the names of the * and ** arguments or None.
153 'defaults' is an n-tuple of the default values of the last n arguments.
153 'defaults' is an n-tuple of the default values of the last n arguments.
154
154
155 Modified version of inspect.getargspec from the Python Standard
155 Modified version of inspect.getargspec from the Python Standard
156 Library."""
156 Library."""
157
157
158 if inspect.isfunction(obj):
158 if inspect.isfunction(obj):
159 func_obj = obj
159 func_obj = obj
160 elif inspect.ismethod(obj):
160 elif inspect.ismethod(obj):
161 func_obj = obj.im_func
161 func_obj = obj.im_func
162 elif hasattr(obj, '__call__'):
162 elif hasattr(obj, '__call__'):
163 func_obj = obj.__call__
163 func_obj = obj.__call__
164 else:
164 else:
165 raise TypeError('arg is not a Python function')
165 raise TypeError('arg is not a Python function')
166 args, varargs, varkw = inspect.getargs(func_obj.func_code)
166 args, varargs, varkw = inspect.getargs(func_obj.func_code)
167 return args, varargs, varkw, func_obj.func_defaults
167 return args, varargs, varkw, func_obj.func_defaults
168
168
169
169
170 def format_argspec(argspec):
170 def format_argspec(argspec):
171 """Format argspect, convenience wrapper around inspect's.
171 """Format argspect, convenience wrapper around inspect's.
172
172
173 This takes a dict instead of ordered arguments and calls
173 This takes a dict instead of ordered arguments and calls
174 inspect.format_argspec with the arguments in the necessary order.
174 inspect.format_argspec with the arguments in the necessary order.
175 """
175 """
176 return inspect.formatargspec(argspec['args'], argspec['varargs'],
176 return inspect.formatargspec(argspec['args'], argspec['varargs'],
177 argspec['varkw'], argspec['defaults'])
177 argspec['varkw'], argspec['defaults'])
178
178
179
179
180 def call_tip(oinfo, format_call=True):
180 def call_tip(oinfo, format_call=True):
181 """Extract call tip data from an oinfo dict.
181 """Extract call tip data from an oinfo dict.
182
182
183 Parameters
183 Parameters
184 ----------
184 ----------
185 oinfo : dict
185 oinfo : dict
186
186
187 format_call : bool, optional
187 format_call : bool, optional
188 If True, the call line is formatted and returned as a string. If not, a
188 If True, the call line is formatted and returned as a string. If not, a
189 tuple of (name, argspec) is returned.
189 tuple of (name, argspec) is returned.
190
190
191 Returns
191 Returns
192 -------
192 -------
193 call_info : None, str or (str, dict) tuple.
193 call_info : None, str or (str, dict) tuple.
194 When format_call is True, the whole call information is formattted as a
194 When format_call is True, the whole call information is formattted as a
195 single string. Otherwise, the object's name and its argspec dict are
195 single string. Otherwise, the object's name and its argspec dict are
196 returned. If no call information is available, None is returned.
196 returned. If no call information is available, None is returned.
197
197
198 docstring : str or None
198 docstring : str or None
199 The most relevant docstring for calling purposes is returned, if
199 The most relevant docstring for calling purposes is returned, if
200 available. The priority is: call docstring for callable instances, then
200 available. The priority is: call docstring for callable instances, then
201 constructor docstring for classes, then main object's docstring otherwise
201 constructor docstring for classes, then main object's docstring otherwise
202 (regular functions).
202 (regular functions).
203 """
203 """
204 # Get call definition
204 # Get call definition
205 argspec = oinfo.get('argspec')
205 argspec = oinfo.get('argspec')
206 if argspec is None:
206 if argspec is None:
207 call_line = None
207 call_line = None
208 else:
208 else:
209 # Callable objects will have 'self' as their first argument, prune
209 # Callable objects will have 'self' as their first argument, prune
210 # it out if it's there for clarity (since users do *not* pass an
210 # it out if it's there for clarity (since users do *not* pass an
211 # extra first argument explicitly).
211 # extra first argument explicitly).
212 try:
212 try:
213 has_self = argspec['args'][0] == 'self'
213 has_self = argspec['args'][0] == 'self'
214 except (KeyError, IndexError):
214 except (KeyError, IndexError):
215 pass
215 pass
216 else:
216 else:
217 if has_self:
217 if has_self:
218 argspec['args'] = argspec['args'][1:]
218 argspec['args'] = argspec['args'][1:]
219
219
220 call_line = oinfo['name']+format_argspec(argspec)
220 call_line = oinfo['name']+format_argspec(argspec)
221
221
222 # Now get docstring.
222 # Now get docstring.
223 # The priority is: call docstring, constructor docstring, main one.
223 # The priority is: call docstring, constructor docstring, main one.
224 doc = oinfo.get('call_docstring')
224 doc = oinfo.get('call_docstring')
225 if doc is None:
225 if doc is None:
226 doc = oinfo.get('init_docstring')
226 doc = oinfo.get('init_docstring')
227 if doc is None:
227 if doc is None:
228 doc = oinfo.get('docstring','')
228 doc = oinfo.get('docstring','')
229
229
230 return call_line, doc
230 return call_line, doc
231
231
232
232
233 class Inspector:
233 class Inspector:
234 def __init__(self, color_table=InspectColors,
234 def __init__(self, color_table=InspectColors,
235 code_color_table=PyColorize.ANSICodeColors,
235 code_color_table=PyColorize.ANSICodeColors,
236 scheme='NoColor',
236 scheme='NoColor',
237 str_detail_level=0):
237 str_detail_level=0):
238 self.color_table = color_table
238 self.color_table = color_table
239 self.parser = PyColorize.Parser(code_color_table,out='str')
239 self.parser = PyColorize.Parser(code_color_table,out='str')
240 self.format = self.parser.format
240 self.format = self.parser.format
241 self.str_detail_level = str_detail_level
241 self.str_detail_level = str_detail_level
242 self.set_active_scheme(scheme)
242 self.set_active_scheme(scheme)
243
243
244 def _getdef(self,obj,oname=''):
244 def _getdef(self,obj,oname=''):
245 """Return the definition header for any callable object.
245 """Return the definition header for any callable object.
246
246
247 If any exception is generated, None is returned instead and the
247 If any exception is generated, None is returned instead and the
248 exception is suppressed."""
248 exception is suppressed."""
249
249
250 try:
250 try:
251 # We need a plain string here, NOT unicode!
251 # We need a plain string here, NOT unicode!
252 hdef = oname + inspect.formatargspec(*getargspec(obj))
252 hdef = oname + inspect.formatargspec(*getargspec(obj))
253 return py3compat.unicode_to_str(hdef, 'ascii')
253 return py3compat.unicode_to_str(hdef, 'ascii')
254 except:
254 except:
255 return None
255 return None
256
256
257 def __head(self,h):
257 def __head(self,h):
258 """Return a header string with proper colors."""
258 """Return a header string with proper colors."""
259 return '%s%s%s' % (self.color_table.active_colors.header,h,
259 return '%s%s%s' % (self.color_table.active_colors.header,h,
260 self.color_table.active_colors.normal)
260 self.color_table.active_colors.normal)
261
261
262 def set_active_scheme(self,scheme):
262 def set_active_scheme(self,scheme):
263 self.color_table.set_active_scheme(scheme)
263 self.color_table.set_active_scheme(scheme)
264 self.parser.color_table.set_active_scheme(scheme)
264 self.parser.color_table.set_active_scheme(scheme)
265
265
266 def noinfo(self,msg,oname):
266 def noinfo(self,msg,oname):
267 """Generic message when no information is found."""
267 """Generic message when no information is found."""
268 print 'No %s found' % msg,
268 print 'No %s found' % msg,
269 if oname:
269 if oname:
270 print 'for %s' % oname
270 print 'for %s' % oname
271 else:
271 else:
272 print
272 print
273
273
274 def pdef(self,obj,oname=''):
274 def pdef(self,obj,oname=''):
275 """Print the definition header for any callable object.
275 """Print the definition header for any callable object.
276
276
277 If the object is a class, print the constructor information."""
277 If the object is a class, print the constructor information."""
278
278
279 if not callable(obj):
279 if not callable(obj):
280 print 'Object is not callable.'
280 print 'Object is not callable.'
281 return
281 return
282
282
283 header = ''
283 header = ''
284
284
285 if inspect.isclass(obj):
285 if inspect.isclass(obj):
286 header = self.__head('Class constructor information:\n')
286 header = self.__head('Class constructor information:\n')
287 obj = obj.__init__
287 obj = obj.__init__
288 elif type(obj) is types.InstanceType:
288 elif type(obj) is types.InstanceType:
289 obj = obj.__call__
289 obj = obj.__call__
290
290
291 output = self._getdef(obj,oname)
291 output = self._getdef(obj,oname)
292 if output is None:
292 if output is None:
293 self.noinfo('definition header',oname)
293 self.noinfo('definition header',oname)
294 else:
294 else:
295 print >>io.stdout, header,self.format(output),
295 print >>io.stdout, header,self.format(output),
296
296
297 # In Python 3, all classes are new-style, so they all have __init__.
297 # In Python 3, all classes are new-style, so they all have __init__.
298 @skip_doctest_py3
298 @skip_doctest_py3
299 def pdoc(self,obj,oname='',formatter = None):
299 def pdoc(self,obj,oname='',formatter = None):
300 """Print the docstring for any object.
300 """Print the docstring for any object.
301
301
302 Optional:
302 Optional:
303 -formatter: a function to run the docstring through for specially
303 -formatter: a function to run the docstring through for specially
304 formatted docstrings.
304 formatted docstrings.
305
305
306 Examples
306 Examples
307 --------
307 --------
308
308
309 In [1]: class NoInit:
309 In [1]: class NoInit:
310 ...: pass
310 ...: pass
311
311
312 In [2]: class NoDoc:
312 In [2]: class NoDoc:
313 ...: def __init__(self):
313 ...: def __init__(self):
314 ...: pass
314 ...: pass
315
315
316 In [3]: %pdoc NoDoc
316 In [3]: %pdoc NoDoc
317 No documentation found for NoDoc
317 No documentation found for NoDoc
318
318
319 In [4]: %pdoc NoInit
319 In [4]: %pdoc NoInit
320 No documentation found for NoInit
320 No documentation found for NoInit
321
321
322 In [5]: obj = NoInit()
322 In [5]: obj = NoInit()
323
323
324 In [6]: %pdoc obj
324 In [6]: %pdoc obj
325 No documentation found for obj
325 No documentation found for obj
326
326
327 In [5]: obj2 = NoDoc()
327 In [5]: obj2 = NoDoc()
328
328
329 In [6]: %pdoc obj2
329 In [6]: %pdoc obj2
330 No documentation found for obj2
330 No documentation found for obj2
331 """
331 """
332
332
333 head = self.__head # For convenience
333 head = self.__head # For convenience
334 lines = []
334 lines = []
335 ds = getdoc(obj)
335 ds = getdoc(obj)
336 if formatter:
336 if formatter:
337 ds = formatter(ds)
337 ds = formatter(ds)
338 if ds:
338 if ds:
339 lines.append(head("Class Docstring:"))
339 lines.append(head("Class Docstring:"))
340 lines.append(indent(ds))
340 lines.append(indent(ds))
341 if inspect.isclass(obj) and hasattr(obj, '__init__'):
341 if inspect.isclass(obj) and hasattr(obj, '__init__'):
342 init_ds = getdoc(obj.__init__)
342 init_ds = getdoc(obj.__init__)
343 if init_ds is not None:
343 if init_ds is not None:
344 lines.append(head("Constructor Docstring:"))
344 lines.append(head("Constructor Docstring:"))
345 lines.append(indent(init_ds))
345 lines.append(indent(init_ds))
346 elif hasattr(obj,'__call__'):
346 elif hasattr(obj,'__call__'):
347 call_ds = getdoc(obj.__call__)
347 call_ds = getdoc(obj.__call__)
348 if call_ds:
348 if call_ds:
349 lines.append(head("Calling Docstring:"))
349 lines.append(head("Calling Docstring:"))
350 lines.append(indent(call_ds))
350 lines.append(indent(call_ds))
351
351
352 if not lines:
352 if not lines:
353 self.noinfo('documentation',oname)
353 self.noinfo('documentation',oname)
354 else:
354 else:
355 page.page('\n'.join(lines))
355 page.page('\n'.join(lines))
356
356
357 def psource(self,obj,oname=''):
357 def psource(self,obj,oname=''):
358 """Print the source code for an object."""
358 """Print the source code for an object."""
359
359
360 # Flush the source cache because inspect can return out-of-date source
360 # Flush the source cache because inspect can return out-of-date source
361 linecache.checkcache()
361 linecache.checkcache()
362 try:
362 try:
363 src = getsource(obj)
363 src = getsource(obj)
364 except:
364 except:
365 self.noinfo('source',oname)
365 self.noinfo('source',oname)
366 else:
366 else:
367 page.page(self.format(py3compat.unicode_to_str(src)))
367 page.page(self.format(py3compat.unicode_to_str(src)))
368
368
369 def pfile(self,obj,oname=''):
369 def pfile(self,obj,oname=''):
370 """Show the whole file where an object was defined."""
370 """Show the whole file where an object was defined."""
371
371
372 try:
372 try:
373 try:
373 try:
374 lineno = inspect.getsourcelines(obj)[1]
374 lineno = inspect.getsourcelines(obj)[1]
375 except TypeError:
375 except TypeError:
376 # For instances, try the class object like getsource() does
376 # For instances, try the class object like getsource() does
377 if hasattr(obj,'__class__'):
377 if hasattr(obj,'__class__'):
378 lineno = inspect.getsourcelines(obj.__class__)[1]
378 lineno = inspect.getsourcelines(obj.__class__)[1]
379 # Adjust the inspected object so getabsfile() below works
379 # Adjust the inspected object so getabsfile() below works
380 obj = obj.__class__
380 obj = obj.__class__
381 except:
381 except:
382 self.noinfo('file',oname)
382 self.noinfo('file',oname)
383 return
383 return
384
384
385 # We only reach this point if object was successfully queried
385 # We only reach this point if object was successfully queried
386
386
387 # run contents of file through pager starting at line
387 # run contents of file through pager starting at line
388 # where the object is defined
388 # where the object is defined
389 ofile = inspect.getabsfile(obj)
389 ofile = inspect.getabsfile(obj)
390
390
391 if ofile.endswith(('.so', '.dll', '.pyd')):
391 if ofile.endswith(('.so', '.dll', '.pyd')):
392 print 'File %r is binary, not printing.' % ofile
392 print 'File %r is binary, not printing.' % ofile
393 elif not os.path.isfile(ofile):
393 elif not os.path.isfile(ofile):
394 print 'File %r does not exist, not printing.' % ofile
394 print 'File %r does not exist, not printing.' % ofile
395 else:
395 else:
396 # Print only text files, not extension binaries. Note that
396 # Print only text files, not extension binaries. Note that
397 # getsourcelines returns lineno with 1-offset and page() uses
397 # getsourcelines returns lineno with 1-offset and page() uses
398 # 0-offset, so we must adjust.
398 # 0-offset, so we must adjust.
399 page.page(self.format(open(ofile).read()),lineno-1)
399 page.page(self.format(open(ofile).read()),lineno-1)
400
400
401 def _format_fields(self, fields, title_width=12):
401 def _format_fields(self, fields, title_width=12):
402 """Formats a list of fields for display.
402 """Formats a list of fields for display.
403
403
404 Parameters
404 Parameters
405 ----------
405 ----------
406 fields : list
406 fields : list
407 A list of 2-tuples: (field_title, field_content)
407 A list of 2-tuples: (field_title, field_content)
408 title_width : int
408 title_width : int
409 How many characters to pad titles to. Default 12.
409 How many characters to pad titles to. Default 12.
410 """
410 """
411 out = []
411 out = []
412 header = self.__head
412 header = self.__head
413 for title, content in fields:
413 for title, content in fields:
414 if len(content.splitlines()) > 1:
414 if len(content.splitlines()) > 1:
415 title = header(title + ":") + "\n"
415 title = header(title + ":") + "\n"
416 else:
416 else:
417 title = header((title+":").ljust(title_width))
417 title = header((title+":").ljust(title_width))
418 out.append(title + content)
418 out.append(title + content)
419 return "\n".join(out)
419 return "\n".join(out)
420
420
421 # The fields to be displayed by pinfo: (fancy_name, key_in_info_dict)
421 # The fields to be displayed by pinfo: (fancy_name, key_in_info_dict)
422 pinfo_fields1 = [("Type", "type_name"),
422 pinfo_fields1 = [("Type", "type_name"),
423 ("Base Class", "base_class"),
423 ("Base Class", "base_class"),
424 ("String Form", "string_form"),
424 ("String Form", "string_form"),
425 ("Namespace", "namespace"),
425 ("Namespace", "namespace"),
426 ("Length", "length"),
426 ("Length", "length"),
427 ("File", "file"),
427 ("File", "file"),
428 ("Definition", "definition")]
428 ("Definition", "definition")]
429
429
430 pinfo_fields_obj = [("Class Docstring", "class_docstring"),
430 pinfo_fields_obj = [("Class Docstring", "class_docstring"),
431 ("Constructor Docstring","init_docstring"),
431 ("Constructor Docstring","init_docstring"),
432 ("Call def", "call_def"),
432 ("Call def", "call_def"),
433 ("Call docstring", "call_docstring")]
433 ("Call docstring", "call_docstring")]
434
434
435 def pinfo(self,obj,oname='',formatter=None,info=None,detail_level=0):
435 def pinfo(self,obj,oname='',formatter=None,info=None,detail_level=0):
436 """Show detailed information about an object.
436 """Show detailed information about an object.
437
437
438 Optional arguments:
438 Optional arguments:
439
439
440 - oname: name of the variable pointing to the object.
440 - oname: name of the variable pointing to the object.
441
441
442 - formatter: special formatter for docstrings (see pdoc)
442 - formatter: special formatter for docstrings (see pdoc)
443
443
444 - info: a structure with some information fields which may have been
444 - info: a structure with some information fields which may have been
445 precomputed already.
445 precomputed already.
446
446
447 - detail_level: if set to 1, more information is given.
447 - detail_level: if set to 1, more information is given.
448 """
448 """
449 info = self.info(obj, oname=oname, formatter=formatter,
449 info = self.info(obj, oname=oname, formatter=formatter,
450 info=info, detail_level=detail_level)
450 info=info, detail_level=detail_level)
451 displayfields = []
451 displayfields = []
452 for title, key in self.pinfo_fields1:
452 for title, key in self.pinfo_fields1:
453 field = info[key]
453 field = info[key]
454 if field is not None:
454 if field is not None:
455 displayfields.append((title, field.rstrip()))
455 displayfields.append((title, field.rstrip()))
456
456
457 # Source or docstring, depending on detail level and whether
457 # Source or docstring, depending on detail level and whether
458 # source found.
458 # source found.
459 if detail_level > 0 and info['source'] is not None:
459 if detail_level > 0 and info['source'] is not None:
460 displayfields.append(("Source", self.format(py3compat.unicode_to_str(info['source']))))
460 displayfields.append(("Source", self.format(py3compat.unicode_to_str(info['source']))))
461 elif info['docstring'] is not None:
461 elif info['docstring'] is not None:
462 displayfields.append(("Docstring", info["docstring"]))
462 displayfields.append(("Docstring", info["docstring"]))
463
463
464 # Constructor info for classes
464 # Constructor info for classes
465 if info['isclass']:
465 if info['isclass']:
466 if info['init_definition'] or info['init_docstring']:
466 if info['init_definition'] or info['init_docstring']:
467 displayfields.append(("Constructor information", ""))
467 displayfields.append(("Constructor information", ""))
468 if info['init_definition'] is not None:
468 if info['init_definition'] is not None:
469 displayfields.append((" Definition",
469 displayfields.append((" Definition",
470 info['init_definition'].rstrip()))
470 info['init_definition'].rstrip()))
471 if info['init_docstring'] is not None:
471 if info['init_docstring'] is not None:
472 displayfields.append((" Docstring",
472 displayfields.append((" Docstring",
473 indent(info['init_docstring'])))
473 indent(info['init_docstring'])))
474
474
475 # Info for objects:
475 # Info for objects:
476 else:
476 else:
477 for title, key in self.pinfo_fields_obj:
477 for title, key in self.pinfo_fields_obj:
478 field = info[key]
478 field = info[key]
479 if field is not None:
479 if field is not None:
480 displayfields.append((title, field.rstrip()))
480 displayfields.append((title, field.rstrip()))
481
481
482 # Finally send to printer/pager:
482 # Finally send to printer/pager:
483 if displayfields:
483 if displayfields:
484 page.page(self._format_fields(displayfields))
484 page.page(self._format_fields(displayfields))
485
485
486 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
486 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
487 """Compute a dict with detailed information about an object.
487 """Compute a dict with detailed information about an object.
488
488
489 Optional arguments:
489 Optional arguments:
490
490
491 - oname: name of the variable pointing to the object.
491 - oname: name of the variable pointing to the object.
492
492
493 - formatter: special formatter for docstrings (see pdoc)
493 - formatter: special formatter for docstrings (see pdoc)
494
494
495 - info: a structure with some information fields which may have been
495 - info: a structure with some information fields which may have been
496 precomputed already.
496 precomputed already.
497
497
498 - detail_level: if set to 1, more information is given.
498 - detail_level: if set to 1, more information is given.
499 """
499 """
500
500
501 obj_type = type(obj)
501 obj_type = type(obj)
502
502
503 header = self.__head
503 header = self.__head
504 if info is None:
504 if info is None:
505 ismagic = 0
505 ismagic = 0
506 isalias = 0
506 isalias = 0
507 ospace = ''
507 ospace = ''
508 else:
508 else:
509 ismagic = info.ismagic
509 ismagic = info.ismagic
510 isalias = info.isalias
510 isalias = info.isalias
511 ospace = info.namespace
511 ospace = info.namespace
512
512
513 # Get docstring, special-casing aliases:
513 # Get docstring, special-casing aliases:
514 if isalias:
514 if isalias:
515 if not callable(obj):
515 if not callable(obj):
516 try:
516 try:
517 ds = "Alias to the system command:\n %s" % obj[1]
517 ds = "Alias to the system command:\n %s" % obj[1]
518 except:
518 except:
519 ds = "Alias: " + str(obj)
519 ds = "Alias: " + str(obj)
520 else:
520 else:
521 ds = "Alias to " + str(obj)
521 ds = "Alias to " + str(obj)
522 if obj.__doc__:
522 if obj.__doc__:
523 ds += "\nDocstring:\n" + obj.__doc__
523 ds += "\nDocstring:\n" + obj.__doc__
524 else:
524 else:
525 ds = getdoc(obj)
525 ds = getdoc(obj)
526 if ds is None:
526 if ds is None:
527 ds = '<no docstring>'
527 ds = '<no docstring>'
528 if formatter is not None:
528 if formatter is not None:
529 ds = formatter(ds)
529 ds = formatter(ds)
530
530
531 # store output in a dict, we initialize it here and fill it as we go
531 # store output in a dict, we initialize it here and fill it as we go
532 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic)
532 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic)
533
533
534 string_max = 200 # max size of strings to show (snipped if longer)
534 string_max = 200 # max size of strings to show (snipped if longer)
535 shalf = int((string_max -5)/2)
535 shalf = int((string_max -5)/2)
536
536
537 if ismagic:
537 if ismagic:
538 obj_type_name = 'Magic function'
538 obj_type_name = 'Magic function'
539 elif isalias:
539 elif isalias:
540 obj_type_name = 'System alias'
540 obj_type_name = 'System alias'
541 else:
541 else:
542 obj_type_name = obj_type.__name__
542 obj_type_name = obj_type.__name__
543 out['type_name'] = obj_type_name
543 out['type_name'] = obj_type_name
544
544
545 try:
545 try:
546 bclass = obj.__class__
546 bclass = obj.__class__
547 out['base_class'] = str(bclass)
547 out['base_class'] = str(bclass)
548 except: pass
548 except: pass
549
549
550 # String form, but snip if too long in ? form (full in ??)
550 # String form, but snip if too long in ? form (full in ??)
551 if detail_level >= self.str_detail_level:
551 if detail_level >= self.str_detail_level:
552 try:
552 try:
553 ostr = str(obj)
553 ostr = str(obj)
554 str_head = 'string_form'
554 str_head = 'string_form'
555 if not detail_level and len(ostr)>string_max:
555 if not detail_level and len(ostr)>string_max:
556 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
556 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
557 ostr = ("\n" + " " * len(str_head.expandtabs())).\
557 ostr = ("\n" + " " * len(str_head.expandtabs())).\
558 join(q.strip() for q in ostr.split("\n"))
558 join(q.strip() for q in ostr.split("\n"))
559 out[str_head] = ostr
559 out[str_head] = ostr
560 except:
560 except:
561 pass
561 pass
562
562
563 if ospace:
563 if ospace:
564 out['namespace'] = ospace
564 out['namespace'] = ospace
565
565
566 # Length (for strings and lists)
566 # Length (for strings and lists)
567 try:
567 try:
568 out['length'] = str(len(obj))
568 out['length'] = str(len(obj))
569 except: pass
569 except: pass
570
570
571 # Filename where object was defined
571 # Filename where object was defined
572 binary_file = False
572 binary_file = False
573 try:
573 try:
574 try:
574 try:
575 fname = inspect.getabsfile(obj)
575 fname = inspect.getabsfile(obj)
576 except TypeError:
576 except TypeError:
577 # For an instance, the file that matters is where its class was
577 # For an instance, the file that matters is where its class was
578 # declared.
578 # declared.
579 if hasattr(obj,'__class__'):
579 if hasattr(obj,'__class__'):
580 fname = inspect.getabsfile(obj.__class__)
580 fname = inspect.getabsfile(obj.__class__)
581 if fname.endswith('<string>'):
581 if fname.endswith('<string>'):
582 fname = 'Dynamically generated function. No source code available.'
582 fname = 'Dynamically generated function. No source code available.'
583 if fname.endswith(('.so', '.dll', '.pyd')):
583 if fname.endswith(('.so', '.dll', '.pyd')):
584 binary_file = True
584 binary_file = True
585 out['file'] = fname
585 out['file'] = fname
586 except:
586 except:
587 # if anything goes wrong, we don't want to show source, so it's as
587 # if anything goes wrong, we don't want to show source, so it's as
588 # if the file was binary
588 # if the file was binary
589 binary_file = True
589 binary_file = True
590
590
591 # reconstruct the function definition and print it:
591 # reconstruct the function definition and print it:
592 defln = self._getdef(obj, oname)
592 defln = self._getdef(obj, oname)
593 if defln:
593 if defln:
594 out['definition'] = self.format(defln)
594 out['definition'] = self.format(defln)
595
595
596 # Docstrings only in detail 0 mode, since source contains them (we
596 # Docstrings only in detail 0 mode, since source contains them (we
597 # avoid repetitions). If source fails, we add them back, see below.
597 # avoid repetitions). If source fails, we add them back, see below.
598 if ds and detail_level == 0:
598 if ds and detail_level == 0:
599 out['docstring'] = ds
599 out['docstring'] = ds
600
600
601 # Original source code for any callable
601 # Original source code for any callable
602 if detail_level:
602 if detail_level:
603 # Flush the source cache because inspect can return out-of-date
603 # Flush the source cache because inspect can return out-of-date
604 # source
604 # source
605 linecache.checkcache()
605 linecache.checkcache()
606 source = None
606 source = None
607 try:
607 try:
608 try:
608 try:
609 source = getsource(obj,binary_file)
609 source = getsource(obj,binary_file)
610 except TypeError:
610 except TypeError:
611 if hasattr(obj,'__class__'):
611 if hasattr(obj,'__class__'):
612 source = getsource(obj.__class__,binary_file)
612 source = getsource(obj.__class__,binary_file)
613 if source is not None:
613 if source is not None:
614 out['source'] = source.rstrip()
614 out['source'] = source.rstrip()
615 except Exception:
615 except Exception:
616 pass
616 pass
617
617
618 if ds and source is None:
618 if ds and source is None:
619 out['docstring'] = ds
619 out['docstring'] = ds
620
620
621
621
622 # Constructor docstring for classes
622 # Constructor docstring for classes
623 if inspect.isclass(obj):
623 if inspect.isclass(obj):
624 out['isclass'] = True
624 out['isclass'] = True
625 # reconstruct the function definition and print it:
625 # reconstruct the function definition and print it:
626 try:
626 try:
627 obj_init = obj.__init__
627 obj_init = obj.__init__
628 except AttributeError:
628 except AttributeError:
629 init_def = init_ds = None
629 init_def = init_ds = None
630 else:
630 else:
631 init_def = self._getdef(obj_init,oname)
631 init_def = self._getdef(obj_init,oname)
632 init_ds = getdoc(obj_init)
632 init_ds = getdoc(obj_init)
633 # Skip Python's auto-generated docstrings
633 # Skip Python's auto-generated docstrings
634 if init_ds and \
634 if init_ds and \
635 init_ds.startswith('x.__init__(...) initializes'):
635 init_ds.startswith('x.__init__(...) initializes'):
636 init_ds = None
636 init_ds = None
637
637
638 if init_def or init_ds:
638 if init_def or init_ds:
639 if init_def:
639 if init_def:
640 out['init_definition'] = self.format(init_def)
640 out['init_definition'] = self.format(init_def)
641 if init_ds:
641 if init_ds:
642 out['init_docstring'] = init_ds
642 out['init_docstring'] = init_ds
643
643
644 # and class docstring for instances:
644 # and class docstring for instances:
645 else:
645 else:
646 # First, check whether the instance docstring is identical to the
646 # First, check whether the instance docstring is identical to the
647 # class one, and print it separately if they don't coincide. In
647 # class one, and print it separately if they don't coincide. In
648 # most cases they will, but it's nice to print all the info for
648 # most cases they will, but it's nice to print all the info for
649 # objects which use instance-customized docstrings.
649 # objects which use instance-customized docstrings.
650 if ds:
650 if ds:
651 try:
651 try:
652 cls = getattr(obj,'__class__')
652 cls = getattr(obj,'__class__')
653 except:
653 except:
654 class_ds = None
654 class_ds = None
655 else:
655 else:
656 class_ds = getdoc(cls)
656 class_ds = getdoc(cls)
657 # Skip Python's auto-generated docstrings
657 # Skip Python's auto-generated docstrings
658 if class_ds and \
658 if class_ds and \
659 (class_ds.startswith('function(code, globals[,') or \
659 (class_ds.startswith('function(code, globals[,') or \
660 class_ds.startswith('instancemethod(function, instance,') or \
660 class_ds.startswith('instancemethod(function, instance,') or \
661 class_ds.startswith('module(name[,') ):
661 class_ds.startswith('module(name[,') ):
662 class_ds = None
662 class_ds = None
663 if class_ds and ds != class_ds:
663 if class_ds and ds != class_ds:
664 out['class_docstring'] = class_ds
664 out['class_docstring'] = class_ds
665
665
666 # Next, try to show constructor docstrings
666 # Next, try to show constructor docstrings
667 try:
667 try:
668 init_ds = getdoc(obj.__init__)
668 init_ds = getdoc(obj.__init__)
669 # Skip Python's auto-generated docstrings
669 # Skip Python's auto-generated docstrings
670 if init_ds and \
670 if init_ds and \
671 init_ds.startswith('x.__init__(...) initializes'):
671 init_ds.startswith('x.__init__(...) initializes'):
672 init_ds = None
672 init_ds = None
673 except AttributeError:
673 except AttributeError:
674 init_ds = None
674 init_ds = None
675 if init_ds:
675 if init_ds:
676 out['init_docstring'] = init_ds
676 out['init_docstring'] = init_ds
677
677
678 # Call form docstring for callable instances
678 # Call form docstring for callable instances
679 if hasattr(obj, '__call__'):
679 if hasattr(obj, '__call__'):
680 call_def = self._getdef(obj.__call__, oname)
680 call_def = self._getdef(obj.__call__, oname)
681 if call_def is not None:
681 if call_def is not None:
682 out['call_def'] = self.format(call_def)
682 out['call_def'] = self.format(call_def)
683 call_ds = getdoc(obj.__call__)
683 call_ds = getdoc(obj.__call__)
684 # Skip Python's auto-generated docstrings
684 # Skip Python's auto-generated docstrings
685 if call_ds and call_ds.startswith('x.__call__(...) <==> x(...)'):
685 if call_ds and call_ds.startswith('x.__call__(...) <==> x(...)'):
686 call_ds = None
686 call_ds = None
687 if call_ds:
687 if call_ds:
688 out['call_docstring'] = call_ds
688 out['call_docstring'] = call_ds
689
689
690 # Compute the object's argspec as a callable. The key is to decide
690 # Compute the object's argspec as a callable. The key is to decide
691 # whether to pull it from the object itself, from its __init__ or
691 # whether to pull it from the object itself, from its __init__ or
692 # from its __call__ method.
692 # from its __call__ method.
693
693
694 if inspect.isclass(obj):
694 if inspect.isclass(obj):
695 # Old-style classes need not have an __init__
695 # Old-style classes need not have an __init__
696 callable_obj = getattr(obj, "__init__", None)
696 callable_obj = getattr(obj, "__init__", None)
697 elif callable(obj):
697 elif callable(obj):
698 callable_obj = obj
698 callable_obj = obj
699 else:
699 else:
700 callable_obj = None
700 callable_obj = None
701
701
702 if callable_obj:
702 if callable_obj:
703 try:
703 try:
704 args, varargs, varkw, defaults = getargspec(callable_obj)
704 args, varargs, varkw, defaults = getargspec(callable_obj)
705 except (TypeError, AttributeError):
705 except (TypeError, AttributeError):
706 # For extensions/builtins we can't retrieve the argspec
706 # For extensions/builtins we can't retrieve the argspec
707 pass
707 pass
708 else:
708 else:
709 out['argspec'] = dict(args=args, varargs=varargs,
709 out['argspec'] = dict(args=args, varargs=varargs,
710 varkw=varkw, defaults=defaults)
710 varkw=varkw, defaults=defaults)
711
711
712 return object_info(**out)
712 return object_info(**out)
713
713
714
714
715 def psearch(self,pattern,ns_table,ns_search=[],
715 def psearch(self,pattern,ns_table,ns_search=[],
716 ignore_case=False,show_all=False):
716 ignore_case=False,show_all=False):
717 """Search namespaces with wildcards for objects.
717 """Search namespaces with wildcards for objects.
718
718
719 Arguments:
719 Arguments:
720
720
721 - pattern: string containing shell-like wildcards to use in namespace
721 - pattern: string containing shell-like wildcards to use in namespace
722 searches and optionally a type specification to narrow the search to
722 searches and optionally a type specification to narrow the search to
723 objects of that type.
723 objects of that type.
724
724
725 - ns_table: dict of name->namespaces for search.
725 - ns_table: dict of name->namespaces for search.
726
726
727 Optional arguments:
727 Optional arguments:
728
728
729 - ns_search: list of namespace names to include in search.
729 - ns_search: list of namespace names to include in search.
730
730
731 - ignore_case(False): make the search case-insensitive.
731 - ignore_case(False): make the search case-insensitive.
732
732
733 - show_all(False): show all names, including those starting with
733 - show_all(False): show all names, including those starting with
734 underscores.
734 underscores.
735 """
735 """
736 #print 'ps pattern:<%r>' % pattern # dbg
736 #print 'ps pattern:<%r>' % pattern # dbg
737
737
738 # defaults
738 # defaults
739 type_pattern = 'all'
739 type_pattern = 'all'
740 filter = ''
740 filter = ''
741
741
742 cmds = pattern.split()
742 cmds = pattern.split()
743 len_cmds = len(cmds)
743 len_cmds = len(cmds)
744 if len_cmds == 1:
744 if len_cmds == 1:
745 # Only filter pattern given
745 # Only filter pattern given
746 filter = cmds[0]
746 filter = cmds[0]
747 elif len_cmds == 2:
747 elif len_cmds == 2:
748 # Both filter and type specified
748 # Both filter and type specified
749 filter,type_pattern = cmds
749 filter,type_pattern = cmds
750 else:
750 else:
751 raise ValueError('invalid argument string for psearch: <%s>' %
751 raise ValueError('invalid argument string for psearch: <%s>' %
752 pattern)
752 pattern)
753
753
754 # filter search namespaces
754 # filter search namespaces
755 for name in ns_search:
755 for name in ns_search:
756 if name not in ns_table:
756 if name not in ns_table:
757 raise ValueError('invalid namespace <%s>. Valid names: %s' %
757 raise ValueError('invalid namespace <%s>. Valid names: %s' %
758 (name,ns_table.keys()))
758 (name,ns_table.keys()))
759
759
760 #print 'type_pattern:',type_pattern # dbg
760 #print 'type_pattern:',type_pattern # dbg
761 search_result = []
761 search_result = []
762 for ns_name in ns_search:
762 for ns_name in ns_search:
763 ns = ns_table[ns_name]
763 ns = ns_table[ns_name]
764 tmp_res = list(list_namespace(ns,type_pattern,filter,
764 tmp_res = list(list_namespace(ns,type_pattern,filter,
765 ignore_case=ignore_case,
765 ignore_case=ignore_case,
766 show_all=show_all))
766 show_all=show_all))
767 search_result.extend(tmp_res)
767 search_result.extend(tmp_res)
768 search_result.sort()
768 search_result.sort()
769
769
770 page.page('\n'.join(search_result))
770 page.page('\n'.join(search_result))
General Comments 0
You need to be logged in to leave comments. Login now