python lsp
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
from collections.abc import Sequence
|
||||
from typing import Any, Optional, Union
|
||||
|
||||
from typing_extensions import Self
|
||||
|
||||
from cattrs._compat import ExceptionGroup
|
||||
|
||||
|
||||
class StructureHandlerNotFoundError(Exception):
|
||||
"""
|
||||
Error raised when structuring cannot find a handler for converting inputs into
|
||||
:attr:`type_`.
|
||||
"""
|
||||
|
||||
def __init__(self, message: str, type_: type) -> None:
|
||||
super().__init__(message)
|
||||
self.type_ = type_
|
||||
|
||||
|
||||
class BaseValidationError(ExceptionGroup):
|
||||
cl: type
|
||||
|
||||
def __new__(cls, message: str, excs: Sequence[Exception], cl: type):
|
||||
obj = super().__new__(cls, message, excs)
|
||||
obj.cl = cl
|
||||
return obj
|
||||
|
||||
def derive(self, excs: Sequence[Exception]) -> Self:
|
||||
return self.__class__(self.message, excs, self.cl)
|
||||
|
||||
|
||||
class IterableValidationNote(str):
|
||||
"""Attached as a note to an exception when an iterable element fails structuring."""
|
||||
|
||||
index: Union[int, str] # Ints for list indices, strs for dict keys
|
||||
type: Any
|
||||
|
||||
def __new__(
|
||||
cls, string: str, index: Union[int, str], type: Any
|
||||
) -> "IterableValidationNote":
|
||||
instance = str.__new__(cls, string)
|
||||
instance.index = index
|
||||
instance.type = type
|
||||
return instance
|
||||
|
||||
def __getnewargs__(self) -> tuple[str, Union[int, str], Any]:
|
||||
return (str(self), self.index, self.type)
|
||||
|
||||
|
||||
class IterableValidationError(BaseValidationError):
|
||||
"""Raised when structuring an iterable."""
|
||||
|
||||
def group_exceptions(
|
||||
self,
|
||||
) -> tuple[list[tuple[Exception, IterableValidationNote]], list[Exception]]:
|
||||
"""Split the exceptions into two groups: with and without validation notes."""
|
||||
excs_with_notes = []
|
||||
other_excs = []
|
||||
for subexc in self.exceptions:
|
||||
if hasattr(subexc, "__notes__"):
|
||||
for note in subexc.__notes__:
|
||||
if note.__class__ is IterableValidationNote:
|
||||
excs_with_notes.append((subexc, note))
|
||||
break
|
||||
else:
|
||||
other_excs.append(subexc)
|
||||
else:
|
||||
other_excs.append(subexc)
|
||||
|
||||
return excs_with_notes, other_excs
|
||||
|
||||
|
||||
class AttributeValidationNote(str):
|
||||
"""Attached as a note to an exception when an attribute fails structuring."""
|
||||
|
||||
name: str
|
||||
type: Any
|
||||
|
||||
def __new__(cls, string: str, name: str, type: Any) -> "AttributeValidationNote":
|
||||
instance = str.__new__(cls, string)
|
||||
instance.name = name
|
||||
instance.type = type
|
||||
return instance
|
||||
|
||||
def __getnewargs__(self) -> tuple[str, str, Any]:
|
||||
return (str(self), self.name, self.type)
|
||||
|
||||
|
||||
class ClassValidationError(BaseValidationError):
|
||||
"""Raised when validating a class if any attributes are invalid."""
|
||||
|
||||
def group_exceptions(
|
||||
self,
|
||||
) -> tuple[list[tuple[Exception, AttributeValidationNote]], list[Exception]]:
|
||||
"""Split the exceptions into two groups: with and without validation notes."""
|
||||
excs_with_notes = []
|
||||
other_excs = []
|
||||
for subexc in self.exceptions:
|
||||
if hasattr(subexc, "__notes__"):
|
||||
for note in subexc.__notes__:
|
||||
if note.__class__ is AttributeValidationNote:
|
||||
excs_with_notes.append((subexc, note))
|
||||
break
|
||||
else:
|
||||
other_excs.append(subexc)
|
||||
else:
|
||||
other_excs.append(subexc)
|
||||
|
||||
return excs_with_notes, other_excs
|
||||
|
||||
|
||||
class ForbiddenExtraKeysError(Exception):
|
||||
"""
|
||||
Raised when `forbid_extra_keys` is activated and such extra keys are detected
|
||||
during structuring.
|
||||
|
||||
The attribute `extra_fields` is a sequence of those extra keys, which were the
|
||||
cause of this error, and `cl` is the class which was structured with those extra
|
||||
keys.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, message: Optional[str], cl: type, extra_fields: set[str]
|
||||
) -> None:
|
||||
self.cl = cl
|
||||
self.extra_fields = extra_fields
|
||||
cln = cl.__name__
|
||||
|
||||
super().__init__(
|
||||
message
|
||||
or f"Extra fields in constructor for {cln}: {', '.join(extra_fields)}"
|
||||
)
|
||||
Reference in New Issue
Block a user