diff options
author | Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> | 2022-06-13 06:29:59 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-13 06:29:59 (GMT) |
commit | 3d1c080591910c9c1ee80e5465ce7c91b67c907d (patch) | |
tree | 73ed1543305b638772713e4440565adf7b49baea | |
parent | 536af65e96490689c4d2eccc0afc3323f5763ff8 (diff) | |
download | cpython-3d1c080591910c9c1ee80e5465ce7c91b67c907d.zip cpython-3d1c080591910c9c1ee80e5465ce7c91b67c907d.tar.gz cpython-3d1c080591910c9c1ee80e5465ce7c91b67c907d.tar.bz2 |
gh-93461: Invalidate sys.path_importer_cache entries with relative paths (GH-93653)
(cherry picked from commit 09243b898a13f3f61e275c1031143d1225e70916)
Co-authored-by: Christian Heimes <christian@python.org>
-rw-r--r-- | Lib/importlib/_bootstrap_external.py | 13 | ||||
-rw-r--r-- | Lib/test/test_import/__init__.py | 14 | ||||
-rw-r--r-- | Lib/test/test_importlib/import_/test_path.py | 15 | ||||
-rw-r--r-- | Lib/test/test_importlib/test_api.py | 2 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Core and Builtins/2022-06-09-19-19-02.gh-issue-93461.5DqP1e.rst | 6 |
5 files changed, 36 insertions, 14 deletions
diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 5f67226..0061ad0 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -1394,7 +1394,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() @@ -1562,9 +1564,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 1f8f7c0..1beb783 100644 --- a/Lib/test/test_importlib/test_api.py +++ b/Lib/test/test_importlib/test_api.py @@ -395,7 +395,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``. |