Fixed #25264 -- Allowed suppressing base command options in --help output.

This also suppresses -verbosity and --trackback options in the
runserver's help.
This commit is contained in:
Jan Szoja 2021-07-25 00:16:00 +01:00 committed by Mariusz Felisiak
parent 97f377cd35
commit b667ac24ea
6 changed files with 105 additions and 12 deletions

View File

@ -2,6 +2,7 @@
Base classes for writing management commands (named commands which can
be executed through ``django-admin`` or ``manage.py``).
"""
import argparse
import os
import sys
import warnings
@ -239,6 +240,7 @@ class BaseCommand:
base_stealth_options = ('stderr', 'stdout')
# Command-specific options not defined by the argument parser.
stealth_options = ()
suppressed_base_arguments = set()
def __init__(self, stdout=None, stderr=None, no_color=False, force_color=False):
self.stdout = OutputWrapper(stdout or sys.stdout)
@ -285,31 +287,37 @@ class BaseCommand:
called_from_command_line=getattr(self, '_called_from_command_line', None),
**kwargs
)
parser.add_argument('--version', action='version', version=self.get_version())
parser.add_argument(
'-v', '--verbosity', default=1,
self.add_base_argument(
parser, '--version', action='version', version=self.get_version(),
help="Show program's version number and exit.",
)
self.add_base_argument(
parser, '-v', '--verbosity', default=1,
type=int, choices=[0, 1, 2, 3],
help='Verbosity level; 0=minimal output, 1=normal output, 2=verbose output, 3=very verbose output',
)
parser.add_argument(
'--settings',
self.add_base_argument(
parser, '--settings',
help=(
'The Python path to a settings module, e.g. '
'"myproject.settings.main". If this isn\'t provided, the '
'DJANGO_SETTINGS_MODULE environment variable will be used.'
),
)
parser.add_argument(
'--pythonpath',
self.add_base_argument(
parser, '--pythonpath',
help='A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".',
)
parser.add_argument('--traceback', action='store_true', help='Raise on CommandError exceptions')
parser.add_argument(
'--no-color', action='store_true',
self.add_base_argument(
parser, '--traceback', action='store_true',
help='Raise on CommandError exceptions.',
)
self.add_base_argument(
parser, '--no-color', action='store_true',
help="Don't colorize the command output.",
)
parser.add_argument(
'--force-color', action='store_true',
self.add_base_argument(
parser, '--force-color', action='store_true',
help='Force colorization of the command output.',
)
if self.requires_system_checks:
@ -326,6 +334,17 @@ class BaseCommand:
"""
pass
def add_base_argument(self, parser, *args, **kwargs):
"""
Call the parser's add_argument() method, suppressing the help text
according to BaseCommand.suppressed_base_arguments.
"""
for arg in args:
if arg in self.suppressed_base_arguments:
kwargs['help'] = argparse.SUPPRESS
break
parser.add_argument(*args, **kwargs)
def print_help(self, prog_name, subcommand):
"""
Print the help message for this command, derived from

View File

@ -27,6 +27,7 @@ class Command(BaseCommand):
# Validation is called explicitly each time the server is reloaded.
requires_system_checks = []
stealth_options = ('shutdown_message',)
suppressed_base_arguments = {'--verbosity', '--traceback'}
default_addr = '127.0.0.1'
default_addr_ipv6 = '::1'

View File

@ -242,6 +242,14 @@ All attributes can be set in your derived class and can be used in
If you pass the :option:`--no-color` option when running your command, all
``self.style()`` calls will return the original string uncolored.
.. attribute:: BaseCommand.suppressed_base_arguments
.. versionadded:: 4.0
The default command options to suppress in the help output. This should be
a set of option names (e.g. ``'--verbosity'``). The default values for the
suppressed options are still passed.
Methods
-------

View File

@ -274,6 +274,10 @@ Management Commands
As a consequence, ``readline`` is no longer loaded if running in *isolated*
mode.
* The new :attr:`BaseCommand.suppressed_base_arguments
<django.core.management.BaseCommand.suppressed_base_arguments>` attribute
allows suppressing unsupported default command options in the help output.
Migrations
~~~~~~~~~~

View File

@ -0,0 +1,24 @@
from django.core.management import BaseCommand
class Command(BaseCommand):
help = 'Test suppress base options command.'
requires_system_checks = []
suppressed_base_arguments = {
'-v',
'--traceback',
'--settings',
'--pythonpath',
'--no-color',
'--force-color',
'--version',
'file',
}
def add_arguments(self, parser):
super().add_arguments(parser)
self.add_base_argument(parser, 'file', nargs='?', help='input file')
def handle(self, *labels, **options):
print('EXECUTE:SuppressBaseOptionsCommand options=%s' % sorted(options.items()))

View File

@ -1381,6 +1381,15 @@ class ManageRunserverEmptyAllowedHosts(AdminScriptTestCase):
self.assertOutput(err, 'CommandError: You must set settings.ALLOWED_HOSTS if DEBUG is False.')
class ManageRunserverHelpOutput(AdminScriptTestCase):
def test_suppressed_options(self):
"""runserver doesn't support --verbosity and --trackback options."""
out, err = self.run_manage(['runserver', '--help'])
self.assertNotInOutput(out, '--verbosity')
self.assertNotInOutput(out, '--trackback')
self.assertOutput(out, '--settings')
class ManageTestserver(SimpleTestCase):
@mock.patch.object(TestserverCommand, 'handle', return_value='')
@ -1847,6 +1856,34 @@ class CommandTypes(AdminScriptTestCase):
"('settings', None), ('traceback', False), ('verbosity', 1)]"
)
def test_suppress_base_options_command_help(self):
args = ['suppress_base_options_command', '--help']
out, err = self.run_manage(args)
self.assertNoOutput(err)
self.assertOutput(out, 'Test suppress base options command.')
self.assertNotInOutput(out, 'input file')
self.assertOutput(out, '-h, --help')
self.assertNotInOutput(out, '--version')
self.assertNotInOutput(out, '--verbosity')
self.assertNotInOutput(out, '-v {0,1,2,3}')
self.assertNotInOutput(out, '--settings')
self.assertNotInOutput(out, '--pythonpath')
self.assertNotInOutput(out, '--traceback')
self.assertNotInOutput(out, '--no-color')
self.assertNotInOutput(out, '--force-color')
def test_suppress_base_options_command_defaults(self):
args = ['suppress_base_options_command']
out, err = self.run_manage(args)
self.assertNoOutput(err)
self.assertOutput(
out,
"EXECUTE:SuppressBaseOptionsCommand options=[('file', None), "
"('force_color', False), ('no_color', False), "
"('pythonpath', None), ('settings', None), "
"('traceback', False), ('verbosity', 1)]"
)
class Discovery(SimpleTestCase):