81 lines
2.6 KiB
Python
81 lines
2.6 KiB
Python
|
from typing import Any, Type, Optional, Set, Dict
|
||
|
from dacite.types import is_union
|
||
|
|
||
|
|
||
|
def _name(type_: Type) -> str:
|
||
|
return type_.__name__ if hasattr(type_, "__name__") and not is_union(type_) else str(type_)
|
||
|
|
||
|
|
||
|
class DaciteError(Exception):
|
||
|
pass
|
||
|
|
||
|
|
||
|
class DaciteFieldError(DaciteError):
|
||
|
def __init__(self, field_path: Optional[str] = None):
|
||
|
super().__init__()
|
||
|
self.field_path = field_path
|
||
|
|
||
|
def update_path(self, parent_field_path: str) -> None:
|
||
|
if self.field_path:
|
||
|
self.field_path = f"{parent_field_path}.{self.field_path}"
|
||
|
else:
|
||
|
self.field_path = parent_field_path
|
||
|
|
||
|
|
||
|
class WrongTypeError(DaciteFieldError):
|
||
|
def __init__(self, field_type: Type, value: Any, field_path: Optional[str] = None) -> None:
|
||
|
super().__init__(field_path=field_path)
|
||
|
self.field_type = field_type
|
||
|
self.value = value
|
||
|
|
||
|
def __str__(self) -> str:
|
||
|
return (
|
||
|
f'wrong value type for field "{self.field_path}" - should be "{_name(self.field_type)}" '
|
||
|
f'instead of value "{self.value}" of type "{_name(type(self.value))}"'
|
||
|
)
|
||
|
|
||
|
|
||
|
class MissingValueError(DaciteFieldError):
|
||
|
def __init__(self, field_path: Optional[str] = None):
|
||
|
super().__init__(field_path=field_path)
|
||
|
|
||
|
def __str__(self) -> str:
|
||
|
return f'missing value for field "{self.field_path}"'
|
||
|
|
||
|
|
||
|
class UnionMatchError(WrongTypeError):
|
||
|
def __str__(self) -> str:
|
||
|
return (
|
||
|
f'can not match type "{_name(type(self.value))}" to any type '
|
||
|
f'of "{self.field_path}" union: {_name(self.field_type)}'
|
||
|
)
|
||
|
|
||
|
|
||
|
class StrictUnionMatchError(DaciteFieldError):
|
||
|
def __init__(self, union_matches: Dict[Type, Any], field_path: Optional[str] = None) -> None:
|
||
|
super().__init__(field_path=field_path)
|
||
|
self.union_matches = union_matches
|
||
|
|
||
|
def __str__(self) -> str:
|
||
|
conflicting_types = ", ".join(_name(type_) for type_ in self.union_matches)
|
||
|
return f'can not choose between possible Union matches for field "{self.field_path}": {conflicting_types}'
|
||
|
|
||
|
|
||
|
class ForwardReferenceError(DaciteError):
|
||
|
def __init__(self, message: str) -> None:
|
||
|
super().__init__()
|
||
|
self.message = message
|
||
|
|
||
|
def __str__(self) -> str:
|
||
|
return f"can not resolve forward reference: {self.message}"
|
||
|
|
||
|
|
||
|
class UnexpectedDataError(DaciteError):
|
||
|
def __init__(self, keys: Set[str]) -> None:
|
||
|
super().__init__()
|
||
|
self.keys = keys
|
||
|
|
||
|
def __str__(self) -> str:
|
||
|
formatted_keys = ", ".join(f'"{key}"' for key in self.keys)
|
||
|
return f"can not match {formatted_keys} to any data class field"
|