Skip to content

Commit 4448993

Browse files
Merge branch 'main' into nested-fwdref
2 parents ca1a18f + c89f76e commit 4448993

18 files changed

+117
-101
lines changed

Doc/library/argparse.rst

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -839,23 +839,11 @@ how the command-line arguments should be handled. The supplied actions are:
839839
>>> parser.parse_args(['--version'])
840840
PROG 2.0
841841

842-
Only actions that consume command-line arguments (e.g. ``'store'``,
843-
``'append'`` or ``'extend'``) can be used with positional arguments.
844-
845-
.. class:: BooleanOptionalAction
846-
847-
You may also specify an arbitrary action by passing an :class:`Action` subclass or
848-
other object that implements the same interface. The :class:`!BooleanOptionalAction`
849-
is available in :mod:`!argparse` and adds support for boolean actions such as
850-
``--foo`` and ``--no-foo``::
851-
852-
>>> import argparse
853-
>>> parser = argparse.ArgumentParser()
854-
>>> parser.add_argument('--foo', action=argparse.BooleanOptionalAction)
855-
>>> parser.parse_args(['--no-foo'])
856-
Namespace(foo=False)
857-
858-
.. versionadded:: 3.9
842+
You may also specify an arbitrary action by passing an :class:`Action` subclass
843+
(e.g. :class:`BooleanOptionalAction`) or other object that implements the same
844+
interface. Only actions that consume command-line arguments (e.g. ``'store'``,
845+
``'append'``, ``'extend'``, or custom actions with non-zero ``nargs``) can be used
846+
with positional arguments.
859847

860848
The recommended way to create a custom action is to extend :class:`Action`,
861849
overriding the :meth:`!__call__` method and optionally the :meth:`!__init__` and
@@ -1429,6 +1417,21 @@ this API may be passed as the ``action`` parameter to
14291417
and return a string which will be used when printing the usage of the program.
14301418
If such method is not provided, a sensible default will be used.
14311419

1420+
.. class:: BooleanOptionalAction
1421+
1422+
A subclass of :class:`Action` for handling boolean flags with positive
1423+
and negative options. Adding a single argument such as ``--foo`` automatically
1424+
creates both ``--foo`` and ``--no-foo`` options, storing ``True`` and ``False``
1425+
respectively::
1426+
1427+
>>> import argparse
1428+
>>> parser = argparse.ArgumentParser()
1429+
>>> parser.add_argument('--foo', action=argparse.BooleanOptionalAction)
1430+
>>> parser.parse_args(['--no-foo'])
1431+
Namespace(foo=False)
1432+
1433+
.. versionadded:: 3.9
1434+
14321435

14331436
The parse_args() method
14341437
-----------------------

Doc/library/http.cookiejar.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,7 @@ Netscape protocol strictness switches:
570570

571571
Don't allow setting cookies whose path doesn't path-match request URI.
572572

573-
:attr:`strict_ns_domain` is a collection of flags. Its value is constructed by
573+
:attr:`~DefaultCookiePolicy.strict_ns_domain` is a collection of flags. Its value is constructed by
574574
or-ing together (for example, ``DomainStrictNoDots|DomainStrictNonDomain`` means
575575
both flags are set).
576576

Doc/library/multiprocessing.rst

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,7 +1118,9 @@ Miscellaneous
11181118
Return a context object which has the same attributes as the
11191119
:mod:`multiprocessing` module.
11201120

1121-
If *method* is ``None`` then the default context is returned.
1121+
If *method* is ``None`` then the default context is returned. Note that if
1122+
the global start method has not been set, this will set it to the
1123+
default method.
11221124
Otherwise *method* should be ``'fork'``, ``'spawn'``,
11231125
``'forkserver'``. :exc:`ValueError` is raised if the specified
11241126
start method is not available. See :ref:`multiprocessing-start-methods`.
@@ -1129,10 +1131,10 @@ Miscellaneous
11291131

11301132
Return the name of start method used for starting processes.
11311133

1132-
If the start method has not been fixed and *allow_none* is false,
1133-
then the start method is fixed to the default and the name is
1134-
returned. If the start method has not been fixed and *allow_none*
1135-
is true then ``None`` is returned.
1134+
If the global start method has not been set and *allow_none* is
1135+
``False``, then the start method is set to the default and the name
1136+
is returned. If the start method has not been set and *allow_none* is
1137+
``True`` then ``None`` is returned.
11361138

11371139
The return value can be ``'fork'``, ``'spawn'``, ``'forkserver'``
11381140
or ``None``. See :ref:`multiprocessing-start-methods`.

Lib/concurrent/interpreters/__init__.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -146,12 +146,8 @@ def __del__(self):
146146
self._decref()
147147

148148
# for pickling:
149-
def __getnewargs__(self):
150-
return (self._id,)
151-
152-
# for pickling:
153-
def __getstate__(self):
154-
return None
149+
def __reduce__(self):
150+
return (type(self), (self._id,))
155151

156152
def _decref(self):
157153
if not self._ownsref:

Lib/concurrent/interpreters/_queues.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,8 @@ def __hash__(self):
129129
return hash(self._id)
130130

131131
# for pickling:
132-
def __getnewargs__(self):
133-
return (self._id,)
134-
135-
# for pickling:
136-
def __getstate__(self):
137-
return None
132+
def __reduce__(self):
133+
return (type(self), (self._id,))
138134

139135
def _set_unbound(self, op, items=None):
140136
assert not hasattr(self, '_unbound')

Lib/test/support/channels.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,8 @@ def __eq__(self, other):
105105
return other._id == self._id
106106

107107
# for pickling:
108-
def __getnewargs__(self):
109-
return (int(self._id),)
110-
111-
# for pickling:
112-
def __getstate__(self):
113-
return None
108+
def __reduce__(self):
109+
return (type(self), (int(self._id),))
114110

115111
@property
116112
def id(self):

Lib/test/test_interpreters/test_api.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -412,9 +412,11 @@ def test_equality(self):
412412

413413
def test_pickle(self):
414414
interp = interpreters.create()
415-
data = pickle.dumps(interp)
416-
unpickled = pickle.loads(data)
417-
self.assertEqual(unpickled, interp)
415+
for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
416+
with self.subTest(protocol=protocol):
417+
data = pickle.dumps(interp, protocol)
418+
unpickled = pickle.loads(data)
419+
self.assertEqual(unpickled, interp)
418420

419421

420422
class TestInterpreterIsRunning(TestBase):

Lib/test/test_interpreters/test_channels.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,11 @@ def test_equality(self):
121121

122122
def test_pickle(self):
123123
ch, _ = channels.create()
124-
data = pickle.dumps(ch)
125-
unpickled = pickle.loads(data)
126-
self.assertEqual(unpickled, ch)
124+
for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
125+
with self.subTest(protocol=protocol):
126+
data = pickle.dumps(ch, protocol)
127+
unpickled = pickle.loads(data)
128+
self.assertEqual(unpickled, ch)
127129

128130

129131
class TestSendChannelAttrs(TestBase):
@@ -152,9 +154,11 @@ def test_equality(self):
152154

153155
def test_pickle(self):
154156
_, ch = channels.create()
155-
data = pickle.dumps(ch)
156-
unpickled = pickle.loads(data)
157-
self.assertEqual(unpickled, ch)
157+
for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
158+
with self.subTest(protocol=protocol):
159+
data = pickle.dumps(ch, protocol)
160+
unpickled = pickle.loads(data)
161+
self.assertEqual(unpickled, ch)
158162

159163

160164
class TestSendRecv(TestBase):

Lib/test/test_interpreters/test_queues.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,11 @@ def test_equality(self):
188188

189189
def test_pickle(self):
190190
queue = queues.create()
191-
data = pickle.dumps(queue)
192-
unpickled = pickle.loads(data)
193-
self.assertEqual(unpickled, queue)
191+
for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
192+
with self.subTest(protocol=protocol):
193+
data = pickle.dumps(queue, protocol)
194+
unpickled = pickle.loads(data)
195+
self.assertEqual(unpickled, queue)
194196

195197

196198
class TestQueueOps(TestBase):

Lib/test/test_typing.py

Lines changed: 26 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1605,7 +1605,10 @@ def func1(*args: *Ts): pass
16051605
self.assertEqual(gth(func1), {'args': Unpack[Ts]})
16061606

16071607
def func2(*args: *tuple[int, str]): pass
1608-
self.assertEqual(gth(func2), {'args': Unpack[tuple[int, str]]})
1608+
hint = gth(func2)['args']
1609+
self.assertIsInstance(hint, types.GenericAlias)
1610+
self.assertEqual(hint.__args__[0], int)
1611+
self.assertIs(hint.__unpacked__, True)
16091612

16101613
class CustomVariadic(Generic[*Ts]): pass
16111614

@@ -1620,7 +1623,10 @@ def func1(*args: '*Ts'): pass
16201623
{'args': Unpack[Ts]})
16211624

16221625
def func2(*args: '*tuple[int, str]'): pass
1623-
self.assertEqual(gth(func2), {'args': Unpack[tuple[int, str]]})
1626+
hint = gth(func2)['args']
1627+
self.assertIsInstance(hint, types.GenericAlias)
1628+
self.assertEqual(hint.__args__[0], int)
1629+
self.assertIs(hint.__unpacked__, True)
16241630

16251631
class CustomVariadic(Generic[*Ts]): pass
16261632

@@ -6303,31 +6309,6 @@ def foo(a: 'whatevers') -> {}:
63036309

63046310

63056311
class InternalsTests(BaseTestCase):
6306-
def test_deprecation_for_no_type_params_passed_to__evaluate(self):
6307-
with self.assertWarnsRegex(
6308-
DeprecationWarning,
6309-
(
6310-
"Failing to pass a value to the 'type_params' parameter "
6311-
"of 'typing._eval_type' is deprecated"
6312-
)
6313-
) as cm:
6314-
self.assertEqual(typing._eval_type(list["int"], globals(), {}), list[int])
6315-
6316-
self.assertEqual(cm.filename, __file__)
6317-
6318-
f = ForwardRef("int")
6319-
6320-
with self.assertWarnsRegex(
6321-
DeprecationWarning,
6322-
(
6323-
"Failing to pass a value to the 'type_params' parameter "
6324-
"of 'typing.ForwardRef._evaluate' is deprecated"
6325-
)
6326-
) as cm:
6327-
self.assertIs(f._evaluate(globals(), {}, recursive_guard=frozenset()), int)
6328-
6329-
self.assertEqual(cm.filename, __file__)
6330-
63316312
def test_collect_parameters(self):
63326313
typing = import_helper.import_fresh_module("typing")
63336314
with self.assertWarnsRegex(
@@ -7114,6 +7095,24 @@ def add_right(self, node: 'Node[T]' = None):
71147095
right_hints = get_type_hints(t.add_right, globals(), locals())
71157096
self.assertEqual(right_hints['node'], Node[T])
71167097

7098+
def test_get_type_hints_preserve_generic_alias_subclasses(self):
7099+
# https://github.com/python/cpython/issues/130870
7100+
# A real world example of this is `collections.abc.Callable`. When parameterized,
7101+
# the result is a subclass of `types.GenericAlias`.
7102+
class MyAlias(types.GenericAlias):
7103+
pass
7104+
7105+
class MyClass:
7106+
def __class_getitem__(cls, args):
7107+
return MyAlias(cls, args)
7108+
7109+
# Using a forward reference is important, otherwise it works as expected.
7110+
# `y` tests that the `GenericAlias` subclass is preserved when stripping `Annotated`.
7111+
def func(x: MyClass['int'], y: MyClass[Annotated[int, ...]]): ...
7112+
7113+
assert isinstance(get_type_hints(func)['x'], MyAlias)
7114+
assert isinstance(get_type_hints(func)['y'], MyAlias)
7115+
71177116

71187117
class GetUtilitiesTestCase(TestCase):
71197118
def test_get_origin(self):

0 commit comments

Comments
 (0)