API Documentation
- class jsonschema_pyref.RefResolver(base_uri: str, referrer: Optional[Union[dict, list, str, int, float, bool]], store: Union[dict, tuple] = (), cache_remote: bool = True, handlers: Union[dict, tuple] = (), urljoin_cache: Optional[Callable[[str, str], str]] = None, remote_cache: Optional[Callable[[str], dict]] = None)[source]
Bases:
jsonschema.validators.RefResolverDrop-in replacement for
jsonschema.RefResolverthat can resolvepy-objandpy-pkgdataURLs.The easiest way to use it is to initialize it using the
from_schemamethod and pass it as a keyword argument tojsonschema.validate:>>> import jsonschema >>> from jsonschema_pyref import RefResolver >>> schema = { ... 'properties': { ... 'a': {'$ref': 'py-obj:jsonschema_pyref.examples.schema1'} ... } ... } ... >>> resolver = RefResolver.from_schema(schema) >>> jsonschema.validate({'a': 'hello'}, schema, resolver=resolver) is None True
- jsonschema_pyref.URL_SCHEME_RESOLVERS = {'py-obj': <function _resolve_url_py_obj>, 'py-pkgdata': <function _resolve_url_py_pkgdata>}
Additional URL handlers for the custom URL schemes supported by this package.
This can be passed to the
handlersargument ofjsonschema.RefResolver, but take note: It is also necessary to override theurljoin_cacheargument to usejsonschema_pyref.urljoinas follows:>>> import jonschema >>> from jsonschema_pyref import URL_SCHEME_RESOLVERS, urljoin >>> from functools import lru_cache >>> resolver = RefResolver({}, {}, handlers=URL_SCHEME_RESOLVERS, ... urljoin_cache=lru_cache(1024)(urljoin))
This boilerplate can be avoided entirely by using the supplied
jsonschema_pyref.RefResolverwhich has these enhancements by default (and is otherwise identical tojsonschema.RefResolver).
- exception jsonschema_pyref.ValidationError(message, validator=<unset>, path=(), cause=None, context=(), validator_value=<unset>, instance=<unset>, schema=<unset>, schema_path=(), parent=None)[source]
Bases:
jsonschema.exceptions._ErrorAn instance was invalid under a provided schema.
- jsonschema_pyref.urljoin(base: str, url: str, allow_fragments: bool = True) str[source]
Extends the stdlib’s
urllib.parse.urljointo support the custom URL schemes implemented by this package.The join semantics for
py-objandpy-pkgdataURLs differ from those of typical http-like URLs, as well as from each other.The rules for
py-objare as follows:If joined with a “relative” URL, if the URL starts with a Python identifier, it is simply appended to the current object path:
>>> from jsonschema_pyref import urljoin >>> urljoin('py-obj:a.b.c', 'd.e') 'py-obj:a.b.c.d.e'
However, if the “relative” URL starts with one or more
., it is processed relative to the base path using similar semantics to Python relative imports. That is, one dot means a different attribute of the same object, and so on:>>> urljoin('py-obj:a.b.c', '.d') 'py-obj:a.b.d' >>> urljoin('py-obj:a.b.c', '..d') 'py-obj:a.d' >>> urljoin('py-obj:a.b.c', '..d.e') 'py-obj:a.d.e'
When joining an absolute URL with the
py-objscheme, the new URL replaces the base:>>> urljoin('py-obj:a.b.c', 'py-obj:d.e.f') 'py-obj:d.e.f'
And likewise when joining an absolute URL with an entirely different scheme:
>>> urljoin('py-obj:a.b.c', 'https://example.com') 'https://example.com'
Fragments are dropped from the base URL, and retained from the joined URL:
>>> urljoin('py-obj:a.b.c#replaced', '.d#fragment') 'py-obj:a.b.d#fragment' >>> urljoin('py-obj:a.b.c#replaced', '#fragment') 'py-obj:a.b.c#fragment'
The rules for
py-pkgdataare as follows:If joined to a relative URL, it is treated as a different file relative to the same package/directory as the base URL, very similarly to how
urllib.parse.urljoinworks for relative paths joined to http(s) URLs:>>> urljoin('py-pkgdata:a.b.c/schema1.json', 'schema2.json') 'py-pkgdata:a.b.c/schema2.json' >>> urljoin('py-pkgdata:a.b.c/schemas/schema1.json', 'schema2.json') 'py-pkgdata:a.b.c/schemas/schema2.json' >>> urljoin('py-pkgdata:a.b.c/schemas/sub/schema1.json', 'schema2.json') 'py-pkgdata:a.b.c/schemas/sub/schema2.json' >>> urljoin('py-pkgdata:a.b.c/schemas/schema1.json', '../more_schemas/schema2.json') 'py-pkgdata:a.b.c/more_schemas/schema2.json'
Note
This does not support relative URLs with a package-relative component, only different paths within the same package. Maybe support for this could be added in the future, but under the current format it’s too ambiguous.
When joining an absolute URL, if the joined URL is in the same package it works the same as the relative case (effectively the joined URL replaces the base):
>>> urljoin('py-pkgdata:a.b.c/schema1.json', 'py-pkgdata:a.b.c/schema2.json') 'py-pkgdata:a.b.c/schema2.json'
Likewise when they are different packages:
>>> urljoin('py-pkgdata:a.b.c/schema1.json', 'py-pkgdata:d.e.f/schema2.json') 'py-pkgdata:d.e.f/schema2.json'
Or if they are the exact same URL, that URL is returned:
>>> urljoin('py-pkgdata:a.b.c/sub/schema1.json', 'py-pkgdata:a.b.c/sub/schema1.json') 'py-pkgdata:a.b.c/sub/schema1.json'
And likewise if they are not the same scheme at all:
>>> urljoin('py-pkgdata:a.b.c/schema1.json', 'http://example.com/schema2.json') 'http://example.com/schema2.json'
The same rules apply for fragments as with
py-obj:>>> urljoin('py-pkgdata:a.b.c/schema1.json#replaced', 'schema2.json#fragment') 'py-pkgdata:a.b.c/schema2.json#fragment' >>> urljoin('py-pkgdata:a.b.c/schema1.json#replaced', '#fragment') 'py-pkgdata:a.b.c/schema1.json#fragment'
- jsonschema_pyref.urlparse(url: str) urllib.parse.ParseResult[source]
Extends the stdlib’s
urllib.parse.urlparseto support the custom URL schemes implemented by this package.
- jsonschema_pyref.validate(document: Optional[Union[dict, list, str, int, float, bool]], schema: Union[dict, bool], cls: Optional[Type] = None, *args: Any, **kwargs: Any)[source]
Drop-in replacement for
jsonschema.validatewhich uses the customizedjsonschema_pyref.RefResolverby default.>>> from jsonschema_pyref import validate >>> schema = { ... 'properties': { ... 'a': {'$ref': 'py-obj:jsonschema_pyref.examples.schema1'} ... } ... } ... >>> validate({'a': 'hello'}, schema) is None True