From a83034654520cce4f30a0691460313190c6aa1bc Mon Sep 17 00:00:00 2001 From: MingxuanGame Date: Sat, 17 Feb 2024 23:18:00 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20Feature:=20=E4=BC=98=E5=8C=96=20py?= =?UTF-8?q?dantic=20=E5=85=BC=E5=AE=B9=E5=87=BD=E6=95=B0=20`model=5Fdump`?= =?UTF-8?q?=20=E5=92=8C=20`type=5Fvalidate=5Fjson`=20(#2579)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Ju4tCode <42488585+yanyongyu@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- nonebot/compat.py | 36 +++++++++++++++++++++++++++++++++--- tests/test_compat.py | 26 +++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/nonebot/compat.py b/nonebot/compat.py index df5dbb0d..dc861b3f 100644 --- a/nonebot/compat.py +++ b/nonebot/compat.py @@ -16,6 +16,7 @@ from typing import ( Dict, List, Type, + Union, TypeVar, Callable, Optional, @@ -54,6 +55,7 @@ __all__ = ( "model_config", "model_dump", "type_validate_python", + "type_validate_json", "custom_validation", ) @@ -195,13 +197,27 @@ if PYDANTIC_V2: # pragma: pydantic-v2 include: Optional[Set[str]] = None, exclude: Optional[Set[str]] = None, by_alias: bool = False, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, ) -> Dict[str, Any]: - return model.model_dump(include=include, exclude=exclude, by_alias=by_alias) + return model.model_dump( + include=include, + exclude=exclude, + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + ) def type_validate_python(type_: Type[T], data: Any) -> T: """Validate data with given type.""" return TypeAdapter(type_).validate_python(data) + def type_validate_json(type_: Type[T], data: Union[str, bytes]) -> T: + """Validate JSON with given type.""" + return TypeAdapter(type_).validate_json(data) + def __get_pydantic_core_schema__( cls: Type["_CustomValidationClass"], source_type: Any, @@ -226,7 +242,7 @@ if PYDANTIC_V2: # pragma: pydantic-v2 else: # pragma: pydantic-v1 from pydantic import Extra - from pydantic import parse_obj_as + from pydantic import parse_obj_as, parse_raw_as from pydantic import BaseConfig as PydanticConfig from pydantic.fields import FieldInfo as BaseFieldInfo from pydantic.fields import ModelField as BaseModelField @@ -341,13 +357,27 @@ else: # pragma: pydantic-v1 include: Optional[Set[str]] = None, exclude: Optional[Set[str]] = None, by_alias: bool = False, + exclude_unset: bool = False, + exclude_defaults: bool = False, + exclude_none: bool = False, ) -> Dict[str, Any]: - return model.dict(include=include, exclude=exclude, by_alias=by_alias) + return model.dict( + include=include, + exclude=exclude, + by_alias=by_alias, + exclude_unset=exclude_unset, + exclude_defaults=exclude_defaults, + exclude_none=exclude_none, + ) def type_validate_python(type_: Type[T], data: Any) -> T: """Validate data with given type.""" return parse_obj_as(type_, data) + def type_validate_json(type_: Type[T], data: Union[str, bytes]) -> T: + """Validate JSON with given type.""" + return parse_raw_as(type_, data) + def custom_validation(class_: Type["CVC"]) -> Type["CVC"]: """Do nothing in pydantic v1""" return class_ diff --git a/tests/test_compat.py b/tests/test_compat.py index 3c020312..a50da686 100644 --- a/tests/test_compat.py +++ b/tests/test_compat.py @@ -1,4 +1,4 @@ -from typing import Any +from typing import Any, Optional from dataclasses import dataclass import pytest @@ -11,6 +11,7 @@ from nonebot.compat import ( PydanticUndefined, model_dump, custom_validation, + type_validate_json, type_validate_python, ) @@ -66,3 +67,26 @@ async def test_custom_validation(): assert type_validate_python(TestModel, {"test": 1}) == TestModel(test=1) assert called == [1, 2] + + +@pytest.mark.asyncio +async def test_validate_json(): + class TestModel(BaseModel): + test1: int + test2: str + test3: bool + test4: dict + test5: list + test6: Optional[int] + + assert type_validate_json( + TestModel, + "{" + ' "test1": 1,' + ' "test2": "2",' + ' "test3": true,' + ' "test4": {},' + ' "test5": [],' + ' "test6": null' + "}", + ) == TestModel(test1=1, test2="2", test3=True, test4={}, test5=[], test6=None)