diff --git a/Lib/test/test_zipfile/_path/test_path.py b/Lib/test/test_zipfile/_path/test_path.py index e7931b6f394075d..f6fac6f441e2605 100644 --- a/Lib/test/test_zipfile/_path/test_path.py +++ b/Lib/test/test_zipfile/_path/test_path.py @@ -551,6 +551,18 @@ def test_is_symlink(self, alpharep): assert not root.joinpath('a.txt').is_symlink() assert root.joinpath('n.txt').is_symlink() + @pass_alpharep + def test_is_symlink_missing(self, alpharep): + """ + is_symlink returns False for entries missing from the archive + (including the root and implied directories) rather than + raising KeyError. + """ + root = zipfile.Path(alpharep) + assert not root.is_symlink() + assert not root.joinpath('b').is_symlink() + assert not root.joinpath('missing.txt').is_symlink() + @pass_alpharep def test_relative_to(self, alpharep): root = zipfile.Path(alpharep) diff --git a/Lib/zipfile/_path/__init__.py b/Lib/zipfile/_path/__init__.py index faae4c84cae5ed2..a815f4d8bfff133 100644 --- a/Lib/zipfile/_path/__init__.py +++ b/Lib/zipfile/_path/__init__.py @@ -414,7 +414,10 @@ def is_symlink(self): """ Return whether this path is a symlink. """ - info = self.root.getinfo(self.at) + try: + info = self.root.getinfo(self.at) + except KeyError: + return False mode = info.external_attr >> 16 return stat.S_ISLNK(mode) diff --git a/Misc/NEWS.d/next/Library/2026-07-02-11-24-08.gh-issue-152762.qL7vXe.rst b/Misc/NEWS.d/next/Library/2026-07-02-11-24-08.gh-issue-152762.qL7vXe.rst new file mode 100644 index 000000000000000..bed2fa7cecfb5e1 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-07-02-11-24-08.gh-issue-152762.qL7vXe.rst @@ -0,0 +1,3 @@ +Fix :meth:`zipfile.Path.is_symlink` raising :exc:`KeyError` for paths not +present in the archive. It now returns ``False``, consistent with the other +:class:`zipfile.Path` predicates and with :meth:`pathlib.Path.is_symlink`.