2024-01-26 11:12:57 +08:00
|
|
|
from dataclasses import dataclass
|
2024-08-11 15:15:59 +08:00
|
|
|
from typing import Any, Optional, Annotated
|
2024-01-26 11:12:57 +08:00
|
|
|
|
|
|
|
import pytest
|
2024-08-11 15:15:59 +08:00
|
|
|
from pydantic import BaseModel, ValidationError
|
2024-01-26 11:12:57 +08:00
|
|
|
|
|
|
|
from nonebot.compat import (
|
|
|
|
DEFAULT_CONFIG,
|
|
|
|
Required,
|
|
|
|
FieldInfo,
|
2024-08-11 15:15:59 +08:00
|
|
|
TypeAdapter,
|
2024-01-26 11:12:57 +08:00
|
|
|
PydanticUndefined,
|
2024-02-05 14:00:49 +08:00
|
|
|
model_dump,
|
2024-01-26 11:12:57 +08:00
|
|
|
custom_validation,
|
2024-02-17 23:18:00 +08:00
|
|
|
type_validate_json,
|
2024-01-26 11:12:57 +08:00
|
|
|
type_validate_python,
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2024-10-26 15:36:01 +08:00
|
|
|
def test_default_config():
|
2024-01-26 11:12:57 +08:00
|
|
|
assert DEFAULT_CONFIG.get("extra") == "allow"
|
|
|
|
assert DEFAULT_CONFIG.get("arbitrary_types_allowed") is True
|
|
|
|
|
|
|
|
|
2024-10-26 15:36:01 +08:00
|
|
|
def test_field_info():
|
2024-01-26 11:12:57 +08:00
|
|
|
# required should be convert to PydanticUndefined
|
|
|
|
assert FieldInfo(Required).default is PydanticUndefined
|
|
|
|
|
|
|
|
# field info should allow extra attributes
|
|
|
|
assert FieldInfo(test="test").extra["test"] == "test"
|
|
|
|
|
|
|
|
|
2024-10-26 15:36:01 +08:00
|
|
|
def test_type_adapter():
|
2024-08-11 15:15:59 +08:00
|
|
|
t = TypeAdapter(Annotated[int, FieldInfo(ge=1)])
|
|
|
|
|
|
|
|
assert t.validate_python(2) == 2
|
|
|
|
|
|
|
|
with pytest.raises(ValidationError):
|
|
|
|
t.validate_python(0)
|
|
|
|
|
|
|
|
assert t.validate_json("2") == 2
|
|
|
|
|
|
|
|
with pytest.raises(ValidationError):
|
|
|
|
t.validate_json("0")
|
|
|
|
|
|
|
|
|
2024-10-26 15:36:01 +08:00
|
|
|
def test_model_dump():
|
2024-02-05 14:00:49 +08:00
|
|
|
class TestModel(BaseModel):
|
|
|
|
test1: int
|
|
|
|
test2: int
|
|
|
|
|
|
|
|
assert model_dump(TestModel(test1=1, test2=2), include={"test1"}) == {"test1": 1}
|
|
|
|
assert model_dump(TestModel(test1=1, test2=2), exclude={"test1"}) == {"test2": 2}
|
|
|
|
|
|
|
|
|
2024-10-26 15:36:01 +08:00
|
|
|
def test_custom_validation():
|
2024-01-26 11:12:57 +08:00
|
|
|
called = []
|
|
|
|
|
|
|
|
@custom_validation
|
|
|
|
@dataclass
|
|
|
|
class TestModel:
|
|
|
|
test: int
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def __get_validators__(cls):
|
|
|
|
yield cls._validate_1
|
|
|
|
yield cls._validate_2
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def _validate_1(cls, v: Any) -> Any:
|
|
|
|
called.append(1)
|
|
|
|
return v
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def _validate_2(cls, v: Any) -> Any:
|
|
|
|
called.append(2)
|
|
|
|
return cls(test=v["test"])
|
|
|
|
|
|
|
|
assert type_validate_python(TestModel, {"test": 1}) == TestModel(test=1)
|
|
|
|
assert called == [1, 2]
|
2024-02-17 23:18:00 +08:00
|
|
|
|
|
|
|
|
2024-10-26 15:36:01 +08:00
|
|
|
def test_validate_json():
|
2024-02-17 23:18:00 +08:00
|
|
|
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)
|