summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Heimes <christian@python.org>2022-06-10 21:56:26 (GMT)
committerGitHub <noreply@github.com>2022-06-10 21:56:26 (GMT)
commit09243b898a13f3f61e275c1031143d1225e70916 (patch)
treefe8d33df19d464585d2f4391c262b225834f3f28
parentcf730b595eea0460a7305205f7dfb6ecf0346351 (diff)
downloadcpython-09243b898a13f3f61e275c1031143d1225e70916.zip
cpython-09243b898a13f3f61e275c1031143d1225e70916.tar.gz
cpython-09243b898a13f3f61e275c1031143d1225e70916.tar.bz2
gh-93461: Invalidate sys.path_importer_cache entries with relative paths (GH-93653)
-rw-r--r--Lib/importlib/_bootstrap_external.py13
-rw-r--r--Lib/test/test_import/__init__.py14
-rw-r--r--Lib/test/test_importlib/import_/test_path.py15
-rw-r--r--Lib/test/test_importlib/test_api.py2
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2022-06-09-19-19-02.gh-issue-93461.5DqP1e.rst6
5 files changed, 36 insertions, 14 deletions
diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py
index 1b66542..8605c2a 100644
--- a/Lib/importlib/_bootstrap_external.py
+++ b/Lib/importlib/_bootstrap_external.py
@@ -1399,7 +1399,9 @@ class PathFinder:
"""Call the invalidate_caches() method on all path entry finders
stored in sys.path_importer_caches (where implemented)."""
for name, finder in list(sys.path_importer_cache.items()):
- if finder is None:
+ # Drop entry if finder name is a relative path. The current
+ # working directory may have changed.
+ if finder is None or not _path_isabs(name):
del sys.path_importer_cache[name]
elif hasattr(finder, 'invalidate_caches'):
finder.invalidate_caches()
@@ -1567,9 +1569,12 @@ class FileFinder:
loaders.extend((suffix, loader) for suffix in suffixes)
self._loaders = loaders
# Base (directory) path
- self.path = path or '.'
- if not _path_isabs(self.path):
- self.path = _path_join(_os.getcwd(), self.path)
+ if not path or path == '.':
+ self.path = _os.getcwd()
+ elif not _path_isabs(path):
+ self.path = _path_join(_os.getcwd(), path)
+ else:
+ self.path = path
self._path_mtime = -1
self._path_cache = set()
self._relaxed_path_cache = set()
diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py
index be2e91d..8357586 100644
--- a/Lib/test/test_import/__init__.py
+++ b/Lib/test/test_import/__init__.py
@@ -927,7 +927,7 @@ class PycacheTests(unittest.TestCase):
m = __import__(TESTFN)
try:
self.assertEqual(m.__file__,
- os.path.join(os.getcwd(), os.curdir, os.path.relpath(pyc_file)))
+ os.path.join(os.getcwd(), os.path.relpath(pyc_file)))
finally:
os.remove(pyc_file)
@@ -935,7 +935,7 @@ class PycacheTests(unittest.TestCase):
# Modules now also have an __cached__ that points to the pyc file.
m = __import__(TESTFN)
pyc_file = importlib.util.cache_from_source(TESTFN + '.py')
- self.assertEqual(m.__cached__, os.path.join(os.getcwd(), os.curdir, pyc_file))
+ self.assertEqual(m.__cached__, os.path.join(os.getcwd(), pyc_file))
@skip_if_dont_write_bytecode
def test___cached___legacy_pyc(self):
@@ -951,7 +951,7 @@ class PycacheTests(unittest.TestCase):
importlib.invalidate_caches()
m = __import__(TESTFN)
self.assertEqual(m.__cached__,
- os.path.join(os.getcwd(), os.curdir, os.path.relpath(pyc_file)))
+ os.path.join(os.getcwd(), os.path.relpath(pyc_file)))
@skip_if_dont_write_bytecode
def test_package___cached__(self):
@@ -971,10 +971,10 @@ class PycacheTests(unittest.TestCase):
m = __import__('pep3147.foo')
init_pyc = importlib.util.cache_from_source(
os.path.join('pep3147', '__init__.py'))
- self.assertEqual(m.__cached__, os.path.join(os.getcwd(), os.curdir, init_pyc))
+ self.assertEqual(m.__cached__, os.path.join(os.getcwd(), init_pyc))
foo_pyc = importlib.util.cache_from_source(os.path.join('pep3147', 'foo.py'))
self.assertEqual(sys.modules['pep3147.foo'].__cached__,
- os.path.join(os.getcwd(), os.curdir, foo_pyc))
+ os.path.join(os.getcwd(), foo_pyc))
def test_package___cached___from_pyc(self):
# Like test___cached__ but ensuring __cached__ when imported from a
@@ -998,10 +998,10 @@ class PycacheTests(unittest.TestCase):
m = __import__('pep3147.foo')
init_pyc = importlib.util.cache_from_source(
os.path.join('pep3147', '__init__.py'))
- self.assertEqual(m.__cached__, os.path.join(os.getcwd(), os.curdir, init_pyc))
+ self.assertEqual(m.__cached__, os.path.join(os.getcwd(), init_pyc))
foo_pyc = importlib.util.cache_from_source(os.path.join('pep3147', 'foo.py'))
self.assertEqual(sys.modules['pep3147.foo'].__cached__,
- os.path.join(os.getcwd(), os.curdir, foo_pyc))
+ os.path.join(os.getcwd(), foo_pyc))
def test_recompute_pyc_same_second(self):
# Even when the source file doesn't change timestamp, a change in
diff --git a/Lib/test/test_importlib/import_/test_path.py b/Lib/test/test_importlib/import_/test_path.py
index 6f1d0ca..de62084 100644
--- a/Lib/test/test_importlib/import_/test_path.py
+++ b/Lib/test/test_importlib/import_/test_path.py
@@ -202,10 +202,11 @@ class FinderTests:
def invalidate_caches(self):
self.called = True
- cache = {'leave_alone': object(), 'finder_to_invalidate': FakeFinder()}
+ key = os.path.abspath('finder_to_invalidate')
+ cache = {'leave_alone': object(), key: FakeFinder()}
with util.import_state(path_importer_cache=cache):
self.machinery.PathFinder.invalidate_caches()
- self.assertTrue(cache['finder_to_invalidate'].called)
+ self.assertTrue(cache[key].called)
def test_invalidate_caches_clear_out_None(self):
# Clear out None in sys.path_importer_cache() when invalidating caches.
@@ -214,6 +215,16 @@ class FinderTests:
self.machinery.PathFinder.invalidate_caches()
self.assertEqual(len(cache), 0)
+ def test_invalidate_caches_clear_out_relative_path(self):
+ class FakeFinder:
+ def invalidate_caches(self):
+ pass
+
+ cache = {'relative_path': FakeFinder()}
+ with util.import_state(path_importer_cache=cache):
+ self.machinery.PathFinder.invalidate_caches()
+ self.assertEqual(cache, {})
+
class FindModuleTests(FinderTests):
def find(self, *args, **kwargs):
diff --git a/Lib/test/test_importlib/test_api.py b/Lib/test/test_importlib/test_api.py
index ddf8094..e94a48f 100644
--- a/Lib/test/test_importlib/test_api.py
+++ b/Lib/test/test_importlib/test_api.py
@@ -396,7 +396,7 @@ class InvalidateCacheTests:
def invalidate_caches(self):
self.called = True
- key = 'gobledeegook'
+ key = os.path.abspath('gobledeegook')
meta_ins = InvalidatingNullFinder()
path_ins = InvalidatingNullFinder()
sys.meta_path.insert(0, meta_ins)
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-09-19-19-02.gh-issue-93461.5DqP1e.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-09-19-19-02.gh-issue-93461.5DqP1e.rst
new file mode 100644
index 0000000..f6ed148
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2022-06-09-19-19-02.gh-issue-93461.5DqP1e.rst
@@ -0,0 +1,6 @@
+:func:`importlib.invalidate_caches` now drops entries from
+:data:`sys.path_importer_cache` with a relative path as name. This solves a
+caching issue when a process changes its current working directory.
+
+``FileFinder`` no longer inserts a dot in the path, e.g.
+``/egg/./spam`` is now ``/egg/spam``.