diff options
-rw-r--r-- | Lib/test/test_importlib/partial/cfimport.py | 38 | ||||
-rw-r--r-- | Lib/test/test_importlib/partial/pool_in_threads.py | 27 | ||||
-rw-r--r-- | Lib/test/test_importlib/test_threaded_import.py | 14 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Core and Builtins/2021-03-16-17-12-54.bpo-43517.zAo6Ws.rst | 2 | ||||
-rw-r--r-- | Python/import.c | 2 |
5 files changed, 81 insertions, 2 deletions
diff --git a/Lib/test/test_importlib/partial/cfimport.py b/Lib/test/test_importlib/partial/cfimport.py new file mode 100644 index 0000000000..c92d2fe1dd --- /dev/null +++ b/Lib/test/test_importlib/partial/cfimport.py @@ -0,0 +1,38 @@ +import os +import sys +import threading +import traceback + + +NLOOPS = 50 +NTHREADS = 30 + + +def t1(): + try: + from concurrent.futures import ThreadPoolExecutor + except Exception: + traceback.print_exc() + os._exit(1) + +def t2(): + try: + from concurrent.futures.thread import ThreadPoolExecutor + except Exception: + traceback.print_exc() + os._exit(1) + +def main(): + for j in range(NLOOPS): + threads = [] + for i in range(NTHREADS): + threads.append(threading.Thread(target=t2 if i % 1 else t1)) + for thread in threads: + thread.start() + for thread in threads: + thread.join() + sys.modules.pop('concurrent.futures', None) + sys.modules.pop('concurrent.futures.thread', None) + +if __name__ == "__main__": + main() diff --git a/Lib/test/test_importlib/partial/pool_in_threads.py b/Lib/test/test_importlib/partial/pool_in_threads.py new file mode 100644 index 0000000000..faa7867b81 --- /dev/null +++ b/Lib/test/test_importlib/partial/pool_in_threads.py @@ -0,0 +1,27 @@ +import multiprocessing +import os +import threading +import traceback + + +def t(): + try: + with multiprocessing.Pool(1): + pass + except Exception: + traceback.print_exc() + os._exit(1) + + +def main(): + threads = [] + for i in range(20): + threads.append(threading.Thread(target=t)) + for thread in threads: + thread.start() + for thread in threads: + thread.join() + + +if __name__ == "__main__": + main() diff --git a/Lib/test/test_importlib/test_threaded_import.py b/Lib/test/test_importlib/test_threaded_import.py index c6a6e1715a..03bde96de6 100644 --- a/Lib/test/test_importlib/test_threaded_import.py +++ b/Lib/test/test_importlib/test_threaded_import.py @@ -17,7 +17,7 @@ from unittest import mock from test.support import (verbose, run_unittest) from test.support.import_helper import forget from test.support.os_helper import (TESTFN, unlink, rmtree) -from test.support import threading_helper +from test.support import script_helper, threading_helper def task(N, done, done_tasks, errors): try: @@ -245,6 +245,18 @@ class ThreadedImportTests(unittest.TestCase): __import__(TESTFN) del sys.modules[TESTFN] + def test_concurrent_futures_circular_import(self): + # Regression test for bpo-43515 + fn = os.path.join(os.path.dirname(__file__), + 'partial', 'cfimport.py') + script_helper.assert_python_ok(fn) + + def test_multiprocessing_pool_circular_import(self): + # Regression test for bpo-41567 + fn = os.path.join(os.path.dirname(__file__), + 'partial', 'pool_in_threads.py') + script_helper.assert_python_ok(fn) + @threading_helper.reap_threads def test_main(): diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-03-16-17-12-54.bpo-43517.zAo6Ws.rst b/Misc/NEWS.d/next/Core and Builtins/2021-03-16-17-12-54.bpo-43517.zAo6Ws.rst new file mode 100644 index 0000000000..0f9926b93f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2021-03-16-17-12-54.bpo-43517.zAo6Ws.rst @@ -0,0 +1,2 @@ +Fix misdetection of circular imports when using ``from pkg.mod import +attr``, which caused false positives in non-trivial multi-threaded code. diff --git a/Python/import.c b/Python/import.c index 538db69af6..d92e46aa67 100644 --- a/Python/import.c +++ b/Python/import.c @@ -1593,7 +1593,7 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals, } if (mod != NULL && mod != Py_None) { - if (import_ensure_initialized(tstate->interp, mod, name) < 0) { + if (import_ensure_initialized(tstate->interp, mod, abs_name) < 0) { goto error; } } |