Kaydet (Commit) b46a1793 authored tarafından Brett Cannon's avatar Brett Cannon

Update importlib.invalidate_caches() to be more general.

üst 9a4d7ddb
......@@ -88,9 +88,12 @@ Functions
.. function:: invalidate_caches()
Invalidate importlib's internal caches. Calling this function may be
needed if some modules are installed while your program is running and
you expect the program to notice the changes.
Invalidate the internal caches of the finders stored at
:data:`sys.path_importer_cache`. If a finder implements
:meth:`abc.Finder.invalidate_caches()` then it will be called to perform the
invalidation. This function may be needed if some modules are installed
while your program is running and you expect the program to notice the
changes.
.. versionadded:: 3.3
......@@ -119,6 +122,12 @@ are also provided to help in implementing the core ABCs.
be the value of :attr:`__path__` from the parent package. If a loader
cannot be found, ``None`` is returned.
.. method:: invalidate_caches()
An optional method which, when called, should invalidate any internal
cache used by the finder. Used by :func:`invalidate_caches()` when
invalidating the caches of all cached finders.
.. class:: Loader
......
"""A pure Python implementation of import.
References on import:
* Language reference
http://docs.python.org/ref/import.html
* __import__ function
http://docs.python.org/lib/built-in-funcs.html
* Packages
http://www.python.org/doc/essays/packages.html
* PEP 235: Import on Case-Insensitive Platforms
http://www.python.org/dev/peps/pep-0235
* PEP 275: Import Modules from Zip Archives
http://www.python.org/dev/peps/pep-0273
* PEP 302: New Import Hooks
http://www.python.org/dev/peps/pep-0302/
* PEP 328: Imports: Multi-line and Absolute/Relative
http://www.python.org/dev/peps/pep-0328
"""
"""A pure Python implementation of import."""
__all__ = ['__import__', 'import_module', 'invalidate_caches']
from . import _bootstrap
......@@ -37,7 +18,15 @@ _bootstrap._setup(sys, imp)
# Public API #########################################################
from ._bootstrap import __import__, invalidate_caches
from ._bootstrap import __import__
def invalidate_caches():
"""Call the invalidate_caches() method on all finders stored in
sys.path_importer_caches (where implemented)."""
for finder in sys.path_importer_cache.values():
if hasattr(finder, 'invalidate_caches'):
finder.invalidate_caches()
def import_module(name, package=None):
......
......@@ -160,17 +160,6 @@ code_type = type(_wrap.__code__)
# Finder/loader utility code ##################################################
_cache_refresh = 0
def invalidate_caches():
"""Invalidate importlib's internal caches.
Calling this function may be needed if some modules are installed while
your program is running and you expect the program to notice the changes.
"""
global _cache_refresh
_cache_refresh += 1
def set_package(fxn):
"""Set __package__ on the returned module."""
......@@ -768,7 +757,10 @@ class _FileFinder:
self._path_mtime = -1
self._path_cache = set()
self._relaxed_path_cache = set()
self._cache_refresh = 0
def invalidate_caches(self):
"""Invalidate the directory mtime."""
self._path_mtime = -1
def find_module(self, fullname):
"""Try to find a loader for the specified module."""
......@@ -777,10 +769,9 @@ class _FileFinder:
mtime = _os.stat(self.path).st_mtime
except OSError:
mtime = -1
if mtime != self._path_mtime or _cache_refresh != self._cache_refresh:
if mtime != self._path_mtime:
self._fill_cache()
self._path_mtime = mtime
self._cache_refresh = _cache_refresh
# tail_module keeps the original casing, for __file__ and friends
if _relax_case():
cache = self._relaxed_path_cache
......
......@@ -143,6 +143,13 @@ class FinderTests(abc.FinderTests):
finally:
os.unlink('mod.py')
def test_invalidate_caches(self):
# invalidate_caches() should reset the mtime.
finder = _bootstrap._FileFinder('', _bootstrap._SourceFinderDetails())
finder._path_mtime = 42
finder.invalidate_caches()
self.assertEqual(finder._path_mtime, -1)
def test_main():
from test.support import run_unittest
......
......@@ -84,6 +84,34 @@ class ImportModuleTests(unittest.TestCase):
importlib.import_module('a.b')
self.assertEqual(b_load_count, 1)
class InvalidateCacheTests(unittest.TestCase):
def test_method_called(self):
# If defined the method should be called.
class InvalidatingNullFinder:
def __init__(self, *ignored):
self.called = False
def find_module(self, *args):
return None
def invalidate_caches(self):
self.called = True
key = 'gobledeegook'
ins = InvalidatingNullFinder()
sys.path_importer_cache[key] = ins
self.addCleanup(lambda: sys.path_importer_cache.__delitem__(key))
importlib.invalidate_caches()
self.assertTrue(ins.called)
def test_method_lacking(self):
# There should be no issues if the method is not defined.
key = 'gobbledeegook'
sys.path_importer_cache[key] = imp.NullImporter('abc')
self.addCleanup(lambda: sys.path_importer_cache.__delitem__(key))
importlib.invalidate_caches() # Shouldn't trigger an exception.
def test_main():
from test.support import run_unittest
run_unittest(ImportModuleTests)
......
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