##// END OF EJS Templates
- Small fixes and updates to 'foo?'.
fperez -
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,555 +1,565 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 $Id: OInspect.py 2480 2007-07-06 19:33:43Z fperez $
9 $Id: OInspect.py 2558 2007-07-25 19:54:28Z fperez $
10 """
10 """
11
11
12 #*****************************************************************************
12 #*****************************************************************************
13 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
13 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
14 #
14 #
15 # Distributed under the terms of the BSD License. The full license is in
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
16 # the file COPYING, distributed as part of this software.
17 #*****************************************************************************
17 #*****************************************************************************
18
18
19 from IPython import Release
19 from IPython import Release
20 __author__ = '%s <%s>' % Release.authors['Fernando']
20 __author__ = '%s <%s>' % Release.authors['Fernando']
21 __license__ = Release.license
21 __license__ = Release.license
22
22
23 __all__ = ['Inspector','InspectColors']
23 __all__ = ['Inspector','InspectColors']
24
24
25 # stdlib modules
25 # stdlib modules
26 import __builtin__
26 import __builtin__
27 import inspect
27 import inspect
28 import linecache
28 import linecache
29 import string
29 import string
30 import StringIO
30 import StringIO
31 import types
31 import types
32 import os
32 import os
33 import sys
33 import sys
34 # IPython's own
34 # IPython's own
35 from IPython import PyColorize
35 from IPython import PyColorize
36 from IPython.genutils import page,indent,Term,mkdict
36 from IPython.genutils import page,indent,Term,mkdict
37 from IPython.Itpl import itpl
37 from IPython.Itpl import itpl
38 from IPython.wildcard import list_namespace
38 from IPython.wildcard import list_namespace
39 from IPython.ColorANSI import *
39 from IPython.ColorANSI import *
40
40
41 #****************************************************************************
41 #****************************************************************************
42 # HACK!!! This is a crude fix for bugs in python 2.3's inspect module. We
42 # HACK!!! This is a crude fix for bugs in python 2.3's inspect module. We
43 # simply monkeypatch inspect with code copied from python 2.4.
43 # simply monkeypatch inspect with code copied from python 2.4.
44 if sys.version_info[:2] == (2,3):
44 if sys.version_info[:2] == (2,3):
45 from inspect import ismodule, getabsfile, modulesbyfile
45 from inspect import ismodule, getabsfile, modulesbyfile
46 def getmodule(object):
46 def getmodule(object):
47 """Return the module an object was defined in, or None if not found."""
47 """Return the module an object was defined in, or None if not found."""
48 if ismodule(object):
48 if ismodule(object):
49 return object
49 return object
50 if hasattr(object, '__module__'):
50 if hasattr(object, '__module__'):
51 return sys.modules.get(object.__module__)
51 return sys.modules.get(object.__module__)
52 try:
52 try:
53 file = getabsfile(object)
53 file = getabsfile(object)
54 except TypeError:
54 except TypeError:
55 return None
55 return None
56 if file in modulesbyfile:
56 if file in modulesbyfile:
57 return sys.modules.get(modulesbyfile[file])
57 return sys.modules.get(modulesbyfile[file])
58 for module in sys.modules.values():
58 for module in sys.modules.values():
59 if hasattr(module, '__file__'):
59 if hasattr(module, '__file__'):
60 modulesbyfile[
60 modulesbyfile[
61 os.path.realpath(
61 os.path.realpath(
62 getabsfile(module))] = module.__name__
62 getabsfile(module))] = module.__name__
63 if file in modulesbyfile:
63 if file in modulesbyfile:
64 return sys.modules.get(modulesbyfile[file])
64 return sys.modules.get(modulesbyfile[file])
65 main = sys.modules['__main__']
65 main = sys.modules['__main__']
66 if not hasattr(object, '__name__'):
66 if not hasattr(object, '__name__'):
67 return None
67 return None
68 if hasattr(main, object.__name__):
68 if hasattr(main, object.__name__):
69 mainobject = getattr(main, object.__name__)
69 mainobject = getattr(main, object.__name__)
70 if mainobject is object:
70 if mainobject is object:
71 return main
71 return main
72 builtin = sys.modules['__builtin__']
72 builtin = sys.modules['__builtin__']
73 if hasattr(builtin, object.__name__):
73 if hasattr(builtin, object.__name__):
74 builtinobject = getattr(builtin, object.__name__)
74 builtinobject = getattr(builtin, object.__name__)
75 if builtinobject is object:
75 if builtinobject is object:
76 return builtin
76 return builtin
77
77
78 inspect.getmodule = getmodule
78 inspect.getmodule = getmodule
79
79
80 #****************************************************************************
80 #****************************************************************************
81 # Builtin color schemes
81 # Builtin color schemes
82
82
83 Colors = TermColors # just a shorthand
83 Colors = TermColors # just a shorthand
84
84
85 # Build a few color schemes
85 # Build a few color schemes
86 NoColor = ColorScheme(
86 NoColor = ColorScheme(
87 'NoColor',{
87 'NoColor',{
88 'header' : Colors.NoColor,
88 'header' : Colors.NoColor,
89 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
89 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
90 } )
90 } )
91
91
92 LinuxColors = ColorScheme(
92 LinuxColors = ColorScheme(
93 'Linux',{
93 'Linux',{
94 'header' : Colors.LightRed,
94 'header' : Colors.LightRed,
95 'normal' : Colors.Normal # color off (usu. Colors.Normal)
95 'normal' : Colors.Normal # color off (usu. Colors.Normal)
96 } )
96 } )
97
97
98 LightBGColors = ColorScheme(
98 LightBGColors = ColorScheme(
99 'LightBG',{
99 'LightBG',{
100 'header' : Colors.Red,
100 'header' : Colors.Red,
101 'normal' : Colors.Normal # color off (usu. Colors.Normal)
101 'normal' : Colors.Normal # color off (usu. Colors.Normal)
102 } )
102 } )
103
103
104 # Build table of color schemes (needed by the parser)
104 # Build table of color schemes (needed by the parser)
105 InspectColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
105 InspectColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
106 'Linux')
106 'Linux')
107
107
108 #****************************************************************************
108 #****************************************************************************
109 # Auxiliary functions
109 # Auxiliary functions
110 def getdoc(obj):
110 def getdoc(obj):
111 """Stable wrapper around inspect.getdoc.
111 """Stable wrapper around inspect.getdoc.
112
112
113 This can't crash because of attribute problems.
113 This can't crash because of attribute problems.
114
114
115 It also attempts to call a getdoc() method on the given object. This
115 It also attempts to call a getdoc() method on the given object. This
116 allows objects which provide their docstrings via non-standard mechanisms
116 allows objects which provide their docstrings via non-standard mechanisms
117 (like Pyro proxies) to still be inspected by ipython's ? system."""
117 (like Pyro proxies) to still be inspected by ipython's ? system."""
118
118
119 ds = None # default return value
119 ds = None # default return value
120 try:
120 try:
121 ds = inspect.getdoc(obj)
121 ds = inspect.getdoc(obj)
122 except:
122 except:
123 # Harden against an inspect failure, which can occur with
123 # Harden against an inspect failure, which can occur with
124 # SWIG-wrapped extensions.
124 # SWIG-wrapped extensions.
125 pass
125 pass
126 # Allow objects to offer customized documentation via a getdoc method:
126 # Allow objects to offer customized documentation via a getdoc method:
127 try:
127 try:
128 ds2 = obj.getdoc()
128 ds2 = obj.getdoc()
129 except:
129 except:
130 pass
130 pass
131 else:
131 else:
132 # if we get extra info, we add it to the normal docstring.
132 # if we get extra info, we add it to the normal docstring.
133 if ds is None:
133 if ds is None:
134 ds = ds2
134 ds = ds2
135 else:
135 else:
136 ds = '%s\n%s' % (ds,ds2)
136 ds = '%s\n%s' % (ds,ds2)
137 return ds
137 return ds
138
138
139 def getsource(obj,is_binary=False):
139 def getsource(obj,is_binary=False):
140 """Wrapper around inspect.getsource.
140 """Wrapper around inspect.getsource.
141
141
142 This can be modified by other projects to provide customized source
142 This can be modified by other projects to provide customized source
143 extraction.
143 extraction.
144
144
145 Inputs:
145 Inputs:
146
146
147 - obj: an object whose source code we will attempt to extract.
147 - obj: an object whose source code we will attempt to extract.
148
148
149 Optional inputs:
149 Optional inputs:
150
150
151 - is_binary: whether the object is known to come from a binary source.
151 - is_binary: whether the object is known to come from a binary source.
152 This implementation will skip returning any output for binary objects, but
152 This implementation will skip returning any output for binary objects, but
153 custom extractors may know how to meaningfully process them."""
153 custom extractors may know how to meaningfully process them."""
154
154
155 if is_binary:
155 if is_binary:
156 return None
156 return None
157 else:
157 else:
158 return inspect.getsource(obj)
158 return inspect.getsource(obj)
159
159
160 #****************************************************************************
160 #****************************************************************************
161 # Class definitions
161 # Class definitions
162
162
163 class myStringIO(StringIO.StringIO):
163 class myStringIO(StringIO.StringIO):
164 """Adds a writeln method to normal StringIO."""
164 """Adds a writeln method to normal StringIO."""
165 def writeln(self,*arg,**kw):
165 def writeln(self,*arg,**kw):
166 """Does a write() and then a write('\n')"""
166 """Does a write() and then a write('\n')"""
167 self.write(*arg,**kw)
167 self.write(*arg,**kw)
168 self.write('\n')
168 self.write('\n')
169
169
170 class Inspector:
170 class Inspector:
171 def __init__(self,color_table,code_color_table,scheme,
171 def __init__(self,color_table,code_color_table,scheme,
172 str_detail_level=0):
172 str_detail_level=0):
173 self.color_table = color_table
173 self.color_table = color_table
174 self.parser = PyColorize.Parser(code_color_table,out='str')
174 self.parser = PyColorize.Parser(code_color_table,out='str')
175 self.format = self.parser.format
175 self.format = self.parser.format
176 self.str_detail_level = str_detail_level
176 self.str_detail_level = str_detail_level
177 self.set_active_scheme(scheme)
177 self.set_active_scheme(scheme)
178
178
179 def __getargspec(self,obj):
179 def __getargspec(self,obj):
180 """Get the names and default values of a function's arguments.
180 """Get the names and default values of a function's arguments.
181
181
182 A tuple of four things is returned: (args, varargs, varkw, defaults).
182 A tuple of four things is returned: (args, varargs, varkw, defaults).
183 'args' is a list of the argument names (it may contain nested lists).
183 'args' is a list of the argument names (it may contain nested lists).
184 'varargs' and 'varkw' are the names of the * and ** arguments or None.
184 'varargs' and 'varkw' are the names of the * and ** arguments or None.
185 'defaults' is an n-tuple of the default values of the last n arguments.
185 'defaults' is an n-tuple of the default values of the last n arguments.
186
186
187 Modified version of inspect.getargspec from the Python Standard
187 Modified version of inspect.getargspec from the Python Standard
188 Library."""
188 Library."""
189
189
190 if inspect.isfunction(obj):
190 if inspect.isfunction(obj):
191 func_obj = obj
191 func_obj = obj
192 elif inspect.ismethod(obj):
192 elif inspect.ismethod(obj):
193 func_obj = obj.im_func
193 func_obj = obj.im_func
194 else:
194 else:
195 raise TypeError, 'arg is not a Python function'
195 raise TypeError, 'arg is not a Python function'
196 args, varargs, varkw = inspect.getargs(func_obj.func_code)
196 args, varargs, varkw = inspect.getargs(func_obj.func_code)
197 return args, varargs, varkw, func_obj.func_defaults
197 return args, varargs, varkw, func_obj.func_defaults
198
198
199 def __getdef(self,obj,oname=''):
199 def __getdef(self,obj,oname=''):
200 """Return the definition header for any callable object.
200 """Return the definition header for any callable object.
201
201
202 If any exception is generated, None is returned instead and the
202 If any exception is generated, None is returned instead and the
203 exception is suppressed."""
203 exception is suppressed."""
204
204
205 try:
205 try:
206 return oname + inspect.formatargspec(*self.__getargspec(obj))
206 return oname + inspect.formatargspec(*self.__getargspec(obj))
207 except:
207 except:
208 return None
208 return None
209
209
210 def __head(self,h):
210 def __head(self,h):
211 """Return a header string with proper colors."""
211 """Return a header string with proper colors."""
212 return '%s%s%s' % (self.color_table.active_colors.header,h,
212 return '%s%s%s' % (self.color_table.active_colors.header,h,
213 self.color_table.active_colors.normal)
213 self.color_table.active_colors.normal)
214
214
215 def set_active_scheme(self,scheme):
215 def set_active_scheme(self,scheme):
216 self.color_table.set_active_scheme(scheme)
216 self.color_table.set_active_scheme(scheme)
217 self.parser.color_table.set_active_scheme(scheme)
217 self.parser.color_table.set_active_scheme(scheme)
218
218
219 def noinfo(self,msg,oname):
219 def noinfo(self,msg,oname):
220 """Generic message when no information is found."""
220 """Generic message when no information is found."""
221 print 'No %s found' % msg,
221 print 'No %s found' % msg,
222 if oname:
222 if oname:
223 print 'for %s' % oname
223 print 'for %s' % oname
224 else:
224 else:
225 print
225 print
226
226
227 def pdef(self,obj,oname=''):
227 def pdef(self,obj,oname=''):
228 """Print the definition header for any callable object.
228 """Print the definition header for any callable object.
229
229
230 If the object is a class, print the constructor information."""
230 If the object is a class, print the constructor information."""
231
231
232 if not callable(obj):
232 if not callable(obj):
233 print 'Object is not callable.'
233 print 'Object is not callable.'
234 return
234 return
235
235
236 header = ''
236 header = ''
237
237
238 if inspect.isclass(obj):
238 if inspect.isclass(obj):
239 header = self.__head('Class constructor information:\n')
239 header = self.__head('Class constructor information:\n')
240 obj = obj.__init__
240 obj = obj.__init__
241 elif type(obj) is types.InstanceType or \
241 elif type(obj) is types.InstanceType or \
242 isinstance(obj,object):
242 isinstance(obj,object):
243 obj = obj.__call__
243 obj = obj.__call__
244
244
245 output = self.__getdef(obj,oname)
245 output = self.__getdef(obj,oname)
246 if output is None:
246 if output is None:
247 self.noinfo('definition header',oname)
247 self.noinfo('definition header',oname)
248 else:
248 else:
249 print >>Term.cout, header,self.format(output),
249 print >>Term.cout, header,self.format(output),
250
250
251 def pdoc(self,obj,oname='',formatter = None):
251 def pdoc(self,obj,oname='',formatter = None):
252 """Print the docstring for any object.
252 """Print the docstring for any object.
253
253
254 Optional:
254 Optional:
255 -formatter: a function to run the docstring through for specially
255 -formatter: a function to run the docstring through for specially
256 formatted docstrings."""
256 formatted docstrings."""
257
257
258 head = self.__head # so that itpl can find it even if private
258 head = self.__head # so that itpl can find it even if private
259 ds = getdoc(obj)
259 ds = getdoc(obj)
260 if formatter:
260 if formatter:
261 ds = formatter(ds)
261 ds = formatter(ds)
262 if inspect.isclass(obj):
262 if inspect.isclass(obj):
263 init_ds = getdoc(obj.__init__)
263 init_ds = getdoc(obj.__init__)
264 output = itpl('$head("Class Docstring:")\n'
264 output = itpl('$head("Class Docstring:")\n'
265 '$indent(ds)\n'
265 '$indent(ds)\n'
266 '$head("Constructor Docstring"):\n'
266 '$head("Constructor Docstring"):\n'
267 '$indent(init_ds)')
267 '$indent(init_ds)')
268 elif (type(obj) is types.InstanceType or isinstance(obj,object)) \
268 elif (type(obj) is types.InstanceType or isinstance(obj,object)) \
269 and hasattr(obj,'__call__'):
269 and hasattr(obj,'__call__'):
270 call_ds = getdoc(obj.__call__)
270 call_ds = getdoc(obj.__call__)
271 if call_ds:
271 if call_ds:
272 output = itpl('$head("Class Docstring:")\n$indent(ds)\n'
272 output = itpl('$head("Class Docstring:")\n$indent(ds)\n'
273 '$head("Calling Docstring:")\n$indent(call_ds)')
273 '$head("Calling Docstring:")\n$indent(call_ds)')
274 else:
274 else:
275 output = ds
275 output = ds
276 else:
276 else:
277 output = ds
277 output = ds
278 if output is None:
278 if output is None:
279 self.noinfo('documentation',oname)
279 self.noinfo('documentation',oname)
280 return
280 return
281 page(output)
281 page(output)
282
282
283 def psource(self,obj,oname=''):
283 def psource(self,obj,oname=''):
284 """Print the source code for an object."""
284 """Print the source code for an object."""
285
285
286 # Flush the source cache because inspect can return out-of-date source
286 # Flush the source cache because inspect can return out-of-date source
287 linecache.checkcache()
287 linecache.checkcache()
288 try:
288 try:
289 src = getsource(obj)
289 src = getsource(obj)
290 except:
290 except:
291 self.noinfo('source',oname)
291 self.noinfo('source',oname)
292 else:
292 else:
293 page(self.format(src))
293 page(self.format(src))
294
294
295 def pfile(self,obj,oname=''):
295 def pfile(self,obj,oname=''):
296 """Show the whole file where an object was defined."""
296 """Show the whole file where an object was defined."""
297 try:
297 try:
298 sourcelines,lineno = inspect.getsourcelines(obj)
298 sourcelines,lineno = inspect.getsourcelines(obj)
299 except:
299 except:
300 self.noinfo('file',oname)
300 self.noinfo('file',oname)
301 else:
301 else:
302 # run contents of file through pager starting at line
302 # run contents of file through pager starting at line
303 # where the object is defined
303 # where the object is defined
304 ofile = inspect.getabsfile(obj)
304 ofile = inspect.getabsfile(obj)
305
305
306 if (ofile.endswith('.so') or ofile.endswith('.dll')):
306 if (ofile.endswith('.so') or ofile.endswith('.dll')):
307 print 'File %r is binary, not printing.' % ofile
307 print 'File %r is binary, not printing.' % ofile
308 elif not os.path.isfile(ofile):
308 elif not os.path.isfile(ofile):
309 print 'File %r does not exist, not printing.' % ofile
309 print 'File %r does not exist, not printing.' % ofile
310 else:
310 else:
311 # Print only text files, not extension binaries.
311 # Print only text files, not extension binaries.
312 page(self.format(open(ofile).read()),lineno)
312 page(self.format(open(ofile).read()),lineno)
313 #page(self.format(open(inspect.getabsfile(obj)).read()),lineno)
313 #page(self.format(open(inspect.getabsfile(obj)).read()),lineno)
314
314
315 def pinfo(self,obj,oname='',formatter=None,info=None,detail_level=0):
315 def pinfo(self,obj,oname='',formatter=None,info=None,detail_level=0):
316 """Show detailed information about an object.
316 """Show detailed information about an object.
317
317
318 Optional arguments:
318 Optional arguments:
319
319
320 - oname: name of the variable pointing to the object.
320 - oname: name of the variable pointing to the object.
321
321
322 - formatter: special formatter for docstrings (see pdoc)
322 - formatter: special formatter for docstrings (see pdoc)
323
323
324 - info: a structure with some information fields which may have been
324 - info: a structure with some information fields which may have been
325 precomputed already.
325 precomputed already.
326
326
327 - detail_level: if set to 1, more information is given.
327 - detail_level: if set to 1, more information is given.
328 """
328 """
329
329
330 obj_type = type(obj)
330 obj_type = type(obj)
331
331
332 header = self.__head
332 header = self.__head
333 if info is None:
333 if info is None:
334 ismagic = 0
334 ismagic = 0
335 isalias = 0
335 isalias = 0
336 ospace = ''
336 ospace = ''
337 else:
337 else:
338 ismagic = info.ismagic
338 ismagic = info.ismagic
339 isalias = info.isalias
339 isalias = info.isalias
340 ospace = info.namespace
340 ospace = info.namespace
341 # Get docstring, special-casing aliases:
341 # Get docstring, special-casing aliases:
342 if isalias:
342 if isalias:
343 if not callable(obj):
343 if not callable(obj):
344 ds = "Alias to the system command:\n %s" % obj[1]
344 ds = "Alias to the system command:\n %s" % obj[1]
345 else:
345 else:
346 ds = "Alias to " + str(obj)
346 ds = "Alias to " + str(obj)
347 else:
347 else:
348 ds = getdoc(obj)
348 ds = getdoc(obj)
349 if ds is None:
349 if ds is None:
350 ds = '<no docstring>'
350 ds = '<no docstring>'
351 if formatter is not None:
351 if formatter is not None:
352 ds = formatter(ds)
352 ds = formatter(ds)
353
353
354 # store output in a list which gets joined with \n at the end.
354 # store output in a list which gets joined with \n at the end.
355 out = myStringIO()
355 out = myStringIO()
356
356
357 string_max = 200 # max size of strings to show (snipped if longer)
357 string_max = 200 # max size of strings to show (snipped if longer)
358 shalf = int((string_max -5)/2)
358 shalf = int((string_max -5)/2)
359
359
360 if ismagic:
360 if ismagic:
361 obj_type_name = 'Magic function'
361 obj_type_name = 'Magic function'
362 elif isalias:
362 elif isalias:
363 obj_type_name = 'System alias'
363 obj_type_name = 'System alias'
364 else:
364 else:
365 obj_type_name = obj_type.__name__
365 obj_type_name = obj_type.__name__
366 out.writeln(header('Type:\t\t')+obj_type_name)
366 out.writeln(header('Type:\t\t')+obj_type_name)
367
367
368 try:
368 try:
369 bclass = obj.__class__
369 bclass = obj.__class__
370 out.writeln(header('Base Class:\t')+str(bclass))
370 out.writeln(header('Base Class:\t')+str(bclass))
371 except: pass
371 except: pass
372
372
373 # String form, but snip if too long in ? form (full in ??)
373 # String form, but snip if too long in ? form (full in ??)
374 if detail_level >= self.str_detail_level:
374 if detail_level >= self.str_detail_level:
375 try:
375 try:
376 ostr = str(obj)
376 ostr = str(obj)
377 str_head = 'String Form:'
377 str_head = 'String Form:'
378 if not detail_level and len(ostr)>string_max:
378 if not detail_level and len(ostr)>string_max:
379 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
379 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
380 ostr = ("\n" + " " * len(str_head.expandtabs())).\
380 ostr = ("\n" + " " * len(str_head.expandtabs())).\
381 join(map(string.strip,ostr.split("\n")))
381 join(map(string.strip,ostr.split("\n")))
382 if ostr.find('\n') > -1:
382 if ostr.find('\n') > -1:
383 # Print multi-line strings starting at the next line.
383 # Print multi-line strings starting at the next line.
384 str_sep = '\n'
384 str_sep = '\n'
385 else:
385 else:
386 str_sep = '\t'
386 str_sep = '\t'
387 out.writeln("%s%s%s" % (header(str_head),str_sep,ostr))
387 out.writeln("%s%s%s" % (header(str_head),str_sep,ostr))
388 except:
388 except:
389 pass
389 pass
390
390
391 if ospace:
391 if ospace:
392 out.writeln(header('Namespace:\t')+ospace)
392 out.writeln(header('Namespace:\t')+ospace)
393
393
394 # Length (for strings and lists)
394 # Length (for strings and lists)
395 try:
395 try:
396 length = str(len(obj))
396 length = str(len(obj))
397 out.writeln(header('Length:\t\t')+length)
397 out.writeln(header('Length:\t\t')+length)
398 except: pass
398 except: pass
399
399
400 # Filename where object was defined
400 # Filename where object was defined
401 binary_file = False
401 binary_file = False
402 try:
402 try:
403 fname = inspect.getabsfile(obj)
403 fname = inspect.getabsfile(obj)
404 if fname.endswith('<string>'):
404 if fname.endswith('<string>'):
405 fname = 'Dynamically generated function. No source code available.'
405 fname = 'Dynamically generated function. No source code available.'
406 if (fname.endswith('.so') or fname.endswith('.dll') or
406 if (fname.endswith('.so') or fname.endswith('.dll') or
407 not os.path.isfile(fname)):
407 not os.path.isfile(fname)):
408 binary_file = True
408 binary_file = True
409 out.writeln(header('File:\t\t')+fname)
409 out.writeln(header('File:\t\t')+fname)
410 except:
410 except:
411 # if anything goes wrong, we don't want to show source, so it's as
411 # if anything goes wrong, we don't want to show source, so it's as
412 # if the file was binary
412 # if the file was binary
413 binary_file = True
413 binary_file = True
414
414
415 # reconstruct the function definition and print it:
415 # reconstruct the function definition and print it:
416 defln = self.__getdef(obj,oname)
416 defln = self.__getdef(obj,oname)
417 if defln:
417 if defln:
418 out.write(header('Definition:\t')+self.format(defln))
418 out.write(header('Definition:\t')+self.format(defln))
419
419
420 # Docstrings only in detail 0 mode, since source contains them (we
420 # Docstrings only in detail 0 mode, since source contains them (we
421 # avoid repetitions). If source fails, we add them back, see below.
421 # avoid repetitions). If source fails, we add them back, see below.
422 if ds and detail_level == 0:
422 if ds and detail_level == 0:
423 out.writeln(header('Docstring:\n') + indent(ds))
423 out.writeln(header('Docstring:\n') + indent(ds))
424
424
425
425
426 # Original source code for any callable
426 # Original source code for any callable
427 if detail_level:
427 if detail_level:
428 # Flush the source cache because inspect can return out-of-date source
428 # Flush the source cache because inspect can return out-of-date source
429 linecache.checkcache()
429 linecache.checkcache()
430 source_success = False
430 source_success = False
431 try:
431 try:
432 source = self.format(getsource(obj,binary_file))
432 source = self.format(getsource(obj,binary_file))
433 if source:
433 if source:
434 out.write(header('Source:\n')+source.rstrip())
434 out.write(header('Source:\n')+source.rstrip())
435 source_success = True
435 source_success = True
436 except Exception, msg:
436 except Exception, msg:
437 pass
437 pass
438
438
439 if ds and not source_success:
439 if ds and not source_success:
440 out.writeln(header('Docstring [source file open failed]:\n')
440 out.writeln(header('Docstring [source file open failed]:\n')
441 + indent(ds))
441 + indent(ds))
442
442
443 # Constructor docstring for classes
443 # Constructor docstring for classes
444 if inspect.isclass(obj):
444 if inspect.isclass(obj):
445 # reconstruct the function definition and print it:
445 # reconstruct the function definition and print it:
446 try:
446 try:
447 obj_init = obj.__init__
447 obj_init = obj.__init__
448 except AttributeError:
448 except AttributeError:
449 init_def = init_ds = None
449 init_def = init_ds = None
450 else:
450 else:
451 init_def = self.__getdef(obj_init,oname)
451 init_def = self.__getdef(obj_init,oname)
452 init_ds = getdoc(obj_init)
452 init_ds = getdoc(obj_init)
453
453
454 if init_def or init_ds:
454 if init_def or init_ds:
455 out.writeln(header('\nConstructor information:'))
455 out.writeln(header('\nConstructor information:'))
456 if init_def:
456 if init_def:
457 out.write(header('Definition:\t')+ self.format(init_def))
457 out.write(header('Definition:\t')+ self.format(init_def))
458 if init_ds:
458 if init_ds:
459 out.writeln(header('Docstring:\n') + indent(init_ds))
459 out.writeln(header('Docstring:\n') + indent(init_ds))
460 # and class docstring for instances:
460 # and class docstring for instances:
461 elif obj_type is types.InstanceType or \
461 elif obj_type is types.InstanceType or \
462 isinstance(obj,object):
462 isinstance(obj,object):
463
463
464 # First, check whether the instance docstring is identical to the
464 # First, check whether the instance docstring is identical to the
465 # class one, and print it separately if they don't coincide. In
465 # class one, and print it separately if they don't coincide. In
466 # most cases they will, but it's nice to print all the info for
466 # most cases they will, but it's nice to print all the info for
467 # objects which use instance-customized docstrings.
467 # objects which use instance-customized docstrings.
468 if ds:
468 if ds:
469 class_ds = getdoc(obj.__class__)
469 class_ds = getdoc(obj.__class__)
470 # Skip Python's auto-generated docstrings
471 if class_ds.startswith('function(code, globals[, name[,') or \
472 class_ds.startswith('instancemethod(function, instance,'):
473 class_ds = None
470 if class_ds and ds != class_ds:
474 if class_ds and ds != class_ds:
471 out.writeln(header('Class Docstring:\n') +
475 out.writeln(header('Class Docstring:\n') +
472 indent(class_ds))
476 indent(class_ds))
473
477
474 # Next, try to show constructor docstrings
478 # Next, try to show constructor docstrings
475 try:
479 try:
476 init_ds = getdoc(obj.__init__)
480 init_ds = getdoc(obj.__init__)
481 # Skip Python's auto-generated docstrings
482 if init_ds.startswith('x.__init__(...) initializes x'):
483 init_ds = None
477 except AttributeError:
484 except AttributeError:
478 init_ds = None
485 init_ds = None
479 if init_ds:
486 if init_ds:
480 out.writeln(header('Constructor Docstring:\n') +
487 out.writeln(header('Constructor Docstring:\n') +
481 indent(init_ds))
488 indent(init_ds))
482
489
483 # Call form docstring for callable instances
490 # Call form docstring for callable instances
484 if hasattr(obj,'__call__'):
491 if hasattr(obj,'__call__'):
485 out.writeln(header('Callable:\t')+'Yes')
492 #out.writeln(header('Callable:\t')+'Yes')
486 call_def = self.__getdef(obj.__call__,oname)
493 call_def = self.__getdef(obj.__call__,oname)
487 if call_def is None:
494 #if call_def is None:
488 out.write(header('Call def:\t')+
495 # out.writeln(header('Call def:\t')+
489 'Calling definition not available.')
496 # 'Calling definition not available.')
490 else:
497 if call_def is not None:
491 out.write(header('Call def:\t')+self.format(call_def))
498 out.writeln(header('Call def:\t')+self.format(call_def))
492 call_ds = getdoc(obj.__call__)
499 call_ds = getdoc(obj.__call__)
500 # Skip Python's auto-generated docstrings
501 if call_ds.startswith('x.__call__(...) <==> x(...)'):
502 call_ds = None
493 if call_ds:
503 if call_ds:
494 out.writeln(header('Call docstring:\n') + indent(call_ds))
504 out.writeln(header('Call docstring:\n') + indent(call_ds))
495
505
496 # Finally send to printer/pager
506 # Finally send to printer/pager
497 output = out.getvalue()
507 output = out.getvalue()
498 if output:
508 if output:
499 page(output)
509 page(output)
500 # end pinfo
510 # end pinfo
501
511
502 def psearch(self,pattern,ns_table,ns_search=[],
512 def psearch(self,pattern,ns_table,ns_search=[],
503 ignore_case=False,show_all=False):
513 ignore_case=False,show_all=False):
504 """Search namespaces with wildcards for objects.
514 """Search namespaces with wildcards for objects.
505
515
506 Arguments:
516 Arguments:
507
517
508 - pattern: string containing shell-like wildcards to use in namespace
518 - pattern: string containing shell-like wildcards to use in namespace
509 searches and optionally a type specification to narrow the search to
519 searches and optionally a type specification to narrow the search to
510 objects of that type.
520 objects of that type.
511
521
512 - ns_table: dict of name->namespaces for search.
522 - ns_table: dict of name->namespaces for search.
513
523
514 Optional arguments:
524 Optional arguments:
515
525
516 - ns_search: list of namespace names to include in search.
526 - ns_search: list of namespace names to include in search.
517
527
518 - ignore_case(False): make the search case-insensitive.
528 - ignore_case(False): make the search case-insensitive.
519
529
520 - show_all(False): show all names, including those starting with
530 - show_all(False): show all names, including those starting with
521 underscores.
531 underscores.
522 """
532 """
523 # defaults
533 # defaults
524 type_pattern = 'all'
534 type_pattern = 'all'
525 filter = ''
535 filter = ''
526
536
527 cmds = pattern.split()
537 cmds = pattern.split()
528 len_cmds = len(cmds)
538 len_cmds = len(cmds)
529 if len_cmds == 1:
539 if len_cmds == 1:
530 # Only filter pattern given
540 # Only filter pattern given
531 filter = cmds[0]
541 filter = cmds[0]
532 elif len_cmds == 2:
542 elif len_cmds == 2:
533 # Both filter and type specified
543 # Both filter and type specified
534 filter,type_pattern = cmds
544 filter,type_pattern = cmds
535 else:
545 else:
536 raise ValueError('invalid argument string for psearch: <%s>' %
546 raise ValueError('invalid argument string for psearch: <%s>' %
537 pattern)
547 pattern)
538
548
539 # filter search namespaces
549 # filter search namespaces
540 for name in ns_search:
550 for name in ns_search:
541 if name not in ns_table:
551 if name not in ns_table:
542 raise ValueError('invalid namespace <%s>. Valid names: %s' %
552 raise ValueError('invalid namespace <%s>. Valid names: %s' %
543 (name,ns_table.keys()))
553 (name,ns_table.keys()))
544
554
545 #print 'type_pattern:',type_pattern # dbg
555 #print 'type_pattern:',type_pattern # dbg
546 search_result = []
556 search_result = []
547 for ns_name in ns_search:
557 for ns_name in ns_search:
548 ns = ns_table[ns_name]
558 ns = ns_table[ns_name]
549 tmp_res = list(list_namespace(ns,type_pattern,filter,
559 tmp_res = list(list_namespace(ns,type_pattern,filter,
550 ignore_case=ignore_case,
560 ignore_case=ignore_case,
551 show_all=show_all))
561 show_all=show_all))
552 search_result.extend(tmp_res)
562 search_result.extend(tmp_res)
553 search_result.sort()
563 search_result.sort()
554
564
555 page('\n'.join(search_result))
565 page('\n'.join(search_result))
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now