diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst index 658209bc55fa14..3a8eab76ca0e2b 100644 --- a/Doc/library/argparse.rst +++ b/Doc/library/argparse.rst @@ -2072,6 +2072,19 @@ Argument groups is now deprecated. +.. class:: ArgumentGroup + + The type of objects returned by :meth:`ArgumentParser.add_argument_group`. + Its :meth:`~ArgumentParser.add_argument` and + :meth:`~ArgumentParser.add_mutually_exclusive_group` methods work as on + :class:`ArgumentParser`. Use :meth:`~ArgumentParser.add_argument_group` + to create instances. Only the methods documented here are part of the + public API; other attributes and methods are implementation details. + + .. versionadded:: next + The private ``_ArgumentGroup`` name remains as an alias. + + Mutual exclusion ^^^^^^^^^^^^^^^^ @@ -2135,6 +2148,20 @@ Mutual exclusion exposed through inheritance. +.. class:: MutuallyExclusiveGroup + + The type of objects returned by + :meth:`ArgumentParser.add_mutually_exclusive_group`. + Its :meth:`~ArgumentParser.add_argument` method works as on + :class:`ArgumentParser`. Use + :meth:`~ArgumentParser.add_mutually_exclusive_group` to create instances. + Only the ``add_argument`` method documented here is part of the public API; + other attributes and methods are implementation details. + + .. versionadded:: next + The private ``_MutuallyExclusiveGroup`` name remains as an alias. + + Parser defaults ^^^^^^^^^^^^^^^ diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst index c2177d0ca3e286..cc1a4ee8efa547 100644 --- a/Doc/whatsnew/3.16.rst +++ b/Doc/whatsnew/3.16.rst @@ -126,6 +126,16 @@ New modules Improved modules ================ +argparse +-------- + +* :class:`~argparse.ArgumentGroup` and + :class:`~argparse.MutuallyExclusiveGroup`, the types returned by + :meth:`~argparse.ArgumentParser.add_argument_group` and + :meth:`~argparse.ArgumentParser.add_mutually_exclusive_group`, are now + public. The ``_``-prefixed names remain as aliases. + (Contributed by Bernát Gábor in :gh:`144812`.) + asyncio ------- diff --git a/Lib/argparse.py b/Lib/argparse.py index 4cf5dca148c969..c01a6351f14482 100644 --- a/Lib/argparse.py +++ b/Lib/argparse.py @@ -67,6 +67,7 @@ __all__ = [ 'ArgumentParser', 'ArgumentError', + 'ArgumentGroup', 'ArgumentTypeError', 'BooleanOptionalAction', 'FileType', @@ -75,6 +76,7 @@ 'RawDescriptionHelpFormatter', 'RawTextHelpFormatter', 'MetavarTypeHelpFormatter', + 'MutuallyExclusiveGroup', 'Namespace', 'Action', 'ONE_OR_MORE', @@ -1699,12 +1701,12 @@ def add_argument(self, *args, **kwargs): return self._add_action(action) def add_argument_group(self, *args, **kwargs): - group = _ArgumentGroup(self, *args, **kwargs) + group = ArgumentGroup(self, *args, **kwargs) self._action_groups.append(group) return group def add_mutually_exclusive_group(self, **kwargs): - group = _MutuallyExclusiveGroup(self, **kwargs) + group = MutuallyExclusiveGroup(self, **kwargs) self._mutually_exclusive_groups.append(group) return group @@ -1892,7 +1894,7 @@ def _check_help(self, action): raise ValueError('badly formed help string') from exc -class _ArgumentGroup(_ActionsContainer): +class ArgumentGroup(_ActionsContainer): def __init__(self, container, title=None, description=None, **kwargs): if 'prefix_chars' in kwargs: @@ -1907,7 +1909,7 @@ def __init__(self, container, title=None, description=None, **kwargs): update('conflict_handler', container.conflict_handler) update('prefix_chars', container.prefix_chars) update('argument_default', container.argument_default) - super_init = super(_ArgumentGroup, self).__init__ + super_init = super(ArgumentGroup, self).__init__ super_init(description=description, **kwargs) # group attributes @@ -1924,21 +1926,21 @@ def __init__(self, container, title=None, description=None, **kwargs): self._mutually_exclusive_groups = container._mutually_exclusive_groups def _add_action(self, action): - action = super(_ArgumentGroup, self)._add_action(action) + action = super(ArgumentGroup, self)._add_action(action) self._group_actions.append(action) return action def _remove_action(self, action): - super(_ArgumentGroup, self)._remove_action(action) + super(ArgumentGroup, self)._remove_action(action) self._group_actions.remove(action) def add_argument_group(self, *args, **kwargs): raise ValueError('argument groups cannot be nested') -class _MutuallyExclusiveGroup(_ArgumentGroup): +class MutuallyExclusiveGroup(ArgumentGroup): def __init__(self, container, required=False): - super(_MutuallyExclusiveGroup, self).__init__(container) + super(MutuallyExclusiveGroup, self).__init__(container) self.required = required self._container = container @@ -1957,6 +1959,10 @@ def _remove_action(self, action): def add_mutually_exclusive_group(self, **kwargs): raise ValueError('mutually exclusive groups cannot be nested') +# Kept for code that imports the pre-3.16 private names. +_ArgumentGroup = ArgumentGroup +_MutuallyExclusiveGroup = MutuallyExclusiveGroup + def _prog_name(prog=None): if prog is not None: return prog diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py index 3abdb3244570a5..e1c4cf6561fc77 100644 --- a/Lib/test/test_argparse.py +++ b/Lib/test/test_argparse.py @@ -3246,6 +3246,20 @@ def test_nested_argument_group(self): 'argument groups cannot be nested', g.add_argument_group) + def test_group_types(self): + parser = argparse.ArgumentParser() + group = parser.add_argument_group() + self.assertIs(type(group), argparse.ArgumentGroup) + self.assertIs(type(parser.add_mutually_exclusive_group()), + argparse.MutuallyExclusiveGroup) + self.assertIs(type(group.add_mutually_exclusive_group()), + argparse.MutuallyExclusiveGroup) + + def test_private_aliases(self): + self.assertIs(argparse._ArgumentGroup, argparse.ArgumentGroup) + self.assertIs(argparse._MutuallyExclusiveGroup, + argparse.MutuallyExclusiveGroup) + # =================== # Parent parser tests # =================== diff --git a/Misc/NEWS.d/next/Library/2026-09-23-23-34-30.gh-issue-144812.ujptbVOI.rst b/Misc/NEWS.d/next/Library/2026-09-23-23-34-30.gh-issue-144812.ujptbVOI.rst new file mode 100644 index 00000000000000..d24f028fdbeaae --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-09-23-23-34-30.gh-issue-144812.ujptbVOI.rst @@ -0,0 +1,3 @@ +Make :class:`argparse.ArgumentGroup` and +:class:`argparse.MutuallyExclusiveGroup` public. The private +``_ArgumentGroup`` and ``_MutuallyExclusiveGroup`` names remain as aliases.