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