[4.0.x] Fixed #33205 -- Made call_command() raise TypeError when dest with multiple arguments is passed.

Backport of c1e4111c74 from main
This commit is contained in:
Hasan Ramezani 2021-10-22 16:38:14 +02:00 committed by Mariusz Felisiak
parent ac815f6ea8
commit c9ebe4ca4e
3 changed files with 54 additions and 0 deletions

View File

@ -149,6 +149,12 @@ def call_command(command_name, *args, **options):
opt.dest in options and
(opt.required or opt in mutually_exclusive_required_options)
):
opt_dest_count = sum(v == opt.dest for v in opt_mapping.values())
if opt_dest_count > 1:
raise TypeError(
f'Cannot pass the dest {opt.dest!r} that matches multiple '
f'arguments via **options.'
)
parse_args.append(min(opt.option_strings))
if isinstance(opt, (_AppendConstAction, _CountAction, _StoreConstAction)):
continue

View File

@ -0,0 +1,13 @@
from django.core.management.base import BaseCommand
class Command(BaseCommand):
def add_arguments(self, parser):
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('--for', dest='until', action='store')
group.add_argument('--until', action='store')
def handle(self, *args, **options):
for option, value in options.items():
if value is not None:
self.stdout.write('%s=%s' % (option, value))

View File

@ -275,6 +275,41 @@ class CommandTests(SimpleTestCase):
)
self.assertIn(expected_output, out.getvalue())
def test_mutually_exclusive_group_required_with_same_dest_options(self):
tests = [
{'until': '2'},
{'for': '1', 'until': '2'},
]
msg = (
"Cannot pass the dest 'until' that matches multiple arguments via "
"**options."
)
for options in tests:
with self.subTest(options=options):
with self.assertRaisesMessage(TypeError, msg):
management.call_command(
'mutually_exclusive_required_with_same_dest',
**options,
)
def test_mutually_exclusive_group_required_with_same_dest_args(self):
tests = [
('--until=1',),
('--until', 1),
('--for=1',),
('--for', 1),
]
for args in tests:
out = StringIO()
with self.subTest(options=args):
management.call_command(
'mutually_exclusive_required_with_same_dest',
*args,
stdout=out,
)
output = out.getvalue()
self.assertIn('until=1', output)
def test_required_list_option(self):
tests = [
(('--foo-list', [1, 2]), {}),