Coverage for tests / test_multi_body_errors.py: 100%

30 statements  

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

1from decimal import Decimal 1abcd

2 

3from dirty_equals import IsOneOf 1abcd

4from fastapi import FastAPI 1abcd

5from fastapi.testclient import TestClient 1abcd

6from inline_snapshot import snapshot 1abcd

7from pydantic import BaseModel, condecimal 1abcd

8 

9app = FastAPI() 1abcd

10 

11 

12class Item(BaseModel): 1abcd

13 name: str 1abcd

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

15 

16 

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

18def save_item_no_body(item: list[Item]): 1abcd

19 return {"item": item} 1efg

20 

21 

22client = TestClient(app) 1abcd

23 

24 

25def test_put_correct_body(): 1abcd

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

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

28 assert response.json() == snapshot( 1efg

29 { 

30 "item": [ 

31 { 

32 "name": "Foo", 

33 "age": "5", 

34 } 

35 ] 

36 } 

37 ) 

38 

39 

40def test_jsonable_encoder_requiring_error(): 1abcd

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

42 assert response.status_code == 422, response.text 1hij

43 assert response.json() == { 1hij

44 "detail": [ 

45 { 

46 "type": "greater_than", 

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

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

49 "input": -1.0, 

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

51 } 

52 ] 

53 } 

54 

55 

56def test_put_incorrect_body_multiple(): 1abcd

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

58 assert response.status_code == 422, response.text 1klm

59 assert response.json() == { 1klm

60 "detail": [ 

61 { 

62 "type": "missing", 

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

64 "msg": "Field required", 

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

66 }, 

67 { 

68 "type": "decimal_parsing", 

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

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

71 "input": "five", 

72 }, 

73 { 

74 "type": "missing", 

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

76 "msg": "Field required", 

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

78 }, 

79 { 

80 "type": "decimal_parsing", 

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

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

83 "input": "six", 

84 }, 

85 ] 

86 } 

87 

88 

89def test_openapi_schema(): 1abcd

90 response = client.get("/openapi.json") 1nop

91 assert response.status_code == 200, response.text 1nop

92 assert response.json() == snapshot( 1nop

93 { 

94 "openapi": "3.1.0", 

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

96 "paths": { 

97 "/items/": { 

98 "post": { 

99 "responses": { 

100 "200": { 

101 "description": "Successful Response", 

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

103 }, 

104 "422": { 

105 "description": "Validation Error", 

106 "content": { 

107 "application/json": { 

108 "schema": { 

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

110 } 

111 } 

112 }, 

113 }, 

114 }, 

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

116 "operationId": "save_item_no_body_items__post", 

117 "requestBody": { 

118 "content": { 

119 "application/json": { 

120 "schema": { 

121 "title": "Item", 

122 "type": "array", 

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

124 } 

125 } 

126 }, 

127 "required": True, 

128 }, 

129 } 

130 } 

131 }, 

132 "components": { 

133 "schemas": { 

134 "Item": { 

135 "title": "Item", 

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

137 "type": "object", 

138 "properties": { 

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

140 "age": { 

141 "title": "Age", 

142 "anyOf": [ 

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

144 IsOneOf( 

145 # pydantic < 2.12.0 

146 {"type": "string"}, 

147 # pydantic >= 2.12.0 

148 { 

149 "type": "string", 

150 "pattern": r"^(?!^[-+.]*$)[+-]?0*\d*\.?\d*$", 

151 }, 

152 ), 

153 ], 

154 }, 

155 }, 

156 }, 

157 "ValidationError": { 

158 "title": "ValidationError", 

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

160 "type": "object", 

161 "properties": { 

162 "loc": { 

163 "title": "Location", 

164 "type": "array", 

165 "items": { 

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

167 }, 

168 }, 

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

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

171 "input": {"title": "Input"}, 

172 "ctx": {"title": "Context", "type": "object"}, 

173 }, 

174 }, 

175 "HTTPValidationError": { 

176 "title": "HTTPValidationError", 

177 "type": "object", 

178 "properties": { 

179 "detail": { 

180 "title": "Detail", 

181 "type": "array", 

182 "items": { 

183 "$ref": "#/components/schemas/ValidationError" 

184 }, 

185 } 

186 }, 

187 }, 

188 } 

189 }, 

190 } 

191 )