From bb937c25d0004e357a29337c3866ed92574b5daf Mon Sep 17 00:00:00 2001 From: Henry Schreiner Date: Fri, 29 May 2026 13:46:40 -0400 Subject: [PATCH 1/2] chore: use lazy imports for concurrent.futures This module has a manual lazy import hack using `__getattr__`. Now that lazy imports exist and cannot be disabled, this could use lazy imports instead. Key differences: this will now show up in sys.lazy_modules when accessed. Error messages should be a bit better without the wrapper `__getattr__` involved. That's the only differences I can think of. Signed-off-by: Henry Schreiner --- Lib/concurrent/futures/__init__.py | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/Lib/concurrent/futures/__init__.py b/Lib/concurrent/futures/__init__.py index d6ac4b3e0b675f6..63e2a647e4001ae 100644 --- a/Lib/concurrent/futures/__init__.py +++ b/Lib/concurrent/futures/__init__.py @@ -17,6 +17,9 @@ wait, as_completed) +lazy from .process import ProcessPoolExecutor +lazy from .thread import ThreadPoolExecutor + __all__ = [ 'FIRST_COMPLETED', 'FIRST_EXCEPTION', @@ -40,26 +43,10 @@ _interpreters = None if _interpreters: + lazy from .interpreter import InterpreterPoolExecutor __all__.append('InterpreterPoolExecutor') def __dir__(): return __all__ + ['__author__', '__doc__'] - -def __getattr__(name): - global ProcessPoolExecutor, ThreadPoolExecutor, InterpreterPoolExecutor - - if name == 'ProcessPoolExecutor': - from .process import ProcessPoolExecutor - return ProcessPoolExecutor - - if name == 'ThreadPoolExecutor': - from .thread import ThreadPoolExecutor - return ThreadPoolExecutor - - if _interpreters and name == 'InterpreterPoolExecutor': - from .interpreter import InterpreterPoolExecutor - return InterpreterPoolExecutor - - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") From cdd9aefe2a3a643a708011f9453b75d66b4464d8 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Fri, 3 Jul 2026 17:30:31 +0000 Subject: [PATCH 2/2] Fix lint errors and add a NEWS entry --- Lib/concurrent/futures/__init__.py | 3 +-- .../Library/2026-07-03-17-29-34.gh-issue-150579.0tLpQukIU.rst | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-07-03-17-29-34.gh-issue-150579.0tLpQukIU.rst diff --git a/Lib/concurrent/futures/__init__.py b/Lib/concurrent/futures/__init__.py index 63e2a647e4001ae..5d53a5ac50931d3 100644 --- a/Lib/concurrent/futures/__init__.py +++ b/Lib/concurrent/futures/__init__.py @@ -43,10 +43,9 @@ _interpreters = None if _interpreters: - lazy from .interpreter import InterpreterPoolExecutor + lazy from .interpreter import InterpreterPoolExecutor # noqa: F401 __all__.append('InterpreterPoolExecutor') def __dir__(): return __all__ + ['__author__', '__doc__'] - diff --git a/Misc/NEWS.d/next/Library/2026-07-03-17-29-34.gh-issue-150579.0tLpQukIU.rst b/Misc/NEWS.d/next/Library/2026-07-03-17-29-34.gh-issue-150579.0tLpQukIU.rst new file mode 100644 index 000000000000000..7aff384431edc77 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-03-17-29-34.gh-issue-150579.0tLpQukIU.rst @@ -0,0 +1,2 @@ +:mod:`concurrent.futures` now uses lazy imports for its executor submodules +instead of a module ``__getattr__`` hook.