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