Fixed #19923 -- Display tracebacks for non-CommandError exceptions

By default, show tracebacks for management command errors when the
exception is not a CommandError.
Thanks Jacob Radford for the report.
This commit is contained in:
Claude Paroz 2013-03-09 12:38:45 +01:00
parent 5e80571bf9
commit 6a91b63842
3 changed files with 24 additions and 7 deletions

View File

@ -241,7 +241,7 @@ class BaseCommand(object):
except Exception as e: except Exception as e:
# self.stderr is not guaranteed to be set here # self.stderr is not guaranteed to be set here
stderr = getattr(self, 'stderr', OutputWrapper(sys.stderr, self.style.ERROR)) stderr = getattr(self, 'stderr', OutputWrapper(sys.stderr, self.style.ERROR))
if options.traceback: if options.traceback or not isinstance(e, CommandError):
stderr.write(traceback.format_exc()) stderr.write(traceback.format_exc())
else: else:
stderr.write('%s: %s' % (e.__class__.__name__, e)) stderr.write('%s: %s' % (e.__class__.__name__, e))

View File

@ -1342,8 +1342,13 @@ Example usage::
django-admin.py syncdb --traceback django-admin.py syncdb --traceback
By default, ``django-admin.py`` will show a simple error message whenever an By default, ``django-admin.py`` will show a simple error message whenever an
error occurs. If you specify ``--traceback``, ``django-admin.py`` will :class:`~django.core.management.CommandError` occurs, but a full stack trace
output a full stack trace whenever an exception is raised. for any other exception. If you specify ``--traceback``, ``django-admin.py``
will also output a full stack trace when a ``CommandError`` is raised.
.. versionchanged:: 1.6
Previously, Django didn't show a full stack trace by default for exceptions
other than ``CommandError``.
.. django-admin-option:: --verbosity .. django-admin-option:: --verbosity

View File

@ -16,7 +16,7 @@ import codecs
from django import conf, bin, get_version from django import conf, bin, get_version
from django.conf import settings from django.conf import settings
from django.core.management import BaseCommand from django.core.management import BaseCommand, CommandError
from django.db import connection from django.db import connection
from django.test.simple import DjangoTestSuiteRunner from django.test.simple import DjangoTestSuiteRunner
from django.utils import unittest from django.utils import unittest
@ -1297,22 +1297,34 @@ class CommandTypes(AdminScriptTestCase):
Also test proper traceback display. Also test proper traceback display.
""" """
command = BaseCommand() command = BaseCommand()
command.execute = lambda args: args # This will trigger TypeError def raise_command_error(*args, **kwargs):
raise CommandError("Custom error")
old_stderr = sys.stderr old_stderr = sys.stderr
sys.stderr = err = StringIO() sys.stderr = err = StringIO()
try: try:
command.execute = lambda args: args # This will trigger TypeError
with self.assertRaises(SystemExit):
command.run_from_argv(['', ''])
err_message = err.getvalue()
# Exceptions other than CommandError automatically output the traceback
self.assertIn("Traceback", err_message)
self.assertIn("TypeError", err_message)
command.execute = raise_command_error
err.truncate(0)
with self.assertRaises(SystemExit): with self.assertRaises(SystemExit):
command.run_from_argv(['', '']) command.run_from_argv(['', ''])
err_message = err.getvalue() err_message = err.getvalue()
self.assertNotIn("Traceback", err_message) self.assertNotIn("Traceback", err_message)
self.assertIn("TypeError", err_message) self.assertIn("CommandError", err_message)
err.truncate(0)
with self.assertRaises(SystemExit): with self.assertRaises(SystemExit):
command.run_from_argv(['', '', '--traceback']) command.run_from_argv(['', '', '--traceback'])
err_message = err.getvalue() err_message = err.getvalue()
self.assertIn("Traceback (most recent call last)", err_message) self.assertIn("Traceback (most recent call last)", err_message)
self.assertIn("TypeError", err_message) self.assertIn("CommandError", err_message)
finally: finally:
sys.stderr = old_stderr sys.stderr = old_stderr