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`
--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
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):
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:
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
# ===================
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):
-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):
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()