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