Fixed #32047 -- Fixed call_command() crash if a constant option from required mutually exclusive group is passed in options.
This commit is contained in:
parent
11c4a4412b
commit
6eb3f53bdd
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue