From 888c86dcf30defe533451bcefc6e09a6e181389f Mon Sep 17 00:00:00 2001
From: Jorge Bastida <me@jorgebastida.com>
Date: Sat, 18 May 2013 18:04:45 +0200
Subject: [PATCH] Fixed #20445 -- Raised original exception after command error

---
 django/core/management/base.py | 14 +++++++-------
 tests/admin_scripts/tests.py   | 22 ++++++++++++----------
 2 files changed, 19 insertions(+), 17 deletions(-)

diff --git a/django/core/management/base.py b/django/core/management/base.py
index ba6ad8f4c0..af040288d0 100644
--- a/django/core/management/base.py
+++ b/django/core/management/base.py
@@ -7,7 +7,6 @@ import os
 import sys
 
 from optparse import make_option, OptionParser
-import traceback
 
 import django
 from django.core.exceptions import ImproperlyConfigured
@@ -171,7 +170,7 @@ class BaseCommand(object):
         make_option('--pythonpath',
             help='A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".'),
         make_option('--traceback', action='store_true',
-            help='Print traceback on exception'),
+            help='Raise on exception'),
     )
     help = ''
     args = ''
@@ -231,7 +230,8 @@ class BaseCommand(object):
         Set up any environment changes requested (e.g., Python path
         and Django settings), then run this command. If the
         command raises a ``CommandError``, intercept it and print it sensibly
-        to stderr.
+        to stderr. If the ``--traceback`` option is present or the raised
+        ``Exception`` is not ``CommandError``, raise it.
         """
         parser = self.create_parser(argv[0], argv[1])
         options, args = parser.parse_args(argv[2:])
@@ -239,12 +239,12 @@ class BaseCommand(object):
         try:
             self.execute(*args, **options.__dict__)
         except Exception as e:
+            if options.traceback or not isinstance(e, CommandError):
+                raise
+
             # self.stderr is not guaranteed to be set here
             stderr = getattr(self, 'stderr', OutputWrapper(sys.stderr, self.style.ERROR))
-            if options.traceback or not isinstance(e, CommandError):
-                stderr.write(traceback.format_exc())
-            else:
-                stderr.write('%s: %s' % (e.__class__.__name__, e))
+            stderr.write('%s: %s' % (e.__class__.__name__, e))
             sys.exit(1)
 
     def execute(self, *args, **options):
diff --git a/tests/admin_scripts/tests.py b/tests/admin_scripts/tests.py
index c8986770f3..f0ef0fb293 100644
--- a/tests/admin_scripts/tests.py
+++ b/tests/admin_scripts/tests.py
@@ -1305,13 +1305,15 @@ class CommandTypes(AdminScriptTestCase):
         sys.stderr = err = StringIO()
         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)
 
+            # If the Exception is not CommandError it should always
+            # raise the original exception.
+            with self.assertRaises(TypeError):
+                command.run_from_argv(['', ''])
+
+            # If the Exception is CommandError and --traceback is not present
+            # this command should raise a SystemExit and don't print any
+            # traceback to the stderr.
             command.execute = raise_command_error
             err.truncate(0)
             with self.assertRaises(SystemExit):
@@ -1320,12 +1322,12 @@ class CommandTypes(AdminScriptTestCase):
             self.assertNotIn("Traceback", err_message)
             self.assertIn("CommandError", err_message)
 
+            # If the Exception is CommandError and --traceback is present
+            # this command should raise the original CommandError as if it
+            # were not a CommandError.
             err.truncate(0)
-            with self.assertRaises(SystemExit):
+            with self.assertRaises(CommandError):
                 command.run_from_argv(['', '', '--traceback'])
-            err_message = err.getvalue()
-            self.assertIn("Traceback (most recent call last)", err_message)
-            self.assertIn("CommandError", err_message)
         finally:
             sys.stderr = old_stderr