diff --git a/src/specify_cli/bundler/services/adapters.py b/src/specify_cli/bundler/services/adapters.py index f6a1d466ba..ca39a2489b 100644 --- a/src/specify_cli/bundler/services/adapters.py +++ b/src/specify_cli/bundler/services/adapters.py @@ -18,7 +18,7 @@ from ..._assets import _locate_core_pack, _repo_root from ..._download_security import MAX_JSON_CATALOG_BYTES, read_response_limited from .. import BundlerError -from ..lib.yamlio import loads_json +from ..lib.yamlio import load_json, loads_json from ..models.catalog import CatalogSource from ..models.manifest import ComponentRef @@ -145,13 +145,13 @@ def fetch(source: CatalogSource) -> dict: path = _file_url_to_path(parsed) if not path.exists(): raise BundlerError(f"Catalog file not found: {path}") - return loads_json(path.read_text(encoding="utf-8"), origin=str(path)) + return load_json(path) if scheme == "" or _is_windows_drive_path(url): path = Path(url) if not path.exists(): raise BundlerError(f"Catalog file not found: {path}") - return loads_json(path.read_text(encoding="utf-8"), origin=str(path)) + return load_json(path) if scheme in ("http", "https"): if not allow_network: diff --git a/tests/unit/test_bundler_adapters.py b/tests/unit/test_bundler_adapters.py index 5ce9e10a12..854e60df3f 100644 --- a/tests/unit/test_bundler_adapters.py +++ b/tests/unit/test_bundler_adapters.py @@ -104,6 +104,18 @@ def test_fetch_rejects_malformed_source_url_cleanly(url): fetcher(_source(url)) +@pytest.mark.parametrize("use_file_url", [False, True], ids=["path", "file-url"]) +def test_local_catalog_decode_errors_are_wrapped(tmp_path, use_file_url): + catalog_path = tmp_path / "catalog.json" + catalog_path.write_bytes(b"\xff\xfe") + url = catalog_path.as_uri() if use_file_url else str(catalog_path) + + fetcher = adapters.make_catalog_fetcher(allow_network=False) + + with pytest.raises(BundlerError, match="Could not read"): + fetcher(_source(url)) + + def test_builtin_community_catalog_fetches_repository_catalog_online(monkeypatch): captured: dict = {}