From fbce24d4a34922ec9d40a7af7927fbcebbbb0206 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Sat, 30 Jan 2021 15:38:44 +0100 Subject: Handle KeyError for unknown resources When importlib.resources (or the importlib_resources backport) uses zipfile.Path in the Python 3.8/3.9 stdlib (rather than the zipp backport), we get KeyError rather than a FileNotFoundError if a resource does not exist. See https://bugs.python.org/issue43063. We work around this by re-raising a KeyError as FileNotFoundError. Fixes #6086 (cherry picked from commit 9313523ae144f350ce5c930e735ba9257c34067e) --- qutebrowser/utils/utils.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/qutebrowser/utils/utils.py b/qutebrowser/utils/utils.py index 5e4c418ff..a52c5fada 100644 --- a/qutebrowser/utils/utils.py +++ b/qutebrowser/utils/utils.py @@ -192,6 +192,21 @@ def _resource_path(filename: str) -> pathlib.Path: return importlib_resources.files(qutebrowser) / filename +@contextlib.contextmanager +def _resource_keyerror_workaround() -> Iterator[None]: + """Re-raise KeyErrors as FileNotFoundErrors. + + WORKAROUND for zipfile.Path resources raising KeyError when a file was notfound: + https://bugs.python.org/issue43063 + + Only needed for Python 3.8 and 3.9. + """ + try: + yield + except KeyError as e: + raise FileNotFoundError(str(e)) + + def _glob_resources( resource_path: pathlib.Path, subdir: str, @@ -240,7 +255,8 @@ def read_file(filename: str) -> str: return _resource_cache[filename] path = _resource_path(filename) - return path.read_text(encoding='utf-8') + with _resource_keyerror_workaround(): + return path.read_text(encoding='utf-8') def read_file_binary(filename: str) -> bytes: @@ -253,7 +269,8 @@ def read_file_binary(filename: str) -> bytes: The file contents as a bytes object. """ path = _resource_path(filename) - return path.read_bytes() + with _resource_keyerror_workaround(): + return path.read_bytes() def parse_version(version: str) -> VersionNumber: -- cgit v1.2.3-54-g00ecf