[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.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
|
||||
|
|
|
@ -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())
|
||||
|
||||
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]), {}),
|
||||
|
|
Loading…
Reference in New Issue