Commit 9e2be606 authored by Brett Cannon's avatar Brett Cannon Committed by GitHub

bpo-33169: Remove values of `None` from sys.path_importer_cache when invalidating caches (GH-6402)

An entry of None in sys.path_importer_cache represents a negative/missing finder for a path, so clearing it out makes sense.
parent 3a9ccee0
......@@ -1081,7 +1081,12 @@ find and load modules.
.. classmethod:: invalidate_caches()
Calls :meth:`importlib.abc.PathEntryFinder.invalidate_caches` on all
finders stored in :attr:`sys.path_importer_cache`.
finders stored in :data:`sys.path_importer_cache` that define the method.
Otherwise entries in :data:`sys.path_importer_cache` set to ``None`` are
deleted.
.. versionchanged:: 3.7
Entries of ``None`` in :data:`sys.path_importer_cache` are deleted.
.. versionchanged:: 3.4
Calls objects in :data:`sys.path_hooks` with the current working
......
......@@ -1181,8 +1181,10 @@ class PathFinder:
def invalidate_caches(cls):
"""Call the invalidate_caches() method on all path entry finders
stored in sys.path_importer_caches (where implemented)."""
for finder in sys.path_importer_cache.values():
if hasattr(finder, 'invalidate_caches'):
for name, finder in list(sys.path_importer_cache.items()):
if finder is None:
del sys.path_importer_cache[name]
elif hasattr(finder, 'invalidate_caches'):
finder.invalidate_caches()
@classmethod
......
......@@ -184,6 +184,27 @@ class FinderTests:
# Do not want FileNotFoundError raised.
self.assertIsNone(self.machinery.PathFinder.find_spec('whatever'))
def test_invalidate_caches_finders(self):
# Finders with an invalidate_caches() method have it called.
class FakeFinder:
def __init__(self):
self.called = False
def invalidate_caches(self):
self.called = True
cache = {'leave_alone': object(), 'finder_to_invalidate': FakeFinder()}
with util.import_state(path_importer_cache=cache):
self.machinery.PathFinder.invalidate_caches()
self.assertTrue(cache['finder_to_invalidate'].called)
def test_invalidate_caches_clear_out_None(self):
# Clear out None in sys.path_importer_cache() when invalidating caches.
cache = {'clear_out': None}
with util.import_state(path_importer_cache=cache):
self.machinery.PathFinder.invalidate_caches()
self.assertEqual(len(cache), 0)
class FindModuleTests(FinderTests):
def find(self, *args, **kwargs):
......
......@@ -406,7 +406,7 @@ class InvalidateCacheTests:
# There should be no issues if the method is not defined.
key = 'gobbledeegook'
sys.path_importer_cache[key] = None
self.addCleanup(lambda: sys.path_importer_cache.__delitem__(key))
self.addCleanup(lambda: sys.path_importer_cache.pop(key, None))
self.init.invalidate_caches() # Shouldn't trigger an exception.
......
Delete entries of ``None`` in :data:`sys.path_importer_cache` when
:meth:`importlib.machinery.invalidate_caches` is called.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment