Coverage for tests / test_union_body_discriminator_annotated.py: 100%
41 statements
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-12 18:15 +0000
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-12 18:15 +0000
1# Ref: https://github.com/fastapi/fastapi/discussions/14495
3from typing import Annotated, Union 1abdc
5import pytest 1abdc
6from fastapi import FastAPI 1abdc
7from fastapi.testclient import TestClient 1abdc
8from inline_snapshot import snapshot 1abdc
9from pydantic import BaseModel 1abdc
12@pytest.fixture(name="client") 1abdc
13def client_fixture() -> TestClient: 1abdc
14 from fastapi import Body 1abc
15 from pydantic import Discriminator, Tag 1abc
17 class Cat(BaseModel): 1abc
18 pet_type: str = "cat" 1abc
19 meows: int 1abc
21 class Dog(BaseModel): 1abc
22 pet_type: str = "dog" 1abc
23 barks: float 1abc
25 def get_pet_type(v): 1abc
26 assert isinstance(v, dict) 1efg
27 return v.get("pet_type", "") 1efg
29 Pet = Annotated[ 1abc
30 Union[Annotated[Cat, Tag("cat")], Annotated[Dog, Tag("dog")]],
31 Discriminator(get_pet_type),
32 ]
34 app = FastAPI() 1abc
36 @app.post("/pet/assignment") 1abc
37 async def create_pet_assignment(pet: Pet = Body()): 1abc
38 return pet 1hij
40 @app.post("/pet/annotated") 1abc
41 async def create_pet_annotated(pet: Annotated[Pet, Body()]): 1abc
42 return pet 1efg
44 client = TestClient(app) 1abc
45 return client 1abc
48def test_union_body_discriminator_assignment(client: TestClient) -> None: 1abdc
49 response = client.post("/pet/assignment", json={"pet_type": "cat", "meows": 5}) 1hij
50 assert response.status_code == 200, response.text 1hij
51 assert response.json() == {"pet_type": "cat", "meows": 5} 1hij
54def test_union_body_discriminator_annotated(client: TestClient) -> None: 1abdc
55 response = client.post("/pet/annotated", json={"pet_type": "dog", "barks": 3.5}) 1efg
56 assert response.status_code == 200, response.text 1efg
57 assert response.json() == {"pet_type": "dog", "barks": 3.5} 1efg
60def test_openapi_schema(client: TestClient) -> None: 1abdc
61 response = client.get("/openapi.json") 1klm
62 assert response.status_code == 200, response.text 1klm
63 assert response.json() == snapshot( 1klm
64 {
65 "openapi": "3.1.0",
66 "info": {"title": "FastAPI", "version": "0.1.0"},
67 "paths": {
68 "/pet/assignment": {
69 "post": {
70 "summary": "Create Pet Assignment",
71 "operationId": "create_pet_assignment_pet_assignment_post",
72 "requestBody": {
73 "content": {
74 "application/json": {
75 "schema": {
76 "anyOf": [
77 {"$ref": "#/components/schemas/Cat"},
78 {"$ref": "#/components/schemas/Dog"},
79 ],
80 "title": "Pet",
81 }
82 }
83 },
84 "required": True,
85 },
86 "responses": {
87 "200": {
88 "description": "Successful Response",
89 "content": {"application/json": {"schema": {}}},
90 },
91 "422": {
92 "description": "Validation Error",
93 "content": {
94 "application/json": {
95 "schema": {
96 "$ref": "#/components/schemas/HTTPValidationError"
97 }
98 }
99 },
100 },
101 },
102 }
103 },
104 "/pet/annotated": {
105 "post": {
106 "summary": "Create Pet Annotated",
107 "operationId": "create_pet_annotated_pet_annotated_post",
108 "requestBody": {
109 "content": {
110 "application/json": {
111 "schema": {
112 "oneOf": [
113 {"$ref": "#/components/schemas/Cat"},
114 {"$ref": "#/components/schemas/Dog"},
115 ],
116 "title": "Pet",
117 }
118 }
119 },
120 "required": True,
121 },
122 "responses": {
123 "200": {
124 "description": "Successful Response",
125 "content": {"application/json": {"schema": {}}},
126 },
127 "422": {
128 "description": "Validation Error",
129 "content": {
130 "application/json": {
131 "schema": {
132 "$ref": "#/components/schemas/HTTPValidationError"
133 }
134 }
135 },
136 },
137 },
138 }
139 },
140 },
141 "components": {
142 "schemas": {
143 "Cat": {
144 "properties": {
145 "pet_type": {
146 "type": "string",
147 "title": "Pet Type",
148 "default": "cat",
149 },
150 "meows": {"type": "integer", "title": "Meows"},
151 },
152 "type": "object",
153 "required": ["meows"],
154 "title": "Cat",
155 },
156 "Dog": {
157 "properties": {
158 "pet_type": {
159 "type": "string",
160 "title": "Pet Type",
161 "default": "dog",
162 },
163 "barks": {"type": "number", "title": "Barks"},
164 },
165 "type": "object",
166 "required": ["barks"],
167 "title": "Dog",
168 },
169 "HTTPValidationError": {
170 "properties": {
171 "detail": {
172 "items": {
173 "$ref": "#/components/schemas/ValidationError"
174 },
175 "type": "array",
176 "title": "Detail",
177 }
178 },
179 "type": "object",
180 "title": "HTTPValidationError",
181 },
182 "ValidationError": {
183 "properties": {
184 "ctx": {"title": "Context", "type": "object"},
185 "input": {"title": "Input"},
186 "loc": {
187 "items": {
188 "anyOf": [{"type": "string"}, {"type": "integer"}]
189 },
190 "type": "array",
191 "title": "Location",
192 },
193 "msg": {"type": "string", "title": "Message"},
194 "type": {"type": "string", "title": "Error Type"},
195 },
196 "type": "object",
197 "required": ["loc", "msg", "type"],
198 "title": "ValidationError",
199 },
200 }
201 },
202 }
203 )