Skip to content

Commit ac17ed6

Browse files
authored
[3.9] bpo-43517: Fix false positive in detection of circular imports (GH-24895) (GH-24948)
(cherry picked from commit 2fd16ef) Co-authored-by: Antoine Pitrou <[email protected]> Automerge-Triggered-By: GH:pitrou
1 parent e8e3419 commit ac17ed6

File tree

5 files changed

+81
-2
lines changed

5 files changed

+81
-2
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import os
2+
import sys
3+
import threading
4+
import traceback
5+
6+
7+
NLOOPS = 50
8+
NTHREADS = 30
9+
10+
11+
def t1():
12+
try:
13+
from concurrent.futures import ThreadPoolExecutor
14+
except Exception:
15+
traceback.print_exc()
16+
os._exit(1)
17+
18+
def t2():
19+
try:
20+
from concurrent.futures.thread import ThreadPoolExecutor
21+
except Exception:
22+
traceback.print_exc()
23+
os._exit(1)
24+
25+
def main():
26+
for j in range(NLOOPS):
27+
threads = []
28+
for i in range(NTHREADS):
29+
threads.append(threading.Thread(target=t2 if i % 1 else t1))
30+
for thread in threads:
31+
thread.start()
32+
for thread in threads:
33+
thread.join()
34+
sys.modules.pop('concurrent.futures', None)
35+
sys.modules.pop('concurrent.futures.thread', None)
36+
37+
if __name__ == "__main__":
38+
main()
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import multiprocessing
2+
import os
3+
import threading
4+
import traceback
5+
6+
7+
def t():
8+
try:
9+
with multiprocessing.Pool(1):
10+
pass
11+
except Exception:
12+
traceback.print_exc()
13+
os._exit(1)
14+
15+
16+
def main():
17+
threads = []
18+
for i in range(20):
19+
threads.append(threading.Thread(target=t))
20+
for thread in threads:
21+
thread.start()
22+
for thread in threads:
23+
thread.join()
24+
25+
26+
if __name__ == "__main__":
27+
main()

Lib/test/test_importlib/test_threaded_import.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from unittest import mock
1717
from test.support import (
1818
verbose, run_unittest, TESTFN, reap_threads,
19-
forget, unlink, rmtree, start_threads)
19+
forget, unlink, rmtree, start_threads, script_helper)
2020

2121
def task(N, done, done_tasks, errors):
2222
try:
@@ -244,6 +244,18 @@ def target():
244244
__import__(TESTFN)
245245
del sys.modules[TESTFN]
246246

247+
def test_concurrent_futures_circular_import(self):
248+
# Regression test for bpo-43515
249+
fn = os.path.join(os.path.dirname(__file__),
250+
'partial', 'cfimport.py')
251+
script_helper.assert_python_ok(fn)
252+
253+
def test_multiprocessing_pool_circular_import(self):
254+
# Regression test for bpo-41567
255+
fn = os.path.join(os.path.dirname(__file__),
256+
'partial', 'pool_in_threads.py')
257+
script_helper.assert_python_ok(fn)
258+
247259

248260
@reap_threads
249261
def test_main():
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix misdetection of circular imports when using ``from pkg.mod import
2+
attr``, which caused false positives in non-trivial multi-threaded code.

Python/import.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1863,7 +1863,7 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *globals,
18631863
}
18641864

18651865
if (mod != NULL && mod != Py_None) {
1866-
if (import_ensure_initialized(tstate, mod, name) < 0) {
1866+
if (import_ensure_initialized(tstate, mod, abs_name) < 0) {
18671867
goto error;
18681868
}
18691869
}

0 commit comments

Comments
 (0)