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:
parent
eafc036476
commit
b9c8bbf372
|
@ -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):
|
||||||
|
|
|
@ -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']
|
||||||
|
|
Loading…
Reference in New Issue