Fixed #19665 -- Ensured proper stderr output for Command.run_from_argv

Thanks Stefan Koegl for the report and Simon Charette for the review.
This commit is contained in:
Claude Paroz 2013-01-25 14:52:24 +01:00
parent eafc036476
commit b9c8bbf372
2 changed files with 32 additions and 2 deletions

View File

@ -221,9 +221,12 @@ class BaseCommand(object):
try: try:
self.execute(*args, **options.__dict__) self.execute(*args, **options.__dict__)
except Exception as e: except Exception as e:
# self.stderr is not guaranteed to be set here
stderr = getattr(self, 'stderr', OutputWrapper(sys.stderr, self.style.ERROR))
if options.traceback: if options.traceback:
self.stderr.write(traceback.format_exc()) stderr.write(traceback.format_exc())
self.stderr.write('%s: %s' % (e.__class__.__name__, e)) else:
stderr.write('%s: %s' % (e.__class__.__name__, e))
sys.exit(1) sys.exit(1)
def execute(self, *args, **options): def execute(self, *args, **options):

View File

@ -16,11 +16,13 @@ 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.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
from django.utils.encoding import force_str, force_text from django.utils.encoding import force_str, force_text
from django.utils._os import upath from django.utils._os import upath
from django.utils.six import StringIO
from django.test import LiveServerTestCase from django.test import LiveServerTestCase
test_dir = os.path.dirname(os.path.dirname(upath(__file__))) test_dir = os.path.dirname(os.path.dirname(upath(__file__)))
@ -1279,6 +1281,31 @@ class CommandTypes(AdminScriptTestCase):
self.assertNoOutput(err) self.assertNoOutput(err)
self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', 'y'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]") self.assertOutput(out, "EXECUTE:BaseCommand labels=('testlabel',), options=[('option_a', 'x'), ('option_b', 'y'), ('option_c', '3'), ('pythonpath', None), ('settings', None), ('traceback', None), ('verbosity', '1')]")
def test_base_run_from_argv(self):
"""
Test run_from_argv properly terminates even with custom execute() (#19665)
Also test proper traceback display.
"""
command = BaseCommand()
command.execute = lambda args: args # This will trigger TypeError
old_stderr = sys.stderr
sys.stderr = err = StringIO()
try:
with self.assertRaises(SystemExit):
command.run_from_argv(['', ''])
err_message = err.getvalue()
self.assertNotIn("Traceback", err_message)
self.assertIn("TypeError", err_message)
with self.assertRaises(SystemExit):
command.run_from_argv(['', '', '--traceback'])
err_message = err.getvalue()
self.assertIn("Traceback (most recent call last)", err_message)
self.assertIn("TypeError", err_message)
finally:
sys.stderr = old_stderr
def test_noargs(self): def test_noargs(self):
"NoArg Commands can be executed" "NoArg Commands can be executed"
args = ['noargs_command'] args = ['noargs_command']