##// END OF EJS Templates
Refactor Inspector.pinfo(), so it no longer duplicates code in Inspector.info()
Thomas Kluyver -
Show More
@@ -18,7 +18,6 b" __all__ = ['Inspector','InspectColors']"
18
18
19 # stdlib modules
19 # stdlib modules
20 import __builtin__
20 import __builtin__
21 import StringIO
22 import inspect
21 import inspect
23 import linecache
22 import linecache
24 import os
23 import os
@@ -75,7 +74,7 b" info_fields = ['type_name', 'base_class', 'string_form', 'namespace',"
75 'call_def', 'call_docstring',
74 'call_def', 'call_docstring',
76 # These won't be printed but will be used to determine how to
75 # These won't be printed but will be used to determine how to
77 # format the object
76 # format the object
78 'ismagic', 'isalias', 'argspec', 'found', 'name',
77 'ismagic', 'isalias', 'isclass', 'argspec', 'found', 'name'
79 ]
78 ]
80
79
81
80
@@ -227,16 +226,6 b' def call_tip(oinfo, format_call=True):'
227
226
228 return call_line, doc
227 return call_line, doc
229
228
230 #****************************************************************************
231 # Class definitions
232
233 class myStringIO(StringIO.StringIO):
234 """Adds a writeln method to normal StringIO."""
235 def writeln(self,*arg,**kw):
236 """Does a write() and then a write('\n')"""
237 self.write(*arg,**kw)
238 self.write('\n')
239
240
229
241 class Inspector:
230 class Inspector:
242 def __init__(self, color_table=InspectColors,
231 def __init__(self, color_table=InspectColors,
@@ -378,6 +367,39 b' class Inspector:'
378 # 0-offset, so we must adjust.
367 # 0-offset, so we must adjust.
379 page.page(self.format(open(ofile).read()),lineno-1)
368 page.page(self.format(open(ofile).read()),lineno-1)
380
369
370 def _format_fields(self, fields, title_width=12):
371 """Formats a list of fields for display.
372
373 Parameters
374 ----------
375 fields : list
376 A list of 2-tuples: (field_title, field_content)
377 title_width : int
378 How many characters to pad titles to. Default 12.
379 """
380 out = []
381 header = self.__head
382 for title, content in fields:
383 if len(content.splitlines()) > 1:
384 title = header(title + ":") + "\n"
385 else:
386 title = header((title+":").ljust(title_width))
387 out.append(title + content)
388 return "\n".join(out)
389
390 # The fields to be displayed by pinfo: (fancy_name, key_in_info_dict)
391 pinfo_fields1 = [("Type", "type_name"),
392 ("Base Class", "base_class"),
393 ("String Form", "string_form"),
394 ("Namespace", "namespace"),
395 ("Length", "length"),
396 ("File", "file"),
397 ("Definition", "definition")]
398
399 pinfo_fields_obj = [("Constructor Docstring","init_docstring"),
400 ("Call def", "call_def"),
401 ("Call docstring", "call_docstring")]
402
381 def pinfo(self,obj,oname='',formatter=None,info=None,detail_level=0):
403 def pinfo(self,obj,oname='',formatter=None,info=None,detail_level=0):
382 """Show detailed information about an object.
404 """Show detailed information about an object.
383
405
@@ -392,215 +414,42 b' class Inspector:'
392
414
393 - detail_level: if set to 1, more information is given.
415 - detail_level: if set to 1, more information is given.
394 """
416 """
395
417 info = self.info(obj, oname=oname, formatter=formatter,
396 obj_type = type(obj)
418 info=info, detail_level=detail_level)
397
419 displayfields = []
398 header = self.__head
420 for title, key in self.pinfo_fields1:
399 if info is None:
421 field = info[key]
400 ismagic = 0
422 if field is not None:
401 isalias = 0
423 displayfields.append((title, field.rstrip()))
402 ospace = ''
424
403 else:
425 # Source or docstring, depending on detail level and whether
404 ismagic = info.ismagic
426 # source found.
405 isalias = info.isalias
427 if detail_level > 0 and info['source'] is not None:
406 ospace = info.namespace
428 displayfields.append(("Source", info['source']))
407 # Get docstring, special-casing aliases:
429 elif info['docstring'] is not None:
408 if isalias:
430 displayfields.append(("Docstring", info["docstring"]))
409 if not callable(obj):
431
410 try:
432 # Constructor info for classes
411 ds = "Alias to the system command:\n %s" % obj[1]
433 if info['isclass']:
412 except:
434 if info['init_definition'] or info['init_docstring']:
413 ds = "Alias: " + str(obj)
435 displayfields.append(("Constructor information", ""))
414 else:
436 if info['init_definition'] is not None:
415 ds = "Alias to " + str(obj)
437 displayfields.append((" Definition",
416 if obj.__doc__:
438 info['init_definition'].rstrip()))
417 ds += "\nDocstring:\n" + obj.__doc__
439 if info['init_docstring'] is not None:
418 else:
440 displayfields.append((" Docstring",
419 ds = getdoc(obj)
441 indent(info['init_docstring'])))
420 if ds is None:
442
421 ds = '<no docstring>'
443 # Info for objects:
422 if formatter is not None:
423 ds = formatter(ds)
424
425 # store output in a list which gets joined with \n at the end.
426 out = myStringIO()
427
428 string_max = 200 # max size of strings to show (snipped if longer)
429 shalf = int((string_max -5)/2)
430
431 if ismagic:
432 obj_type_name = 'Magic function'
433 elif isalias:
434 obj_type_name = 'System alias'
435 else:
444 else:
436 obj_type_name = obj_type.__name__
445 for title, key in self.pinfo_fields_obj:
437 out.writeln(header('Type:\t\t')+obj_type_name)
446 field = info[key]
438
447 if field is not None:
439 try:
448 displayfields.append((title, field.rstrip()))
440 bclass = obj.__class__
441 out.writeln(header('Base Class:\t')+str(bclass))
442 except: pass
443
444 # String form, but snip if too long in ? form (full in ??)
445 if detail_level >= self.str_detail_level:
446 try:
447 ostr = str(obj)
448 str_head = 'String Form:'
449 if not detail_level and len(ostr)>string_max:
450 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
451 ostr = ("\n" + " " * len(str_head.expandtabs())).\
452 join(q.strip() for q in ostr.split("\n"))
453 if ostr.find('\n') > -1:
454 # Print multi-line strings starting at the next line.
455 str_sep = '\n'
456 else:
457 str_sep = '\t'
458 out.writeln("%s%s%s" % (header(str_head),str_sep,ostr))
459 except:
460 pass
461
462 if ospace:
463 out.writeln(header('Namespace:\t')+ospace)
464
465 # Length (for strings and lists)
466 try:
467 length = str(len(obj))
468 out.writeln(header('Length:\t\t')+length)
469 except: pass
470
449
471 # Filename where object was defined
450 # Finally send to printer/pager:
472 binary_file = False
451 if displayfields:
473 try:
452 page.page(self._format_fields(displayfields))
474 try:
475 fname = inspect.getabsfile(obj)
476 except TypeError:
477 # For an instance, the file that matters is where its class was
478 # declared.
479 if hasattr(obj,'__class__'):
480 fname = inspect.getabsfile(obj.__class__)
481 if fname.endswith('<string>'):
482 fname = 'Dynamically generated function. No source code available.'
483 if (fname.endswith('.so') or fname.endswith('.dll')):
484 binary_file = True
485 out.writeln(header('File:\t\t')+fname)
486 except:
487 # if anything goes wrong, we don't want to show source, so it's as
488 # if the file was binary
489 binary_file = True
490
491 # reconstruct the function definition and print it:
492 defln = self._getdef(obj,oname)
493 if defln:
494 out.write(header('Definition:\t')+self.format(defln))
495
496 # Docstrings only in detail 0 mode, since source contains them (we
497 # avoid repetitions). If source fails, we add them back, see below.
498 if ds and detail_level == 0:
499 out.writeln(header('Docstring:\n') + indent(ds))
500
501 # Original source code for any callable
502 if detail_level:
503 # Flush the source cache because inspect can return out-of-date
504 # source
505 linecache.checkcache()
506 source_success = False
507 try:
508 try:
509 src = getsource(obj,binary_file)
510 except TypeError:
511 if hasattr(obj,'__class__'):
512 src = getsource(obj.__class__,binary_file)
513 if src is not None:
514 source = self.format(src)
515 out.write(header('Source:\n')+source.rstrip()+'\n')
516 source_success = True
517 except Exception, msg:
518 pass
519
520 if ds and not source_success:
521 out.writeln(header('Docstring [source file open failed]:\n')
522 + indent(ds))
523
524 # Constructor docstring for classes
525 if inspect.isclass(obj):
526 # reconstruct the function definition and print it:
527 try:
528 obj_init = obj.__init__
529 except AttributeError:
530 init_def = init_ds = None
531 else:
532 init_def = self._getdef(obj_init,oname)
533 init_ds = getdoc(obj_init)
534 # Skip Python's auto-generated docstrings
535 if init_ds and \
536 init_ds.startswith('x.__init__(...) initializes'):
537 init_ds = None
538
539 if init_def or init_ds:
540 out.writeln(header('Constructor information:'))
541 if init_def:
542 out.write(header('Definition:\t')+ self.format(init_def))
543 if init_ds:
544 out.writeln(header('Docstring:\n') + indent(init_ds))
545 # and class docstring for instances:
546 elif obj_type is types.InstanceType or \
547 isinstance(obj,object):
548
549 # First, check whether the instance docstring is identical to the
550 # class one, and print it separately if they don't coincide. In
551 # most cases they will, but it's nice to print all the info for
552 # objects which use instance-customized docstrings.
553 if ds:
554 try:
555 cls = getattr(obj,'__class__')
556 except:
557 class_ds = None
558 else:
559 class_ds = getdoc(cls)
560 # Skip Python's auto-generated docstrings
561 if class_ds and \
562 (class_ds.startswith('function(code, globals[,') or \
563 class_ds.startswith('instancemethod(function, instance,') or \
564 class_ds.startswith('module(name[,') ):
565 class_ds = None
566 if class_ds and ds != class_ds:
567 out.writeln(header('Class Docstring:\n') +
568 indent(class_ds))
569
570 # Next, try to show constructor docstrings
571 try:
572 init_ds = getdoc(obj.__init__)
573 # Skip Python's auto-generated docstrings
574 if init_ds and \
575 init_ds.startswith('x.__init__(...) initializes'):
576 init_ds = None
577 except AttributeError:
578 init_ds = None
579 if init_ds:
580 out.writeln(header('Constructor Docstring:\n') +
581 indent(init_ds))
582
583 # Call form docstring for callable instances
584 if hasattr(obj,'__call__'):
585 #out.writeln(header('Callable:\t')+'Yes')
586 call_def = self._getdef(obj.__call__,oname)
587 #if call_def is None:
588 # out.writeln(header('Call def:\t')+
589 # 'Calling definition not available.')
590 if call_def is not None:
591 out.writeln(header('Call def:\t')+self.format(call_def))
592 call_ds = getdoc(obj.__call__)
593 # Skip Python's auto-generated docstrings
594 if call_ds and call_ds.startswith('x.__call__(...) <==> x(...)'):
595 call_ds = None
596 if call_ds:
597 out.writeln(header('Call docstring:\n') + indent(call_ds))
598
599 # Finally send to printer/pager
600 output = out.getvalue()
601 if output:
602 page.page(output)
603 # end pinfo
604
453
605 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
454 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
606 """Compute a dict with detailed information about an object.
455 """Compute a dict with detailed information about an object.
@@ -675,11 +524,6 b' class Inspector:'
675 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
524 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
676 ostr = ("\n" + " " * len(str_head.expandtabs())).\
525 ostr = ("\n" + " " * len(str_head.expandtabs())).\
677 join(q.strip() for q in ostr.split("\n"))
526 join(q.strip() for q in ostr.split("\n"))
678 if ostr.find('\n') > -1:
679 # Print multi-line strings starting at the next line.
680 str_sep = '\n'
681 else:
682 str_sep = '\t'
683 out[str_head] = ostr
527 out[str_head] = ostr
684 except:
528 except:
685 pass
529 pass
@@ -738,11 +582,14 b' class Inspector:'
738 source = self.format(src)
582 source = self.format(src)
739 out['source'] = source.rstrip()
583 out['source'] = source.rstrip()
740 source_success = True
584 source_success = True
741 except Exception, msg:
585 except Exception:
742 pass
586 if ds:
587 out['docstring'] = ds
588
743
589
744 # Constructor docstring for classes
590 # Constructor docstring for classes
745 if inspect.isclass(obj):
591 if inspect.isclass(obj):
592 out['isclass'] = True
746 # reconstruct the function definition and print it:
593 # reconstruct the function definition and print it:
747 try:
594 try:
748 obj_init = obj.__init__
595 obj_init = obj.__init__
@@ -763,8 +610,7 b' class Inspector:'
763 out['init_docstring'] = init_ds
610 out['init_docstring'] = init_ds
764
611
765 # and class docstring for instances:
612 # and class docstring for instances:
766 elif obj_type is types.InstanceType or \
613 else:
767 isinstance(obj, object):
768 # First, check whether the instance docstring is identical to the
614 # First, check whether the instance docstring is identical to the
769 # class one, and print it separately if they don't coincide. In
615 # class one, and print it separately if they don't coincide. In
770 # most cases they will, but it's nice to print all the info for
616 # most cases they will, but it's nice to print all the info for
General Comments 0
You need to be logged in to leave comments. Login now