mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
[3.9] bpo-45703: Invalidate _NamespacePath cache on importlib.invalidate_cache (GH-29384) (GH-30922) (GH-31076)
Consider the following directory structure: . └── PATH1 └── namespace └── sub1 └── __init__.py And both PATH1 and PATH2 in sys path: $ PYTHONPATH=PATH1:PATH2 python3.11 >>> import namespace >>> import namespace.sub1 >>> namespace.__path__ _NamespacePath(['.../PATH1/namespace']) >>> ... While this interpreter still runs, PATH2/namespace/sub2 is created: . ├── PATH1 │ └── namespace │ └── sub1 │ └── __init__.py └── PATH2 └── namespace └── sub2 └── __init__.py The newly created module cannot be imported: >>> ... >>> namespace.__path__ _NamespacePath(['.../PATH1/namespace']) >>> import namespace.sub2 Traceback (most recent call last): File "<stdin>", line 1, in <module> ModuleNotFoundError: No module named 'namespace.sub2' Calling importlib.invalidate_caches() now newly allows to import it: >>> import importlib >>> importlib.invalidate_caches() >>> namespace.__path__ _NamespacePath(['.../PATH1/namespace']) >>> import namespace.sub2 >>> namespace.__path__ _NamespacePath(['.../PATH1/namespace', '.../PATH2/namespace']) This was not previously possible. Co-Authored-By: Miro Hrončok <miro@hroncok.cz> Automerge-Triggered-By: GH:encukou
This commit is contained in:
parent
0371e5d7f1
commit
8d239bfdcc
4 changed files with 991 additions and 935 deletions
|
@ -1209,10 +1209,15 @@ class _NamespacePath:
|
|||
using path_finder. For top-level modules, the parent module's path
|
||||
is sys.path."""
|
||||
|
||||
# When invalidate_caches() is called, this epoch is incremented
|
||||
# https://bugs.python.org/issue45703
|
||||
_epoch = 0
|
||||
|
||||
def __init__(self, name, path, path_finder):
|
||||
self._name = name
|
||||
self._path = path
|
||||
self._last_parent_path = tuple(self._get_parent_path())
|
||||
self._last_epoch = self._epoch
|
||||
self._path_finder = path_finder
|
||||
|
||||
def _find_parent_path_names(self):
|
||||
|
@ -1232,7 +1237,7 @@ class _NamespacePath:
|
|||
def _recalculate(self):
|
||||
# If the parent's path has changed, recalculate _path
|
||||
parent_path = tuple(self._get_parent_path()) # Make a copy
|
||||
if parent_path != self._last_parent_path:
|
||||
if parent_path != self._last_parent_path or self._epoch != self._last_epoch:
|
||||
spec = self._path_finder(self._name, parent_path)
|
||||
# Note that no changes are made if a loader is returned, but we
|
||||
# do remember the new parent path
|
||||
|
@ -1240,6 +1245,7 @@ class _NamespacePath:
|
|||
if spec.submodule_search_locations:
|
||||
self._path = spec.submodule_search_locations
|
||||
self._last_parent_path = parent_path # Save the copy
|
||||
self._last_epoch = self._epoch
|
||||
return self._path
|
||||
|
||||
def __iter__(self):
|
||||
|
@ -1320,6 +1326,9 @@ class PathFinder:
|
|||
del sys.path_importer_cache[name]
|
||||
elif hasattr(finder, 'invalidate_caches'):
|
||||
finder.invalidate_caches()
|
||||
# Also invalidate the caches of _NamespacePaths
|
||||
# https://bugs.python.org/issue45703
|
||||
_NamespacePath._epoch += 1
|
||||
|
||||
@classmethod
|
||||
def _path_hooks(cls, path):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue