Improve handling of exceptions.

This commit is contained in:
Georg Brandl 2008-03-18 19:17:56 +00:00
parent 4eaf9b5da5
commit d3c0de7d62
3 changed files with 66 additions and 20 deletions

View File

@ -12,11 +12,15 @@
import os import os
import sys import sys
import getopt import getopt
import traceback
from os import path from os import path
from cStringIO import StringIO 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.application import Sphinx
from sphinx.util.console import nocolor from sphinx.util.console import darkred, nocolor
__revision__ = '$Revision$' __revision__ = '$Revision$'
__version__ = '0.1.' + __revision__[11:-2] __version__ = '0.1.' + __revision__[11:-2]
@ -27,8 +31,9 @@ def usage(argv, msg=None):
print >>sys.stderr, msg print >>sys.stderr, msg
print >>sys.stderr print >>sys.stderr
print >>sys.stderr, """\ print >>sys.stderr, """\
usage: %s [options] sourcedir outdir [filenames...]" Sphinx v%s
options: -b <builder> -- builder to use; default is html 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 -a -- write all files; default is to only write new and changed files
-E -- don't use a saved environment, always read all files -E -- don't use a saved environment, always read all files
-d <path> -- path for the cached environment and doctree files -d <path> -- path for the cached environment and doctree files
@ -37,10 +42,10 @@ options: -b <builder> -- builder to use; default is html
-N -- do not do colored output -N -- do not do colored output
-q -- no output on stdout, just warnings on stderr -q -- no output on stdout, just warnings on stderr
-P -- run Pdb on exception -P -- run Pdb on exception
modi: Modi:
* without -a and without filenames, write new and changed files. * without -a and without filenames, write new and changed files.
* with -a, write all files. * with -a, write all files.
* with filenames, write these.""" % (argv[0],) * with filenames, write these.""" % (__version__, argv[0])
def main(argv=sys.argv): def main(argv=sys.argv):
@ -104,24 +109,43 @@ def main(argv=sys.argv):
elif opt == '-P': elif opt == '-P':
use_pdb = True use_pdb = True
app = Sphinx(srcdir, outdir, doctreedir, buildername,
confoverrides, status, sys.stderr, freshenv)
if not app.builder:
return 1
try: try:
app = Sphinx(srcdir, outdir, doctreedir, buildername,
confoverrides, status, sys.stderr, freshenv)
if not app.builder:
return 1
if all_files: if all_files:
app.builder.build_all() app.builder.build_all()
elif filenames: elif filenames:
app.builder.build_specific(filenames) app.builder.build_specific(filenames)
else: else:
app.builder.build_update() 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: except:
if not use_pdb: # catches BaseExceptions in 2.5 -- SystemExit, KeyboardInterrupt
raise pass
import pdb, traceback
traceback.print_exc()
pdb.post_mortem(sys.exc_info()[2])
if __name__ == '__main__': if __name__ == '__main__':

View File

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

View File

@ -12,6 +12,7 @@
import os import os
import sys import sys
import fnmatch import fnmatch
import tempfile
import traceback import traceback
from os import path from os import path
@ -120,3 +121,27 @@ def rpartition(s, t):
if i != -1: if i != -1:
return s[:i], s[i+len(t):] return s[:i], s[i+len(t):]
return '', s 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