Skip to content

Commit 8e8c3f9

Browse files
adamchainzfelixxm
authored andcommitted
Refs #29501 -- Allowed customizing exit status for management commands.
1 parent 6cad911 commit 8e8c3f9

File tree

5 files changed

+21
-7
lines changed

5 files changed

+21
-7
lines changed

django/core/management/base.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ class CommandError(Exception):
2626
error) is the preferred way to indicate that something has gone
2727
wrong in the execution of a command.
2828
"""
29-
pass
29+
def __init__(self, *args, returncode=1, **kwargs):
30+
self.returncode = returncode
31+
super().__init__(*args, **kwargs)
3032

3133

3234
class SystemCheckError(CommandError):
@@ -335,7 +337,7 @@ def run_from_argv(self, argv):
335337
self.stderr.write(str(e), lambda x: x)
336338
else:
337339
self.stderr.write('%s: %s' % (e.__class__.__name__, e))
338-
sys.exit(1)
340+
sys.exit(e.returncode)
339341
finally:
340342
try:
341343
connections.close_all()

docs/howto/custom-management-commands.txt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -340,16 +340,22 @@ Rather than implementing :meth:`~BaseCommand.handle`, subclasses must implement
340340
Command exceptions
341341
------------------
342342

343-
.. exception:: CommandError
343+
.. exception:: CommandError(returncode=1)
344344

345345
Exception class indicating a problem while executing a management command.
346346

347347
If this exception is raised during the execution of a management command from a
348348
command line console, it will be caught and turned into a nicely-printed error
349349
message to the appropriate output stream (i.e., stderr); as a result, raising
350350
this exception (with a sensible description of the error) is the preferred way
351-
to indicate that something has gone wrong in the execution of a command.
351+
to indicate that something has gone wrong in the execution of a command. It
352+
accepts the optional ``returncode`` argument to customize the exit status for
353+
the management command to exit with, using :func:`sys.exit`.
352354

353355
If a management command is called from code through
354356
:func:`~django.core.management.call_command`, it's up to you to catch the
355357
exception when needed.
358+
359+
.. versionchanged:: 3.1
360+
361+
The ``returncode`` argument was added.

docs/releases/3.1.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,10 @@ Management Commands
313313
* The new :option:`migrate --check` option makes the command exit with a
314314
non-zero status when unapplied migrations are detected.
315315

316+
* The new ``returncode`` argument for
317+
:attr:`~django.core.management.CommandError` allows customizing the exit
318+
status for management commands.
319+
316320
Migrations
317321
~~~~~~~~~~
318322

tests/user_commands/management/commands/dance.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def add_arguments(self, parser):
1515
def handle(self, *args, **options):
1616
example = options["example"]
1717
if example == "raise":
18-
raise CommandError()
18+
raise CommandError(returncode=3)
1919
if options['verbosity'] > 0:
2020
self.stdout.write("I don't feel like dancing %s." % options["style"])
2121
self.stdout.write(','.join(options))

tests/user_commands/tests.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,14 @@ def test_system_exit(self):
5757
""" Exception raised in a command should raise CommandError with
5858
call_command, but SystemExit when run from command line
5959
"""
60-
with self.assertRaises(CommandError):
60+
with self.assertRaises(CommandError) as cm:
6161
management.call_command('dance', example="raise")
62+
self.assertEqual(cm.exception.returncode, 3)
6263
dance.Command.requires_system_checks = False
6364
try:
64-
with captured_stderr() as stderr, self.assertRaises(SystemExit):
65+
with captured_stderr() as stderr, self.assertRaises(SystemExit) as cm:
6566
management.ManagementUtility(['manage.py', 'dance', '--example=raise']).execute()
67+
self.assertEqual(cm.exception.code, 3)
6668
finally:
6769
dance.Command.requires_system_checks = True
6870
self.assertIn("CommandError", stderr.getvalue())

0 commit comments

Comments
 (0)