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