[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:
parent
ac815f6ea8
commit
c9ebe4ca4e
|
@ -149,6 +149,12 @@ def call_command(command_name, *args, **options):
|
||||||
opt.dest in options and
|
opt.dest in options and
|
||||||
(opt.required or opt in mutually_exclusive_required_options)
|
(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))
|
parse_args.append(min(opt.option_strings))
|
||||||
if isinstance(opt, (_AppendConstAction, _CountAction, _StoreConstAction)):
|
if isinstance(opt, (_AppendConstAction, _CountAction, _StoreConstAction)):
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -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))
|
|
@ -275,6 +275,41 @@ class CommandTests(SimpleTestCase):
|
||||||
)
|
)
|
||||||
self.assertIn(expected_output, out.getvalue())
|
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):
|
def test_required_list_option(self):
|
||||||
tests = [
|
tests = [
|
||||||
(('--foo-list', [1, 2]), {}),
|
(('--foo-list', [1, 2]), {}),
|
||||||
|
|
Loading…
Reference in New Issue