aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--Doc/library/argparse.rst37
-rw-r--r--Doc/library/multiprocessing.rst12
-rw-r--r--Lib/concurrent/interpreters/__init__.py8
-rw-r--r--Lib/concurrent/interpreters/_queues.py8
-rw-r--r--Lib/test/support/channels.py8
-rw-r--r--Lib/test/test_interpreters/test_api.py8
-rw-r--r--Lib/test/test_interpreters/test_channels.py16
-rw-r--r--Lib/test/test_interpreters/test_queues.py8
-rw-r--r--Lib/test/test_typing.py25
-rw-r--r--Lib/typing.py8
-rw-r--r--Misc/NEWS.d/next/Core_and_Builtins/2025-07-06-14-53-19.gh-issue-109700.KVNQQi.rst1
-rw-r--r--Misc/NEWS.d/next/Library/2025-07-05-09-45-04.gh-issue-136286.N67Amr.rst2
-rw-r--r--Misc/NEWS.d/next/Library/2025-07-06-10-18-48.gh-issue-136021.f-FJYT.rst3
-rw-r--r--Objects/dictobject.c1
14 files changed, 61 insertions, 84 deletions
diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst
index a03d88092db..f189f6b8fa8 100644
--- a/Doc/library/argparse.rst
+++ b/Doc/library/argparse.rst
@@ -839,23 +839,11 @@ how the command-line arguments should be handled. The supplied actions are:
>>> parser.parse_args(['--version'])
PROG 2.0
-Only actions that consume command-line arguments (e.g. ``'store'``,
-``'append'`` or ``'extend'``) can be used with positional arguments.
-
-.. class:: BooleanOptionalAction
-
- You may also specify an arbitrary action by passing an :class:`Action` subclass or
- other object that implements the same interface. The :class:`!BooleanOptionalAction`
- is available in :mod:`!argparse` and adds support for boolean actions such as
- ``--foo`` and ``--no-foo``::
-
- >>> import argparse
- >>> parser = argparse.ArgumentParser()
- >>> parser.add_argument('--foo', action=argparse.BooleanOptionalAction)
- >>> parser.parse_args(['--no-foo'])
- Namespace(foo=False)
-
- .. versionadded:: 3.9
+You may also specify an arbitrary action by passing an :class:`Action` subclass
+(e.g. :class:`BooleanOptionalAction`) or other object that implements the same
+interface. Only actions that consume command-line arguments (e.g. ``'store'``,
+``'append'``, ``'extend'``, or custom actions with non-zero ``nargs``) can be used
+with positional arguments.
The recommended way to create a custom action is to extend :class:`Action`,
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
and return a string which will be used when printing the usage of the program.
If such method is not provided, a sensible default will be used.
+.. class:: BooleanOptionalAction
+
+ A subclass of :class:`Action` for handling boolean flags with positive
+ and negative options. Adding a single argument such as ``--foo`` automatically
+ creates both ``--foo`` and ``--no-foo`` options, storing ``True`` and ``False``
+ respectively::
+
+ >>> import argparse
+ >>> parser = argparse.ArgumentParser()
+ >>> parser.add_argument('--foo', action=argparse.BooleanOptionalAction)
+ >>> parser.parse_args(['--no-foo'])
+ Namespace(foo=False)
+
+ .. versionadded:: 3.9
+
The parse_args() method
-----------------------
diff --git a/Doc/library/multiprocessing.rst b/Doc/library/multiprocessing.rst
index fc3c1134f97..546876bd925 100644
--- a/Doc/library/multiprocessing.rst
+++ b/Doc/library/multiprocessing.rst
@@ -1118,7 +1118,9 @@ Miscellaneous
Return a context object which has the same attributes as the
:mod:`multiprocessing` module.
- If *method* is ``None`` then the default context is returned.
+ If *method* is ``None`` then the default context is returned. Note that if
+ the global start method has not been set, this will set it to the
+ default method.
Otherwise *method* should be ``'fork'``, ``'spawn'``,
``'forkserver'``. :exc:`ValueError` is raised if the specified
start method is not available. See :ref:`multiprocessing-start-methods`.
@@ -1129,10 +1131,10 @@ Miscellaneous
Return the name of start method used for starting processes.
- If the start method has not been fixed and *allow_none* is false,
- then the start method is fixed to the default and the name is
- returned. If the start method has not been fixed and *allow_none*
- is true then ``None`` is returned.
+ If the global start method has not been set and *allow_none* is
+ ``False``, then the start method is set to the default and the name
+ is returned. If the start method has not been set and *allow_none* is
+ ``True`` then ``None`` is returned.
The return value can be ``'fork'``, ``'spawn'``, ``'forkserver'``
or ``None``. See :ref:`multiprocessing-start-methods`.
diff --git a/Lib/concurrent/interpreters/__init__.py b/Lib/concurrent/interpreters/__init__.py
index 0fd661249a2..aa46a2b37a4 100644
--- a/Lib/concurrent/interpreters/__init__.py
+++ b/Lib/concurrent/interpreters/__init__.py
@@ -146,12 +146,8 @@ class Interpreter:
self._decref()
# for pickling:
- def __getnewargs__(self):
- return (self._id,)
-
- # for pickling:
- def __getstate__(self):
- return None
+ def __reduce__(self):
+ return (type(self), (self._id,))
def _decref(self):
if not self._ownsref:
diff --git a/Lib/concurrent/interpreters/_queues.py b/Lib/concurrent/interpreters/_queues.py
index 99987f2f692..9c12b2c8c24 100644
--- a/Lib/concurrent/interpreters/_queues.py
+++ b/Lib/concurrent/interpreters/_queues.py
@@ -129,12 +129,8 @@ class Queue:
return hash(self._id)
# for pickling:
- def __getnewargs__(self):
- return (self._id,)
-
- # for pickling:
- def __getstate__(self):
- return None
+ def __reduce__(self):
+ return (type(self), (self._id,))
def _set_unbound(self, op, items=None):
assert not hasattr(self, '_unbound')
diff --git a/Lib/test/support/channels.py b/Lib/test/support/channels.py
index b2de24d9d3e..fab1797659b 100644
--- a/Lib/test/support/channels.py
+++ b/Lib/test/support/channels.py
@@ -105,12 +105,8 @@ class _ChannelEnd:
return other._id == self._id
# for pickling:
- def __getnewargs__(self):
- return (int(self._id),)
-
- # for pickling:
- def __getstate__(self):
- return None
+ def __reduce__(self):
+ return (type(self), (int(self._id),))
@property
def id(self):
diff --git a/Lib/test/test_interpreters/test_api.py b/Lib/test/test_interpreters/test_api.py
index 0ee4582b5d1..a34b20beaca 100644
--- a/Lib/test/test_interpreters/test_api.py
+++ b/Lib/test/test_interpreters/test_api.py
@@ -412,9 +412,11 @@ class InterpreterObjectTests(TestBase):
def test_pickle(self):
interp = interpreters.create()
- data = pickle.dumps(interp)
- unpickled = pickle.loads(data)
- self.assertEqual(unpickled, interp)
+ for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
+ with self.subTest(protocol=protocol):
+ data = pickle.dumps(interp, protocol)
+ unpickled = pickle.loads(data)
+ self.assertEqual(unpickled, interp)
class TestInterpreterIsRunning(TestBase):
diff --git a/Lib/test/test_interpreters/test_channels.py b/Lib/test/test_interpreters/test_channels.py
index 109ddf34453..52827357078 100644
--- a/Lib/test/test_interpreters/test_channels.py
+++ b/Lib/test/test_interpreters/test_channels.py
@@ -121,9 +121,11 @@ class TestRecvChannelAttrs(TestBase):
def test_pickle(self):
ch, _ = channels.create()
- data = pickle.dumps(ch)
- unpickled = pickle.loads(data)
- self.assertEqual(unpickled, ch)
+ for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
+ with self.subTest(protocol=protocol):
+ data = pickle.dumps(ch, protocol)
+ unpickled = pickle.loads(data)
+ self.assertEqual(unpickled, ch)
class TestSendChannelAttrs(TestBase):
@@ -152,9 +154,11 @@ class TestSendChannelAttrs(TestBase):
def test_pickle(self):
_, ch = channels.create()
- data = pickle.dumps(ch)
- unpickled = pickle.loads(data)
- self.assertEqual(unpickled, ch)
+ for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
+ with self.subTest(protocol=protocol):
+ data = pickle.dumps(ch, protocol)
+ unpickled = pickle.loads(data)
+ self.assertEqual(unpickled, ch)
class TestSendRecv(TestBase):
diff --git a/Lib/test/test_interpreters/test_queues.py b/Lib/test/test_interpreters/test_queues.py
index cb17340f581..5451c6654ac 100644
--- a/Lib/test/test_interpreters/test_queues.py
+++ b/Lib/test/test_interpreters/test_queues.py
@@ -188,9 +188,11 @@ class QueueTests(TestBase):
def test_pickle(self):
queue = queues.create()
- data = pickle.dumps(queue)
- unpickled = pickle.loads(data)
- self.assertEqual(unpickled, queue)
+ for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
+ with self.subTest(protocol=protocol):
+ data = pickle.dumps(queue, protocol)
+ unpickled = pickle.loads(data)
+ self.assertEqual(unpickled, queue)
class TestQueueOps(TestBase):
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index bef6773ad6c..932c7b9c0a5 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -6309,31 +6309,6 @@ class NoTypeCheckTests(BaseTestCase):
class InternalsTests(BaseTestCase):
- def test_deprecation_for_no_type_params_passed_to__evaluate(self):
- with self.assertWarnsRegex(
- DeprecationWarning,
- (
- "Failing to pass a value to the 'type_params' parameter "
- "of 'typing._eval_type' is deprecated"
- )
- ) as cm:
- self.assertEqual(typing._eval_type(list["int"], globals(), {}), list[int])
-
- self.assertEqual(cm.filename, __file__)
-
- f = ForwardRef("int")
-
- with self.assertWarnsRegex(
- DeprecationWarning,
- (
- "Failing to pass a value to the 'type_params' parameter "
- "of 'typing.ForwardRef._evaluate' is deprecated"
- )
- ) as cm:
- self.assertIs(f._evaluate(globals(), {}, recursive_guard=frozenset()), int)
-
- self.assertEqual(cm.filename, __file__)
-
def test_collect_parameters(self):
typing = import_helper.import_fresh_module("typing")
with self.assertWarnsRegex(
diff --git a/Lib/typing.py b/Lib/typing.py
index 27105838a0a..3ef377b9542 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -437,10 +437,7 @@ class _Sentinel:
return '<sentinel>'
-_sentinel = _Sentinel()
-
-
-def _eval_type(t, globalns, localns, type_params=_sentinel, *, recursive_guard=frozenset(),
+def _eval_type(t, globalns, localns, type_params, *, recursive_guard=frozenset(),
format=None, owner=None):
"""Evaluate all forward references in the given type t.
@@ -448,9 +445,6 @@ def _eval_type(t, globalns, localns, type_params=_sentinel, *, recursive_guard=f
recursive_guard is used to prevent infinite recursion with a recursive
ForwardRef.
"""
- if type_params is _sentinel:
- _deprecation_warning_for_no_type_params_passed("typing._eval_type")
- type_params = ()
if isinstance(t, _lazy_annotationlib.ForwardRef):
# If the forward_ref has __forward_module__ set, evaluate() infers the globals
# from the module, and it will probably pick better than the globals we have here.
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-06-14-53-19.gh-issue-109700.KVNQQi.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-06-14-53-19.gh-issue-109700.KVNQQi.rst
new file mode 100644
index 00000000000..a37f4a51050
--- /dev/null
+++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-06-14-53-19.gh-issue-109700.KVNQQi.rst
@@ -0,0 +1 @@
+Fix memory error handling in :c:func:`PyDict_SetDefault`.
diff --git a/Misc/NEWS.d/next/Library/2025-07-05-09-45-04.gh-issue-136286.N67Amr.rst b/Misc/NEWS.d/next/Library/2025-07-05-09-45-04.gh-issue-136286.N67Amr.rst
new file mode 100644
index 00000000000..0a0d66ac0b8
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-07-05-09-45-04.gh-issue-136286.N67Amr.rst
@@ -0,0 +1,2 @@
+Fix pickling failures for protocols 0 and 1 for many objects realted to
+subinterpreters.
diff --git a/Misc/NEWS.d/next/Library/2025-07-06-10-18-48.gh-issue-136021.f-FJYT.rst b/Misc/NEWS.d/next/Library/2025-07-06-10-18-48.gh-issue-136021.f-FJYT.rst
new file mode 100644
index 00000000000..39a848c11eb
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-07-06-10-18-48.gh-issue-136021.f-FJYT.rst
@@ -0,0 +1,3 @@
+Make ``type_params`` parameter required in :func:`!typing._eval_type` after
+a deprecation period for not providing this parameter. Also remove the
+:exc:`DeprecationWarning` for the old behavior.
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 6b7b150f0e2..be62ae5eefd 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -4411,6 +4411,7 @@ dict_setdefault_ref_lock_held(PyObject *d, PyObject *key, PyObject *default_valu
if (result) {
*result = NULL;
}
+ return -1;
}
STORE_USED(mp, mp->ma_used + 1);