Anonymous avatar Anonymous committed a348723

Improve handling of exceptions.

Comments (0)

Files changed (3)

sphinx/__init__.py

 import os
 import sys
 import getopt
+import traceback
 from os import path
 from cStringIO import StringIO
 
+from docutils.utils import SystemMessage
+
+from sphinx.util import format_exception_cut_frames, save_traceback
 from sphinx.application import Sphinx
-from sphinx.util.console import nocolor
+from sphinx.util.console import darkred, nocolor
 
 __revision__ = '$Revision$'
 __version__ = '0.1.' + __revision__[11:-2]
         print >>sys.stderr, msg
         print >>sys.stderr
     print >>sys.stderr, """\
-usage: %s [options] sourcedir outdir [filenames...]"
-options: -b <builder> -- builder to use; default is html
+Sphinx v%s
+Usage: %s [options] sourcedir outdir [filenames...]"
+Options: -b <builder> -- builder to use; default is html
          -a        -- write all files; default is to only write new and changed files
          -E        -- don't use a saved environment, always read all files
          -d <path> -- path for the cached environment and doctree files
          -N        -- do not do colored output
          -q        -- no output on stdout, just warnings on stderr
          -P        -- run Pdb on exception
-modi:
+Modi:
 * without -a and without filenames, write new and changed files.
 * with -a, write all files.
-* with filenames, write these.""" % (argv[0],)
+* with filenames, write these.""" % (__version__, argv[0])
 
 
 def main(argv=sys.argv):
         elif opt == '-P':
             use_pdb = True
 
-    app = Sphinx(srcdir, outdir, doctreedir, buildername,
-                 confoverrides, status, sys.stderr, freshenv)
-    if not app.builder:
-        return 1
+    try:
+        app = Sphinx(srcdir, outdir, doctreedir, buildername,
+                     confoverrides, status, sys.stderr, freshenv)
+        if not app.builder:
+            return 1
 
-    try:
         if all_files:
             app.builder.build_all()
         elif filenames:
             app.builder.build_specific(filenames)
         else:
             app.builder.build_update()
+    except Exception, err:
+        if use_pdb:
+            import pdb
+            print >>sys.stderr, darkred('Exception occurred while building, '
+                                        'starting debugger:')
+            traceback.print_exc()
+            pdb.post_mortem(sys.exc_info()[2])
+        else:
+            if isinstance(err, SystemMessage):
+                print >>sys.stderr, darkred('reST markup error:')
+                print >>sys.stderr, str(err)
+            else:
+                print >>sys.stderr, darkred('Exception occurred:')
+                print >>sys.stderr, format_exception_cut_frames().rstrip()
+                tbpath = save_traceback()
+                print >>sys.stderr, darkred('The full traceback has been saved '
+                                            'in %s, if you want to report the '
+                                            'issue to the author.' % tbpath)
+                print >>sys.stderr, ('Please also report this if it was a user '
+                                     'error, so that a better error message '
+                                     'can be provided next time.')
+                print >>sys.stderr, 'Send reports to georg@python.org. Thanks!'
     except:
-        if not use_pdb:
-            raise
-        import pdb, traceback
-        traceback.print_exc()
-        pdb.post_mortem(sys.exc_info()[2])
+        # catches BaseExceptions in 2.5 -- SystemExit, KeyboardInterrupt
+        pass
 
 
 if __name__ == '__main__':

sphinx/builder.py

         self.warn = app.warn
         self.info = app.info
         self.config = app.config
+        1/0
 
         # if None, this is set in load_env()
         self.env = env
         self.env.set_warnfunc(warnings.append)
         for docname in self.status_iterator(sorted(docnames),
                                             'writing output... ', darkgreen):
-            try:
-                doctree = self.env.get_and_resolve_doctree(docname, self)
-            except Exception, err:
-                warnings.append('%s:: doctree not found!' % docname)
-                continue
+            doctree = self.env.get_and_resolve_doctree(docname, self)
             self.write_doc(docname, doctree)
         for warning in warnings:
             if warning.strip():

sphinx/util/__init__.py

 import os
 import sys
 import fnmatch
+import tempfile
 import traceback
 from os import path
 
     if i != -1:
         return s[:i], s[i+len(t):]
     return '', s
+
+
+def format_exception_cut_frames(x=1):
+    """
+    Format an exception with traceback, but only the last x frames.
+    """
+    typ, val, tb = sys.exc_info()
+    #res = ['Traceback (most recent call last):\n']
+    res = []
+    tbres = traceback.format_tb(tb)
+    res += tbres[-x:]
+    res += traceback.format_exception_only(typ, val)
+    return ''.join(res)
+
+
+def save_traceback():
+    """
+    Save the current exception's traceback in a temporary file.
+    """
+    exc = traceback.format_exc()
+    fd, path = tempfile.mkstemp('.log', 'sphinx-err-')
+    os.write(fd, exc)
+    os.close(fd)
+    return path
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.