GH-127133: Remove ability to nest argument groups & mutually exclusive groups (#127186)
This commit is contained in:
committed by
GitHub
parent
f7bb658124
commit
2104bde572
@@ -1926,11 +1926,10 @@ Argument groups
|
||||
Note that any arguments not in your user-defined groups will end up back
|
||||
in the usual "positional arguments" and "optional arguments" sections.
|
||||
|
||||
.. versionchanged:: 3.11
|
||||
Calling :meth:`add_argument_group` on an argument group is deprecated.
|
||||
This feature was never supported and does not always work correctly.
|
||||
The function exists on the API by accident through inheritance and
|
||||
will be removed in the future.
|
||||
.. deprecated-removed:: 3.11 3.14
|
||||
Calling :meth:`add_argument_group` on an argument group now raises an
|
||||
exception. This nesting was never supported, often failed to work
|
||||
correctly, and was unintentionally exposed through inheritance.
|
||||
|
||||
.. deprecated:: 3.14
|
||||
Passing prefix_chars_ to :meth:`add_argument_group`
|
||||
@@ -1993,11 +1992,11 @@ Mutual exclusion
|
||||
--foo FOO foo help
|
||||
--bar BAR bar help
|
||||
|
||||
.. versionchanged:: 3.11
|
||||
Calling :meth:`add_argument_group` or :meth:`add_mutually_exclusive_group`
|
||||
on a mutually exclusive group is deprecated. These features were never
|
||||
supported and do not always work correctly. The functions exist on the
|
||||
API by accident through inheritance and will be removed in the future.
|
||||
.. deprecated-removed:: 3.11 3.14
|
||||
Calling :meth:`add_argument_group` or :meth:`add_mutually_exclusive_group`
|
||||
on a mutually exclusive group now raises an exception. This nesting was
|
||||
never supported, often failed to work correctly, and was unintentionally
|
||||
exposed through inheritance.
|
||||
|
||||
|
||||
Parser defaults
|
||||
|
||||
@@ -641,6 +641,14 @@ argparse
|
||||
of :class:`!argparse.BooleanOptionalAction`.
|
||||
They were deprecated since 3.12.
|
||||
|
||||
* Calling :meth:`~argparse.ArgumentParser.add_argument_group` on an argument
|
||||
group, and calling :meth:`~argparse.ArgumentParser.add_argument_group` or
|
||||
:meth:`~argparse.ArgumentParser.add_mutually_exclusive_group` on a mutually
|
||||
exclusive group now raise exceptions. This nesting was never supported,
|
||||
often failed to work correctly, and was unintentionally exposed through
|
||||
inheritance. This functionality has been deprecated since Python 3.11.
|
||||
(Contributed by Savannah Ostrowski in :gh:`127186`.)
|
||||
|
||||
ast
|
||||
---
|
||||
|
||||
|
||||
@@ -1709,14 +1709,7 @@ class _ArgumentGroup(_ActionsContainer):
|
||||
self._group_actions.remove(action)
|
||||
|
||||
def add_argument_group(self, *args, **kwargs):
|
||||
import warnings
|
||||
warnings.warn(
|
||||
"Nesting argument groups is deprecated.",
|
||||
category=DeprecationWarning,
|
||||
stacklevel=2
|
||||
)
|
||||
return super().add_argument_group(*args, **kwargs)
|
||||
|
||||
raise ValueError('argument groups cannot be nested')
|
||||
|
||||
class _MutuallyExclusiveGroup(_ArgumentGroup):
|
||||
|
||||
@@ -1737,15 +1730,8 @@ class _MutuallyExclusiveGroup(_ArgumentGroup):
|
||||
self._container._remove_action(action)
|
||||
self._group_actions.remove(action)
|
||||
|
||||
def add_mutually_exclusive_group(self, *args, **kwargs):
|
||||
import warnings
|
||||
warnings.warn(
|
||||
"Nesting mutually exclusive groups is deprecated.",
|
||||
category=DeprecationWarning,
|
||||
stacklevel=2
|
||||
)
|
||||
return super().add_mutually_exclusive_group(*args, **kwargs)
|
||||
|
||||
def add_mutually_exclusive_group(self, **kwargs):
|
||||
raise ValueError('mutually exclusive groups cannot be nested')
|
||||
|
||||
def _prog_name(prog=None):
|
||||
if prog is not None:
|
||||
|
||||
@@ -2997,6 +2997,13 @@ class TestGroupConstructor(TestCase):
|
||||
self.assertEqual(msg, str(cm.warning))
|
||||
self.assertEqual(cm.filename, __file__)
|
||||
|
||||
def test_nested_argument_group(self):
|
||||
parser = argparse.ArgumentParser()
|
||||
g = parser.add_argument_group()
|
||||
self.assertRaisesRegex(ValueError,
|
||||
'argument groups cannot be nested',
|
||||
g.add_argument_group)
|
||||
|
||||
# ===================
|
||||
# Parent parser tests
|
||||
# ===================
|
||||
@@ -3297,6 +3304,14 @@ class TestMutuallyExclusiveGroupErrors(TestCase):
|
||||
with self.assertRaises(ValueError):
|
||||
parser.parse_args(['-h'])
|
||||
|
||||
def test_nested_mutex_groups(self):
|
||||
parser = argparse.ArgumentParser(prog='PROG')
|
||||
g = parser.add_mutually_exclusive_group()
|
||||
g.add_argument("--spam")
|
||||
self.assertRaisesRegex(ValueError,
|
||||
'mutually exclusive groups cannot be nested',
|
||||
g.add_mutually_exclusive_group)
|
||||
|
||||
class MEMixin(object):
|
||||
|
||||
def test_failures_when_not_required(self):
|
||||
@@ -3664,55 +3679,6 @@ class TestMutuallyExclusiveOptionalsAndPositionalsMixed(MEMixin, TestCase):
|
||||
-c c help
|
||||
'''
|
||||
|
||||
class TestMutuallyExclusiveNested(MEMixin, TestCase):
|
||||
|
||||
# Nesting mutually exclusive groups is an undocumented feature
|
||||
# that came about by accident through inheritance and has been
|
||||
# the source of many bugs. It is deprecated and this test should
|
||||
# eventually be removed along with it.
|
||||
|
||||
def get_parser(self, required):
|
||||
parser = ErrorRaisingArgumentParser(prog='PROG')
|
||||
group = parser.add_mutually_exclusive_group(required=required)
|
||||
group.add_argument('-a')
|
||||
group.add_argument('-b')
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter('ignore', DeprecationWarning)
|
||||
group2 = group.add_mutually_exclusive_group(required=required)
|
||||
group2.add_argument('-c')
|
||||
group2.add_argument('-d')
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter('ignore', DeprecationWarning)
|
||||
group3 = group2.add_mutually_exclusive_group(required=required)
|
||||
group3.add_argument('-e')
|
||||
group3.add_argument('-f')
|
||||
return parser
|
||||
|
||||
usage_when_not_required = '''\
|
||||
usage: PROG [-h] [-a A | -b B | [-c C | -d D | [-e E | -f F]]]
|
||||
'''
|
||||
usage_when_required = '''\
|
||||
usage: PROG [-h] (-a A | -b B | (-c C | -d D | (-e E | -f F)))
|
||||
'''
|
||||
|
||||
help = '''\
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
-a A
|
||||
-b B
|
||||
-c C
|
||||
-d D
|
||||
-e E
|
||||
-f F
|
||||
'''
|
||||
|
||||
# We are only interested in testing the behavior of format_usage().
|
||||
test_failures_when_not_required = None
|
||||
test_failures_when_required = None
|
||||
test_successes_when_not_required = None
|
||||
test_successes_when_required = None
|
||||
|
||||
|
||||
class TestMutuallyExclusiveOptionalOptional(MEMixin, TestCase):
|
||||
def get_parser(self, required=None):
|
||||
@@ -4883,25 +4849,6 @@ class TestHelpUsageNoWhitespaceCrash(TestCase):
|
||||
usage = 'usage: PROG [-h]\n'
|
||||
self.assertEqual(parser.format_usage(), usage)
|
||||
|
||||
def test_nested_mutex_groups(self):
|
||||
parser = argparse.ArgumentParser(prog='PROG')
|
||||
g = parser.add_mutually_exclusive_group()
|
||||
g.add_argument("--spam")
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter('ignore', DeprecationWarning)
|
||||
gg = g.add_mutually_exclusive_group()
|
||||
gg.add_argument("--hax")
|
||||
gg.add_argument("--hox", help=argparse.SUPPRESS)
|
||||
gg.add_argument("--hex")
|
||||
g.add_argument("--eggs")
|
||||
parser.add_argument("--num")
|
||||
|
||||
usage = textwrap.dedent('''\
|
||||
usage: PROG [-h] [--spam SPAM | [--hax HAX | --hex HEX] | --eggs EGGS]
|
||||
[--num NUM]
|
||||
''')
|
||||
self.assertEqual(parser.format_usage(), usage)
|
||||
|
||||
def test_long_mutex_groups_wrap(self):
|
||||
parser = argparse.ArgumentParser(prog='PROG')
|
||||
g = parser.add_mutually_exclusive_group()
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
Calling :meth:`argparse.ArgumentParser.add_argument_group` on an argument group,
|
||||
and calling :meth:`argparse.ArgumentParser.add_argument_group` or
|
||||
:meth:`argparse.ArgumentParser.add_mutually_exclusive_group` on a mutually
|
||||
exclusive group now raise exceptions. This nesting was never supported, often
|
||||
failed to work correctly, and was unintentionally exposed through inheritance.
|
||||
This functionality has been deprecated since Python 3.11.
|
||||
Reference in New Issue
Block a user