From f0d78bd3e21cc6edeb65726d19c37b3f5109ebbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Perceval=20Wajsb=C3=BCrt?= Date: Thu, 21 Nov 2024 02:58:54 +0100 Subject: [PATCH] test: improve aslist test --- tests/test_as_list.py | 77 ++++++++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 23 deletions(-) diff --git a/tests/test_as_list.py b/tests/test_as_list.py index 1918f9c..a164926 100644 --- a/tests/test_as_list.py +++ b/tests/test_as_list.py @@ -1,38 +1,31 @@ -from dataclasses import is_dataclass -from typing import Generic, List, TypeVar +from functools import lru_cache +from typing import TYPE_CHECKING, Generic, List, TypeVar, Union import pydantic import pytest -from pydantic import BaseModel -from typing_extensions import is_typeddict from confit import validate_arguments from confit.errors import ConfitValidationError, patch_errors T = TypeVar("T") -if pydantic.VERSION < "2": - def cast(type_, obj): - class Model(pydantic.BaseModel): - __root__: type_ - - class Config: - arbitrary_types_allowed = True - - return Model(__root__=obj).__root__ - -else: - from pydantic.type_adapter import ConfigDict, TypeAdapter +if pydantic.VERSION >= "2": from pydantic_core import core_schema - def make_type_adapter(type_): - config = None - if not issubclass(type, BaseModel) or is_dataclass(type) or is_typeddict(type): - config = ConfigDict(arbitrary_types_allowed=True) - return TypeAdapter(type_, config=config) - def cast(type_, obj): - return make_type_adapter(type_).validate_python(obj) +class Validated: + @classmethod + def __get_validators__(cls): + yield cls.validate + + @classmethod + def __get_pydantic_core_schema__(cls, source, handler): + return core_schema.chain_schema( + [ + core_schema.no_info_plain_validator_function(v) + for v in cls.__get_validators__() + ] + ) class MetaAsList(type): @@ -68,6 +61,44 @@ class AsList(Generic[T], metaclass=MetaAsList): pass +if pydantic.VERSION < "2": + + def cast(type_, obj): + class Model(pydantic.BaseModel): + __root__: type_ + + class Config: + arbitrary_types_allowed = True + + return Model(__root__=obj).__root__ + +else: + from dataclasses import is_dataclass + + from pydantic import BaseModel + from pydantic.type_adapter import ConfigDict, TypeAdapter + from typing_extensions import is_typeddict + + @lru_cache(maxsize=32) + def make_type_adapter(type_): + config = None + + if not ( + (isinstance(type_, type) and issubclass(type_, BaseModel)) + or is_dataclass(type_) + or is_typeddict(type_) + ): + config = ConfigDict(arbitrary_types_allowed=True) + return TypeAdapter(type_, config=config) + + def cast(type_, obj): + return make_type_adapter(type_).validate_python(obj) + + +if TYPE_CHECKING: + AsList = Union[T, List[T]] # noqa: F811 + + def test_as_list(): @validate_arguments def func(a: AsList[int]):