@@ -786,6 +786,24 @@ def find_distributions(self, context=Context()) -> Iterable[Distribution]:
786786 """
787787
788788
789+ def _clear_lru_cache_after_fork (func ):
790+ """Wrap ``func`` with ``functools.lru_cache`` and clear it after ``fork``.
791+
792+ ``FastPath`` caches zip-backed ``pathlib.Path`` objects that keep a
793+ reference to the parent's open ``ZipFile`` handle. Re-using a cached
794+ instance in a forked child can therefore resurrect invalid file pointers
795+ and trigger ``BadZipFile``/``OSError`` failures (python/importlib_metadata#520).
796+ Registering ``cache_clear`` with ``os.register_at_fork`` ensures every
797+ process gets a pristine cache and opens its own archive handles.
798+ """
799+
800+ cached = functools .lru_cache ()(func )
801+ register = getattr (os , 'register_at_fork' , None )
802+ if register is not None :
803+ register (after_in_child = cached .cache_clear )
804+ return cached
805+
806+
789807class FastPath :
790808 """
791809 Micro-optimized class for searching a root for children.
@@ -802,8 +820,7 @@ class FastPath:
802820 True
803821 """
804822
805- # The following cache is cleared at fork, see os.register_at_fork below
806- @functools .lru_cache () # type: ignore[misc]
823+ @_clear_lru_cache_after_fork # type: ignore[misc]
807824 def __new__ (cls , root ):
808825 return super ().__new__ (cls )
809826
@@ -843,11 +860,6 @@ def mtime(self):
843860 def lookup (self , mtime ):
844861 return Lookup (self )
845862
846- # Clear FastPath.__new__ cache when forked, avoids trying to re-useing open
847- # file pointers from zipp.Path/zipfile.Path objects in forked process
848- os .register_at_fork (after_in_child = FastPath .__new__ .cache_clear )
849-
850-
851863class Lookup :
852864 """
853865 A micro-optimized class for searching a (fast) path for metadata.
0 commit comments