API Reference¶
Cross-specification, implementation-agnostic JSON referencing.
- class referencing.Registry(resources=HashTrieMap({}), anchors: HashTrieMap[tuple[URI, str], AnchorType[D]] = HashTrieMap({}), uncrawled: HashTrieSet[URI] = HashTrieSet({}), retrieve: Retrieve[D] = <function _fail_to_retrieve>)[source]¶
A registry of
Resource
s, each identified by their canonical URIs.Registries store a collection of in-memory resources, and optionally enable additional resources which may be stored elsewhere (e.g. in a database, a separate set of files, over the network, etc.).
They also lazily walk their known resources, looking for subresources within them. In other words, subresources contained within any added resources will be retrievable via their own IDs (though this discovery of subresources will be delayed until necessary).
Registries are immutable, and their methods return new instances of the registry with the additional resources added to them.
The
retrieve
argument can be used to configure retrieval of resources dynamically, either over the network, from a database, or the like. Pass it a callable which will be called if any URI not present in the registry is accessed. It must either return aResource
or else raise aNoSuchResource
exception indicating that the resource does not exist even according to the retrieval logic.- __getitem__(uri: str) Resource[D] [source]¶
Return the (already crawled)
Resource
identified by the given URI.
- __rmatmul__(new: Resource[D] | Iterable[Resource[D]]) Registry[D] [source]¶
Create a new registry with resource(s) added using their internal IDs.
Resources must have a internal IDs (e.g. the $id keyword in modern JSON Schema versions), otherwise an error will be raised.
Both a single resource as well as an iterable of resources works, i.e.:
resource @ registry
or[iterable, of, multiple, resources] @ registry
which – again, assuming the resources have internal IDs – is equivalent to calling
Registry.with_resources
as such:registry.with_resources( (resource.id(), resource) for resource in new_resources )
- Raises:
NoInternalID – if the resource(s) in fact do not have IDs
- get_or_retrieve(uri: str) Retrieved[D, Resource[D]] [source]¶
Get a resource from the registry, crawling or retrieving if necessary.
May involve crawling to find the given URI if it is not already known, so the returned object is a
Retrieved
object which contains both the resource value as well as the registry which ultimately contained it.
- anchor(uri: str, name: str)[source]¶
Retrieve a given anchor from a resource which must already be crawled.
- with_resource(uri: str, resource: Resource[D])[source]¶
Add the given
Resource
to the registry, without crawling it.
- with_resources(pairs: Iterable[tuple[str, Resource[D]]]) Registry[D] [source]¶
Add the given
Resource
s to the registry, without crawling them.
- with_contents(pairs: Iterable[tuple[str, D]], **kwargs: Any) Registry[D] [source]¶
Add the given contents to the registry, autodetecting when necessary.
- combine(*registries: Registry[D]) Registry[D] [source]¶
Combine together one or more other registries, producing a unified one.
- class referencing.Resource(contents: D, specification: Specification[D])[source]¶
A document (deserialized JSON) with a concrete interpretation under a spec.
In other words, a Python object, along with an instance of
Specification
which describes how the document interacts with referencing – both internally (how it refers to otherResource
s) and externally (how it should be identified such that it is referenceable by other documents).- classmethod from_contents(contents: ~referencing.typing.D, default_specification: type[~referencing._core.Specification[~referencing.typing.D]] | ~referencing._core.Specification[~referencing.typing.D] = <class 'referencing._core.Specification'>) Resource[D] [source]¶
Create a resource guessing which specification applies to the contents.
- Raises:
CannotDetermineSpecification – if the given contents don’t have any discernible information which could be used to guess which specification they identify as
- classmethod opaque(contents: D) Resource[D] [source]¶
Create an opaque
Resource
– i.e. one with opaque specification.See
Specification.OPAQUE
for details.
- class referencing.Specification(name: str, id_of: Callable[[D], URI | None], subresources_of: Callable[[D], Iterable[D]], maybe_in_subresource: _MaybeInSubresource[D], anchors_in: Callable[[Specification[D], D], Iterable[AnchorType[D]]])[source]¶
A specification which defines referencing behavior.
The various methods of a
Specification
allow for varying referencing behavior across JSON Schema specification versions, etc.- subresources_of: Callable[[D], Iterable[D]]¶
Retrieve the subresources of the given document (without traversing into the subresources themselves).
- maybe_in_subresource: _MaybeInSubresource[D]¶
While resolving a JSON pointer, conditionally enter a subresource (if e.g. we have just entered a keyword whose value is a subresource)
- OPAQUE: ClassVar[Specification[Any]] = <Specification name='opaque'>¶
An opaque specification where resources have no subresources nor internal identifiers.
- detect() Specification[D] ¶
Attempt to discern which specification applies to the given contents.
May be called either as an instance method or as a class method, with slightly different behavior in the following case:
Recall that not all contents contains enough internal information about which specification it is written for – the JSON Schema
{}
, for instance, is valid under many different dialects and may be interpreted as any one of them.When this method is used as an instance method (i.e. called on a specific specification), that specification is used as the default if the given contents are unidentifiable.
On the other hand when called as a class method, an error is raised.
To reiterate,
DRAFT202012.detect({})
will returnDRAFT202012
whereas the class methodSpecification.detect({})
will raise an error.(Note that of course
DRAFT202012.detect(...)
may return some other specification when given a schema which does identify as being for another version).- Raises:
CannotDetermineSpecification – if the given contents don’t have any discernible information which could be used to guess which specification they identify as
Private Objects¶
The following objects are private in the sense that constructing or importing them is not part of the referencing
public API, as their name indicates (by virtue of beginning with an underscore).
They are however public in the sense that other public API functions may return objects of these types.
Plainly then, you may rely on their methods and attributes not changing in backwards incompatible ways once referencing
itself is stable, but may not rely on importing or constructing them yourself.
- class referencing._core.Resolved(contents: D, resolver: Resolver[D])[source]¶
A reference resolved to its contents by a
Resolver
.
- class referencing._core.Retrieved(value: AnchorOrResource, registry: Registry[D])[source]¶
A value retrieved from a
Registry
.- value: AnchorOrResource¶
- class referencing._core.AnchorOrResource¶
An anchor or resource.
alias of TypeVar(‘AnchorOrResource’, ~referencing.typing.Anchor[~typing.Any], ~referencing._core.Resource[~typing.Any])
- class referencing._core.Resolver(base_uri: URI, registry: Registry[D], previous: List[URI] = List([]))[source]¶
A reference resolver.
Resolvers help resolve references (including relative ones) by pairing a fixed base URI with a
Registry
.This object, under normal circumstances, is expected to be used by implementers of libraries built on top of
referencing
(e.g. JSON Schema implementations or other libraries resolving JSON references), not directly by end-users populating registries or while writing schemas or other resources.References are resolved against the base URI, and the combined URI is then looked up within the registry.
The process of resolving a reference may itself involve calculating a new base URI for future reference resolution (e.g. if an intermediate resource sets a new base URI), or may involve encountering additional subresources and adding them to a new registry.
- lookup(ref: str) Resolved[D] [source]¶
Resolve the given reference to the resource it points to.
- Raises:
exceptions.Unresolvable – or a subclass thereof (see below) if the reference isn’t resolvable
exceptions.NoSuchAnchor – if the reference is to a URI where a resource exists but contains a plain name fragment which does not exist within the resource
exceptions.PointerToNowhere – if the reference is to a URI where a resource exists but contains a JSON pointer to a location within the resource that does not exist
- class referencing._core._Unset¶
A sentinel object used internally to satisfy the type checker.
Neither accessing nor explicitly passing this object anywhere is public API, and it is only documented here at all to get Sphinx to not complain.
Submodules¶
referencing.jsonschema¶
Referencing implementations for JSON Schema specs (historic & current).
- referencing.jsonschema.ObjectSchema¶
A JSON Schema which is a JSON object
- referencing.jsonschema.SchemaResource¶
A Resource whose contents are JSON Schemas
- referencing.jsonschema.SchemaRegistry¶
A JSON Schema Registry
- referencing.jsonschema.EMPTY_REGISTRY: Registry[bool | Mapping[str, Any]] = <Registry (0 resources)>¶
The empty JSON Schema Registry
- exception referencing.jsonschema.UnknownDialect(uri: str)[source]¶
A dialect identifier was found for a dialect unknown by this library.
If it’s a custom (“unofficial”) dialect, be sure you’ve registered it.
- referencing.jsonschema.DRAFT202012 = <Specification name='draft2020-12'>¶
JSON Schema draft 2020-12
- referencing.jsonschema.DRAFT201909 = <Specification name='draft2019-09'>¶
JSON Schema draft 2019-09
- referencing.jsonschema.DRAFT7 = <Specification name='draft-07'>¶
JSON Schema draft 7
- referencing.jsonschema.DRAFT6 = <Specification name='draft-06'>¶
JSON Schema draft 6
- referencing.jsonschema.DRAFT4 = <Specification name='draft-04'>¶
JSON Schema draft 4
- referencing.jsonschema.DRAFT3 = <Specification name='draft-03'>¶
JSON Schema draft 3
- referencing.jsonschema.specification_with(dialect_id: str, default: Specification[Any] | _Unset = _Unset.SENTINEL) Specification[Any] [source]¶
Retrieve the
Specification
with the given dialect identifier.- Raises:
UnknownDialect – if the given
dialect_id
isn’t known
- class referencing.jsonschema.DynamicAnchor(name: str, resource: Resource[bool | Mapping[str, Any]])[source]¶
Dynamic anchors, introduced in draft 2020.
- referencing.jsonschema.lookup_recursive_ref(resolver: Resolver[bool | Mapping[str, Any]]) Resolved[bool | Mapping[str, Any]] [source]¶
Recursive references (via recursive anchors), present only in draft 2019.
As per the 2019 specification (§ 8.2.4.2.1), only the
#
recursive reference is supported (and is therefore assumed to be the relevant reference).
referencing.exceptions¶
Errors, oh no!
- exception referencing.exceptions.NoSuchResource(ref: URI)[source]¶
Bases:
KeyError
The given URI is not present in a registry.
Unlike most exceptions, this class is intended to be publicly instantiable and is part of the public API of the package.
- exception referencing.exceptions.NoInternalID(resource: Resource[Any])[source]¶
Bases:
Exception
A resource has no internal ID, but one is needed.
E.g. in modern JSON Schema drafts, this is the $id keyword.
One might be needed if a resource was to-be added to a registry but no other URI is available, and the resource doesn’t declare its canonical URI.
- exception referencing.exceptions.Unretrievable(ref: URI)[source]¶
Bases:
KeyError
The given URI is not present in a registry, and retrieving it failed.
- exception referencing.exceptions.CannotDetermineSpecification(contents: Any)[source]¶
Bases:
Exception
Attempting to detect the appropriate
Specification
failed.This happens if no discernible information is found in the contents of the new resource which would help identify it.
- exception referencing.exceptions.Unresolvable(ref: URI)[source]¶
Bases:
Exception
A reference was unresolvable.
- exception referencing.exceptions.PointerToNowhere(ref: URI, resource: Resource[Any])[source]¶
Bases:
Unresolvable
A JSON Pointer leads to a part of a document that does not exist.
referencing.retrieval¶
Helpers related to (dynamic) resource retrieval.
- referencing.retrieval.to_cached_resource(cache: Callable[[Retrieve[D]], Retrieve[D]] | None = None, loads: Callable[[_T], D] = <function loads>, from_contents: Callable[[D], Resource[D]] = <bound method Resource.from_contents of <class 'referencing._core.Resource'>>) Callable[[Callable[[URI], _T]], Retrieve[D]] [source]¶
Create a retriever which caches its return values from a simpler callable.
Takes a function which returns things like serialized JSON (strings) and returns something suitable for passing to
Registry
as a retrieve function.This decorator both reduces a small bit of boilerplate for a common case (deserializing JSON from strings and creating
Resource
objects from the result) as well as makes the probable need for caching a bit easier. Retrievers which otherwise do expensive operations (like hitting the network) might otherwise be called repeatedly.Examples
from referencing import Registry from referencing.typing import URI import referencing.retrieval @referencing.retrieval.to_cached_resource() def retrieve(uri: URI): print(f"Retrieved {uri}") # Normally, go get some expensive JSON from the network, a file ... return ''' { "$schema": "https://json-schema.org/draft/2020-12/schema", "foo": "bar" } ''' one = Registry(retrieve=retrieve).get_or_retrieve("urn:example:foo") print(one.value.contents["foo"]) # Retrieving the same URI again reuses the same value (and thus doesn't # print another retrieval message here) two = Registry(retrieve=retrieve).get_or_retrieve("urn:example:foo") print(two.value.contents["foo"])
Retrieved urn:example:foo bar bar
- class referencing.retrieval._T¶
A serialized document (e.g. a JSON string)
alias of TypeVar(‘_T’)
referencing.typing¶
Type-annotation related support for the referencing library.
- class referencing.typing.D¶
The type of documents within a registry.
alias of TypeVar(‘D’)
- class referencing.typing.Retrieve(*args, **kwargs)[source]¶
A retrieval callable, usable within a
Registry
for resource retrieval.Does not make assumptions about where the resource might be coming from.