Bug report
Bug description:
Under 3.15, this doesn't work:
lazy from concurrent.futures import ProcessPoolExecutor
def square(x):
return x * x
def main():
with ProcessPoolExecutor(max_workers=2) as executor:
results = list(executor.map(square, [1, 2, 3, 4]))
print(results)
if __name__ == "__main__":
main()
(I'm running with uv run --python=3.15 lazy.py) Without the lazy this works. If you use lazy import concurrent.futures it works. It also breaks in __lazy_modules__ form (which is how I ran into it). It breaks with ThreadPoolExecutor too.
The (rather poor) error message:
Traceback (most recent call last):
File "/Users/henryfs/git/tmp/cpylazyproc/lazy.py", line 1, in <module>
lazy from concurrent.futures import ProcessPoolExecutor
ImportError: deferred import of 'concurrent.futures.ProcessPoolExecutor' raised an exception during resolution
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/henryfs/git/tmp/cpylazyproc/lazy.py", line 15, in <module>
main()
~~~~^^
File "/Users/henryfs/git/tmp/cpylazyproc/lazy.py", line 9, in main
with ProcessPoolExecutor(max_workers=2) as executor:
^^^^^^^^^^^^^^^^^^^
ImportError: cannot import name 'ProcessPoolExecutor' from 'concurrent.futures' (/Users/henryfs/.local/share/uv/python/cpython-3.15.0b1-macos-aarch64-none/lib/python3.15/concurrent/futures/__init__.py)
I believe this is broken because concurrent.futures has a classic lazy import hack:
|
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}") |
I think there are two issues:
- Lazy imports ideally shouldn't break this hack, unless there's something fundamental that can't be fixed
- This hack should be replaced with lazy imports (now that
=none has been removed, it should be safe)
CPython versions tested on:
3.15
Operating systems tested on:
macOS
Linked PRs
Bug report
Bug description:
Under 3.15, this doesn't work:
(I'm running with
uv run --python=3.15 lazy.py) Without the lazy this works. If you uselazy import concurrent.futuresit works. It also breaks in__lazy_modules__form (which is how I ran into it). It breaks withThreadPoolExecutortoo.The (rather poor) error message:
I believe this is broken because
concurrent.futureshas a classic lazy import hack:cpython/Lib/concurrent/futures/__init__.py
Lines 50 to 65 in b980552
I think there are two issues:
=nonehas been removed, it should be safe)CPython versions tested on:
3.15
Operating systems tested on:
macOS
Linked PRs