Browse Source
fix: Propagate Pydantic's model config
pull/12504/head
Nikita Zavadin
6 months ago
No known key found for this signature in database
GPG Key ID: 9F14940057AA9BBD
2 changed files with
34 additions and
2 deletions
-
fastapi/_compat.py
-
tests/test_compat.py
|
|
@ -87,6 +87,7 @@ if PYDANTIC_V2: |
|
|
|
class ModelField: |
|
|
|
field_info: FieldInfo |
|
|
|
name: str |
|
|
|
model_config: BaseConfig | None = None |
|
|
|
mode: Literal["validation", "serialization"] = "validation" |
|
|
|
|
|
|
|
@property |
|
|
@ -108,7 +109,8 @@ if PYDANTIC_V2: |
|
|
|
|
|
|
|
def __post_init__(self) -> None: |
|
|
|
self._type_adapter: TypeAdapter[Any] = TypeAdapter( |
|
|
|
Annotated[self.field_info.annotation, self.field_info] |
|
|
|
Annotated[self.field_info.annotation, self.field_info], |
|
|
|
config=self.model_config, |
|
|
|
) |
|
|
|
|
|
|
|
def get_default(self) -> Any: |
|
|
@ -282,7 +284,9 @@ if PYDANTIC_V2: |
|
|
|
|
|
|
|
def get_model_fields(model: Type[BaseModel]) -> List[ModelField]: |
|
|
|
return [ |
|
|
|
ModelField(field_info=field_info, name=name) |
|
|
|
ModelField( |
|
|
|
field_info=field_info, name=name, model_config=model.model_config |
|
|
|
) |
|
|
|
for name, field_info in model.model_fields.items() |
|
|
|
] |
|
|
|
|
|
|
|
|
|
@ -80,6 +80,34 @@ def test_complex(): |
|
|
|
assert response2.json() == [1, 2] |
|
|
|
|
|
|
|
|
|
|
|
def test_propagates_pydantic_model_config(): |
|
|
|
app = FastAPI() |
|
|
|
|
|
|
|
class Missing: |
|
|
|
def __bool__(self): |
|
|
|
return False |
|
|
|
|
|
|
|
class Model(BaseModel): |
|
|
|
model_config = ConfigDict( |
|
|
|
arbitrary_types_allowed=True, |
|
|
|
) |
|
|
|
value: str | Missing = Missing() |
|
|
|
|
|
|
|
@app.post("/") |
|
|
|
def foo(req: Model) -> str | None: |
|
|
|
return req.value or None |
|
|
|
|
|
|
|
client = TestClient(app) |
|
|
|
|
|
|
|
response = client.post("/", json={}) |
|
|
|
assert response.status_code == 200, response.text |
|
|
|
assert response.json() is None |
|
|
|
|
|
|
|
response2 = client.post("/", json={"value": "foo"}) |
|
|
|
assert response2.status_code == 200, response2.text |
|
|
|
assert response2.json() == "foo" |
|
|
|
|
|
|
|
|
|
|
|
def test_is_bytes_sequence_annotation_union(): |
|
|
|
# For coverage |
|
|
|
# TODO: in theory this would allow declaring types that could be lists of bytes |
|
|
|