Skip to content

Commit cbdacbf

Browse files
committed
gh-144812: Make argparse group classes public
Code that annotates the return values of add_argument_group() and add_mutually_exclusive_group() has to import the private _ArgumentGroup and _MutuallyExclusiveGroup today. Public names give that code a supported type, and the old names stay as aliases so existing imports keep working.
1 parent 6893326 commit cbdacbf

5 files changed

Lines changed: 66 additions & 8 deletions

File tree

‎Doc/library/argparse.rst‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2068,6 +2068,18 @@ Argument groups
20682068
is now deprecated.
20692069

20702070

2071+
.. class:: ArgumentGroup
2072+
2073+
The type of objects returned by :meth:`ArgumentParser.add_argument_group`.
2074+
Its :meth:`~ArgumentParser.add_argument` and
2075+
:meth:`~ArgumentParser.add_mutually_exclusive_group` methods work as on
2076+
:class:`ArgumentParser`. Use :meth:`~ArgumentParser.add_argument_group`
2077+
to create instances; the constructor is an implementation detail.
2078+
2079+
.. versionadded:: next
2080+
The private ``_ArgumentGroup`` name remains as an alias.
2081+
2082+
20712083
Mutual exclusion
20722084
^^^^^^^^^^^^^^^^
20732085

@@ -2131,6 +2143,19 @@ Mutual exclusion
21312143
exposed through inheritance.
21322144

21332145

2146+
.. class:: MutuallyExclusiveGroup
2147+
2148+
The type of objects returned by
2149+
:meth:`ArgumentParser.add_mutually_exclusive_group`.
2150+
Its :meth:`~ArgumentParser.add_argument` method works as on
2151+
:class:`ArgumentParser`. Use
2152+
:meth:`~ArgumentParser.add_mutually_exclusive_group` to create instances;
2153+
the constructor is an implementation detail.
2154+
2155+
.. versionadded:: next
2156+
The private ``_MutuallyExclusiveGroup`` name remains as an alias.
2157+
2158+
21342159
Parser defaults
21352160
^^^^^^^^^^^^^^^
21362161

‎Doc/whatsnew/3.16.rst‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,16 @@ New modules
108108
Improved modules
109109
================
110110

111+
argparse
112+
--------
113+
114+
* :class:`~argparse.ArgumentGroup` and
115+
:class:`~argparse.MutuallyExclusiveGroup`, the types returned by
116+
:meth:`~argparse.ArgumentParser.add_argument_group` and
117+
:meth:`~argparse.ArgumentParser.add_mutually_exclusive_group`, are now
118+
public. The ``_``-prefixed names remain as aliases.
119+
(Contributed by Bernát Gábor in :gh:`144812`.)
120+
111121
asyncio
112122
-------
113123

‎Lib/argparse.py‎

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
__all__ = [
6868
'ArgumentParser',
6969
'ArgumentError',
70+
'ArgumentGroup',
7071
'ArgumentTypeError',
7172
'BooleanOptionalAction',
7273
'FileType',
@@ -75,6 +76,7 @@
7576
'RawDescriptionHelpFormatter',
7677
'RawTextHelpFormatter',
7778
'MetavarTypeHelpFormatter',
79+
'MutuallyExclusiveGroup',
7880
'Namespace',
7981
'Action',
8082
'ONE_OR_MORE',
@@ -1699,12 +1701,12 @@ def add_argument(self, *args, **kwargs):
16991701
return self._add_action(action)
17001702

17011703
def add_argument_group(self, *args, **kwargs):
1702-
group = _ArgumentGroup(self, *args, **kwargs)
1704+
group = ArgumentGroup(self, *args, **kwargs)
17031705
self._action_groups.append(group)
17041706
return group
17051707

17061708
def add_mutually_exclusive_group(self, **kwargs):
1707-
group = _MutuallyExclusiveGroup(self, **kwargs)
1709+
group = MutuallyExclusiveGroup(self, **kwargs)
17081710
self._mutually_exclusive_groups.append(group)
17091711
return group
17101712

@@ -1892,7 +1894,7 @@ def _check_help(self, action):
18921894
raise ValueError('badly formed help string') from exc
18931895

18941896

1895-
class _ArgumentGroup(_ActionsContainer):
1897+
class ArgumentGroup(_ActionsContainer):
18961898

18971899
def __init__(self, container, title=None, description=None, **kwargs):
18981900
if 'prefix_chars' in kwargs:
@@ -1907,7 +1909,7 @@ def __init__(self, container, title=None, description=None, **kwargs):
19071909
update('conflict_handler', container.conflict_handler)
19081910
update('prefix_chars', container.prefix_chars)
19091911
update('argument_default', container.argument_default)
1910-
super_init = super(_ArgumentGroup, self).__init__
1912+
super_init = super(ArgumentGroup, self).__init__
19111913
super_init(description=description, **kwargs)
19121914

19131915
# group attributes
@@ -1924,21 +1926,21 @@ def __init__(self, container, title=None, description=None, **kwargs):
19241926
self._mutually_exclusive_groups = container._mutually_exclusive_groups
19251927

19261928
def _add_action(self, action):
1927-
action = super(_ArgumentGroup, self)._add_action(action)
1929+
action = super(ArgumentGroup, self)._add_action(action)
19281930
self._group_actions.append(action)
19291931
return action
19301932

19311933
def _remove_action(self, action):
1932-
super(_ArgumentGroup, self)._remove_action(action)
1934+
super(ArgumentGroup, self)._remove_action(action)
19331935
self._group_actions.remove(action)
19341936

19351937
def add_argument_group(self, *args, **kwargs):
19361938
raise ValueError('argument groups cannot be nested')
19371939

1938-
class _MutuallyExclusiveGroup(_ArgumentGroup):
1940+
class MutuallyExclusiveGroup(ArgumentGroup):
19391941

19401942
def __init__(self, container, required=False):
1941-
super(_MutuallyExclusiveGroup, self).__init__(container)
1943+
super(MutuallyExclusiveGroup, self).__init__(container)
19421944
self.required = required
19431945
self._container = container
19441946

@@ -1957,6 +1959,10 @@ def _remove_action(self, action):
19571959
def add_mutually_exclusive_group(self, **kwargs):
19581960
raise ValueError('mutually exclusive groups cannot be nested')
19591961

1962+
# Kept for code that imports the pre-3.16 private names.
1963+
_ArgumentGroup = ArgumentGroup
1964+
_MutuallyExclusiveGroup = MutuallyExclusiveGroup
1965+
19601966
def _prog_name(prog=None):
19611967
if prog is not None:
19621968
return prog

‎Lib/test/test_argparse.py‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3246,6 +3246,20 @@ def test_nested_argument_group(self):
32463246
'argument groups cannot be nested',
32473247
g.add_argument_group)
32483248

3249+
def test_group_types(self):
3250+
parser = argparse.ArgumentParser()
3251+
group = parser.add_argument_group()
3252+
self.assertIs(type(group), argparse.ArgumentGroup)
3253+
self.assertIs(type(parser.add_mutually_exclusive_group()),
3254+
argparse.MutuallyExclusiveGroup)
3255+
self.assertIs(type(group.add_mutually_exclusive_group()),
3256+
argparse.MutuallyExclusiveGroup)
3257+
3258+
def test_private_aliases(self):
3259+
self.assertIs(argparse._ArgumentGroup, argparse.ArgumentGroup)
3260+
self.assertIs(argparse._MutuallyExclusiveGroup,
3261+
argparse.MutuallyExclusiveGroup)
3262+
32493263
# ===================
32503264
# Parent parser tests
32513265
# ===================
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Make :class:`argparse.ArgumentGroup` and
2+
:class:`argparse.MutuallyExclusiveGroup` public. The private
3+
``_ArgumentGroup`` and ``_MutuallyExclusiveGroup`` names remain as aliases.

0 commit comments

Comments
 (0)