GH-127133: Remove ability to nest argument groups & mutually exclusive groups (#127186)

This commit is contained in:
Savannah Ostrowski
2024-11-24 07:20:37 -08:00
committed by GitHub
parent f7bb658124
commit 2104bde572
5 changed files with 41 additions and 95 deletions

View File

@@ -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

View File

@@ -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
---

View File

@@ -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:

View File

@@ -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()

View File

@@ -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.