mirror of
https://github.com/python/cpython.git
synced 2025-11-03 19:34:08 +00:00
bpo-30814: Fixed a race condition when import a submodule from a package. (#2580)
This commit is contained in:
parent
1ccbad9c95
commit
b4baacee1a
7 changed files with 352 additions and 337 deletions
|
|
@ -956,9 +956,19 @@ def _find_and_load_unlocked(name, import_):
|
|||
|
||||
|
||||
def _find_and_load(name, import_):
|
||||
"""Find and load the module, and release the import lock."""
|
||||
with _ModuleLockManager(name):
|
||||
return _find_and_load_unlocked(name, import_)
|
||||
"""Find and load the module."""
|
||||
_imp.acquire_lock()
|
||||
if name not in sys.modules:
|
||||
with _ModuleLockManager(name):
|
||||
return _find_and_load_unlocked(name, import_)
|
||||
module = sys.modules[name]
|
||||
if module is None:
|
||||
_imp.release_lock()
|
||||
message = ('import of {} halted; '
|
||||
'None in sys.modules'.format(name))
|
||||
raise ModuleNotFoundError(message, name=name)
|
||||
_lock_unlock_module(name)
|
||||
return module
|
||||
|
||||
|
||||
def _gcd_import(name, package=None, level=0):
|
||||
|
|
@ -973,17 +983,7 @@ def _gcd_import(name, package=None, level=0):
|
|||
_sanity_check(name, package, level)
|
||||
if level > 0:
|
||||
name = _resolve_name(name, package, level)
|
||||
_imp.acquire_lock()
|
||||
if name not in sys.modules:
|
||||
return _find_and_load(name, _gcd_import)
|
||||
module = sys.modules[name]
|
||||
if module is None:
|
||||
_imp.release_lock()
|
||||
message = ('import of {} halted; '
|
||||
'None in sys.modules'.format(name))
|
||||
raise ModuleNotFoundError(message, name=name)
|
||||
_lock_unlock_module(name)
|
||||
return module
|
||||
return _find_and_load(name, _gcd_import)
|
||||
|
||||
|
||||
def _handle_fromlist(module, fromlist, import_):
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ import py_compile
|
|||
import random
|
||||
import stat
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
import unittest
|
||||
import unittest.mock as mock
|
||||
import textwrap
|
||||
|
|
@ -380,6 +382,32 @@ class ImportTests(unittest.TestCase):
|
|||
self.assertEqual(str(cm.exception),
|
||||
"cannot import name 'does_not_exist' from '<unknown module name>' (unknown location)")
|
||||
|
||||
def test_concurrency(self):
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'data'))
|
||||
try:
|
||||
exc = None
|
||||
def run():
|
||||
event.wait()
|
||||
try:
|
||||
import package
|
||||
except BaseException as e:
|
||||
nonlocal exc
|
||||
exc = e
|
||||
|
||||
for i in range(10):
|
||||
event = threading.Event()
|
||||
threads = [threading.Thread(target=run) for x in range(2)]
|
||||
try:
|
||||
with test.support.start_threads(threads, event.set):
|
||||
time.sleep(0)
|
||||
finally:
|
||||
sys.modules.pop('package', None)
|
||||
sys.modules.pop('package.submodule', None)
|
||||
if exc is not None:
|
||||
raise exc
|
||||
finally:
|
||||
del sys.path[0]
|
||||
|
||||
|
||||
@skip_if_dont_write_bytecode
|
||||
class FilePermissionTests(unittest.TestCase):
|
||||
|
|
|
|||
2
Lib/test/test_import/data/package/__init__.py
Normal file
2
Lib/test/test_import/data/package/__init__.py
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
import package.submodule
|
||||
package.submodule
|
||||
0
Lib/test/test_import/data/package/submodule.py
Normal file
0
Lib/test/test_import/data/package/submodule.py
Normal file
Loading…
Add table
Add a link
Reference in a new issue