///|
/// All errors raised by this library (Python's `referencing.exceptions`, plus
/// `referencing.jsonschema.UnknownDialect`).
///
/// Python models these as an exception class hierarchy where
/// `PointerToNowhere`, `NoSuchAnchor` and `InvalidAnchor` are subclasses of
/// `Unresolvable`; use `ReferencingError::is_unresolvable` to test for
/// "an `Unresolvable` or any subclass thereof".
///
/// `Show` renders the same text as Python's `str(error)`.
pub(all) suberror ReferencingError {
/// The given URI is not present in a registry.
NoSuchResource(reference~ : String)
/// A resource has no internal ID, but one is needed.
NoInternalID(resource~ : Resource)
/// The given URI is not present in a registry, and retrieving it failed.
/// `cause` is the error raised by the retrieval function (Python's
/// `__cause__`); it does not take part in equality.
Unretrievable(reference~ : String, cause~ : Error?)
/// Attempting to detect the appropriate `Specification` failed.
CannotDetermineSpecification(contents~ : Json)
/// A reference was unresolvable.
Unresolvable(reference~ : String)
/// A JSON Pointer leads to a part of a document that does not exist.
/// (An `Unresolvable`.)
PointerToNowhere(reference~ : String, resource~ : Resource)
/// An anchor does not exist within a particular resource.
/// (An `Unresolvable`.)
NoSuchAnchor(reference~ : String, resource~ : Resource, anchor~ : String)
/// An anchor which could never exist in a resource was dereferenced.
/// (An `Unresolvable`.)
InvalidAnchor(reference~ : String, resource~ : Resource, anchor~ : String)
/// A dialect identifier was found for a dialect unknown by this library
/// (Python's `referencing.jsonschema.UnknownDialect`).
UnknownDialect(uri~ : String)
}
///|
/// Whether this error is an `Unresolvable` or one of its "subclasses"
/// (`PointerToNowhere`, `NoSuchAnchor`, `InvalidAnchor`), i.e. whether
/// Python's `except referencing.exceptions.Unresolvable` would catch it.
pub fn ReferencingError::is_unresolvable(self : ReferencingError) -> Bool {
self
is (Unresolvable(..)
| PointerToNowhere(..)
| NoSuchAnchor(..)
| InvalidAnchor(..))
}
///|
/// The `ref` carried by the error, if it has one.
pub fn ReferencingError::reference(self : ReferencingError) -> String? {
match self {
NoSuchResource(reference~)
| Unretrievable(reference~, ..)
| Unresolvable(reference~)
| PointerToNowhere(reference~, ..)
| NoSuchAnchor(reference~, ..)
| InvalidAnchor(reference~, ..) => Some(reference)
NoInternalID(..) | CannotDetermineSpecification(..) | UnknownDialect(..) =>
None
}
}
///|
/// Structural equality (as upstream's attrs-based `__eq__`), where errors of
/// different kinds are never equal and an `Unretrievable`'s cause is ignored.
pub impl Eq for ReferencingError with fn equal(self, other) {
match (self, other) {
(NoSuchResource(reference=a), NoSuchResource(reference=b)) => a == b
(NoInternalID(resource=a), NoInternalID(resource=b)) => a == b
(Unretrievable(reference=a, ..), Unretrievable(reference=b, ..)) => a == b
(
CannotDetermineSpecification(contents=a),
CannotDetermineSpecification(contents=b),
) => a == b
(Unresolvable(reference=a), Unresolvable(reference=b)) => a == b
(
PointerToNowhere(reference=a, resource=r),
PointerToNowhere(reference=b, resource=s),
) => a == b && r == s
(
NoSuchAnchor(reference=a, resource=r, anchor=x),
NoSuchAnchor(reference=b, resource=s, anchor=y),
) => a == b && r == s && x == y
(
InvalidAnchor(reference=a, resource=r, anchor=x),
InvalidAnchor(reference=b, resource=s, anchor=y),
) => a == b && r == s && x == y
(UnknownDialect(uri=a), UnknownDialect(uri=b)) => a == b
_ => false
}
}
///|
/// Renders exactly what Python's `str(error)` renders.
pub impl Show for ReferencingError with fn output(self, logger) {
match self {
// KeyError subclasses: str() is the repr() of the single argument
NoSuchResource(reference~) | Unretrievable(reference~, ..) =>
logger.write_string(py_str_repr(reference))
NoInternalID(resource~) => logger.write_string(Show::to_string(resource))
CannotDetermineSpecification(contents~) =>
logger.write_string(py_str(contents))
Unresolvable(reference~) => logger.write_string(reference)
PointerToNowhere(reference~, resource~) => {
logger.write_string(
"\{py_str_repr(reference)} does not exist within \{py_repr(resource.contents)}",
)
if reference == "/" {
logger.write_string(
". The pointer '/' is a valid JSON Pointer but it points to an empty string property ''. If you intended to point to the entire resource, you should use '#'.",
)
}
}
NoSuchAnchor(anchor~, resource~, ..) =>
logger.write_string(
"\{py_str_repr(anchor)} does not exist within \{py_repr(resource.contents)}",
)
InvalidAnchor(anchor~, ..) =>
logger.write_string(
"'#\{anchor}' is not a valid anchor, neither as a plain name anchor nor as a JSON Pointer. You may have intended to use '#/\{anchor}', as the slash is required *before each segment* of a JSON pointer.",
)
UnknownDialect(uri~) => logger.write_string(uri)
}
}
///|
/// Recover a `ReferencingError` from a generic `Error` (as raised by e.g.
/// `Resolver::lookup`), if it is one.
pub fn ReferencingError::from_error(error : Error) -> ReferencingError? {
match error {
NoSuchResource(reference~) => Some(NoSuchResource(reference~))
NoInternalID(resource~) => Some(NoInternalID(resource~))
Unretrievable(reference~, cause~) => Some(Unretrievable(reference~, cause~))
CannotDetermineSpecification(contents~) =>
Some(CannotDetermineSpecification(contents~))
Unresolvable(reference~) => Some(Unresolvable(reference~))
PointerToNowhere(reference~, resource~) =>
Some(PointerToNowhere(reference~, resource~))
NoSuchAnchor(reference~, resource~, anchor~) =>
Some(NoSuchAnchor(reference~, resource~, anchor~))
InvalidAnchor(reference~, resource~, anchor~) =>
Some(InvalidAnchor(reference~, resource~, anchor~))
UnknownDialect(uri~) => Some(UnknownDialect(uri~))
_ => None
}
}
///|
/// Whether a generic `Error` is an `Unresolvable` (or a "subclass" thereof),
/// i.e. whether Python's `except referencing.exceptions.Unresolvable` would
/// catch it.
pub fn is_unresolvable(error : Error) -> Bool {
ReferencingError::from_error(error) is Some(e) && e.is_unresolvable()
}