[Python-checkins] CVS: python/nondist/sandbox/help pydoc.py,1.4,1.5

Ka-Ping Yee ping@users.sourceforge.net
Tue, 27 Feb 2001 01:25:40 -0800


Update of /cvsroot/python/python/nondist/sandbox/help
In directory usw-pr-cvs1:/tmp/cvs-serv27658

Modified Files:
	pydoc.py 
Log Message:
Gracefully handle errors during import.


Index: pydoc.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/help/pydoc.py,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -r1.4 -r1.5
*** pydoc.py	2001/02/27 07:41:09	1.4
--- pydoc.py	2001/02/27 09:25:38	1.5
***************
*** 75,78 ****
--- 75,79 ----
  
  def getdoc(object):
+     """Get the doc string or comments for an object."""
      result = inspect.getdoc(object)
      if not result:
***************
*** 82,85 ****
--- 83,87 ----
  
  def classname(object, modname):
+     """Get a class name and qualify it with a module name if necessary."""
      name = object.__name__
      if object.__module__ != modname:
***************
*** 113,117 ****
  
  def modulename(path):
!     """If the given filename is a module, return the module name."""
      filename = os.path.basename(path)
      if lower(filename[-3:]) == '.py':
--- 115,119 ----
  
  def modulename(path):
!     """Return the Python module name for a given path, or None."""
      filename = os.path.basename(path)
      if lower(filename[-3:]) == '.py':
***************
*** 124,143 ****
          return filename[:-13]
  
  def importfile(path):
      """Import a Python source file or compiled file given its path."""
      try:
!         file = open(path, 'r')
!         filename = os.path.basename(path)
!         if lower(filename[-3:]) == '.py':
!             return imp.load_module(
!                 filename[:-3], file, path, ('.py', 'r', imp.PY_SOURCE))
!         if lower(filename[-4:]) == '.pyc':
!             return imp.load_module(
!                 filename[:-4], file, path, ('.py', 'r', imp.PY_COMPILED))
!     finally:
!         file.close()
  
  def ispackage(path):
!     """Guess whether a given path refers to a package directory."""
      if os.path.isdir(path):
          init = os.path.join(path, '__init__.py')
--- 126,160 ----
          return filename[:-13]
  
+ class DocImportError(Exception):
+     """Class for errors while trying to import something to document it."""
+     def __init__(self, filename, etype, evalue):
+         self.filename = filename
+         self.etype = etype
+         self.evalue = evalue
+         if type(etype) is types.ClassType:
+             etype = etype.__name__
+         self.args = '%s: %s' % (etype, evalue)
+ 
  def importfile(path):
      """Import a Python source file or compiled file given its path."""
+     magic = imp.get_magic()
+     file = open(path, 'r')
+     if file.read(len(magic)) == magic:
+         kind = imp.PY_COMPILED
+     else:
+         kind = imp.PY_SOURCE
+     file.close()
+     filename = os.path.basename(path)
+     name, ext = os.path.splitext(filename)
+     file = open(path, 'r')
      try:
!         module = imp.load_module(name, file, path, (ext, 'r', kind))
!     except:
!         raise DocImportError(path, sys.exc_type, sys.exc_value)
!     file.close()
!     return module
  
  def ispackage(path):
!     """Guess whether a path refers to a package directory."""
      if os.path.isdir(path):
          init = os.path.join(path, '__init__.py')
***************
*** 150,154 ****
  class Doc:
      def document(self, object, *args):
!         """Generate documentation for a given object."""
          args = (object,) + args
          if inspect.ismodule(object): return apply(self.docmodule, args)
--- 167,171 ----
  class Doc:
      def document(self, object, *args):
!         """Generate documentation for an object."""
          args = (object,) + args
          if inspect.ismodule(object): return apply(self.docmodule, args)
***************
*** 162,165 ****
--- 179,183 ----
  
  class HTMLRepr(Repr):
+     """Class for safely making an HTML representation of a Python object."""
      def __init__(self):
          Repr.__init__(self)
***************
*** 195,198 ****
--- 213,218 ----
  
  class HTMLDoc(Doc):
+     """Formatter class for HTML documentation."""
+ 
      # ------------------------------------------- HTML formatting utilities
  
***************
*** 202,205 ****
--- 222,226 ----
  
      def preformat(self, text):
+         """Format literal preformatted text."""
          text = self.escape(expandtabs(text))
          return replace(text, ('\n\n', '\n \n'), ('\n\n', '\n \n'),
***************
*** 207,210 ****
--- 228,232 ----
  
      def multicolumn(self, list, format, cols=4):
+         """Format a list of items into a multi-column list."""
          result = ''
          rows = (len(list)+cols-1)/cols
***************
*** 219,222 ****
--- 241,245 ----
  
      def heading(self, title, fgcol, bgcol, extras=''):
+         """Format a page heading."""
          return """
  <p><table width="100%%" cellspacing=0 cellpadding=0 border=0>
***************
*** 229,232 ****
--- 252,256 ----
      def section(self, title, fgcol, bgcol, contents, width=20,
                  prelude='', marginalia=None, gap='&nbsp;&nbsp;&nbsp;'):
+         """Format a section with a heading."""
          if marginalia is None:
              marginalia = '&nbsp;' * width
***************
*** 249,252 ****
--- 273,277 ----
  
      def bigsection(self, title, *args):
+         """Format a section with a big heading."""
          title = '<big><strong>%s</strong></big>' % title
          return apply(self.section, (title,) + args)
***************
*** 261,264 ****
--- 286,290 ----
  
      def namelink(self, name, *dicts):
+         """Make a link for an identifier, given name-to-URL mappings."""
          for dict in dicts:
              if dict.has_key(name):
***************
*** 267,270 ****
--- 293,297 ----
  
      def classlink(self, object, modname, *dicts):
+         """Make a link for a class."""
          name = object.__name__
          if object.__module__ != modname:
***************
*** 275,279 ****
--- 302,311 ----
          return name
  
+     def modulelink(self, object):
+         """Make a link for a module."""
+         return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
+ 
      def modpkglink(self, (name, path, ispackage, shadowed)):
+         """Make a link for a module or package to display in an index."""
          if shadowed:
              return '<font color="#909090">%s</font>' % name
***************
*** 288,294 ****
          return '<a href="%s">%s</a>' % (url, text)
  
-     def modulelink(self, object):
-         return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
- 
      def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
          """Mark up some plain text, given a context of symbols to look for.
--- 320,323 ----
***************
*** 337,341 ****
  
      def docmodule(self, object):
!         """Produce HTML documentation for a given module object."""
          name = object.__name__
          result = ''
--- 366,370 ----
  
      def docmodule(self, object):
!         """Produce HTML documentation for a module object."""
          name = object.__name__
          result = ''
***************
*** 428,432 ****
  
      def docclass(self, object, funcs={}, classes={}):
!         """Produce HTML documentation for a given class object."""
          name = object.__name__
          bases = object.__bases__
--- 457,461 ----
  
      def docclass(self, object, funcs={}, classes={}):
!         """Produce HTML documentation for a class object."""
          name = object.__name__
          bases = object.__bases__
***************
*** 453,466 ****
  
      def docmethod(self, object, funcs={}, classes={}, methods={}, clname=''):
!         """Produce HTML documentation for a given method object."""
          return self.document(
              object.im_func, funcs, classes, methods, clname)
  
      def formatvalue(self, object):
          return ('<small><font color="#909090">=%s</font></small>' %
                  self.repr(object))
  
      def docfunction(self, object, funcs={}, classes={}, methods={}, clname=''):
!         """Produce HTML documentation for a given function object."""
          args, varargs, varkw, defaults = inspect.getargspec(object)
          argspec = inspect.formatargspec(
--- 482,496 ----
  
      def docmethod(self, object, funcs={}, classes={}, methods={}, clname=''):
!         """Produce HTML documentation for a method object."""
          return self.document(
              object.im_func, funcs, classes, methods, clname)
  
      def formatvalue(self, object):
+         """Format an argument default value as text."""
          return ('<small><font color="#909090">=%s</font></small>' %
                  self.repr(object))
  
      def docfunction(self, object, funcs={}, classes={}, methods={}, clname=''):
!         """Produce HTML documentation for a function object."""
          args, varargs, varkw, defaults = inspect.getargspec(object)
          argspec = inspect.formatargspec(
***************
*** 480,487 ****
  
      def docbuiltin(self, object, *extras):
!         """Produce HTML documentation for a given built-in function."""
          return '<dl><dt><strong>%s</strong>(...)</dl>' % object.__name__
  
      def page(self, object):
          return '''<!doctype html public "-//W3C//DTD HTML 4.0 Transitional//EN">
  <html><title>Python: %s</title>
--- 510,518 ----
  
      def docbuiltin(self, object, *extras):
!         """Produce HTML documentation for a built-in function."""
          return '<dl><dt><strong>%s</strong>(...)</dl>' % object.__name__
  
      def page(self, object):
+         """Produce a complete HTML page of documentation for an object."""
          return '''<!doctype html public "-//W3C//DTD HTML 4.0 Transitional//EN">
  <html><title>Python: %s</title>
***************
*** 492,496 ****
  
      def index(self, dir, shadowed=None):
!         """Generate an index for a given directory."""
          modpkgs = []
          if shadowed is None: shadowed = {}
--- 523,527 ----
  
      def index(self, dir, shadowed=None):
!         """Generate an HTML index for a directory of modules."""
          modpkgs = []
          if shadowed is None: shadowed = {}
***************
*** 522,525 ****
--- 553,557 ----
  
  class TextRepr(Repr):
+     """Class for safely making a text representation of a Python object."""
      def __init__(self):
          Repr.__init__(self)
***************
*** 541,544 ****
--- 573,578 ----
  
  class TextDoc(Doc):
+     """Formatter class for text documentation."""
+ 
      # ------------------------------------------- text formatting utilities
  
***************
*** 593,597 ****
              lines = lines[2:]
          result = result + self.section('NAME', name)
!         try: file = inspect.getfile(object) # XXX
          except TypeError: file = None
          result = result + self.section('FILE', file or '(built-in)')
--- 627,631 ----
              lines = lines[2:]
          result = result + self.section('NAME', name)
!         try: file = inspect.getfile(object) # XXX or getsourcefile?
          except TypeError: file = None
          result = result + self.section('FILE', file or '(built-in)')
***************
*** 684,694 ****
  
      def docmethod(self, object):
          return self.document(object.im_func)
  
      def formatvalue(self, object):
          return '=' + self.repr(object)
  
      def docfunction(self, object):
!         """Produce text documentation for a given function object."""
          try:
              args, varargs, varkw, defaults = inspect.getargspec(object)
--- 718,730 ----
  
      def docmethod(self, object):
+         """Produce text documentation for a method object."""
          return self.document(object.im_func)
  
      def formatvalue(self, object):
+         """Format an argument default value as text."""
          return '=' + self.repr(object)
  
      def docfunction(self, object):
!         """Produce text documentation for a function object."""
          try:
              args, varargs, varkw, defaults = inspect.getargspec(object)
***************
*** 709,712 ****
--- 745,749 ----
  
      def docbuiltin(self, object):
+         """Produce text documentation for a built-in function object."""
          return (self.bold(object.__name__) + '(...)\n' +
                  rstrip(self.indent(object.__doc__)) + '\n')
***************
*** 842,852 ****
          path = join(parts[:n], '.')
          try:
!             mod = __import__(path)
!         except ImportError:
              break
          try:
              mod = reload(mod)
!         except ImportError:
!             pass
          try:
              x = mod
--- 879,891 ----
          path = join(parts[:n], '.')
          try:
!             file, filename, (ext, mode, kind) = imp.find_module(path)
!         except ImportError: # module not found, so keep looking
              break
+         if file: file.close()
          try:
+             mod = __import__(path)
              mod = reload(mod)
!         except: # error occurred in the module during import, so report it
!             raise DocImportError(filename, sys.exc_type, sys.exc_value)
          try:
              x = mod
***************
*** 867,875 ****
      """Display documentation on an object (for interactive use)."""
      if type(thing) is type(""):
!         path, x = find(thing)
          if x:
              thing = x
          else:
!             print 'could not import or find %s' % thing
              return
  
--- 906,918 ----
      """Display documentation on an object (for interactive use)."""
      if type(thing) is type(""):
!         try:
!             path, x = find(thing)
!         except DocImportError, value:
!             print 'problem in %s - %s' % (value.filename, value.args)
!             return
          if x:
              thing = x
          else:
!             print 'could not import or find %s' % repr(thing)
              return
  
***************
*** 974,978 ****
  'There is no Python module or object named "%s".' % path)
              else:
!                 contents = html.heading(
                      '<br><big><big><strong>&nbsp;'
                      'Python: Index of Modules'
--- 1017,1021 ----
  'There is no Python module or object named "%s".' % path)
              else:
!                 heading = html.heading(
                      '<br><big><big><strong>&nbsp;'
                      'Python: Index of Modules'
***************
*** 982,991 ****
                  for name in sys.builtin_module_names:
                      builtins.append('<a href="%s.html">%s</a>' % (name, name))
!                 contents.append('<p>Built-in modules: ')
!                 contents.append(join(builtins, ', '))
                  seen = {}
                  for dir in pathdirs():
!                     contents.append(html.index(dir, seen))
!                 self.send_document('Index of Modules', contents)
  
          def log_message(self, *args): pass
--- 1025,1033 ----
                  for name in sys.builtin_module_names:
                      builtins.append('<a href="%s.html">%s</a>' % (name, name))
!                 indices = ['<p>Built-in modules: ' + join(builtins, ', ')]
                  seen = {}
                  for dir in pathdirs():
!                     indices.append(html.index(dir, seen))
!                 self.send_document('Index of Modules', heading + join(indices))
  
          def log_message(self, *args): pass
***************
*** 1012,1016 ****
      import getopt
      class BadUsage: pass
-     class ErrorMessage: pass
  
      try:
--- 1054,1057 ----
***************
*** 1037,1046 ****
              if args:
                  for arg in args:
!                     if os.path.isfile(arg):
!                         arg = importfile(arg)
!                     if writing:
!                         if os.path.isdir(arg): writedocs(arg)
!                         else: writedoc(arg)
!                     else: man(arg)
              else:
                  if sys.platform in ['mac', 'win', 'win32', 'nt']:
--- 1078,1091 ----
              if args:
                  for arg in args:
!                     try:
!                         if os.path.isfile(arg):
!                             arg = importfile(arg)
!                         if writing:
!                             if os.path.isdir(arg): writedocs(arg)
!                             else: writedoc(arg)
!                         else: man(arg)
!                     except DocImportError, value:
!                         print 'problem in %s - %s' % (
!                             value.filename, value.args)
              else:
                  if sys.platform in ['mac', 'win', 'win32', 'nt']:
***************
*** 1056,1062 ****
                  else:
                      raise BadUsage
- 
-     except ErrorMessage, value:
-         print value
  
      except (getopt.error, BadUsage):
--- 1101,1104 ----