Coverage for tests/test_openapi_separate_input_output_schemas.py: 100%

72 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-08-08 03:53 +0000

1from typing import List, Optional 1abcde

2 

3from fastapi import FastAPI 1abcde

4from fastapi.testclient import TestClient 1abcde

5from pydantic import BaseModel 1abcde

6 

7from .utils import PYDANTIC_V2, needs_pydanticv2 1abcde

8 

9 

10class SubItem(BaseModel): 1abcde

11 subname: str 1abcde

12 sub_description: Optional[str] = None 1abcde

13 tags: List[str] = [] 1abcde

14 if PYDANTIC_V2: 1abcde

15 model_config = {"json_schema_serialization_defaults_required": True} 1abcde

16 

17 

18class Item(BaseModel): 1abcde

19 name: str 1abcde

20 description: Optional[str] = None 1abcde

21 sub: Optional[SubItem] = None 1abcde

22 if PYDANTIC_V2: 1abcde

23 model_config = {"json_schema_serialization_defaults_required": True} 1abcde

24 

25 

26def get_app_client(separate_input_output_schemas: bool = True) -> TestClient: 1abcde

27 app = FastAPI(separate_input_output_schemas=separate_input_output_schemas) 1abcde

28 

29 @app.post("/items/") 1abcde

30 def create_item(item: Item): 1abcde

31 return item 1abcde

32 

33 @app.post("/items-list/") 1abcde

34 def create_item_list(item: List[Item]): 1abcde

35 return item 1abcde

36 

37 @app.get("/items/") 1abcde

38 def read_items() -> List[Item]: 1abcde

39 return [ 1abcde

40 Item( 

41 name="Portal Gun", 

42 description="Device to travel through the multi-rick-verse", 

43 sub=SubItem(subname="subname"), 

44 ), 

45 Item(name="Plumbus"), 

46 ] 

47 

48 client = TestClient(app) 1abcde

49 return client 1abcde

50 

51 

52def test_create_item(): 1abcde

53 client = get_app_client() 1abcde

54 client_no = get_app_client(separate_input_output_schemas=False) 1abcde

55 response = client.post("/items/", json={"name": "Plumbus"}) 1abcde

56 response2 = client_no.post("/items/", json={"name": "Plumbus"}) 1abcde

57 assert response.status_code == response2.status_code == 200, response.text 1abcde

58 assert ( 1abcde

59 response.json() 

60 == response2.json() 

61 == {"name": "Plumbus", "description": None, "sub": None} 

62 ) 

63 

64 

65def test_create_item_with_sub(): 1abcde

66 client = get_app_client() 1abcde

67 client_no = get_app_client(separate_input_output_schemas=False) 1abcde

68 data = { 1abcde

69 "name": "Plumbus", 

70 "sub": {"subname": "SubPlumbus", "sub_description": "Sub WTF"}, 

71 } 

72 response = client.post("/items/", json=data) 1abcde

73 response2 = client_no.post("/items/", json=data) 1abcde

74 assert response.status_code == response2.status_code == 200, response.text 1abcde

75 assert ( 1abcde

76 response.json() 

77 == response2.json() 

78 == { 

79 "name": "Plumbus", 

80 "description": None, 

81 "sub": {"subname": "SubPlumbus", "sub_description": "Sub WTF", "tags": []}, 

82 } 

83 ) 

84 

85 

86def test_create_item_list(): 1abcde

87 client = get_app_client() 1abcde

88 client_no = get_app_client(separate_input_output_schemas=False) 1abcde

89 data = [ 1abcde

90 {"name": "Plumbus"}, 

91 { 

92 "name": "Portal Gun", 

93 "description": "Device to travel through the multi-rick-verse", 

94 }, 

95 ] 

96 response = client.post("/items-list/", json=data) 1abcde

97 response2 = client_no.post("/items-list/", json=data) 1abcde

98 assert response.status_code == response2.status_code == 200, response.text 1abcde

99 assert ( 1abcde

100 response.json() 

101 == response2.json() 

102 == [ 

103 {"name": "Plumbus", "description": None, "sub": None}, 

104 { 

105 "name": "Portal Gun", 

106 "description": "Device to travel through the multi-rick-verse", 

107 "sub": None, 

108 }, 

109 ] 

110 ) 

111 

112 

113def test_read_items(): 1abcde

114 client = get_app_client() 1abcde

115 client_no = get_app_client(separate_input_output_schemas=False) 1abcde

116 response = client.get("/items/") 1abcde

117 response2 = client_no.get("/items/") 1abcde

118 assert response.status_code == response2.status_code == 200, response.text 1abcde

119 assert ( 1abcde

120 response.json() 

121 == response2.json() 

122 == [ 

123 { 

124 "name": "Portal Gun", 

125 "description": "Device to travel through the multi-rick-verse", 

126 "sub": {"subname": "subname", "sub_description": None, "tags": []}, 

127 }, 

128 {"name": "Plumbus", "description": None, "sub": None}, 

129 ] 

130 ) 

131 

132 

133@needs_pydanticv2 1abcde

134def test_openapi_schema(): 1abcde

135 client = get_app_client() 1abcde

136 response = client.get("/openapi.json") 1abcde

137 assert response.status_code == 200, response.text 1abcde

138 assert response.json() == { 1abcde

139 "openapi": "3.1.0", 

140 "info": {"title": "FastAPI", "version": "0.1.0"}, 

141 "paths": { 

142 "/items/": { 

143 "get": { 

144 "summary": "Read Items", 

145 "operationId": "read_items_items__get", 

146 "responses": { 

147 "200": { 

148 "description": "Successful Response", 

149 "content": { 

150 "application/json": { 

151 "schema": { 

152 "items": { 

153 "$ref": "#/components/schemas/Item-Output" 

154 }, 

155 "type": "array", 

156 "title": "Response Read Items Items Get", 

157 } 

158 } 

159 }, 

160 } 

161 }, 

162 }, 

163 "post": { 

164 "summary": "Create Item", 

165 "operationId": "create_item_items__post", 

166 "requestBody": { 

167 "content": { 

168 "application/json": { 

169 "schema": {"$ref": "#/components/schemas/Item-Input"} 

170 } 

171 }, 

172 "required": True, 

173 }, 

174 "responses": { 

175 "200": { 

176 "description": "Successful Response", 

177 "content": {"application/json": {"schema": {}}}, 

178 }, 

179 "422": { 

180 "description": "Validation Error", 

181 "content": { 

182 "application/json": { 

183 "schema": { 

184 "$ref": "#/components/schemas/HTTPValidationError" 

185 } 

186 } 

187 }, 

188 }, 

189 }, 

190 }, 

191 }, 

192 "/items-list/": { 

193 "post": { 

194 "summary": "Create Item List", 

195 "operationId": "create_item_list_items_list__post", 

196 "requestBody": { 

197 "content": { 

198 "application/json": { 

199 "schema": { 

200 "items": { 

201 "$ref": "#/components/schemas/Item-Input" 

202 }, 

203 "type": "array", 

204 "title": "Item", 

205 } 

206 } 

207 }, 

208 "required": True, 

209 }, 

210 "responses": { 

211 "200": { 

212 "description": "Successful Response", 

213 "content": {"application/json": {"schema": {}}}, 

214 }, 

215 "422": { 

216 "description": "Validation Error", 

217 "content": { 

218 "application/json": { 

219 "schema": { 

220 "$ref": "#/components/schemas/HTTPValidationError" 

221 } 

222 } 

223 }, 

224 }, 

225 }, 

226 } 

227 }, 

228 }, 

229 "components": { 

230 "schemas": { 

231 "HTTPValidationError": { 

232 "properties": { 

233 "detail": { 

234 "items": {"$ref": "#/components/schemas/ValidationError"}, 

235 "type": "array", 

236 "title": "Detail", 

237 } 

238 }, 

239 "type": "object", 

240 "title": "HTTPValidationError", 

241 }, 

242 "Item-Input": { 

243 "properties": { 

244 "name": {"type": "string", "title": "Name"}, 

245 "description": { 

246 "anyOf": [{"type": "string"}, {"type": "null"}], 

247 "title": "Description", 

248 }, 

249 "sub": { 

250 "anyOf": [ 

251 {"$ref": "#/components/schemas/SubItem-Input"}, 

252 {"type": "null"}, 

253 ] 

254 }, 

255 }, 

256 "type": "object", 

257 "required": ["name"], 

258 "title": "Item", 

259 }, 

260 "Item-Output": { 

261 "properties": { 

262 "name": {"type": "string", "title": "Name"}, 

263 "description": { 

264 "anyOf": [{"type": "string"}, {"type": "null"}], 

265 "title": "Description", 

266 }, 

267 "sub": { 

268 "anyOf": [ 

269 {"$ref": "#/components/schemas/SubItem-Output"}, 

270 {"type": "null"}, 

271 ] 

272 }, 

273 }, 

274 "type": "object", 

275 "required": ["name", "description", "sub"], 

276 "title": "Item", 

277 }, 

278 "SubItem-Input": { 

279 "properties": { 

280 "subname": {"type": "string", "title": "Subname"}, 

281 "sub_description": { 

282 "anyOf": [{"type": "string"}, {"type": "null"}], 

283 "title": "Sub Description", 

284 }, 

285 "tags": { 

286 "items": {"type": "string"}, 

287 "type": "array", 

288 "title": "Tags", 

289 "default": [], 

290 }, 

291 }, 

292 "type": "object", 

293 "required": ["subname"], 

294 "title": "SubItem", 

295 }, 

296 "SubItem-Output": { 

297 "properties": { 

298 "subname": {"type": "string", "title": "Subname"}, 

299 "sub_description": { 

300 "anyOf": [{"type": "string"}, {"type": "null"}], 

301 "title": "Sub Description", 

302 }, 

303 "tags": { 

304 "items": {"type": "string"}, 

305 "type": "array", 

306 "title": "Tags", 

307 "default": [], 

308 }, 

309 }, 

310 "type": "object", 

311 "required": ["subname", "sub_description", "tags"], 

312 "title": "SubItem", 

313 }, 

314 "ValidationError": { 

315 "properties": { 

316 "loc": { 

317 "items": { 

318 "anyOf": [{"type": "string"}, {"type": "integer"}] 

319 }, 

320 "type": "array", 

321 "title": "Location", 

322 }, 

323 "msg": {"type": "string", "title": "Message"}, 

324 "type": {"type": "string", "title": "Error Type"}, 

325 }, 

326 "type": "object", 

327 "required": ["loc", "msg", "type"], 

328 "title": "ValidationError", 

329 }, 

330 } 

331 }, 

332 } 

333 

334 

335@needs_pydanticv2 1abcde

336def test_openapi_schema_no_separate(): 1abcde

337 client = get_app_client(separate_input_output_schemas=False) 1abcde

338 response = client.get("/openapi.json") 1abcde

339 assert response.status_code == 200, response.text 1abcde

340 assert response.json() == { 1abcde

341 "openapi": "3.1.0", 

342 "info": {"title": "FastAPI", "version": "0.1.0"}, 

343 "paths": { 

344 "/items/": { 

345 "get": { 

346 "summary": "Read Items", 

347 "operationId": "read_items_items__get", 

348 "responses": { 

349 "200": { 

350 "description": "Successful Response", 

351 "content": { 

352 "application/json": { 

353 "schema": { 

354 "items": {"$ref": "#/components/schemas/Item"}, 

355 "type": "array", 

356 "title": "Response Read Items Items Get", 

357 } 

358 } 

359 }, 

360 } 

361 }, 

362 }, 

363 "post": { 

364 "summary": "Create Item", 

365 "operationId": "create_item_items__post", 

366 "requestBody": { 

367 "content": { 

368 "application/json": { 

369 "schema": {"$ref": "#/components/schemas/Item"} 

370 } 

371 }, 

372 "required": True, 

373 }, 

374 "responses": { 

375 "200": { 

376 "description": "Successful Response", 

377 "content": {"application/json": {"schema": {}}}, 

378 }, 

379 "422": { 

380 "description": "Validation Error", 

381 "content": { 

382 "application/json": { 

383 "schema": { 

384 "$ref": "#/components/schemas/HTTPValidationError" 

385 } 

386 } 

387 }, 

388 }, 

389 }, 

390 }, 

391 }, 

392 "/items-list/": { 

393 "post": { 

394 "summary": "Create Item List", 

395 "operationId": "create_item_list_items_list__post", 

396 "requestBody": { 

397 "content": { 

398 "application/json": { 

399 "schema": { 

400 "items": {"$ref": "#/components/schemas/Item"}, 

401 "type": "array", 

402 "title": "Item", 

403 } 

404 } 

405 }, 

406 "required": True, 

407 }, 

408 "responses": { 

409 "200": { 

410 "description": "Successful Response", 

411 "content": {"application/json": {"schema": {}}}, 

412 }, 

413 "422": { 

414 "description": "Validation Error", 

415 "content": { 

416 "application/json": { 

417 "schema": { 

418 "$ref": "#/components/schemas/HTTPValidationError" 

419 } 

420 } 

421 }, 

422 }, 

423 }, 

424 } 

425 }, 

426 }, 

427 "components": { 

428 "schemas": { 

429 "HTTPValidationError": { 

430 "properties": { 

431 "detail": { 

432 "items": {"$ref": "#/components/schemas/ValidationError"}, 

433 "type": "array", 

434 "title": "Detail", 

435 } 

436 }, 

437 "type": "object", 

438 "title": "HTTPValidationError", 

439 }, 

440 "Item": { 

441 "properties": { 

442 "name": {"type": "string", "title": "Name"}, 

443 "description": { 

444 "anyOf": [{"type": "string"}, {"type": "null"}], 

445 "title": "Description", 

446 }, 

447 "sub": { 

448 "anyOf": [ 

449 {"$ref": "#/components/schemas/SubItem"}, 

450 {"type": "null"}, 

451 ] 

452 }, 

453 }, 

454 "type": "object", 

455 "required": ["name"], 

456 "title": "Item", 

457 }, 

458 "SubItem": { 

459 "properties": { 

460 "subname": {"type": "string", "title": "Subname"}, 

461 "sub_description": { 

462 "anyOf": [{"type": "string"}, {"type": "null"}], 

463 "title": "Sub Description", 

464 }, 

465 "tags": { 

466 "items": {"type": "string"}, 

467 "type": "array", 

468 "title": "Tags", 

469 "default": [], 

470 }, 

471 }, 

472 "type": "object", 

473 "required": ["subname"], 

474 "title": "SubItem", 

475 }, 

476 "ValidationError": { 

477 "properties": { 

478 "loc": { 

479 "items": { 

480 "anyOf": [{"type": "string"}, {"type": "integer"}] 

481 }, 

482 "type": "array", 

483 "title": "Location", 

484 }, 

485 "msg": {"type": "string", "title": "Message"}, 

486 "type": {"type": "string", "title": "Error Type"}, 

487 }, 

488 "type": "object", 

489 "required": ["loc", "msg", "type"], 

490 "title": "ValidationError", 

491 }, 

492 } 

493 }, 

494 }