You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			166 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Python
		
	
			
		
		
	
	
			166 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Python
		
	
| """
 | |
| Errors, oh no!
 | |
| """
 | |
| 
 | |
| from __future__ import annotations
 | |
| 
 | |
| from typing import TYPE_CHECKING, Any
 | |
| 
 | |
| import attrs
 | |
| 
 | |
| from referencing._attrs import frozen
 | |
| 
 | |
| if TYPE_CHECKING:
 | |
|     from referencing import Resource
 | |
|     from referencing.typing import URI
 | |
| 
 | |
| 
 | |
| @frozen
 | |
| class NoSuchResource(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.
 | |
|     """
 | |
| 
 | |
|     ref: URI
 | |
| 
 | |
|     def __eq__(self, other: object) -> bool:
 | |
|         if self.__class__ is not other.__class__:
 | |
|             return NotImplemented
 | |
|         return attrs.astuple(self) == attrs.astuple(other)
 | |
| 
 | |
|     def __hash__(self) -> int:
 | |
|         return hash(attrs.astuple(self))
 | |
| 
 | |
| 
 | |
| @frozen
 | |
| class NoInternalID(Exception):
 | |
|     """
 | |
|     A resource has no internal ID, but one is needed.
 | |
| 
 | |
|     E.g. in modern JSON Schema drafts, this is the :kw:`$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.
 | |
|     """
 | |
| 
 | |
|     resource: Resource[Any]
 | |
| 
 | |
|     def __eq__(self, other: object) -> bool:
 | |
|         if self.__class__ is not other.__class__:
 | |
|             return NotImplemented
 | |
|         return attrs.astuple(self) == attrs.astuple(other)
 | |
| 
 | |
|     def __hash__(self) -> int:
 | |
|         return hash(attrs.astuple(self))
 | |
| 
 | |
| 
 | |
| @frozen
 | |
| class Unretrievable(KeyError):
 | |
|     """
 | |
|     The given URI is not present in a registry, and retrieving it failed.
 | |
|     """
 | |
| 
 | |
|     ref: URI
 | |
| 
 | |
|     def __eq__(self, other: object) -> bool:
 | |
|         if self.__class__ is not other.__class__:
 | |
|             return NotImplemented
 | |
|         return attrs.astuple(self) == attrs.astuple(other)
 | |
| 
 | |
|     def __hash__(self) -> int:
 | |
|         return hash(attrs.astuple(self))
 | |
| 
 | |
| 
 | |
| @frozen
 | |
| class CannotDetermineSpecification(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.
 | |
|     """
 | |
| 
 | |
|     contents: Any
 | |
| 
 | |
|     def __eq__(self, other: object) -> bool:
 | |
|         if self.__class__ is not other.__class__:
 | |
|             return NotImplemented
 | |
|         return attrs.astuple(self) == attrs.astuple(other)
 | |
| 
 | |
|     def __hash__(self) -> int:
 | |
|         return hash(attrs.astuple(self))
 | |
| 
 | |
| 
 | |
| @attrs.frozen  # Because here we allow subclassing below.
 | |
| class Unresolvable(Exception):
 | |
|     """
 | |
|     A reference was unresolvable.
 | |
|     """
 | |
| 
 | |
|     ref: URI
 | |
| 
 | |
|     def __eq__(self, other: object) -> bool:
 | |
|         if self.__class__ is not other.__class__:
 | |
|             return NotImplemented
 | |
|         return attrs.astuple(self) == attrs.astuple(other)
 | |
| 
 | |
|     def __hash__(self) -> int:
 | |
|         return hash(attrs.astuple(self))
 | |
| 
 | |
| 
 | |
| @frozen
 | |
| class PointerToNowhere(Unresolvable):
 | |
|     """
 | |
|     A JSON Pointer leads to a part of a document that does not exist.
 | |
|     """
 | |
| 
 | |
|     resource: Resource[Any]
 | |
| 
 | |
|     def __str__(self) -> str:
 | |
|         msg = f"{self.ref!r} does not exist within {self.resource.contents!r}"
 | |
|         if self.ref == "/":
 | |
|             msg += (
 | |
|                 ". 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 '#'."
 | |
|             )
 | |
|         return msg
 | |
| 
 | |
| 
 | |
| @frozen
 | |
| class NoSuchAnchor(Unresolvable):
 | |
|     """
 | |
|     An anchor does not exist within a particular resource.
 | |
|     """
 | |
| 
 | |
|     resource: Resource[Any]
 | |
|     anchor: str
 | |
| 
 | |
|     def __str__(self) -> str:
 | |
|         return (
 | |
|             f"{self.anchor!r} does not exist within {self.resource.contents!r}"
 | |
|         )
 | |
| 
 | |
| 
 | |
| @frozen
 | |
| class InvalidAnchor(Unresolvable):
 | |
|     """
 | |
|     An anchor which could never exist in a resource was dereferenced.
 | |
| 
 | |
|     It is somehow syntactically invalid.
 | |
|     """
 | |
| 
 | |
|     resource: Resource[Any]
 | |
|     anchor: str
 | |
| 
 | |
|     def __str__(self) -> str:
 | |
|         return (
 | |
|             f"'#{self.anchor}' is not a valid anchor, neither as a "
 | |
|             "plain name anchor nor as a JSON Pointer. You may have intended "
 | |
|             f"to use '#/{self.anchor}', as the slash is required *before each "
 | |
|             "segment* of a JSON pointer."
 | |
|         )
 |