57 lines
1.8 KiB
Python
57 lines
1.8 KiB
Python
from dataclasses import dataclass
|
|
from functools import partial
|
|
from types import FunctionType, MethodType
|
|
from typing import Any, Mapping, Optional, TYPE_CHECKING, Type, TypeVar
|
|
|
|
from apischema.fields import FIELDS_SET_ATTR
|
|
from apischema.objects import object_fields
|
|
|
|
if TYPE_CHECKING:
|
|
from apischema.validation.validators import Validator
|
|
|
|
MOCK_FIELDS_FIELD = "__mock_fields__"
|
|
MOCK_CLS_FIELD = "__mock_cls__"
|
|
|
|
|
|
class NonTrivialDependency(Exception):
|
|
def __init__(self, attr: str):
|
|
self.attr = attr
|
|
self.validator: Optional["Validator"] = None
|
|
|
|
|
|
@dataclass(init=False)
|
|
class ValidatorMock:
|
|
def __init__(self, cls: Type, values: Mapping[str, Any]):
|
|
self.cls = cls
|
|
self.values = values
|
|
|
|
def __getattribute__(self, name: str) -> Any:
|
|
values = super().__getattribute__("values")
|
|
if name in values:
|
|
return values[name]
|
|
cls = super().__getattribute__("cls")
|
|
fields = object_fields(cls, deserialization=True)
|
|
if name in fields:
|
|
if fields[name].required:
|
|
raise NonTrivialDependency(name)
|
|
return fields[name].get_default()
|
|
if name == "__class__":
|
|
return cls
|
|
if name == "__dict__":
|
|
return {**values, FIELDS_SET_ATTR: set(values)}
|
|
if name == FIELDS_SET_ATTR:
|
|
return set(values)
|
|
if hasattr(cls, name):
|
|
member = getattr(cls, name)
|
|
# for classmethod (staticmethod are not handled)
|
|
if isinstance(member, MethodType):
|
|
return member
|
|
if isinstance(member, FunctionType):
|
|
return partial(member, self)
|
|
if isinstance(member, property):
|
|
return member.fget(self) # type: ignore
|
|
return member
|
|
raise NonTrivialDependency(name)
|
|
|
|
|
|
T = TypeVar("T")
|