Fixed #32047 -- Fixed call_command() crash if a constant option from required mutually exclusive group is passed in options.

This commit is contained in:
Hasan Ramezani 2020-09-29 15:51:42 +02:00 committed by Mariusz Felisiak
parent 11c4a4412b
commit 6eb3f53bdd
3 changed files with 43 additions and 4 deletions

View File

@ -2,7 +2,9 @@ import functools
import os
import pkgutil
import sys
from argparse import _SubParsersAction
from argparse import (
_AppendConstAction, _CountAction, _StoreConstAction, _SubParsersAction,
)
from collections import defaultdict
from difflib import get_close_matches
from importlib import import_module
@ -138,7 +140,9 @@ def call_command(command_name, *args, **options):
# Any required arguments which are passed in via **options must be passed
# to parse_args().
parse_args += [
'{}={}'.format(min(opt.option_strings), arg_options[opt.dest])
min(opt.option_strings)
if isinstance(opt, (_AppendConstAction, _CountAction, _StoreConstAction))
else '{}={}'.format(min(opt.option_strings), arg_options[opt.dest])
for opt in parser_actions if (
opt.dest in options and
(opt.required or opt in mutually_exclusive_required_options)

View File

@ -7,6 +7,13 @@ class Command(BaseCommand):
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('--foo-id', type=int, nargs='?', default=None)
group.add_argument('--foo-name', type=str, nargs='?', default=None)
group.add_argument('--append_const', action='append_const', const=42)
group.add_argument('--const', action='store_const', const=31)
group.add_argument('--count', action='count')
group.add_argument('--flag_false', action='store_false')
group.add_argument('--flag_true', action='store_true')
def handle(self, *args, **options):
self.stdout.write(','.join(options))
for option, value in options.items():
if value is not None:
self.stdout.write('%s=%s' % (option, value))

View File

@ -243,10 +243,38 @@ class CommandTests(SimpleTestCase):
self.assertIn('foo_id', out.getvalue())
management.call_command('mutually_exclusive_required', foo_name='foo', stdout=out)
self.assertIn('foo_name', out.getvalue())
msg = 'Error: one of the arguments --foo-id --foo-name is required'
msg = (
'Error: one of the arguments --foo-id --foo-name --append_const '
'--const --count --flag_false --flag_true is required'
)
with self.assertRaisesMessage(CommandError, msg):
management.call_command('mutually_exclusive_required', stdout=out)
def test_mutually_exclusive_group_required_const_options(self):
tests = [
('append_const', [42]),
('const', 31),
('count', 1),
('flag_false', False),
('flag_true', True),
]
for arg, value in tests:
out = StringIO()
expected_output = '%s=%s' % (arg, value)
with self.subTest(arg=arg):
management.call_command(
'mutually_exclusive_required',
'--%s' % arg,
stdout=out,
)
self.assertIn(expected_output, out.getvalue())
out.truncate(0)
management.call_command(
'mutually_exclusive_required',
**{arg: value, 'stdout': out},
)
self.assertIn(expected_output, out.getvalue())
def test_subparser(self):
out = StringIO()
management.call_command('subparser', 'foo', 12, stdout=out)