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
Resources, 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
retrieveargument 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 aResourceor else raise aNoSuchResourceexception indicating that the resource does not exist even according to the retrieval logic.- __getitem__(uri: str) Resource[D][source]¶
Return the (already crawled)
Resourceidentified 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 @ registryor[iterable, of, multiple, resources] @ registry
which – again, assuming the resources have internal IDs – is equivalent to calling
Registry.with_resourcesas such:registry.with_resources( (resource.id(), resource) for resource in new_resources )
- Raises:
NoInternalID – if the resource(s) in fact do not have IDs
- anchor(uri: str, name: str)[source]¶
Retrieve a given anchor from a resource which must already be crawled.
- combine(*registries: Registry[D]) Registry[D][source]¶
Combine together one or more other registries, producing a unified one.
- 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
Retrievedobject which contains both the resource value as well as the registry which ultimately contained it.
- resolver(base_uri: str = '') Resolver[D][source]¶
Return a
Resolverwhich resolves references against this registry.
- resolver_with_root(resource: Resource[D]) Resolver[D][source]¶
Return a
Resolverwith a specific root resource.
- with_contents(pairs: Iterable[tuple[str, D]], **kwargs: Any) Registry[D][source]¶
Add the given contents to the registry, autodetecting when necessary.
- 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
Specificationwhich describes how the document interacts with referencing – both internally (how it refers to otherResources) and externally (how it should be identified such that it is referenceable by other documents).- anchors() Iterable[Anchor[D]][source]¶
Retrieve this resource’s (specification-specific) identifier.
- 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.OPAQUEfor 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
Specificationallow 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.
- create_resource(contents: D) Resource[D][source]¶
Create a resource which is interpreted using this specification.
- detect() Specification[D]¶
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.Schema = bool | collections.abc.Mapping[str, typing.Any]¶
A JSON Schema of any kind
- 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
Specificationwith the given dialect identifier.- Raises:
UnknownDialect – if the given
dialect_idisn’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:
KeyErrorThe 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:
ExceptionA 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:
KeyErrorThe given URI is not present in a registry, and retrieving it failed.
- exception referencing.exceptions.CannotDetermineSpecification(contents: Any)[source]¶
Bases:
ExceptionAttempting to detect the appropriate
Specificationfailed.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:
ExceptionA reference was unresolvable.
- exception referencing.exceptions.PointerToNowhere(ref: URI, resource: Resource[Any])[source]¶
Bases:
UnresolvableA 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
Registryas a retrieve function.This decorator both reduces a small bit of boilerplate for a common case (deserializing JSON from strings and creating
Resourceobjects 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
Registryfor resource retrieval.Does not make assumptions about where the resource might be coming from.