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 os
|
||||||
import pkgutil
|
import pkgutil
|
||||||
import sys
|
import sys
|
||||||
from argparse import _SubParsersAction
|
from argparse import (
|
||||||
|
_AppendConstAction, _CountAction, _StoreConstAction, _SubParsersAction,
|
||||||
|
)
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from difflib import get_close_matches
|
from difflib import get_close_matches
|
||||||
from importlib import import_module
|
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
|
# Any required arguments which are passed in via **options must be passed
|
||||||
# to parse_args().
|
# to parse_args().
|
||||||
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 (
|
for opt in parser_actions if (
|
||||||
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)
|
||||||
|
|
|
@ -7,6 +7,13 @@ class Command(BaseCommand):
|
||||||
group = parser.add_mutually_exclusive_group(required=True)
|
group = parser.add_mutually_exclusive_group(required=True)
|
||||||
group.add_argument('--foo-id', type=int, nargs='?', default=None)
|
group.add_argument('--foo-id', type=int, nargs='?', default=None)
|
||||||
group.add_argument('--foo-name', type=str, 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):
|
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())
|
self.assertIn('foo_id', out.getvalue())
|
||||||
management.call_command('mutually_exclusive_required', foo_name='foo', stdout=out)
|
management.call_command('mutually_exclusive_required', foo_name='foo', stdout=out)
|
||||||
self.assertIn('foo_name', out.getvalue())
|
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):
|
with self.assertRaisesMessage(CommandError, msg):
|
||||||
management.call_command('mutually_exclusive_required', stdout=out)
|
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):
|
def test_subparser(self):
|
||||||
out = StringIO()
|
out = StringIO()
|
||||||
management.call_command('subparser', 'foo', 12, stdout=out)
|
management.call_command('subparser', 'foo', 12, stdout=out)
|
||||||
|
|
Loading…
Reference in New Issue