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