summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Johnson <me@adamj.eu>2020-04-14 08:56:16 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2020-04-14 13:22:47 +0200
commit8e8c3f964e23e669fc563a74750e51abba4c2e3a (patch)
tree35a0060e2aebb7f97cc7eff303c2e8c812999787
parent6cad911674dc067ffab44eea4f5c8170fa0a89b1 (diff)
Refs #29501 -- Allowed customizing exit status for management commands.
-rw-r--r--django/core/management/base.py6
-rw-r--r--docs/howto/custom-management-commands.txt10
-rw-r--r--docs/releases/3.1.txt4
-rw-r--r--tests/user_commands/management/commands/dance.py2
-rw-r--r--tests/user_commands/tests.py6
5 files changed, 21 insertions, 7 deletions
diff --git a/django/core/management/base.py b/django/core/management/base.py
index 82da46875a..0091908fed 100644
--- a/django/core/management/base.py
+++ b/django/core/management/base.py
@@ -26,7 +26,9 @@ class CommandError(Exception):
error) is the preferred way to indicate that something has gone
wrong in the execution of a command.
"""
- pass
+ def __init__(self, *args, returncode=1, **kwargs):
+ self.returncode = returncode
+ super().__init__(*args, **kwargs)
class SystemCheckError(CommandError):
@@ -335,7 +337,7 @@ class BaseCommand:
self.stderr.write(str(e), lambda x: x)
else:
self.stderr.write('%s: %s' % (e.__class__.__name__, e))
- sys.exit(1)
+ sys.exit(e.returncode)
finally:
try:
connections.close_all()
diff --git a/docs/howto/custom-management-commands.txt b/docs/howto/custom-management-commands.txt
index ec83dda381..77c4c61e8c 100644
--- a/docs/howto/custom-management-commands.txt
+++ b/docs/howto/custom-management-commands.txt
@@ -340,7 +340,7 @@ Rather than implementing :meth:`~BaseCommand.handle`, subclasses must implement
Command exceptions
------------------
-.. exception:: CommandError
+.. exception:: CommandError(returncode=1)
Exception class indicating a problem while executing a management command.
@@ -348,8 +348,14 @@ If this exception is raised during the execution of a management command from a
command line console, it will be caught and turned into a nicely-printed error
message to the appropriate output stream (i.e., stderr); as a result, raising
this exception (with a sensible description of the error) is the preferred way
-to indicate that something has gone wrong in the execution of a command.
+to indicate that something has gone wrong in the execution of a command. It
+accepts the optional ``returncode`` argument to customize the exit status for
+the management command to exit with, using :func:`sys.exit`.
If a management command is called from code through
:func:`~django.core.management.call_command`, it's up to you to catch the
exception when needed.
+
+.. versionchanged:: 3.1
+
+ The ``returncode`` argument was added.
diff --git a/docs/releases/3.1.txt b/docs/releases/3.1.txt
index 07f316a701..dbf599fb48 100644
--- a/docs/releases/3.1.txt
+++ b/docs/releases/3.1.txt
@@ -313,6 +313,10 @@ Management Commands
* The new :option:`migrate --check` option makes the command exit with a
non-zero status when unapplied migrations are detected.
+* The new ``returncode`` argument for
+ :attr:`~django.core.management.CommandError` allows customizing the exit
+ status for management commands.
+
Migrations
~~~~~~~~~~
diff --git a/tests/user_commands/management/commands/dance.py b/tests/user_commands/management/commands/dance.py
index 81d6ec9c26..82cfc3338a 100644
--- a/tests/user_commands/management/commands/dance.py
+++ b/tests/user_commands/management/commands/dance.py
@@ -15,7 +15,7 @@ class Command(BaseCommand):
def handle(self, *args, **options):
example = options["example"]
if example == "raise":
- raise CommandError()
+ raise CommandError(returncode=3)
if options['verbosity'] > 0:
self.stdout.write("I don't feel like dancing %s." % options["style"])
self.stdout.write(','.join(options))
diff --git a/tests/user_commands/tests.py b/tests/user_commands/tests.py
index b770e8e459..b1d00f278d 100644
--- a/tests/user_commands/tests.py
+++ b/tests/user_commands/tests.py
@@ -57,12 +57,14 @@ class CommandTests(SimpleTestCase):
""" Exception raised in a command should raise CommandError with
call_command, but SystemExit when run from command line
"""
- with self.assertRaises(CommandError):
+ with self.assertRaises(CommandError) as cm:
management.call_command('dance', example="raise")
+ self.assertEqual(cm.exception.returncode, 3)
dance.Command.requires_system_checks = False
try:
- with captured_stderr() as stderr, self.assertRaises(SystemExit):
+ with captured_stderr() as stderr, self.assertRaises(SystemExit) as cm:
management.ManagementUtility(['manage.py', 'dance', '--example=raise']).execute()
+ self.assertEqual(cm.exception.code, 3)
finally:
dance.Command.requires_system_checks = True
self.assertIn("CommandError", stderr.getvalue())