From d5060f7808d2b9a86ac4ca5c447750b089cd3c16 Mon Sep 17 00:00:00 2001 From: Kir Chou Date: Wed, 10 Dec 2025 23:19:01 +0900 Subject: [PATCH 1/9] Add register_unbound in _crossinterp.py and initialize it in _queues.py --- Lib/concurrent/interpreters/_crossinterp.py | 4 ++++ Lib/concurrent/interpreters/_queues.py | 1 + 2 files changed, 5 insertions(+) diff --git a/Lib/concurrent/interpreters/_crossinterp.py b/Lib/concurrent/interpreters/_crossinterp.py index a5f46b20fbb4c5..6424318fe971eb 100644 --- a/Lib/concurrent/interpreters/_crossinterp.py +++ b/Lib/concurrent/interpreters/_crossinterp.py @@ -82,6 +82,10 @@ def __repr__(self): for k, v in _UNBOUND_CONSTANT_TO_FLAG.items()} +def register_unbound(unbound, flag): + _UNBOUND_CONSTANT_TO_FLAG[unbound] = flag + + def serialize_unbound(unbound): op = unbound try: diff --git a/Lib/concurrent/interpreters/_queues.py b/Lib/concurrent/interpreters/_queues.py index ee159d7de63827..29f05377eac779 100644 --- a/Lib/concurrent/interpreters/_queues.py +++ b/Lib/concurrent/interpreters/_queues.py @@ -47,6 +47,7 @@ class ItemInterpreterDestroyed(QueueError, UNBOUND = _crossinterp.UnboundItem.singleton('queue', __name__) +_crossinterp.register_unbound(UNBOUND, 3) def _serialize_unbound(unbound): From fb22cf6c3b544669254a942f237d9a126f99b442 Mon Sep 17 00:00:00 2001 From: Kir Chou Date: Thu, 11 Dec 2025 00:20:22 +0900 Subject: [PATCH 2/9] Change to directly import UNBOUND. --- Lib/concurrent/interpreters/_crossinterp.py | 4 ---- Lib/concurrent/interpreters/_queues.py | 6 +----- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/Lib/concurrent/interpreters/_crossinterp.py b/Lib/concurrent/interpreters/_crossinterp.py index 6424318fe971eb..a5f46b20fbb4c5 100644 --- a/Lib/concurrent/interpreters/_crossinterp.py +++ b/Lib/concurrent/interpreters/_crossinterp.py @@ -82,10 +82,6 @@ def __repr__(self): for k, v in _UNBOUND_CONSTANT_TO_FLAG.items()} -def register_unbound(unbound, flag): - _UNBOUND_CONSTANT_TO_FLAG[unbound] = flag - - def serialize_unbound(unbound): op = unbound try: diff --git a/Lib/concurrent/interpreters/_queues.py b/Lib/concurrent/interpreters/_queues.py index 29f05377eac779..cb60be18b39e86 100644 --- a/Lib/concurrent/interpreters/_queues.py +++ b/Lib/concurrent/interpreters/_queues.py @@ -11,7 +11,7 @@ QueueError, QueueNotFoundError, ) from ._crossinterp import ( - UNBOUND_ERROR, UNBOUND_REMOVE, + UNBOUND, UNBOUND_ERROR, UNBOUND_REMOVE, ) __all__ = [ @@ -46,10 +46,6 @@ class ItemInterpreterDestroyed(QueueError, _PICKLED = 1 -UNBOUND = _crossinterp.UnboundItem.singleton('queue', __name__) -_crossinterp.register_unbound(UNBOUND, 3) - - def _serialize_unbound(unbound): if unbound is UNBOUND: unbound = _crossinterp.UNBOUND From 7c3245fbf46df4a397004ddfe52a89e148e76d76 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Wed, 10 Dec 2025 15:27:59 +0000 Subject: [PATCH 3/9] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2025-12-10-15-27-58.gh-issue-142414.zTHgP-.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2025-12-10-15-27-58.gh-issue-142414.zTHgP-.rst diff --git a/Misc/NEWS.d/next/Library/2025-12-10-15-27-58.gh-issue-142414.zTHgP-.rst b/Misc/NEWS.d/next/Library/2025-12-10-15-27-58.gh-issue-142414.zTHgP-.rst new file mode 100644 index 00000000000000..1da59fe68d78b5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-12-10-15-27-58.gh-issue-142414.zTHgP-.rst @@ -0,0 +1 @@ +Align UNBOUND usage in Lib/concurrent/interpreters/_queues.py and Lib/concurrent/interpreters/_crossinterp.py. From 32617a06c314fa2db2119d560c065d672c048fc7 Mon Sep 17 00:00:00 2001 From: Kir Date: Thu, 11 Dec 2025 00:28:57 +0900 Subject: [PATCH 4/9] Update 2025-12-10-15-27-58.gh-issue-142414.zTHgP-.rst --- .../next/Library/2025-12-10-15-27-58.gh-issue-142414.zTHgP-.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-12-10-15-27-58.gh-issue-142414.zTHgP-.rst b/Misc/NEWS.d/next/Library/2025-12-10-15-27-58.gh-issue-142414.zTHgP-.rst index 1da59fe68d78b5..1653dc050c37d2 100644 --- a/Misc/NEWS.d/next/Library/2025-12-10-15-27-58.gh-issue-142414.zTHgP-.rst +++ b/Misc/NEWS.d/next/Library/2025-12-10-15-27-58.gh-issue-142414.zTHgP-.rst @@ -1 +1 @@ -Align UNBOUND usage in Lib/concurrent/interpreters/_queues.py and Lib/concurrent/interpreters/_crossinterp.py. +Align UNBOUND in Lib/concurrent/interpreters/_queues.py and Lib/concurrent/interpreters/_crossinterp.py. From 5730fd50f7e5ef4d164a34466ee11e8ce9ba710d Mon Sep 17 00:00:00 2001 From: Kir Date: Thu, 11 Dec 2025 00:46:22 +0900 Subject: [PATCH 5/9] Update 2025-12-10-15-27-58.gh-issue-142414.zTHgP-.rst --- .../next/Library/2025-12-10-15-27-58.gh-issue-142414.zTHgP-.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-12-10-15-27-58.gh-issue-142414.zTHgP-.rst b/Misc/NEWS.d/next/Library/2025-12-10-15-27-58.gh-issue-142414.zTHgP-.rst index 1653dc050c37d2..684403a302d5f4 100644 --- a/Misc/NEWS.d/next/Library/2025-12-10-15-27-58.gh-issue-142414.zTHgP-.rst +++ b/Misc/NEWS.d/next/Library/2025-12-10-15-27-58.gh-issue-142414.zTHgP-.rst @@ -1 +1 @@ -Align UNBOUND in Lib/concurrent/interpreters/_queues.py and Lib/concurrent/interpreters/_crossinterp.py. +Unified the UNBOUND constant in the internal implementation of Lib/concurrent/interpreters. From fcb33853a7151d6fdb0e2a867215dae3a140c257 Mon Sep 17 00:00:00 2001 From: Kir Chou Date: Thu, 11 Dec 2025 11:02:07 +0900 Subject: [PATCH 6/9] Add the repro test into test_queues.py. --- Lib/test/test_interpreters/test_queues.py | 9 +++++++++ .../2025-12-10-15-27-58.gh-issue-142414.zTHgP-.rst | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_interpreters/test_queues.py b/Lib/test/test_interpreters/test_queues.py index 77334aea3836b9..c5e78235c855df 100644 --- a/Lib/test/test_interpreters/test_queues.py +++ b/Lib/test/test_interpreters/test_queues.py @@ -8,6 +8,7 @@ # Raise SkipTest if subinterpreters not supported. _queues = import_helper.import_module('_interpqueues') from concurrent import interpreters +from concurrent.futures import InterpreterPoolExecutor from concurrent.interpreters import _queues as queues, _crossinterp from .utils import _run_output, TestBase as _TestBase @@ -93,6 +94,14 @@ def test_bind_release(self): with self.assertRaises(queues.QueueError): _queues.release(qid) + def test_interpreter_pool_executor_after_reload(self): + # Regression test for gh-142414 (KeyError in serialize_unbound). + importlib.reload(queues) + code = "import struct" + with InterpreterPoolExecutor(max_workers=1) as executor: + results = executor.map(exec, [code] * 1) + self.assertEqual(list(results), [None] * 1) + class QueueTests(TestBase): diff --git a/Misc/NEWS.d/next/Library/2025-12-10-15-27-58.gh-issue-142414.zTHgP-.rst b/Misc/NEWS.d/next/Library/2025-12-10-15-27-58.gh-issue-142414.zTHgP-.rst index 684403a302d5f4..9a9e03b47d0035 100644 --- a/Misc/NEWS.d/next/Library/2025-12-10-15-27-58.gh-issue-142414.zTHgP-.rst +++ b/Misc/NEWS.d/next/Library/2025-12-10-15-27-58.gh-issue-142414.zTHgP-.rst @@ -1 +1 @@ -Unified the UNBOUND constant in the internal implementation of Lib/concurrent/interpreters. +Fix spurious KeyError when concurrent.interpreters is reloaded after import. From 9a85aadd107438b42cd1f267cc7a0718d380d339 Mon Sep 17 00:00:00 2001 From: Kir Chou Date: Thu, 11 Dec 2025 19:05:49 +0900 Subject: [PATCH 7/9] Address "./python -m test test_interpreters test_concurrent_futures.test_interpreter_pool" --- Lib/concurrent/interpreters/_crossinterp.py | 11 +++++++++++ .../test_concurrent_futures/test_interpreter_pool.py | 2 ++ 2 files changed, 13 insertions(+) diff --git a/Lib/concurrent/interpreters/_crossinterp.py b/Lib/concurrent/interpreters/_crossinterp.py index a5f46b20fbb4c5..46a596caed0cd9 100644 --- a/Lib/concurrent/interpreters/_crossinterp.py +++ b/Lib/concurrent/interpreters/_crossinterp.py @@ -68,6 +68,17 @@ def __repr__(self): return f'{self._MODULE}.{self._NAME}' # return f'interpreters._queues.UNBOUND' + def __hash__(self): + return hash((self._NAME, self._MODULE)) + + def __reduce__(self): + return self._NAME + + def __eq__(self, other): + if other is self: + return True + return repr(other) == repr(self) + UNBOUND = object.__new__(UnboundItem) UNBOUND_ERROR = object() diff --git a/Lib/test/test_concurrent_futures/test_interpreter_pool.py b/Lib/test/test_concurrent_futures/test_interpreter_pool.py index 7241fcc4b1e74d..5c84a42d74fee4 100644 --- a/Lib/test/test_concurrent_futures/test_interpreter_pool.py +++ b/Lib/test/test_concurrent_futures/test_interpreter_pool.py @@ -427,6 +427,8 @@ def run(taskid, ready, blocker): ready.get(timeout=1) # blocking except interpreters.QueueEmpty: pass + except queues.QueueEmpty: + pass else: done += 1 pending -= done From 4a7e0ee83c663662b0ad80f6d2ce3743b1f91fe1 Mon Sep 17 00:00:00 2001 From: Kir Date: Thu, 11 Dec 2025 23:21:00 +0900 Subject: [PATCH 8/9] Update Misc/NEWS.d/next/Library/2025-12-10-15-27-58.gh-issue-142414.zTHgP-.rst Co-authored-by: Peter Bierma --- .../next/Library/2025-12-10-15-27-58.gh-issue-142414.zTHgP-.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-12-10-15-27-58.gh-issue-142414.zTHgP-.rst b/Misc/NEWS.d/next/Library/2025-12-10-15-27-58.gh-issue-142414.zTHgP-.rst index 9a9e03b47d0035..147c6e4b5dee2c 100644 --- a/Misc/NEWS.d/next/Library/2025-12-10-15-27-58.gh-issue-142414.zTHgP-.rst +++ b/Misc/NEWS.d/next/Library/2025-12-10-15-27-58.gh-issue-142414.zTHgP-.rst @@ -1 +1 @@ -Fix spurious KeyError when concurrent.interpreters is reloaded after import. +Fix spurious :exc:`KeyError` when :mod:`concurrent.interpreters` is reloaded after import. From 99873e8b32b6542b723b01350dad03b7bf0973b3 Mon Sep 17 00:00:00 2001 From: Kir Chou Date: Fri, 12 Dec 2025 00:23:51 +0900 Subject: [PATCH 9/9] Remove picklable functions. We don't need to make singleton picklabe based on the current tests. --- Lib/concurrent/interpreters/_crossinterp.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/Lib/concurrent/interpreters/_crossinterp.py b/Lib/concurrent/interpreters/_crossinterp.py index 46a596caed0cd9..a5f46b20fbb4c5 100644 --- a/Lib/concurrent/interpreters/_crossinterp.py +++ b/Lib/concurrent/interpreters/_crossinterp.py @@ -68,17 +68,6 @@ def __repr__(self): return f'{self._MODULE}.{self._NAME}' # return f'interpreters._queues.UNBOUND' - def __hash__(self): - return hash((self._NAME, self._MODULE)) - - def __reduce__(self): - return self._NAME - - def __eq__(self, other): - if other is self: - return True - return repr(other) == repr(self) - UNBOUND = object.__new__(UnboundItem) UNBOUND_ERROR = object()