Coverage for tests/test_multi_body_errors.py: 100%

30 statements  

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

1from decimal import Decimal 1abcde

2from typing import List 1abcde

3 

4from dirty_equals import IsDict, IsOneOf 1abcde

5from fastapi import FastAPI 1abcde

6from fastapi.testclient import TestClient 1abcde

7from pydantic import BaseModel, condecimal 1abcde

8 

9app = FastAPI() 1abcde

10 

11 

12class Item(BaseModel): 1abcde

13 name: str 1abcde

14 age: condecimal(gt=Decimal(0.0)) # type: ignore 1abcde

15 

16 

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

18def save_item_no_body(item: List[Item]): 1abcde

19 return {"item": item} 1abcde

20 

21 

22client = TestClient(app) 1abcde

23 

24 

25def test_put_correct_body(): 1abcde

26 response = client.post("/items/", json=[{"name": "Foo", "age": 5}]) 1abcde

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

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

29 "item": [ 

30 { 

31 "name": "Foo", 

32 "age": IsOneOf( 

33 5, 

34 # TODO: remove when deprecating Pydantic v1 

35 "5", 

36 ), 

37 } 

38 ] 

39 } 

40 

41 

42def test_jsonable_encoder_requiring_error(): 1abcde

43 response = client.post("/items/", json=[{"name": "Foo", "age": -1.0}]) 1abcde

44 assert response.status_code == 422, response.text 1abcde

45 assert response.json() == IsDict( 1abcde

46 { 

47 "detail": [ 

48 { 

49 "type": "greater_than", 

50 "loc": ["body", 0, "age"], 

51 "msg": "Input should be greater than 0", 

52 "input": -1.0, 

53 "ctx": {"gt": 0}, 

54 } 

55 ] 

56 } 

57 ) | IsDict( 

58 # TODO: remove when deprecating Pydantic v1 

59 { 

60 "detail": [ 

61 { 

62 "ctx": {"limit_value": 0.0}, 

63 "loc": ["body", 0, "age"], 

64 "msg": "ensure this value is greater than 0", 

65 "type": "value_error.number.not_gt", 

66 } 

67 ] 

68 } 

69 ) 

70 

71 

72def test_put_incorrect_body_multiple(): 1abcde

73 response = client.post("/items/", json=[{"age": "five"}, {"age": "six"}]) 1abcde

74 assert response.status_code == 422, response.text 1abcde

75 assert response.json() == IsDict( 1abcde

76 { 

77 "detail": [ 

78 { 

79 "type": "missing", 

80 "loc": ["body", 0, "name"], 

81 "msg": "Field required", 

82 "input": {"age": "five"}, 

83 }, 

84 { 

85 "type": "decimal_parsing", 

86 "loc": ["body", 0, "age"], 

87 "msg": "Input should be a valid decimal", 

88 "input": "five", 

89 }, 

90 { 

91 "type": "missing", 

92 "loc": ["body", 1, "name"], 

93 "msg": "Field required", 

94 "input": {"age": "six"}, 

95 }, 

96 { 

97 "type": "decimal_parsing", 

98 "loc": ["body", 1, "age"], 

99 "msg": "Input should be a valid decimal", 

100 "input": "six", 

101 }, 

102 ] 

103 } 

104 ) | IsDict( 

105 # TODO: remove when deprecating Pydantic v1 

106 { 

107 "detail": [ 

108 { 

109 "loc": ["body", 0, "name"], 

110 "msg": "field required", 

111 "type": "value_error.missing", 

112 }, 

113 { 

114 "loc": ["body", 0, "age"], 

115 "msg": "value is not a valid decimal", 

116 "type": "type_error.decimal", 

117 }, 

118 { 

119 "loc": ["body", 1, "name"], 

120 "msg": "field required", 

121 "type": "value_error.missing", 

122 }, 

123 { 

124 "loc": ["body", 1, "age"], 

125 "msg": "value is not a valid decimal", 

126 "type": "type_error.decimal", 

127 }, 

128 ] 

129 } 

130 ) 

131 

132 

133def test_openapi_schema(): 1abcde

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

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

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

137 "openapi": "3.1.0", 

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

139 "paths": { 

140 "/items/": { 

141 "post": { 

142 "responses": { 

143 "200": { 

144 "description": "Successful Response", 

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

146 }, 

147 "422": { 

148 "description": "Validation Error", 

149 "content": { 

150 "application/json": { 

151 "schema": { 

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

153 } 

154 } 

155 }, 

156 }, 

157 }, 

158 "summary": "Save Item No Body", 

159 "operationId": "save_item_no_body_items__post", 

160 "requestBody": { 

161 "content": { 

162 "application/json": { 

163 "schema": { 

164 "title": "Item", 

165 "type": "array", 

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

167 } 

168 } 

169 }, 

170 "required": True, 

171 }, 

172 } 

173 } 

174 }, 

175 "components": { 

176 "schemas": { 

177 "Item": { 

178 "title": "Item", 

179 "required": ["name", "age"], 

180 "type": "object", 

181 "properties": { 

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

183 "age": IsDict( 

184 { 

185 "title": "Age", 

186 "anyOf": [ 

187 {"exclusiveMinimum": 0.0, "type": "number"}, 

188 {"type": "string"}, 

189 ], 

190 } 

191 ) 

192 | IsDict( 

193 # TODO: remove when deprecating Pydantic v1 

194 { 

195 "title": "Age", 

196 "exclusiveMinimum": 0.0, 

197 "type": "number", 

198 } 

199 ), 

200 }, 

201 }, 

202 "ValidationError": { 

203 "title": "ValidationError", 

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

205 "type": "object", 

206 "properties": { 

207 "loc": { 

208 "title": "Location", 

209 "type": "array", 

210 "items": { 

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

212 }, 

213 }, 

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

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

216 }, 

217 }, 

218 "HTTPValidationError": { 

219 "title": "HTTPValidationError", 

220 "type": "object", 

221 "properties": { 

222 "detail": { 

223 "title": "Detail", 

224 "type": "array", 

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

226 } 

227 }, 

228 }, 

229 } 

230 }, 

231 }