Coverage for tests / test_compat.py: 100%
71 statements
« prev ^ index » next coverage.py v7.13.3, created at 2026-04-06 01:24 +0000
« prev ^ index » next coverage.py v7.13.3, created at 2026-04-06 01:24 +0000
1from fastapi import FastAPI, UploadFile 1efgh
2from fastapi._compat import ( 1efgh
3 Undefined,
4 is_uploadfile_sequence_annotation,
5)
6from fastapi._compat.shared import is_bytes_sequence_annotation 1efgh
7from fastapi.testclient import TestClient 1efgh
8from pydantic import BaseModel, ConfigDict 1efgh
9from pydantic.fields import FieldInfo 1efgh
12def test_model_field_default_required(): 1efgh
13 from fastapi._compat import v2 1yzAB
15 # For coverage
16 field_info = FieldInfo(annotation=str) 1yzAB
17 field = v2.ModelField(name="foo", field_info=field_info) 1yzAB
18 assert field.default is Undefined 1yzAB
21def test_complex(): 1efgh
22 app = FastAPI() 1ijkl
24 @app.post("/") 1ijkl
25 def foo(foo: str | list[int]): 1ijkl
26 return foo 1ijkl
28 client = TestClient(app) 1ijkl
30 response = client.post("/", json="bar") 1ijkl
31 assert response.status_code == 200, response.text 1ijkl
32 assert response.json() == "bar" 1ijkl
34 response2 = client.post("/", json=[1, 2]) 1ijkl
35 assert response2.status_code == 200, response2.text 1ijkl
36 assert response2.json() == [1, 2] 1ijkl
39def test_propagates_pydantic2_model_config(): 1efgh
40 app = FastAPI() 1abcd
42 class Missing: 1abcd
43 def __bool__(self): 1abcd
44 return False 1abcd
46 class EmbeddedModel(BaseModel): 1abcd
47 model_config = ConfigDict(arbitrary_types_allowed=True) 1abcd
48 value: str | Missing = Missing() 1abcd
50 class Model(BaseModel): 1abcd
51 model_config = ConfigDict( 1abcd
52 arbitrary_types_allowed=True,
53 )
54 value: str | Missing = Missing() 1abcd
55 embedded_model: EmbeddedModel = EmbeddedModel() 1abcd
57 @app.post("/") 1abcd
58 def foo(req: Model) -> dict[str, str | None]: 1abcd
59 return { 1abcd
60 "value": req.value or None,
61 "embedded_value": req.embedded_model.value or None,
62 }
64 client = TestClient(app) 1abcd
66 response = client.post("/", json={}) 1abcd
67 assert response.status_code == 200, response.text 1abcd
68 assert response.json() == { 1abcd
69 "value": None,
70 "embedded_value": None,
71 }
73 response2 = client.post( 1abcd
74 "/", json={"value": "foo", "embedded_model": {"value": "bar"}}
75 )
76 assert response2.status_code == 200, response2.text 1abcd
77 assert response2.json() == { 1abcd
78 "value": "foo",
79 "embedded_value": "bar",
80 }
83def test_is_bytes_sequence_annotation_union(): 1efgh
84 # For coverage
85 # TODO: in theory this would allow declaring types that could be lists of bytes
86 # to be read from files and other types, but I'm not even sure it's a good idea
87 # to support it as a first class "feature"
88 assert is_bytes_sequence_annotation(list[str] | list[bytes]) 1CDEF
91def test_is_uploadfile_sequence_annotation(): 1efgh
92 # For coverage
93 # TODO: in theory this would allow declaring types that could be lists of UploadFile
94 # and other types, but I'm not even sure it's a good idea to support it as a first
95 # class "feature"
96 assert is_uploadfile_sequence_annotation(list[str] | list[UploadFile]) 1GHIJ
99def test_serialize_sequence_value_with_optional_list(): 1efgh
100 """Test that serialize_sequence_value handles optional lists correctly."""
101 from fastapi._compat import v2 1qrst
103 field_info = FieldInfo(annotation=list[str] | None) 1qrst
104 field = v2.ModelField(name="items", field_info=field_info) 1qrst
105 result = v2.serialize_sequence_value(field=field, value=["a", "b", "c"]) 1qrst
106 assert result == ["a", "b", "c"] 1qrst
107 assert isinstance(result, list) 1qrst
110def test_serialize_sequence_value_with_optional_list_pipe_union(): 1efgh
111 """Test that serialize_sequence_value handles optional lists correctly (with new syntax)."""
112 from fastapi._compat import v2 1uvwx
114 field_info = FieldInfo(annotation=list[str] | None) 1uvwx
115 field = v2.ModelField(name="items", field_info=field_info) 1uvwx
116 result = v2.serialize_sequence_value(field=field, value=["a", "b", "c"]) 1uvwx
117 assert result == ["a", "b", "c"] 1uvwx
118 assert isinstance(result, list) 1uvwx
121def test_serialize_sequence_value_with_none_first_in_union(): 1efgh
122 """Test that serialize_sequence_value handles Union[None, List[...]] correctly."""
123 from typing import Union 1mnop
125 from fastapi._compat import v2 1mnop
127 # Use Union[None, list[str]] to ensure None comes first in the union args
128 field_info = FieldInfo(annotation=Union[None, list[str]]) # noqa: UP007 1mnop
129 field = v2.ModelField(name="items", field_info=field_info) 1mnop
130 result = v2.serialize_sequence_value(field=field, value=["x", "y"]) 1mnop
131 assert result == ["x", "y"] 1mnop
132 assert isinstance(result, list) 1mnop