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