Browse Source

🔥 Remove and update Pydantic v1 tests

pull/14609/head
Sebastián Ramírez 7 months ago
parent
commit
de015ae49d
  1. 49
      tests/test_compat.py
  2. 45
      tests/test_inherited_custom_class.py
  3. 58
      tests/test_jsonable_encoder.py
  4. 2
      tests/test_pydantic_v1_error.py

49
tests/test_compat.py

@ -1,20 +1,17 @@
from typing import Any, Union
from typing import Union
from fastapi import FastAPI, UploadFile
from fastapi._compat import (
Undefined,
_get_model_config,
get_cached_model_fields,
is_scalar_field,
is_uploadfile_sequence_annotation,
may_v1,
)
from fastapi._compat.shared import is_bytes_sequence_annotation
from fastapi.testclient import TestClient
from pydantic import BaseModel, ConfigDict
from pydantic.fields import FieldInfo
from .utils import needs_py310, needs_py_lt_314
from .utils import needs_py310
def test_model_field_default_required():
@ -26,18 +23,6 @@ def test_model_field_default_required():
assert field.default is Undefined
@needs_py_lt_314
def test_v1_plain_validator_function():
from fastapi._compat import v1
# For coverage
def func(v): # pragma: no cover
return v
result = v1.with_info_plain_validator_function(func)
assert result == {}
def test_is_model_field():
# For coverage
from fastapi._compat import _is_model_field
@ -165,33 +150,3 @@ def test_serialize_sequence_value_with_none_first_in_union():
result = v2.serialize_sequence_value(field=field, value=["x", "y"])
assert result == ["x", "y"]
assert isinstance(result, list)
@needs_py_lt_314
def test_is_pv1_scalar_field():
from fastapi._compat import v1
# For coverage
class Model(v1.BaseModel):
foo: Union[str, dict[str, Any]]
fields = v1.get_model_fields(Model)
assert not is_scalar_field(fields[0])
@needs_py_lt_314
def test_get_model_fields_cached():
from fastapi._compat import v1
class Model(may_v1.BaseModel):
foo: str
non_cached_fields = v1.get_model_fields(Model)
non_cached_fields2 = v1.get_model_fields(Model)
cached_fields = get_cached_model_fields(Model)
cached_fields2 = get_cached_model_fields(Model)
for f1, f2 in zip(cached_fields, cached_fields2):
assert f1 is f2
assert non_cached_fields is not non_cached_fields2
assert cached_fields is cached_fields2

45
tests/test_inherited_custom_class.py

@ -5,8 +5,6 @@ from fastapi import FastAPI
from fastapi.testclient import TestClient
from pydantic import BaseModel
from .utils import needs_pydanticv1
class MyUuid:
def __init__(self, uuid_string: str):
@ -67,46 +65,3 @@ def test_pydanticv2():
assert response_pydantic.json() == {
"a_uuid": "b8799909-f914-42de-91bc-95c819218d01"
}
# TODO: remove when deprecating Pydantic v1
@needs_pydanticv1
def test_pydanticv1():
from pydantic import v1
app = FastAPI()
@app.get("/fast_uuid")
def return_fast_uuid():
asyncpg_uuid = MyUuid("a10ff360-3b1e-4984-a26f-d3ab460bdb51")
assert isinstance(asyncpg_uuid, uuid.UUID)
assert type(asyncpg_uuid) is not uuid.UUID
with pytest.raises(TypeError):
vars(asyncpg_uuid)
return {"fast_uuid": asyncpg_uuid}
class SomeCustomClass(v1.BaseModel):
class Config:
arbitrary_types_allowed = True
json_encoders = {uuid.UUID: str}
a_uuid: MyUuid
@app.get("/get_custom_class")
def return_some_user():
# Test that the fix also works for custom pydantic classes
return SomeCustomClass(a_uuid=MyUuid("b8799909-f914-42de-91bc-95c819218d01"))
client = TestClient(app)
with client:
response_simple = client.get("/fast_uuid")
response_pydantic = client.get("/get_custom_class")
assert response_simple.json() == {
"fast_uuid": "a10ff360-3b1e-4984-a26f-d3ab460bdb51"
}
assert response_pydantic.json() == {
"a_uuid": "b8799909-f914-42de-91bc-95c819218d01"
}

58
tests/test_jsonable_encoder.py

@ -10,6 +10,7 @@ from typing import Optional
import pytest
from fastapi._compat import Undefined
from fastapi.encoders import jsonable_encoder
from fastapi.exceptions import PydanticV1NotSupportedError
from pydantic import BaseModel, Field, ValidationError
from .utils import needs_pydanticv1
@ -156,29 +157,16 @@ def test_encode_custom_json_encoders_model_pydanticv2():
assert jsonable_encoder(subclass_model) == {"dt_field": "2019-01-01T08:00:00+00:00"}
# TODO: remove when deprecating Pydantic v1
@needs_pydanticv1
def test_encode_custom_json_encoders_model_pydanticv1():
def test_json_encoder_error_with_pydanticv1():
from pydantic import v1
class ModelWithCustomEncoder(v1.BaseModel):
dt_field: datetime
class Config:
json_encoders = {
datetime: lambda dt: dt.replace(
microsecond=0, tzinfo=timezone.utc
).isoformat()
}
class ModelV1(v1.BaseModel):
name: str
class ModelWithCustomEncoderSubclass(ModelWithCustomEncoder):
class Config:
pass
model = ModelWithCustomEncoder(dt_field=datetime(2019, 1, 1, 8))
assert jsonable_encoder(model) == {"dt_field": "2019-01-01T08:00:00+00:00"}
subclass_model = ModelWithCustomEncoderSubclass(dt_field=datetime(2019, 1, 1, 8))
assert jsonable_encoder(subclass_model) == {"dt_field": "2019-01-01T08:00:00+00:00"}
data = ModelV1(name="test")
with pytest.raises(PydanticV1NotSupportedError):
jsonable_encoder(data)
def test_encode_model_with_config():
@ -214,27 +202,6 @@ def test_encode_model_with_default():
}
@needs_pydanticv1
def test_custom_encoders():
from pydantic import v1
class safe_datetime(datetime):
pass
class MyModel(v1.BaseModel):
dt_field: safe_datetime
instance = MyModel(dt_field=safe_datetime.now())
encoded_instance = jsonable_encoder(
instance, custom_encoder={safe_datetime: lambda o: o.strftime("%H:%M:%S")}
)
assert encoded_instance["dt_field"] == instance.dt_field.strftime("%H:%M:%S")
encoded_instance2 = jsonable_encoder(instance)
assert encoded_instance2["dt_field"] == instance.dt_field.isoformat()
def test_custom_enum_encoders():
def custom_enum_encoder(v: Enum):
return v.value.lower()
@ -287,17 +254,6 @@ def test_encode_pure_path():
assert jsonable_encoder({"path": test_path}) == {"path": str(test_path)}
@needs_pydanticv1
def test_encode_root():
from pydantic import v1
class ModelWithRoot(v1.BaseModel):
__root__: str
model = ModelWithRoot(__root__="Foo")
assert jsonable_encoder(model) == "Foo"
def test_decimal_encoder_float():
data = {"value": Decimal(1.23)}
assert jsonable_encoder(data) == {"value": 1.23}

2
tests/test_pydantic_v1_error.py

@ -8,7 +8,7 @@ if sys.version_info >= (3, 14):
skip_module_if_py_gte_314()
from fastapi import FastAPI
from fastapi._compat.v1 import BaseModel
from fastapi._compat.may_v1 import BaseModel
from fastapi.exceptions import PydanticV1NotSupportedError

Loading…
Cancel
Save