Fixed #29301 -- Added custom help formatter to BaseCommand class
This partially reverts c3055242c8
.
Thanks Adam Johnson and Carlton Gibson for the reviews.
This commit is contained in:
parent
e9bd1a3e12
commit
ce3351b950
|
@ -4,7 +4,7 @@ be executed through ``django-admin`` or ``manage.py``).
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser, HelpFormatter
|
||||||
from io import TextIOBase
|
from io import TextIOBase
|
||||||
|
|
||||||
import django
|
import django
|
||||||
|
@ -88,6 +88,29 @@ def no_translations(handle_func):
|
||||||
return wrapped
|
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):
|
class OutputWrapper(TextIOBase):
|
||||||
"""
|
"""
|
||||||
Wrapper around stdout/stderr
|
Wrapper around stdout/stderr
|
||||||
|
@ -229,12 +252,10 @@ class BaseCommand:
|
||||||
parser = CommandParser(
|
parser = CommandParser(
|
||||||
prog='%s %s' % (os.path.basename(prog_name), subcommand),
|
prog='%s %s' % (os.path.basename(prog_name), subcommand),
|
||||||
description=self.help or None,
|
description=self.help or None,
|
||||||
|
formatter_class=DjangoHelpFormatter,
|
||||||
missing_args_message=getattr(self, 'missing_args_message', None),
|
missing_args_message=getattr(self, 'missing_args_message', None),
|
||||||
called_from_command_line=getattr(self, '_called_from_command_line', 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('--version', action='version', version=self.get_version())
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'-v', '--verbosity', action='store', dest='verbosity', default=1,
|
'-v', '--verbosity', action='store', dest='verbosity', default=1,
|
||||||
|
@ -258,6 +279,7 @@ class BaseCommand:
|
||||||
'--no-color', action='store_true', dest='no_color',
|
'--no-color', action='store_true', dest='no_color',
|
||||||
help="Don't colorize the command output.",
|
help="Don't colorize the command output.",
|
||||||
)
|
)
|
||||||
|
self.add_arguments(parser)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
def add_arguments(self, parser):
|
def add_arguments(self, parser):
|
||||||
|
|
|
@ -145,6 +145,11 @@ Management Commands
|
||||||
* The new :option:`inspectdb --include-views` option allows creating models
|
* The new :option:`inspectdb --include-views` option allows creating models
|
||||||
for database views.
|
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
|
Migrations
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -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'
|
|
@ -205,6 +205,11 @@ class CommandTests(SimpleTestCase):
|
||||||
self.assertIn('need_me', out.getvalue())
|
self.assertIn('need_me', out.getvalue())
|
||||||
self.assertIn('needme2', 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):
|
def test_subparser(self):
|
||||||
out = StringIO()
|
out = StringIO()
|
||||||
management.call_command('subparser', 'foo', 12, stdout=out)
|
management.call_command('subparser', 'foo', 12, stdout=out)
|
||||||
|
|
Loading…
Reference in New Issue