Coverage for tests / test_request_params / test_query / test_optional_str.py: 100%

123 statements  

« prev     ^ index     » next       coverage.py v7.13.3, created at 2026-02-12 18:15 +0000

1from typing import Annotated, Optional 1abcd

2 

3import pytest 1abcd

4from fastapi import FastAPI, Query 1abcd

5from fastapi.testclient import TestClient 1abcd

6from inline_snapshot import snapshot 1abcd

7from pydantic import BaseModel, Field 1abcd

8 

9app = FastAPI() 1abcd

10 

11# ===================================================================================== 

12# Without aliases 

13 

14 

15@app.get("/optional-str") 1abcd

16async def read_optional_str(p: Optional[str] = None): 1abcd

17 return {"p": p} 1efghij

18 

19 

20class QueryModelOptionalStr(BaseModel): 1abcd

21 p: Optional[str] = None 1abcd

22 

23 

24@app.get("/model-optional-str") 1abcd

25async def read_model_optional_str(p: Annotated[QueryModelOptionalStr, Query()]): 1abcd

26 return {"p": p.p} 1efghij

27 

28 

29@pytest.mark.parametrize( 1abcd

30 "path", 

31 ["/optional-str", "/model-optional-str"], 

32) 

33def test_optional_str_schema(path: str): 1abcd

34 assert app.openapi()["paths"][path]["get"]["parameters"] == snapshot( 1OPQ

35 [ 

36 { 

37 "required": False, 

38 "schema": { 

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

40 "title": "P", 

41 }, 

42 "name": "p", 

43 "in": "query", 

44 } 

45 ] 

46 ) 

47 

48 

49@pytest.mark.parametrize( 1abcd

50 "path", 

51 ["/optional-str", "/model-optional-str"], 

52) 

53def test_optional_str_missing(path: str): 1abcd

54 client = TestClient(app) 1fhj

55 response = client.get(path) 1fhj

56 assert response.status_code == 200 1fhj

57 assert response.json() == {"p": None} 1fhj

58 

59 

60@pytest.mark.parametrize( 1abcd

61 "path", 

62 ["/optional-str", "/model-optional-str"], 

63) 

64def test_optional_str(path: str): 1abcd

65 client = TestClient(app) 1egi

66 response = client.get(f"{path}?p=hello") 1egi

67 assert response.status_code == 200 1egi

68 assert response.json() == {"p": "hello"} 1egi

69 

70 

71# ===================================================================================== 

72# Alias 

73 

74 

75@app.get("/optional-alias") 1abcd

76async def read_optional_alias( 1abcd

77 p: Annotated[Optional[str], Query(alias="p_alias")] = None, 

78): 

79 return {"p": p} 1klmnopqrs

80 

81 

82class QueryModelOptionalAlias(BaseModel): 1abcd

83 p: Optional[str] = Field(None, alias="p_alias") 1abcd

84 

85 

86@app.get("/model-optional-alias") 1abcd

87async def read_model_optional_alias(p: Annotated[QueryModelOptionalAlias, Query()]): 1abcd

88 return {"p": p.p} 1klmnopqrs

89 

90 

91@pytest.mark.parametrize( 1abcd

92 "path", 

93 ["/optional-alias", "/model-optional-alias"], 

94) 

95def test_optional_str_alias_schema(path: str): 1abcd

96 assert app.openapi()["paths"][path]["get"]["parameters"] == snapshot( 1RST

97 [ 

98 { 

99 "required": False, 

100 "schema": { 

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

102 "title": "P Alias", 

103 }, 

104 "name": "p_alias", 

105 "in": "query", 

106 } 

107 ] 

108 ) 

109 

110 

111@pytest.mark.parametrize( 1abcd

112 "path", 

113 ["/optional-alias", "/model-optional-alias"], 

114) 

115def test_optional_alias_missing(path: str): 1abcd

116 client = TestClient(app) 1mps

117 response = client.get(path) 1mps

118 assert response.status_code == 200 1mps

119 assert response.json() == {"p": None} 1mps

120 

121 

122@pytest.mark.parametrize( 1abcd

123 "path", 

124 ["/optional-alias", "/model-optional-alias"], 

125) 

126def test_optional_alias_by_name(path: str): 1abcd

127 client = TestClient(app) 1lor

128 response = client.get(f"{path}?p=hello") 1lor

129 assert response.status_code == 200 1lor

130 assert response.json() == {"p": None} 1lor

131 

132 

133@pytest.mark.parametrize( 1abcd

134 "path", 

135 [ 

136 "/optional-alias", 

137 "/model-optional-alias", 

138 ], 

139) 

140def test_optional_alias_by_alias(path: str): 1abcd

141 client = TestClient(app) 1knq

142 response = client.get(f"{path}?p_alias=hello") 1knq

143 assert response.status_code == 200 1knq

144 assert response.json() == {"p": "hello"} 1knq

145 

146 

147# ===================================================================================== 

148# Validation alias 

149 

150 

151@app.get("/optional-validation-alias") 1abcd

152def read_optional_validation_alias( 1abcd

153 p: Annotated[Optional[str], Query(validation_alias="p_val_alias")] = None, 

154): 

155 return {"p": p} 1tuvwxyzAB

156 

157 

158class QueryModelOptionalValidationAlias(BaseModel): 1abcd

159 p: Optional[str] = Field(None, validation_alias="p_val_alias") 1abcd

160 

161 

162@app.get("/model-optional-validation-alias") 1abcd

163def read_model_optional_validation_alias( 1abcd

164 p: Annotated[QueryModelOptionalValidationAlias, Query()], 

165): 

166 return {"p": p.p} 1tuvwxyzAB

167 

168 

169@pytest.mark.parametrize( 1abcd

170 "path", 

171 ["/optional-validation-alias", "/model-optional-validation-alias"], 

172) 

173def test_optional_validation_alias_schema(path: str): 1abcd

174 assert app.openapi()["paths"][path]["get"]["parameters"] == snapshot( 1UVW

175 [ 

176 { 

177 "required": False, 

178 "schema": { 

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

180 "title": "P Val Alias", 

181 }, 

182 "name": "p_val_alias", 

183 "in": "query", 

184 } 

185 ] 

186 ) 

187 

188 

189@pytest.mark.parametrize( 1abcd

190 "path", 

191 ["/optional-validation-alias", "/model-optional-validation-alias"], 

192) 

193def test_optional_validation_alias_missing(path: str): 1abcd

194 client = TestClient(app) 1vyB

195 response = client.get(path) 1vyB

196 assert response.status_code == 200 1vyB

197 assert response.json() == {"p": None} 1vyB

198 

199 

200@pytest.mark.parametrize( 1abcd

201 "path", 

202 [ 

203 "/optional-validation-alias", 

204 "/model-optional-validation-alias", 

205 ], 

206) 

207def test_optional_validation_alias_by_name(path: str): 1abcd

208 client = TestClient(app) 1twz

209 response = client.get(f"{path}?p=hello") 1twz

210 assert response.status_code == 200 1twz

211 assert response.json() == {"p": None} 1twz

212 

213 

214@pytest.mark.parametrize( 1abcd

215 "path", 

216 [ 

217 "/optional-validation-alias", 

218 "/model-optional-validation-alias", 

219 ], 

220) 

221def test_optional_validation_alias_by_validation_alias(path: str): 1abcd

222 client = TestClient(app) 1uxA

223 response = client.get(f"{path}?p_val_alias=hello") 1uxA

224 assert response.status_code == 200 1uxA

225 assert response.json() == {"p": "hello"} 1uxA

226 

227 

228# ===================================================================================== 

229# Alias and validation alias 

230 

231 

232@app.get("/optional-alias-and-validation-alias") 1abcd

233def read_optional_alias_and_validation_alias( 1abcd

234 p: Annotated[ 

235 Optional[str], Query(alias="p_alias", validation_alias="p_val_alias") 

236 ] = None, 

237): 

238 return {"p": p} 1CDEFGHIJKLMN

239 

240 

241class QueryModelOptionalAliasAndValidationAlias(BaseModel): 1abcd

242 p: Optional[str] = Field(None, alias="p_alias", validation_alias="p_val_alias") 1abcd

243 

244 

245@app.get("/model-optional-alias-and-validation-alias") 1abcd

246def read_model_optional_alias_and_validation_alias( 1abcd

247 p: Annotated[QueryModelOptionalAliasAndValidationAlias, Query()], 

248): 

249 return {"p": p.p} 1CDEFGHIJKLMN

250 

251 

252@pytest.mark.parametrize( 1abcd

253 "path", 

254 [ 

255 "/optional-alias-and-validation-alias", 

256 "/model-optional-alias-and-validation-alias", 

257 ], 

258) 

259def test_optional_alias_and_validation_alias_schema(path: str): 1abcd

260 assert app.openapi()["paths"][path]["get"]["parameters"] == snapshot( 1XYZ

261 [ 

262 { 

263 "required": False, 

264 "schema": { 

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

266 "title": "P Val Alias", 

267 }, 

268 "name": "p_val_alias", 

269 "in": "query", 

270 } 

271 ] 

272 ) 

273 

274 

275@pytest.mark.parametrize( 1abcd

276 "path", 

277 [ 

278 "/optional-alias-and-validation-alias", 

279 "/model-optional-alias-and-validation-alias", 

280 ], 

281) 

282def test_optional_alias_and_validation_alias_missing(path: str): 1abcd

283 client = TestClient(app) 1FJN

284 response = client.get(path) 1FJN

285 assert response.status_code == 200 1FJN

286 assert response.json() == {"p": None} 1FJN

287 

288 

289@pytest.mark.parametrize( 1abcd

290 "path", 

291 [ 

292 "/optional-alias-and-validation-alias", 

293 "/model-optional-alias-and-validation-alias", 

294 ], 

295) 

296def test_optional_alias_and_validation_alias_by_name(path: str): 1abcd

297 client = TestClient(app) 1DHL

298 response = client.get(f"{path}?p=hello") 1DHL

299 assert response.status_code == 200 1DHL

300 assert response.json() == {"p": None} 1DHL

301 

302 

303@pytest.mark.parametrize( 1abcd

304 "path", 

305 [ 

306 "/optional-alias-and-validation-alias", 

307 "/model-optional-alias-and-validation-alias", 

308 ], 

309) 

310def test_optional_alias_and_validation_alias_by_alias(path: str): 1abcd

311 client = TestClient(app) 1CGK

312 response = client.get(f"{path}?p_alias=hello") 1CGK

313 assert response.status_code == 200 1CGK

314 assert response.json() == {"p": None} 1CGK

315 

316 

317@pytest.mark.parametrize( 1abcd

318 "path", 

319 [ 

320 "/optional-alias-and-validation-alias", 

321 "/model-optional-alias-and-validation-alias", 

322 ], 

323) 

324def test_optional_alias_and_validation_alias_by_validation_alias(path: str): 1abcd

325 client = TestClient(app) 1EIM

326 response = client.get(f"{path}?p_val_alias=hello") 1EIM

327 assert response.status_code == 200 1EIM

328 assert response.json() == {"p": "hello"} 1EIM