summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Graham <timograham@gmail.com>2015-08-18 12:46:03 -0400
committerTim Graham <timograham@gmail.com>2015-09-23 19:31:10 -0400
commit6a70cb53971a19f2d9e71d5ee24bfb0e844b4d9d (patch)
treea12774fd9787b8f8b4581daca60de6beacf8e943
parent3bbebd06adc36f31877a9c0af6c20c5b5a71a900 (diff)
Refs #19973 -- Removed optparse support in management commands per deprecation timeline.
-rw-r--r--django/core/management/__init__.py33
-rw-r--r--django/core/management/base.py104
-rw-r--r--django/core/management/commands/test.py7
-rw-r--r--docs/howto/custom-management-commands.txt40
-rw-r--r--docs/releases/1.8.txt15
-rw-r--r--docs/topics/testing/advanced.txt16
-rw-r--r--tests/user_commands/management/commands/optparse_cmd.py22
-rw-r--r--tests/user_commands/tests.py19
8 files changed, 47 insertions, 209 deletions
diff --git a/django/core/management/__init__.py b/django/core/management/__init__.py
index dec7c052b3..7e4982f0a2 100644
--- a/django/core/management/__init__.py
+++ b/django/core/management/__init__.py
@@ -100,19 +100,16 @@ def call_command(name, *args, **options):
# Simulate argument parsing to get the option defaults (see #10080 for details).
parser = command.create_parser('', name)
- if command.use_argparse:
- # Use the `dest` option name from the parser option
- opt_mapping = {sorted(s_opt.option_strings)[0].lstrip('-').replace('-', '_'): s_opt.dest
- for s_opt in parser._actions if s_opt.option_strings}
- arg_options = {opt_mapping.get(key, key): value for key, value in options.items()}
- defaults = parser.parse_args(args=args)
- defaults = dict(defaults._get_kwargs(), **arg_options)
- # Move positional args out of options to mimic legacy optparse
- args = defaults.pop('args', ())
- else:
- # Legacy optparse method
- defaults, _ = parser.parse_args(args=[])
- defaults = dict(defaults.__dict__, **options)
+ # Use the `dest` option name from the parser option
+ opt_mapping = {
+ sorted(s_opt.option_strings)[0].lstrip('-').replace('-', '_'): s_opt.dest
+ for s_opt in parser._actions if s_opt.option_strings
+ }
+ arg_options = {opt_mapping.get(key, key): value for key, value in options.items()}
+ defaults = parser.parse_args(args=args)
+ defaults = dict(defaults._get_kwargs(), **arg_options)
+ # Move positional args out of options to mimic legacy optparse
+ args = defaults.pop('args', ())
if 'skip_checks' not in options:
defaults['skip_checks'] = True
@@ -249,12 +246,10 @@ class ManagementUtility(object):
# user will find out once they execute the command.
pass
parser = subcommand_cls.create_parser('', cwords[0])
- if subcommand_cls.use_argparse:
- options.extend((sorted(s_opt.option_strings)[0], s_opt.nargs != 0) for s_opt in
- parser._actions if s_opt.option_strings)
- else:
- options.extend((s_opt.get_opt_string(), s_opt.nargs != 0) for s_opt in
- parser.option_list)
+ options.extend(
+ (sorted(s_opt.option_strings)[0], s_opt.nargs != 0)
+ for s_opt in parser._actions if s_opt.option_strings
+ )
# filter out previously specified options from available options
prev_opts = [x.split('=')[0] for x in cwords[1:cword - 1]]
options = [opt for opt in options if opt[0] not in prev_opts]
diff --git a/django/core/management/base.py b/django/core/management/base.py
index 7eaea741e0..10d1b728fe 100644
--- a/django/core/management/base.py
+++ b/django/core/management/base.py
@@ -9,7 +9,6 @@ import os
import sys
import warnings
from argparse import ArgumentParser
-from optparse import OptionParser
import django
from django.core import checks
@@ -152,12 +151,6 @@ class BaseCommand(object):
Several attributes affect behavior at various steps along the way:
- ``args``
- A string listing the arguments accepted by the command,
- suitable for use in help messages; e.g., a command which takes
- a list of application names might set this to '<app_label
- app_label ...>'.
-
``can_import_settings``
A boolean indicating whether the command needs to be able to
import Django settings; if ``True``, ``execute()`` will verify
@@ -168,12 +161,6 @@ class BaseCommand(object):
A short description of the command, which will be printed in
help messages.
- ``option_list``
- This is the list of ``optparse`` options which will be fed
- into the command's ``OptionParser`` for parsing arguments.
- Deprecated and will be removed in Django 1.10.
- Use ``add_arguments`` instead.
-
``output_transaction``
A boolean indicating whether the command outputs SQL
statements; if ``True``, the output will automatically be
@@ -207,9 +194,7 @@ class BaseCommand(object):
to settings. This condition will generate a CommandError.
"""
# Metadata about this command.
- option_list = ()
help = ''
- args = ''
# Configuration shortcuts that alter various logic.
_called_from_command_line = False
@@ -227,10 +212,6 @@ class BaseCommand(object):
self.style = color_style()
self.stderr.style_func = self.style.ERROR
- @property
- def use_argparse(self):
- return not bool(self.option_list)
-
def get_version(self):
"""
Return the Django version, which should be correct for all
@@ -255,59 +236,26 @@ class BaseCommand(object):
Create and return the ``ArgumentParser`` which will be used to
parse the arguments to this command.
"""
- if not self.use_argparse:
- def store_as_int(option, opt_str, value, parser):
- setattr(parser.values, option.dest, int(value))
-
- # Backwards compatibility: use deprecated optparse module
- warnings.warn("OptionParser usage for Django management commands "
- "is deprecated, use ArgumentParser instead",
- RemovedInDjango110Warning)
- parser = OptionParser(prog=prog_name,
- usage=self.usage(subcommand),
- version=self.get_version())
- parser.add_option('-v', '--verbosity', action='callback', dest='verbosity', default=1,
- type='choice', choices=['0', '1', '2', '3'], callback=store_as_int,
- help='Verbosity level; 0=minimal output, 1=normal output, 2=verbose output, 3=very verbose output')
- parser.add_option('--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_option('--pythonpath',
- help='A directory to add to the Python path, e.g. "/home/djangoprojects/myproject".'),
- parser.add_option('--traceback', action='store_true',
- help='Raise on CommandError exceptions')
- parser.add_option('--no-color', action='store_true', dest='no_color', default=False,
- help="Don't colorize the command output.")
- for opt in self.option_list:
- parser.add_option(opt)
- else:
- parser = CommandParser(self, prog="%s %s" % (os.path.basename(prog_name), subcommand),
- description=self.help or None)
- parser.add_argument('--version', action='version', version=self.get_version())
- parser.add_argument('-v', '--verbosity', action='store', dest='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',
- 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',
- 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', dest='no_color', default=False,
- help="Don't colorize the command output.")
- if self.args:
- # Keep compatibility and always accept positional arguments, like optparse when args is set
- parser.add_argument('args', nargs='*')
- self.add_arguments(parser)
+ parser = CommandParser(self, prog="%s %s" % (os.path.basename(prog_name), subcommand),
+ description=self.help or None)
+ parser.add_argument('--version', action='version', version=self.get_version())
+ parser.add_argument('-v', '--verbosity', action='store', dest='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',
+ 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',
+ 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', dest='no_color', default=False,
+ help="Don't colorize the command output.")
+ self.add_arguments(parser)
return parser
def add_arguments(self, parser):
@@ -335,14 +283,10 @@ class BaseCommand(object):
self._called_from_command_line = True
parser = self.create_parser(argv[0], argv[1])
- if self.use_argparse:
- options = parser.parse_args(argv[2:])
- cmd_options = vars(options)
- # Move positional args out of options to mimic legacy optparse
- args = cmd_options.pop('args', ())
- else:
- options, args = parser.parse_args(argv[2:])
- cmd_options = vars(options)
+ options = parser.parse_args(argv[2:])
+ cmd_options = vars(options)
+ # Move positional args out of options to mimic legacy optparse
+ args = cmd_options.pop('args', ())
handle_default_options(options)
try:
self.execute(*args, **cmd_options)
diff --git a/django/core/management/commands/test.py b/django/core/management/commands/test.py
index ad54994d74..6fdaca944c 100644
--- a/django/core/management/commands/test.py
+++ b/django/core/management/commands/test.py
@@ -50,13 +50,6 @@ class Command(BaseCommand):
'default value is localhost:8081-8179.'),
test_runner_class = get_runner(settings, self.test_runner)
- if hasattr(test_runner_class, 'option_list'):
- # Keeping compatibility with both optparse and argparse at this level
- # would be too heavy for a non-critical item
- raise RuntimeError(
- "The method to extend accepted command-line arguments by the "
- "test management command has changed in Django 1.8. Please "
- "create an add_arguments class method to achieve this.")
if hasattr(test_runner_class, 'add_arguments'):
test_runner_class.add_arguments(parser)
diff --git a/docs/howto/custom-management-commands.txt b/docs/howto/custom-management-commands.txt
index d5dd800a94..cc7653dd8e 100644
--- a/docs/howto/custom-management-commands.txt
+++ b/docs/howto/custom-management-commands.txt
@@ -69,16 +69,6 @@ look like this::
self.stdout.write('Successfully closed poll "%s"' % poll_id)
-.. versionchanged:: 1.8
-
- Before Django 1.8, management commands were based on the :py:mod:`optparse`
- module, and positional arguments were passed in ``*args`` while optional
- arguments were passed in ``**options``. Now that management commands use
- :py:mod:`argparse` for argument parsing, all arguments are passed in
- ``**options`` by default, unless you name your positional arguments to
- ``args`` (compatibility mode). You are encouraged to exclusively use
- ``**options`` for new commands.
-
.. _management-commands-output:
.. note::
@@ -128,12 +118,6 @@ options can be added in the :meth:`~BaseCommand.add_arguments` method like this:
poll.delete()
# ...
-.. versionchanged:: 1.8
-
- Previously, only the standard :py:mod:`optparse` library was supported and
- you would have to extend the command ``option_list`` variable with
- ``optparse.make_option()``.
-
The option (``delete`` in our example) is available in the options dict
parameter of the handle method. See the :py:mod:`argparse` Python documentation
for more about ``add_argument`` usage.
@@ -227,19 +211,6 @@ Attributes
All attributes can be set in your derived class and can be used in
:class:`BaseCommand`’s :ref:`subclasses<ref-basecommand-subclasses>`.
-.. attribute:: BaseCommand.args
-
- A string listing the arguments accepted by the command,
- suitable for use in help messages; e.g., a command which takes
- a list of application names might set this to '<app_label
- app_label ...>'.
-
- .. deprecated:: 1.8
-
- This should be done now in the :meth:`~BaseCommand.add_arguments()`
- method, by calling the ``parser.add_argument()`` method. See the
- ``closepoll`` example above.
-
.. attribute:: BaseCommand.can_import_settings
A boolean indicating whether the command needs to be able to
@@ -261,17 +232,6 @@ All attributes can be set in your derived class and can be used in
the message error returned in the case of missing arguments. The default is
output by :py:mod:`argparse` ("too few arguments").
-.. attribute:: BaseCommand.option_list
-
- This is the list of ``optparse`` options which will be fed
- into the command's ``OptionParser`` for parsing arguments.
-
- .. deprecated:: 1.8
-
- You should now override the :meth:`~BaseCommand.add_arguments` method
- to add custom arguments accepted by your command. See :ref:`the example
- above <custom-commands-options>`.
-
.. attribute:: BaseCommand.output_transaction
A boolean indicating whether the command outputs SQL statements; if
diff --git a/docs/releases/1.8.txt b/docs/releases/1.8.txt
index 1e0c233cba..e6b606505f 100644
--- a/docs/releases/1.8.txt
+++ b/docs/releases/1.8.txt
@@ -738,15 +738,14 @@ Management commands that only accept positional arguments
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you have written a custom management command that only accepts positional
-arguments and you didn't specify the
-:attr:`~django.core.management.BaseCommand.args` command variable, you might
-get an error like ``Error: unrecognized arguments: ...``, as variable parsing
-is now based on :py:mod:`argparse` which doesn't implicitly accept positional
+arguments and you didn't specify the ``args`` command variable, you might get
+an error like ``Error: unrecognized arguments: ...``, as variable parsing is
+now based on :py:mod:`argparse` which doesn't implicitly accept positional
arguments. You can make your command backwards compatible by simply setting the
-:attr:`~django.core.management.BaseCommand.args` class variable. However, if
-you don't have to keep compatibility with older Django versions, it's better to
-implement the new :meth:`~django.core.management.BaseCommand.add_arguments`
-method as described in :doc:`/howto/custom-management-commands`.
+``args`` class variable. However, if you don't have to keep compatibility with
+older Django versions, it's better to implement the new
+:meth:`~django.core.management.BaseCommand.add_arguments` method as described
+in :doc:`/howto/custom-management-commands`.
Custom test management command arguments through test runner
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/topics/testing/advanced.txt b/docs/topics/testing/advanced.txt
index eacc04c6d6..f2a2b103fc 100644
--- a/docs/topics/testing/advanced.txt
+++ b/docs/topics/testing/advanced.txt
@@ -417,10 +417,6 @@ execute and tear down the test suite.
.. versionchanged:: 1.8
- Previously, you had to provide an ``option_list`` attribute to a
- subclassed test runner to add options to the list of command-line
- options that the :djadmin:`test` command could use.
-
The ``keepdb``, ``reverse``, and ``debug_sql`` arguments were added.
Attributes
@@ -448,18 +444,6 @@ Attributes
By default it is set to ``unittest.defaultTestLoader``. You can override
this attribute if your tests are going to be loaded in unusual ways.
-.. attribute:: DiscoverRunner.option_list
-
- This is the tuple of ``optparse`` options which will be fed into the
- management command's ``OptionParser`` for parsing arguments. See the
- documentation for Python's ``optparse`` module for more details.
-
- .. deprecated:: 1.8
-
- You should now override the :meth:`~DiscoverRunner.add_arguments` class
- method to add custom arguments accepted by the :djadmin:`test`
- management command.
-
Methods
~~~~~~~
diff --git a/tests/user_commands/management/commands/optparse_cmd.py b/tests/user_commands/management/commands/optparse_cmd.py
deleted file mode 100644
index 09de44b200..0000000000
--- a/tests/user_commands/management/commands/optparse_cmd.py
+++ /dev/null
@@ -1,22 +0,0 @@
-from optparse import make_option
-
-from django.core.management.base import BaseCommand
-
-
-class Command(BaseCommand):
- help = "Test optparse compatibility."
- args = ''
-
- option_list = BaseCommand.option_list + (
- make_option("-s", "--style", default="Rock'n'Roll"),
- make_option("-x", "--example")
- )
-
- def handle(self, *args, **options):
- options["example"]
- # BaseCommand default option is available
- options['verbosity']
- assert (
- isinstance(options['verbosity'], int), "verbosity option is not int, but %s" % type(options['verbosity'])
- )
- self.stdout.write("All right, let's dance %s." % options["style"])
diff --git a/tests/user_commands/tests.py b/tests/user_commands/tests.py
index a50e714c94..8bceccc487 100644
--- a/tests/user_commands/tests.py
+++ b/tests/user_commands/tests.py
@@ -5,11 +5,10 @@ from django.core import management
from django.core.management import BaseCommand, CommandError, find_commands
from django.core.management.utils import find_command, popen_wrapper
from django.db import connection
-from django.test import SimpleTestCase, ignore_warnings, override_settings
-from django.test.utils import captured_stderr, captured_stdout, extend_sys_path
+from django.test import SimpleTestCase, override_settings
+from django.test.utils import captured_stderr, extend_sys_path
from django.utils import translation
from django.utils._os import upath
-from django.utils.deprecation import RemovedInDjango110Warning
from django.utils.six import StringIO
@@ -104,20 +103,6 @@ class CommandTests(SimpleTestCase):
self.assertNotIn("opt_3", out.getvalue())
self.assertNotIn("opt-3", out.getvalue())
- @ignore_warnings(category=RemovedInDjango110Warning)
- def test_optparse_compatibility(self):
- """
- optparse should be supported during Django 1.8/1.9 releases.
- """
- out = StringIO()
- management.call_command('optparse_cmd', stdout=out)
- self.assertEqual(out.getvalue(), "All right, let's dance Rock'n'Roll.\n")
-
- # Simulate command line execution
- with captured_stdout() as stdout, captured_stderr():
- management.execute_from_command_line(['django-admin', 'optparse_cmd'])
- self.assertEqual(stdout.getvalue(), "All right, let's dance Rock'n'Roll.\n")
-
def test_calling_a_command_with_only_empty_parameter_should_ends_gracefully(self):
out = StringIO()
management.call_command('hal', "--empty", stdout=out)