From 6ed477458544f3945f1cf574f591ad7561bd5c5d Mon Sep 17 00:00:00 2001 From: AN Long Date: Mon, 7 Jul 2025 22:13:40 +0900 Subject: [PATCH 01/13] Fix import behavior for concurrent.futures.InterpreterPoolExecutor --- Lib/concurrent/futures/__init__.py | 10 +++++++--- .../2025-07-07-22-12-32.gh-issue-136380.1b_nXl.rst | 3 +++ 2 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2025-07-07-22-12-32.gh-issue-136380.1b_nXl.rst diff --git a/Lib/concurrent/futures/__init__.py b/Lib/concurrent/futures/__init__.py index 7ada7431c1ab8c..fa3ef0c2a206a5 100644 --- a/Lib/concurrent/futures/__init__.py +++ b/Lib/concurrent/futures/__init__.py @@ -39,8 +39,12 @@ def __dir__(): return __all__ + ('__author__', '__doc__') +_no_interpreter_pool_executor = False + + def __getattr__(name): global ProcessPoolExecutor, ThreadPoolExecutor, InterpreterPoolExecutor + global _no_interpreter_pool_executor if name == 'ProcessPoolExecutor': from .process import ProcessPoolExecutor as pe @@ -52,13 +56,13 @@ def __getattr__(name): ThreadPoolExecutor = te return te - if name == 'InterpreterPoolExecutor': + if name == 'InterpreterPoolExecutor' and not _no_interpreter_pool_executor: try: from .interpreter import InterpreterPoolExecutor as ie except ModuleNotFoundError: - ie = InterpreterPoolExecutor = None + _no_interpreter_pool_executor = True else: InterpreterPoolExecutor = ie - return ie + return ie raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/Misc/NEWS.d/next/Library/2025-07-07-22-12-32.gh-issue-136380.1b_nXl.rst b/Misc/NEWS.d/next/Library/2025-07-07-22-12-32.gh-issue-136380.1b_nXl.rst new file mode 100644 index 00000000000000..ec2b8a74e58285 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-07-07-22-12-32.gh-issue-136380.1b_nXl.rst @@ -0,0 +1,3 @@ +Raises :exc:`AttributeError` when accessing +``concurrent.futures.InterpreterPoolExecutor`` and :mod:`_interpreter` is +not available. From cc1a90a40b8a38cd1a3d506e5287257d6f4a5f85 Mon Sep 17 00:00:00 2001 From: AN Long Date: Mon, 7 Jul 2025 22:26:33 +0900 Subject: [PATCH 02/13] Fix rst marker --- .../next/Library/2025-07-07-22-12-32.gh-issue-136380.1b_nXl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-07-07-22-12-32.gh-issue-136380.1b_nXl.rst b/Misc/NEWS.d/next/Library/2025-07-07-22-12-32.gh-issue-136380.1b_nXl.rst index ec2b8a74e58285..13dd90e3de6443 100644 --- a/Misc/NEWS.d/next/Library/2025-07-07-22-12-32.gh-issue-136380.1b_nXl.rst +++ b/Misc/NEWS.d/next/Library/2025-07-07-22-12-32.gh-issue-136380.1b_nXl.rst @@ -1,3 +1,3 @@ Raises :exc:`AttributeError` when accessing -``concurrent.futures.InterpreterPoolExecutor`` and :mod:`_interpreter` is +``concurrent.futures.InterpreterPoolExecutor`` and ``_interpreter`` is not available. From 7508c7376e71f71fc2523d1f9afd7cd6a6f99417 Mon Sep 17 00:00:00 2001 From: AN Long Date: Mon, 7 Jul 2025 22:57:13 +0900 Subject: [PATCH 03/13] Fix import start --- Lib/concurrent/futures/__init__.py | 33 ++++++++++++++++-------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/Lib/concurrent/futures/__init__.py b/Lib/concurrent/futures/__init__.py index fa3ef0c2a206a5..c7d8f83c1af1e2 100644 --- a/Lib/concurrent/futures/__init__.py +++ b/Lib/concurrent/futures/__init__.py @@ -17,7 +17,7 @@ wait, as_completed) -__all__ = ( +__all__ = [ 'FIRST_COMPLETED', 'FIRST_EXCEPTION', 'ALL_COMPLETED', @@ -29,22 +29,29 @@ 'Executor', 'wait', 'as_completed', - 'InterpreterPoolExecutor', 'ProcessPoolExecutor', 'ThreadPoolExecutor', -) +] -def __dir__(): - return __all__ + ('__author__', '__doc__') +_have__interpreters = False + +try: + import _interpreters + _have__interpreters = True +except ModuleNotFoundError: + pass +if _have__interpreters: + __all__.append('InterpreterPoolExecutor') -_no_interpreter_pool_executor = False + +def __dir__(): + return __all__ + ('__author__', '__doc__') def __getattr__(name): global ProcessPoolExecutor, ThreadPoolExecutor, InterpreterPoolExecutor - global _no_interpreter_pool_executor if name == 'ProcessPoolExecutor': from .process import ProcessPoolExecutor as pe @@ -56,13 +63,9 @@ def __getattr__(name): ThreadPoolExecutor = te return te - if name == 'InterpreterPoolExecutor' and not _no_interpreter_pool_executor: - try: - from .interpreter import InterpreterPoolExecutor as ie - except ModuleNotFoundError: - _no_interpreter_pool_executor = True - else: - InterpreterPoolExecutor = ie - return ie + if _have__interpreters and name == 'InterpreterPoolExecutor': + from .interpreter import InterpreterPoolExecutor as ie + InterpreterPoolExecutor = ie + return ie raise AttributeError(f"module {__name__!r} has no attribute {name!r}") From fe2c921a3a9ce810b1bec2146a40790dd852d9ac Mon Sep 17 00:00:00 2001 From: AN Long Date: Tue, 8 Jul 2025 01:20:06 +0900 Subject: [PATCH 04/13] Update Lib/concurrent/futures/__init__.py Co-authored-by: Serhiy Storchaka --- Lib/concurrent/futures/__init__.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Lib/concurrent/futures/__init__.py b/Lib/concurrent/futures/__init__.py index c7d8f83c1af1e2..5cf092485d3793 100644 --- a/Lib/concurrent/futures/__init__.py +++ b/Lib/concurrent/futures/__init__.py @@ -64,8 +64,7 @@ def __getattr__(name): return te if _have__interpreters and name == 'InterpreterPoolExecutor': - from .interpreter import InterpreterPoolExecutor as ie - InterpreterPoolExecutor = ie - return ie + from .interpreter import InterpreterPoolExecutor + return InterpreterPoolExecutor raise AttributeError(f"module {__name__!r} has no attribute {name!r}") From 0f1c7b2a6d63e6d7eac8439579a0294b55e686bb Mon Sep 17 00:00:00 2001 From: AN Long Date: Tue, 8 Jul 2025 01:21:01 +0900 Subject: [PATCH 05/13] Update Misc/NEWS.d/next/Library/2025-07-07-22-12-32.gh-issue-136380.1b_nXl.rst Co-authored-by: Peter Bierma --- .../next/Library/2025-07-07-22-12-32.gh-issue-136380.1b_nXl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-07-07-22-12-32.gh-issue-136380.1b_nXl.rst b/Misc/NEWS.d/next/Library/2025-07-07-22-12-32.gh-issue-136380.1b_nXl.rst index 13dd90e3de6443..4ac04b9c0a6c5c 100644 --- a/Misc/NEWS.d/next/Library/2025-07-07-22-12-32.gh-issue-136380.1b_nXl.rst +++ b/Misc/NEWS.d/next/Library/2025-07-07-22-12-32.gh-issue-136380.1b_nXl.rst @@ -1,3 +1,3 @@ Raises :exc:`AttributeError` when accessing -``concurrent.futures.InterpreterPoolExecutor`` and ``_interpreter`` is +:class:`concurrent.futures.InterpreterPoolExecutor` and subinterpreters are not available. From 30a34ddd8803bb9257bd046a8cad31406ea13597 Mon Sep 17 00:00:00 2001 From: AN Long Date: Tue, 8 Jul 2025 01:22:10 +0900 Subject: [PATCH 06/13] Simplify the try import codes --- Lib/concurrent/futures/__init__.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/Lib/concurrent/futures/__init__.py b/Lib/concurrent/futures/__init__.py index 5cf092485d3793..b6f0985058ea75 100644 --- a/Lib/concurrent/futures/__init__.py +++ b/Lib/concurrent/futures/__init__.py @@ -34,15 +34,14 @@ ] -_have__interpreters = False +_interpreters = None try: import _interpreters - _have__interpreters = True except ModuleNotFoundError: pass -if _have__interpreters: +if _interpreters: __all__.append('InterpreterPoolExecutor') @@ -54,16 +53,14 @@ def __getattr__(name): global ProcessPoolExecutor, ThreadPoolExecutor, InterpreterPoolExecutor if name == 'ProcessPoolExecutor': - from .process import ProcessPoolExecutor as pe - ProcessPoolExecutor = pe - return pe + from .process import ProcessPoolExecutor + return ProcessPoolExecutor if name == 'ThreadPoolExecutor': - from .thread import ThreadPoolExecutor as te - ThreadPoolExecutor = te - return te + from .thread import ThreadPoolExecutor + return ThreadPoolExecutor - if _have__interpreters and name == 'InterpreterPoolExecutor': + if _interpreters and name == 'InterpreterPoolExecutor': from .interpreter import InterpreterPoolExecutor return InterpreterPoolExecutor From 1946abd3dfce7f57be483a6f7bcddc79bfe7a8d6 Mon Sep 17 00:00:00 2001 From: AN Long Date: Tue, 8 Jul 2025 01:56:24 +0900 Subject: [PATCH 07/13] Add test --- .../test_interpreter_pool.py | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/Lib/test/test_concurrent_futures/test_interpreter_pool.py b/Lib/test/test_concurrent_futures/test_interpreter_pool.py index 844dfdd6fc901c..494d1c72206ce4 100644 --- a/Lib/test/test_concurrent_futures/test_interpreter_pool.py +++ b/Lib/test/test_concurrent_futures/test_interpreter_pool.py @@ -2,7 +2,9 @@ import contextlib import io import os +import subprocess import sys +import textwrap import time import unittest from concurrent.futures.interpreter import BrokenInterpreterPool @@ -457,6 +459,38 @@ def test_free_reference(self): # Weak references don't cross between interpreters. raise unittest.SkipTest('not applicable') + def test_import_interpreter_pool_executor(self): + # Test the import behavior normally if _interpreters is unavailable. + code = textwrap.dedent(f""" + from concurrent import futures + import sys + # Set it to None to emulate the case when _interpreter is unavailable. + futures._interpreters = None + + try: + futures.InterpreterPoolExecutor + except AttributeError: + pass + else: + print('AttributeError not raised!', file=sys.stderr) + sys.exit(1) + + try: + from concurrent.futures import InterpreterPoolExecutor + except ImportError: + pass + else: + print('ImportError not raised!', file=sys.stderr) + sys.exit(1) + + + from concurrent.futures import * + """) + + cmd = [sys.executable, '-c', code] + p = subprocess.run(cmd, capture_output=True) + self.assertEqual(p.returncode, 0, p.stderr.decode()) + class AsyncioTest(InterpretersMixin, testasyncio_utils.TestCase): From f0c58ae9fad351b2e65ce7f880720384ecb42676 Mon Sep 17 00:00:00 2001 From: AN Long Date: Tue, 8 Jul 2025 02:01:11 +0900 Subject: [PATCH 08/13] Fix test --- Lib/test/test_concurrent_futures/test_interpreter_pool.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_concurrent_futures/test_interpreter_pool.py b/Lib/test/test_concurrent_futures/test_interpreter_pool.py index 494d1c72206ce4..b81269ebb7ea9a 100644 --- a/Lib/test/test_concurrent_futures/test_interpreter_pool.py +++ b/Lib/test/test_concurrent_futures/test_interpreter_pool.py @@ -459,6 +459,7 @@ def test_free_reference(self): # Weak references don't cross between interpreters. raise unittest.SkipTest('not applicable') + @support.requires_subprocess() def test_import_interpreter_pool_executor(self): # Test the import behavior normally if _interpreters is unavailable. code = textwrap.dedent(f""" From 6a17c55bdb3da4c11e00c70aaf315c647969aa4d Mon Sep 17 00:00:00 2001 From: AN Long Date: Tue, 8 Jul 2025 02:08:02 +0900 Subject: [PATCH 09/13] Fix test --- Lib/test/test_concurrent_futures/test_interpreter_pool.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/Lib/test/test_concurrent_futures/test_interpreter_pool.py b/Lib/test/test_concurrent_futures/test_interpreter_pool.py index b81269ebb7ea9a..6427ee8fe7ee52 100644 --- a/Lib/test/test_concurrent_futures/test_interpreter_pool.py +++ b/Lib/test/test_concurrent_futures/test_interpreter_pool.py @@ -483,9 +483,6 @@ def test_import_interpreter_pool_executor(self): else: print('ImportError not raised!', file=sys.stderr) sys.exit(1) - - - from concurrent.futures import * """) cmd = [sys.executable, '-c', code] From 93366305bc4528d060211485cebf2ab06f9554dc Mon Sep 17 00:00:00 2001 From: AN Long Date: Tue, 8 Jul 2025 02:17:26 +0900 Subject: [PATCH 10/13] Better test --- Lib/test/test_concurrent_futures/test_interpreter_pool.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_concurrent_futures/test_interpreter_pool.py b/Lib/test/test_concurrent_futures/test_interpreter_pool.py index 6427ee8fe7ee52..0e8f43eeb6c51d 100644 --- a/Lib/test/test_concurrent_futures/test_interpreter_pool.py +++ b/Lib/test/test_concurrent_futures/test_interpreter_pool.py @@ -463,10 +463,10 @@ def test_free_reference(self): def test_import_interpreter_pool_executor(self): # Test the import behavior normally if _interpreters is unavailable. code = textwrap.dedent(f""" - from concurrent import futures import sys # Set it to None to emulate the case when _interpreter is unavailable. - futures._interpreters = None + sys.modules['_interpreters'] = None + from concurrent import futures try: futures.InterpreterPoolExecutor @@ -483,6 +483,8 @@ def test_import_interpreter_pool_executor(self): else: print('ImportError not raised!', file=sys.stderr) sys.exit(1) + + from concurrent.futures import * """) cmd = [sys.executable, '-c', code] From 36f0a0c0549c824113f5d6a4451544a7329da0a1 Mon Sep 17 00:00:00 2001 From: AN Long Date: Tue, 8 Jul 2025 22:02:14 +0900 Subject: [PATCH 11/13] Update Lib/concurrent/futures/__init__.py Co-authored-by: sobolevn --- Lib/concurrent/futures/__init__.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Lib/concurrent/futures/__init__.py b/Lib/concurrent/futures/__init__.py index b6f0985058ea75..e717222cf98b32 100644 --- a/Lib/concurrent/futures/__init__.py +++ b/Lib/concurrent/futures/__init__.py @@ -34,12 +34,10 @@ ] -_interpreters = None - try: import _interpreters -except ModuleNotFoundError: - pass +except ImportError: + _interpreters = None if _interpreters: __all__.append('InterpreterPoolExecutor') From 0a9d5c81ee37ef67429ffcea40688e52d93aeeeb Mon Sep 17 00:00:00 2001 From: AN Long Date: Tue, 8 Jul 2025 22:06:04 +0900 Subject: [PATCH 12/13] Update Lib/test/test_concurrent_futures/test_interpreter_pool.py Co-authored-by: sobolevn --- Lib/test/test_concurrent_futures/test_interpreter_pool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_concurrent_futures/test_interpreter_pool.py b/Lib/test/test_concurrent_futures/test_interpreter_pool.py index 0e8f43eeb6c51d..764af2c3fb6ca9 100644 --- a/Lib/test/test_concurrent_futures/test_interpreter_pool.py +++ b/Lib/test/test_concurrent_futures/test_interpreter_pool.py @@ -462,7 +462,7 @@ def test_free_reference(self): @support.requires_subprocess() def test_import_interpreter_pool_executor(self): # Test the import behavior normally if _interpreters is unavailable. - code = textwrap.dedent(f""" + code = textwrap.dedent(""" import sys # Set it to None to emulate the case when _interpreter is unavailable. sys.modules['_interpreters'] = None From b2e6e698c26eeda350ec7e1ec0f9f55b6423bafc Mon Sep 17 00:00:00 2001 From: AN Long Date: Tue, 8 Jul 2025 22:06:37 +0900 Subject: [PATCH 13/13] Update test --- Lib/test/test_concurrent_futures/test_interpreter_pool.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Lib/test/test_concurrent_futures/test_interpreter_pool.py b/Lib/test/test_concurrent_futures/test_interpreter_pool.py index 764af2c3fb6ca9..b10bbebd0984c4 100644 --- a/Lib/test/test_concurrent_futures/test_interpreter_pool.py +++ b/Lib/test/test_concurrent_futures/test_interpreter_pool.py @@ -485,11 +485,18 @@ def test_import_interpreter_pool_executor(self): sys.exit(1) from concurrent.futures import * + + if 'InterpreterPoolExecutor' in globals(): + print('InterpreterPoolExecutor should not be imported!', + file=sys.stderr) + sys.exit(1) """) cmd = [sys.executable, '-c', code] p = subprocess.run(cmd, capture_output=True) self.assertEqual(p.returncode, 0, p.stderr.decode()) + self.assertEqual(p.stdout.decode(), '') + self.assertEqual(p.stderr.decode(), '') class AsyncioTest(InterpretersMixin, testasyncio_utils.TestCase): pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy