mirror of
https://github.com/python/cpython.git
synced 2025-12-08 06:10:17 +00:00
[3.14] gh-136380: Fix import behavior for concurrent.futures.InterpreterPoolExecutor (GH-136381) (#136420)
gh-136380: Fix import behavior for `concurrent.futures.InterpreterPoolExecutor` (GH-136381)
(cherry picked from commit 490eea0281)
Co-authored-by: AN Long <aisk@users.noreply.github.com>
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
Co-authored-by: Peter Bierma <zintensitydev@gmail.com>
Co-authored-by: sobolevn <mail@sobolevn.me>
This commit is contained in:
parent
0a15ae71ad
commit
f937b9fffb
3 changed files with 62 additions and 17 deletions
|
|
@ -17,7 +17,7 @@
|
||||||
wait,
|
wait,
|
||||||
as_completed)
|
as_completed)
|
||||||
|
|
||||||
__all__ = (
|
__all__ = [
|
||||||
'FIRST_COMPLETED',
|
'FIRST_COMPLETED',
|
||||||
'FIRST_EXCEPTION',
|
'FIRST_EXCEPTION',
|
||||||
'ALL_COMPLETED',
|
'ALL_COMPLETED',
|
||||||
|
|
@ -29,10 +29,18 @@
|
||||||
'Executor',
|
'Executor',
|
||||||
'wait',
|
'wait',
|
||||||
'as_completed',
|
'as_completed',
|
||||||
'InterpreterPoolExecutor',
|
|
||||||
'ProcessPoolExecutor',
|
'ProcessPoolExecutor',
|
||||||
'ThreadPoolExecutor',
|
'ThreadPoolExecutor',
|
||||||
)
|
]
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
import _interpreters
|
||||||
|
except ImportError:
|
||||||
|
_interpreters = None
|
||||||
|
|
||||||
|
if _interpreters:
|
||||||
|
__all__.append('InterpreterPoolExecutor')
|
||||||
|
|
||||||
|
|
||||||
def __dir__():
|
def __dir__():
|
||||||
|
|
@ -43,22 +51,15 @@ def __getattr__(name):
|
||||||
global ProcessPoolExecutor, ThreadPoolExecutor, InterpreterPoolExecutor
|
global ProcessPoolExecutor, ThreadPoolExecutor, InterpreterPoolExecutor
|
||||||
|
|
||||||
if name == 'ProcessPoolExecutor':
|
if name == 'ProcessPoolExecutor':
|
||||||
from .process import ProcessPoolExecutor as pe
|
from .process import ProcessPoolExecutor
|
||||||
ProcessPoolExecutor = pe
|
return ProcessPoolExecutor
|
||||||
return pe
|
|
||||||
|
|
||||||
if name == 'ThreadPoolExecutor':
|
if name == 'ThreadPoolExecutor':
|
||||||
from .thread import ThreadPoolExecutor as te
|
from .thread import ThreadPoolExecutor
|
||||||
ThreadPoolExecutor = te
|
return ThreadPoolExecutor
|
||||||
return te
|
|
||||||
|
|
||||||
if name == 'InterpreterPoolExecutor':
|
if _interpreters and name == 'InterpreterPoolExecutor':
|
||||||
try:
|
from .interpreter import InterpreterPoolExecutor
|
||||||
from .interpreter import InterpreterPoolExecutor as ie
|
return InterpreterPoolExecutor
|
||||||
except ModuleNotFoundError:
|
|
||||||
ie = InterpreterPoolExecutor = None
|
|
||||||
else:
|
|
||||||
InterpreterPoolExecutor = ie
|
|
||||||
return ie
|
|
||||||
|
|
||||||
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@
|
||||||
import contextlib
|
import contextlib
|
||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
import textwrap
|
||||||
import time
|
import time
|
||||||
import unittest
|
import unittest
|
||||||
from concurrent.futures.interpreter import BrokenInterpreterPool
|
from concurrent.futures.interpreter import BrokenInterpreterPool
|
||||||
|
|
@ -457,6 +459,45 @@ def test_free_reference(self):
|
||||||
# Weak references don't cross between interpreters.
|
# Weak references don't cross between interpreters.
|
||||||
raise unittest.SkipTest('not applicable')
|
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("""
|
||||||
|
import sys
|
||||||
|
# Set it to None to emulate the case when _interpreter is unavailable.
|
||||||
|
sys.modules['_interpreters'] = None
|
||||||
|
from concurrent import futures
|
||||||
|
|
||||||
|
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 *
|
||||||
|
|
||||||
|
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):
|
class AsyncioTest(InterpretersMixin, testasyncio_utils.TestCase):
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
Raises :exc:`AttributeError` when accessing
|
||||||
|
:class:`concurrent.futures.InterpreterPoolExecutor` and subinterpreters are
|
||||||
|
not available.
|
||||||
Loading…
Add table
Add a link
Reference in a new issue