Skip to content
This repository was archived by the owner on Dec 28, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Miscellaneous:
* Rename submodules `json-schema-spec-2019-09` and `json-schema-spec-2020-12` to
`json-schema-2019-09` and `json-schema-2020-12`, respectively
(run ``git submodule init`` to update local git config)
* LocalSource now includes the filename in the CatalogError when the file is not found


v0.10.0 (2023-04-01)
Expand Down
13 changes: 12 additions & 1 deletion jschon/catalog/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,16 @@ def __call__(self, relative_path: str) -> JSONCompatible:
filepath = str(filepath)
filepath += self.suffix

return json_loadf(filepath)
try:
return json_loadf(filepath)
except OSError as e:
if e.filename is not None:
# The filename for OSError is not included in
# the exception args, which is what the Catalog
# puts in the CatalogError. So it needs to be
# added separately for filesystem errors.
raise CatalogError(f'{e.strerror}: {e.filename!r}')
raise


class RemoteSource(Source):
Expand Down Expand Up @@ -136,6 +145,8 @@ def load_json(self, uri: URI) -> JSONCompatible:
relative_path = uristr[len(base_uristr):]
try:
return source(relative_path)
except CatalogError:
raise
except Exception as e:
raise CatalogError(*e.args) from e

Expand Down
18 changes: 18 additions & 0 deletions tests/test_catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import tempfile
import uuid
import itertools
import re

import pytest
from unittest.mock import patch

from jschon import (
Catalog,
Expand Down Expand Up @@ -84,6 +86,22 @@ def test_local_source(base_uri, setup_tmpdir, new_catalog):
new_catalog.load_json(URI(f'{base_uri}{subdir_name}/baz'))


def test_local_source_file_not_found(local_catalog):
stem = 'not-there'
fullname = str(pathlib.Path(__file__).parent / 'data' / f'{stem}.json')
with pytest.raises(CatalogError, match=f"'{re.escape(fullname)}'$"):
local_catalog.get_schema(URI(f'https://example.com/{stem}'))


def test_local_source_ioerror_no_file(local_catalog):
with patch('builtins.open') as m:
# This plain IOError will have an empty string as the message,
# without a filename that triggers different exception handling.
m.side_effect = IOError
with pytest.raises(CatalogError, match=r'^$'):
local_catalog.get_schema(URI('https://example.com/does-not-matter'))


@pytest.mark.parametrize('base_uri', [
'http://example.com/',
'http://example.com/foo/',
Expand Down