summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaude Paroz <claude@2xlibre.net>2018-05-21 11:32:51 +0200
committerClaude Paroz <claude@2xlibre.net>2018-06-06 19:16:10 +0200
commitce3351b9508896afdf87d11bd64fd6b5ad928228 (patch)
tree2a29a1e01b4df1765c101be40ca76bb5b840d3b0
parente9bd1a3e12df132527a8d8bea95858e856ac7be4 (diff)
Fixed #29301 -- Added custom help formatter to BaseCommand class
This partially reverts c3055242c81812278ebdc93dd109f30d2cbd1610. Thanks Adam Johnson and Carlton Gibson for the reviews.
-rw-r--r--django/core/management/base.py30
-rw-r--r--docs/releases/2.1.txt5
-rw-r--r--tests/user_commands/management/commands/common_args.py16
-rw-r--r--tests/user_commands/tests.py5
4 files changed, 52 insertions, 4 deletions
diff --git a/django/core/management/base.py b/django/core/management/base.py
index d6b4e27b78..e3374f678b 100644
--- a/django/core/management/base.py
+++ b/django/core/management/base.py
@@ -4,7 +4,7 @@ be executed through ``django-admin`` or ``manage.py``).
"""
import os
import sys
-from argparse import ArgumentParser
+from argparse import ArgumentParser, HelpFormatter
from io import TextIOBase
import django
@@ -88,6 +88,29 @@ def no_translations(handle_func):
return wrapped
+class DjangoHelpFormatter(HelpFormatter):
+ """
+ Customized formatter so that command-specific arguments appear in the
+ --help output before arguments common to all commands.
+ """
+ show_last = {
+ '--version', '--verbosity', '--traceback', '--settings', '--pythonpath',
+ '--no-color',
+ }
+
+ def _reordered_actions(self, actions):
+ return sorted(
+ actions,
+ key=lambda a: set(a.option_strings) & self.show_last != set()
+ )
+
+ def add_usage(self, usage, actions, *args, **kwargs):
+ super().add_usage(usage, self._reordered_actions(actions), *args, **kwargs)
+
+ def add_arguments(self, actions):
+ super().add_arguments(self._reordered_actions(actions))
+
+
class OutputWrapper(TextIOBase):
"""
Wrapper around stdout/stderr
@@ -229,12 +252,10 @@ class BaseCommand:
parser = CommandParser(
prog='%s %s' % (os.path.basename(prog_name), subcommand),
description=self.help or None,
+ formatter_class=DjangoHelpFormatter,
missing_args_message=getattr(self, 'missing_args_message', None),
called_from_command_line=getattr(self, '_called_from_command_line', None),
)
- # Add command-specific arguments first so that they appear in the
- # --help output before arguments common to all commands.
- self.add_arguments(parser)
parser.add_argument('--version', action='version', version=self.get_version())
parser.add_argument(
'-v', '--verbosity', action='store', dest='verbosity', default=1,
@@ -258,6 +279,7 @@ class BaseCommand:
'--no-color', action='store_true', dest='no_color',
help="Don't colorize the command output.",
)
+ self.add_arguments(parser)
return parser
def add_arguments(self, parser):
diff --git a/docs/releases/2.1.txt b/docs/releases/2.1.txt
index cf2dbd6920..81f112b464 100644
--- a/docs/releases/2.1.txt
+++ b/docs/releases/2.1.txt
@@ -145,6 +145,11 @@ Management Commands
* The new :option:`inspectdb --include-views` option allows creating models
for database views.
+* The :class:`~django.core.management.BaseCommand` class now uses a custom help
+ formatter so that the standard options like ``--verbosity`` or ``--settings``
+ appear last in the help output, giving a more prominent position to subclassed
+ command's options.
+
Migrations
~~~~~~~~~~
diff --git a/tests/user_commands/management/commands/common_args.py b/tests/user_commands/management/commands/common_args.py
new file mode 100644
index 0000000000..d7b288a267
--- /dev/null
+++ b/tests/user_commands/management/commands/common_args.py
@@ -0,0 +1,16 @@
+from argparse import ArgumentError
+
+from django.core.management.base import BaseCommand, CommandError
+
+
+class Command(BaseCommand):
+ def add_arguments(self, parser):
+ try:
+ parser.add_argument('--version', action='version', version='A.B.C')
+ except ArgumentError:
+ pass
+ else:
+ raise CommandError('--version argument does no yet exist')
+
+ def handle(self, *args, **options):
+ return 'Detected that --version already exists'
diff --git a/tests/user_commands/tests.py b/tests/user_commands/tests.py
index 92263f58d6..e90d29bb0f 100644
--- a/tests/user_commands/tests.py
+++ b/tests/user_commands/tests.py
@@ -205,6 +205,11 @@ class CommandTests(SimpleTestCase):
self.assertIn('need_me', out.getvalue())
self.assertIn('needme2', out.getvalue())
+ def test_command_add_arguments_after_common_arguments(self):
+ out = StringIO()
+ management.call_command('common_args', stdout=out)
+ self.assertIn('Detected that --version already exists', out.getvalue())
+
def test_subparser(self):
out = StringIO()
management.call_command('subparser', 'foo', 12, stdout=out)