summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Szoja <jszoja@gmail.com>2021-07-25 00:16:00 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2021-08-31 11:04:02 +0200
commitb667ac24ead73300c49e265201b6c0b913ee36a3 (patch)
tree983386432906bc7372abee193a5bb50f20bb894b
parent97f377cd3520794f7d4e97b7aa1fa2093c426273 (diff)
Fixed #25264 -- Allowed suppressing base command options in --help output.
This also suppresses -verbosity and --trackback options in the runserver's help.
-rw-r--r--django/core/management/base.py43
-rw-r--r--django/core/management/commands/runserver.py1
-rw-r--r--docs/howto/custom-management-commands.txt8
-rw-r--r--docs/releases/4.0.txt4
-rw-r--r--tests/admin_scripts/management/commands/suppress_base_options_command.py24
-rw-r--r--tests/admin_scripts/tests.py37
6 files changed, 105 insertions, 12 deletions
diff --git a/django/core/management/base.py b/django/core/management/base.py
index 463e4e8665..2044b85754 100644
--- a/django/core/management/base.py
+++ b/django/core/management/base.py
@@ -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
diff --git a/django/core/management/commands/runserver.py b/django/core/management/commands/runserver.py
index 66f5217820..473fde0de0 100644
--- a/django/core/management/commands/runserver.py
+++ b/django/core/management/commands/runserver.py
@@ -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'
diff --git a/docs/howto/custom-management-commands.txt b/docs/howto/custom-management-commands.txt
index 3ecde33d67..0cb06a826d 100644
--- a/docs/howto/custom-management-commands.txt
+++ b/docs/howto/custom-management-commands.txt
@@ -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
-------
diff --git a/docs/releases/4.0.txt b/docs/releases/4.0.txt
index 53b738c8ec..5849b08cd4 100644
--- a/docs/releases/4.0.txt
+++ b/docs/releases/4.0.txt
@@ -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
~~~~~~~~~~
diff --git a/tests/admin_scripts/management/commands/suppress_base_options_command.py b/tests/admin_scripts/management/commands/suppress_base_options_command.py
new file mode 100644
index 0000000000..769ef3178c
--- /dev/null
+++ b/tests/admin_scripts/management/commands/suppress_base_options_command.py
@@ -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()))
diff --git a/tests/admin_scripts/tests.py b/tests/admin_scripts/tests.py
index e5216e93e9..a3ceb8ad75 100644
--- a/tests/admin_scripts/tests.py
+++ b/tests/admin_scripts/tests.py
@@ -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):