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