summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Tomic <atomic777@gmail.com>2018-03-02 12:25:08 -0500
committerTim Graham <timograham@gmail.com>2018-03-02 12:25:08 -0500
commita1a3e515616da102fc48a1e1af8a5b2f429f747e (patch)
tree9b4d8d0fc4de50f09aa6be39a4ed00842a5ce2bb
parent40bac28faabbacd0875e59455cd80fb1dbb16966 (diff)
Fixed #29133 -- Fixed call_command() crash if a required option is passed in options.
-rw-r--r--django/core/management/__init__.py9
-rw-r--r--tests/user_commands/management/commands/required_option.py11
-rw-r--r--tests/user_commands/tests.py12
3 files changed, 31 insertions, 1 deletions
diff --git a/django/core/management/__init__.py b/django/core/management/__init__.py
index 4d26c98d09..688340e49d 100644
--- a/django/core/management/__init__.py
+++ b/django/core/management/__init__.py
@@ -117,7 +117,14 @@ def call_command(command_name, *args, **options):
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=[str(a) for a in args])
+ parse_args = [str(a) for a in args]
+ # Any required arguments which are passed in via **options must must be
+ # passed to parse_args().
+ parse_args += [
+ '{}={}'.format(min(opt.option_strings), arg_options[opt.dest])
+ for opt in parser._actions if opt.required and opt.dest in options
+ ]
+ defaults = parser.parse_args(args=parse_args)
defaults = dict(defaults._get_kwargs(), **arg_options)
# Raise an error if any unknown options were passed.
stealth_options = set(command.base_stealth_options + command.stealth_options)
diff --git a/tests/user_commands/management/commands/required_option.py b/tests/user_commands/management/commands/required_option.py
new file mode 100644
index 0000000000..3b30ed942e
--- /dev/null
+++ b/tests/user_commands/management/commands/required_option.py
@@ -0,0 +1,11 @@
+from django.core.management.base import BaseCommand
+
+
+class Command(BaseCommand):
+
+ def add_arguments(self, parser):
+ parser.add_argument('-n', '--need-me', required=True)
+ parser.add_argument('-t', '--need-me-too', required=True, dest='needme2')
+
+ def handle(self, *args, **options):
+ self.stdout.write(','.join(options))
diff --git a/tests/user_commands/tests.py b/tests/user_commands/tests.py
index 3900a58247..ae05bcfe25 100644
--- a/tests/user_commands/tests.py
+++ b/tests/user_commands/tests.py
@@ -194,6 +194,18 @@ class CommandTests(SimpleTestCase):
with self.assertRaisesMessage(TypeError, msg):
management.call_command('dance', unrecognized=1, unrecognized2=1)
+ def test_call_command_with_required_parameters_in_options(self):
+ out = StringIO()
+ management.call_command('required_option', need_me='foo', needme2='bar', stdout=out)
+ self.assertIn('need_me', out.getvalue())
+ self.assertIn('needme2', out.getvalue())
+
+ def test_call_command_with_required_parameters_in_mixed_options(self):
+ out = StringIO()
+ management.call_command('required_option', '--need-me=foo', needme2='bar', stdout=out)
+ self.assertIn('need_me', out.getvalue())
+ self.assertIn('needme2', out.getvalue())
+
class CommandRunTests(AdminScriptTestCase):
"""