#2695: better error handling for setup_command

This commit is contained in:
Takeshi KOMIYA 2016-08-17 23:51:00 +09:00
parent fae9eb7784
commit ca5ad2d541
2 changed files with 62 additions and 68 deletions

View File

@ -55,6 +55,56 @@ class MyFormatter(optparse.IndentedHelpFormatter):
return "\n".join(result)
def handle_exception(app, opts, exception, stderr=sys.stderr):
if opts.pdb:
import pdb
print(red('Exception occurred while building, starting debugger:'),
file=stderr)
traceback.print_exc()
pdb.post_mortem(sys.exc_info()[2])
else:
print(file=stderr)
if opts.verbosity or opts.traceback:
traceback.print_exc(None, stderr)
print(file=stderr)
if isinstance(exception, KeyboardInterrupt):
print('interrupted!', file=stderr)
elif isinstance(exception, SystemMessage):
print(red('reST markup error:'), file=stderr)
print(terminal_safe(exception.args[0]), file=stderr)
elif isinstance(exception, SphinxError):
print(red('%s:' % exception.category), file=stderr)
print(terminal_safe(text_type(exception)), file=stderr)
elif isinstance(exception, UnicodeError):
print(red('Encoding error:'), file=stderr)
print(terminal_safe(text_type(exception)), file=stderr)
tbpath = save_traceback(app)
print(red('The full traceback has been saved in %s, if you want '
'to report the issue to the developers.' % tbpath),
file=stderr)
elif isinstance(exception, RuntimeError) and 'recursion depth' in str(exception):
print(red('Recursion error:'), file=stderr)
print(terminal_safe(text_type(exception)), file=stderr)
print(file=stderr)
print('This can happen with very large or deeply nested source '
'files. You can carefully increase the default Python '
'recursion limit of 1000 in conf.py with e.g.:', file=stderr)
print(' import sys; sys.setrecursionlimit(1500)', file=stderr)
else:
print(red('Exception occurred:'), file=stderr)
print(format_exception_cut_frames().rstrip(), file=stderr)
tbpath = save_traceback(app)
print(red('The full traceback has been saved in %s, if you '
'want to report the issue to the developers.' % tbpath),
file=stderr)
print('Please also report this if it was a user error, so '
'that a better error message can be provided next time.',
file=stderr)
print('A bug report can be filed in the tracker at '
'<https://github.com/sphinx-doc/sphinx/issues>. Thanks!',
file=stderr)
def main(argv):
if not color_terminal():
nocolor()
@ -243,52 +293,6 @@ def main(argv):
opts.warningiserror, opts.tags, opts.verbosity, opts.jobs)
app.build(opts.force_all, filenames)
return app.statuscode
except (Exception, KeyboardInterrupt) as err:
if opts.pdb:
import pdb
print(red('Exception occurred while building, starting debugger:'),
file=error)
traceback.print_exc()
pdb.post_mortem(sys.exc_info()[2])
else:
print(file=error)
if opts.verbosity or opts.traceback:
traceback.print_exc(None, error)
print(file=error)
if isinstance(err, KeyboardInterrupt):
print('interrupted!', file=error)
elif isinstance(err, SystemMessage):
print(red('reST markup error:'), file=error)
print(terminal_safe(err.args[0]), file=error)
elif isinstance(err, SphinxError):
print(red('%s:' % err.category), file=error)
print(terminal_safe(text_type(err)), file=error)
elif isinstance(err, UnicodeError):
print(red('Encoding error:'), file=error)
print(terminal_safe(text_type(err)), file=error)
tbpath = save_traceback(app)
print(red('The full traceback has been saved in %s, if you want '
'to report the issue to the developers.' % tbpath),
file=error)
elif isinstance(err, RuntimeError) and 'recursion depth' in str(err):
print(red('Recursion error:'), file=error)
print(terminal_safe(text_type(err)), file=error)
print(file=error)
print('This can happen with very large or deeply nested source '
'files. You can carefully increase the default Python '
'recursion limit of 1000 in conf.py with e.g.:', file=error)
print(' import sys; sys.setrecursionlimit(1500)', file=error)
else:
print(red('Exception occurred:'), file=error)
print(format_exception_cut_frames().rstrip(), file=error)
tbpath = save_traceback(app)
print(red('The full traceback has been saved in %s, if you '
'want to report the issue to the developers.' % tbpath),
file=error)
print('Please also report this if it was a user error, so '
'that a better error message can be provided next time.',
file=error)
print('A bug report can be filed in the tracker at '
'<https://github.com/sphinx-doc/sphinx/issues>. Thanks!',
file=error)
except (Exception, KeyboardInterrupt) as exc:
handle_exception(app, opts, exc, error)
return 1

View File

@ -15,15 +15,14 @@ from __future__ import print_function
import sys
import os
import traceback
from six import StringIO, string_types
from distutils.cmd import Command
from distutils.errors import DistutilsOptionError, DistutilsExecError
from six import StringIO, string_types
from sphinx.application import Sphinx
from sphinx.util.console import darkred, nocolor, color_terminal
from sphinx.cmdline import handle_exception
from sphinx.util.console import nocolor, color_terminal
from sphinx.util.osutil import abspath
@ -99,6 +98,8 @@ class BuildDoc(Command):
self.config_dir = None
self.link_index = False
self.copyright = ''
self.verbosity = 0
self.traceback = False
def _guess_source_dir(self):
for guess in ('doc', 'docs'):
@ -173,21 +174,10 @@ class BuildDoc(Command):
if app.statuscode:
raise DistutilsExecError(
'caused by %s builder.' % app.builder.name)
except Exception as err:
if self.pdb:
import pdb
print(darkred('Exception occurred while building, starting debugger:'),
file=sys.stderr)
traceback.print_exc()
pdb.post_mortem(sys.exc_info()[2])
else:
from docutils.utils import SystemMessage
if isinstance(err, SystemMessage):
print(darkred('reST markup error:'), file=sys.stderr)
print(err.args[0].encode('ascii', 'backslashreplace'),
file=sys.stderr)
else:
raise
except Exception as exc:
handle_exception(app, self, exc, sys.stderr)
if not self.pdb:
raise SystemExit(1)
if self.link_index:
src = app.config.master_doc + app.builder.out_suffix