From fedc38a6daa2fb49664206e8a5967f296780bffe Mon Sep 17 00:00:00 2001 From: Matthew Somerville Date: Tue, 31 Jan 2017 14:42:55 +0000 Subject: [PATCH] Only add 'args' argument once to command parser. If a custom management LabelCommand or AppCommand uses 'args' then only the last positional argument provided is passed to the command, because argparse's behaviour when two calls to add_argument with the same name is undefined (it appears to put all the arguments bar one in the first '*' argument, then the last one in the '+' argument). This shows this with a test, and fixes it by not making the first call to parser.add_argument('args') if it's a LabelCommand or AppCommand. --- django/core/management/base.py | 2 +- tests/admin_scripts/tests.py | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/django/core/management/base.py b/django/core/management/base.py index 971e26caced67..0128aa7309f9e 100644 --- a/django/core/management/base.py +++ b/django/core/management/base.py @@ -349,7 +349,7 @@ def store_as_int(option, opt_str, value, parser): 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: + if self.args and not isinstance(self, LabelCommand) and not isinstance(self, AppCommand): # Keep compatibility and always accept positional arguments, like optparse when args is set parser.add_argument('args', nargs='*') self.add_arguments(parser) diff --git a/tests/admin_scripts/tests.py b/tests/admin_scripts/tests.py index a8617fbb2a2f8..a263a80f4d8a5 100644 --- a/tests/admin_scripts/tests.py +++ b/tests/admin_scripts/tests.py @@ -1683,6 +1683,14 @@ def test_label_command_multiple_label(self): self.assertOutput(out, "EXECUTE:LabelCommand label=testlabel, options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', False), ('verbosity', 1)]") self.assertOutput(out, "EXECUTE:LabelCommand label=anotherlabel, options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', False), ('verbosity', 1)]") + def test_label_command_with_args_multiple_label(self): + "User LabelCommands using 'args' are executed multiple times if multiple labels are provided" + args = ['label_command_with_args', 'testlabel', 'anotherlabel'] + out, err = self.run_manage(args) + self.assertNoOutput(err) + self.assertOutput(out, "EXECUTE:LabelCommand label=testlabel, options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', False), ('verbosity', 1)]") + self.assertOutput(out, "EXECUTE:LabelCommand label=anotherlabel, options=[('no_color', False), ('pythonpath', None), ('settings', None), ('traceback', False), ('verbosity', 1)]") + @ignore_warnings(category=RemovedInDjango19Warning) def test_requires_model_validation_and_requires_system_checks_both_defined(self): from .management.commands.validation_command import InvalidCommand