fastapi 0.97.0__py3-none-any.whl → 0.100.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of fastapi might be problematic. Click here for more details.
- fastapi/__init__.py +1 -1
- fastapi/_compat.py +597 -0
- fastapi/applications.py +21 -22
- fastapi/datastructures.py +31 -4
- fastapi/dependencies/models.py +1 -1
- fastapi/dependencies/utils.py +76 -120
- fastapi/encoders.py +91 -13
- fastapi/exceptions.py +20 -8
- fastapi/openapi/constants.py +1 -0
- fastapi/openapi/models.py +195 -52
- fastapi/openapi/utils.py +62 -39
- fastapi/param_functions.py +15 -1
- fastapi/params.py +57 -8
- fastapi/routing.py +79 -46
- fastapi/security/oauth2.py +16 -12
- fastapi/types.py +9 -1
- fastapi/utils.py +62 -60
- {fastapi-0.97.0.dist-info → fastapi-0.100.0b1.dist-info}/METADATA +3 -3
- {fastapi-0.97.0.dist-info → fastapi-0.100.0b1.dist-info}/RECORD +21 -20
- {fastapi-0.97.0.dist-info → fastapi-0.100.0b1.dist-info}/WHEEL +0 -0
- {fastapi-0.97.0.dist-info → fastapi-0.100.0b1.dist-info}/licenses/LICENSE +0 -0
fastapi/param_functions.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from typing import Any, Callable, Dict, Optional, Sequence
|
|
2
2
|
|
|
3
3
|
from fastapi import params
|
|
4
|
-
from
|
|
4
|
+
from fastapi._compat import Undefined
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
def Path( # noqa: N802
|
|
@@ -16,6 +16,7 @@ def Path( # noqa: N802
|
|
|
16
16
|
le: Optional[float] = None,
|
|
17
17
|
min_length: Optional[int] = None,
|
|
18
18
|
max_length: Optional[int] = None,
|
|
19
|
+
pattern: Optional[str] = None,
|
|
19
20
|
regex: Optional[str] = None,
|
|
20
21
|
example: Any = Undefined,
|
|
21
22
|
examples: Optional[Dict[str, Any]] = None,
|
|
@@ -34,6 +35,7 @@ def Path( # noqa: N802
|
|
|
34
35
|
le=le,
|
|
35
36
|
min_length=min_length,
|
|
36
37
|
max_length=max_length,
|
|
38
|
+
pattern=pattern,
|
|
37
39
|
regex=regex,
|
|
38
40
|
example=example,
|
|
39
41
|
examples=examples,
|
|
@@ -55,6 +57,7 @@ def Query( # noqa: N802
|
|
|
55
57
|
le: Optional[float] = None,
|
|
56
58
|
min_length: Optional[int] = None,
|
|
57
59
|
max_length: Optional[int] = None,
|
|
60
|
+
pattern: Optional[str] = None,
|
|
58
61
|
regex: Optional[str] = None,
|
|
59
62
|
example: Any = Undefined,
|
|
60
63
|
examples: Optional[Dict[str, Any]] = None,
|
|
@@ -73,6 +76,7 @@ def Query( # noqa: N802
|
|
|
73
76
|
le=le,
|
|
74
77
|
min_length=min_length,
|
|
75
78
|
max_length=max_length,
|
|
79
|
+
pattern=pattern,
|
|
76
80
|
regex=regex,
|
|
77
81
|
example=example,
|
|
78
82
|
examples=examples,
|
|
@@ -95,6 +99,7 @@ def Header( # noqa: N802
|
|
|
95
99
|
le: Optional[float] = None,
|
|
96
100
|
min_length: Optional[int] = None,
|
|
97
101
|
max_length: Optional[int] = None,
|
|
102
|
+
pattern: Optional[str] = None,
|
|
98
103
|
regex: Optional[str] = None,
|
|
99
104
|
example: Any = Undefined,
|
|
100
105
|
examples: Optional[Dict[str, Any]] = None,
|
|
@@ -114,6 +119,7 @@ def Header( # noqa: N802
|
|
|
114
119
|
le=le,
|
|
115
120
|
min_length=min_length,
|
|
116
121
|
max_length=max_length,
|
|
122
|
+
pattern=pattern,
|
|
117
123
|
regex=regex,
|
|
118
124
|
example=example,
|
|
119
125
|
examples=examples,
|
|
@@ -135,6 +141,7 @@ def Cookie( # noqa: N802
|
|
|
135
141
|
le: Optional[float] = None,
|
|
136
142
|
min_length: Optional[int] = None,
|
|
137
143
|
max_length: Optional[int] = None,
|
|
144
|
+
pattern: Optional[str] = None,
|
|
138
145
|
regex: Optional[str] = None,
|
|
139
146
|
example: Any = Undefined,
|
|
140
147
|
examples: Optional[Dict[str, Any]] = None,
|
|
@@ -153,6 +160,7 @@ def Cookie( # noqa: N802
|
|
|
153
160
|
le=le,
|
|
154
161
|
min_length=min_length,
|
|
155
162
|
max_length=max_length,
|
|
163
|
+
pattern=pattern,
|
|
156
164
|
regex=regex,
|
|
157
165
|
example=example,
|
|
158
166
|
examples=examples,
|
|
@@ -176,6 +184,7 @@ def Body( # noqa: N802
|
|
|
176
184
|
le: Optional[float] = None,
|
|
177
185
|
min_length: Optional[int] = None,
|
|
178
186
|
max_length: Optional[int] = None,
|
|
187
|
+
pattern: Optional[str] = None,
|
|
179
188
|
regex: Optional[str] = None,
|
|
180
189
|
example: Any = Undefined,
|
|
181
190
|
examples: Optional[Dict[str, Any]] = None,
|
|
@@ -194,6 +203,7 @@ def Body( # noqa: N802
|
|
|
194
203
|
le=le,
|
|
195
204
|
min_length=min_length,
|
|
196
205
|
max_length=max_length,
|
|
206
|
+
pattern=pattern,
|
|
197
207
|
regex=regex,
|
|
198
208
|
example=example,
|
|
199
209
|
examples=examples,
|
|
@@ -214,6 +224,7 @@ def Form( # noqa: N802
|
|
|
214
224
|
le: Optional[float] = None,
|
|
215
225
|
min_length: Optional[int] = None,
|
|
216
226
|
max_length: Optional[int] = None,
|
|
227
|
+
pattern: Optional[str] = None,
|
|
217
228
|
regex: Optional[str] = None,
|
|
218
229
|
example: Any = Undefined,
|
|
219
230
|
examples: Optional[Dict[str, Any]] = None,
|
|
@@ -231,6 +242,7 @@ def Form( # noqa: N802
|
|
|
231
242
|
le=le,
|
|
232
243
|
min_length=min_length,
|
|
233
244
|
max_length=max_length,
|
|
245
|
+
pattern=pattern,
|
|
234
246
|
regex=regex,
|
|
235
247
|
example=example,
|
|
236
248
|
examples=examples,
|
|
@@ -251,6 +263,7 @@ def File( # noqa: N802
|
|
|
251
263
|
le: Optional[float] = None,
|
|
252
264
|
min_length: Optional[int] = None,
|
|
253
265
|
max_length: Optional[int] = None,
|
|
266
|
+
pattern: Optional[str] = None,
|
|
254
267
|
regex: Optional[str] = None,
|
|
255
268
|
example: Any = Undefined,
|
|
256
269
|
examples: Optional[Dict[str, Any]] = None,
|
|
@@ -268,6 +281,7 @@ def File( # noqa: N802
|
|
|
268
281
|
le=le,
|
|
269
282
|
min_length=min_length,
|
|
270
283
|
max_length=max_length,
|
|
284
|
+
pattern=pattern,
|
|
271
285
|
regex=regex,
|
|
272
286
|
example=example,
|
|
273
287
|
examples=examples,
|
fastapi/params.py
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
|
-
from typing import Any, Callable, Dict, Optional, Sequence
|
|
2
|
+
from typing import Any, Callable, Dict, Optional, Sequence, Type
|
|
3
3
|
|
|
4
|
-
from pydantic.fields import FieldInfo
|
|
4
|
+
from pydantic.fields import FieldInfo
|
|
5
|
+
|
|
6
|
+
from ._compat import PYDANTIC_V2, Undefined
|
|
5
7
|
|
|
6
8
|
|
|
7
9
|
class ParamTypes(Enum):
|
|
@@ -18,6 +20,7 @@ class Param(FieldInfo):
|
|
|
18
20
|
self,
|
|
19
21
|
default: Any = Undefined,
|
|
20
22
|
*,
|
|
23
|
+
annotation: Optional[Type[Any]] = None,
|
|
21
24
|
alias: Optional[str] = None,
|
|
22
25
|
title: Optional[str] = None,
|
|
23
26
|
description: Optional[str] = None,
|
|
@@ -27,6 +30,7 @@ class Param(FieldInfo):
|
|
|
27
30
|
le: Optional[float] = None,
|
|
28
31
|
min_length: Optional[int] = None,
|
|
29
32
|
max_length: Optional[int] = None,
|
|
33
|
+
pattern: Optional[str] = None,
|
|
30
34
|
regex: Optional[str] = None,
|
|
31
35
|
example: Any = Undefined,
|
|
32
36
|
examples: Optional[Dict[str, Any]] = None,
|
|
@@ -36,9 +40,8 @@ class Param(FieldInfo):
|
|
|
36
40
|
):
|
|
37
41
|
self.deprecated = deprecated
|
|
38
42
|
self.example = example
|
|
39
|
-
self.examples = examples
|
|
40
43
|
self.include_in_schema = include_in_schema
|
|
41
|
-
|
|
44
|
+
kwargs = dict(
|
|
42
45
|
default=default,
|
|
43
46
|
alias=alias,
|
|
44
47
|
title=title,
|
|
@@ -49,9 +52,19 @@ class Param(FieldInfo):
|
|
|
49
52
|
le=le,
|
|
50
53
|
min_length=min_length,
|
|
51
54
|
max_length=max_length,
|
|
52
|
-
regex=regex,
|
|
53
55
|
**extra,
|
|
54
56
|
)
|
|
57
|
+
if PYDANTIC_V2:
|
|
58
|
+
kwargs["annotation"] = annotation
|
|
59
|
+
kwargs["pattern"] = pattern or regex
|
|
60
|
+
else:
|
|
61
|
+
# TODO: pv2 figure out how to deprecate regex
|
|
62
|
+
kwargs["regex"] = pattern or regex
|
|
63
|
+
|
|
64
|
+
super().__init__(**kwargs)
|
|
65
|
+
# TODO: pv2 decide how to handle OpenAPI examples vs JSON Schema examples
|
|
66
|
+
# and how to deprecate OpenAPI examples
|
|
67
|
+
self.examples = examples # type: ignore[assignment]
|
|
55
68
|
|
|
56
69
|
def __repr__(self) -> str:
|
|
57
70
|
return f"{self.__class__.__name__}({self.default})"
|
|
@@ -64,6 +77,7 @@ class Path(Param):
|
|
|
64
77
|
self,
|
|
65
78
|
default: Any = ...,
|
|
66
79
|
*,
|
|
80
|
+
annotation: Optional[Type[Any]] = None,
|
|
67
81
|
alias: Optional[str] = None,
|
|
68
82
|
title: Optional[str] = None,
|
|
69
83
|
description: Optional[str] = None,
|
|
@@ -73,6 +87,7 @@ class Path(Param):
|
|
|
73
87
|
le: Optional[float] = None,
|
|
74
88
|
min_length: Optional[int] = None,
|
|
75
89
|
max_length: Optional[int] = None,
|
|
90
|
+
pattern: Optional[str] = None,
|
|
76
91
|
regex: Optional[str] = None,
|
|
77
92
|
example: Any = Undefined,
|
|
78
93
|
examples: Optional[Dict[str, Any]] = None,
|
|
@@ -84,6 +99,7 @@ class Path(Param):
|
|
|
84
99
|
self.in_ = self.in_
|
|
85
100
|
super().__init__(
|
|
86
101
|
default=default,
|
|
102
|
+
annotation=annotation,
|
|
87
103
|
alias=alias,
|
|
88
104
|
title=title,
|
|
89
105
|
description=description,
|
|
@@ -93,6 +109,7 @@ class Path(Param):
|
|
|
93
109
|
le=le,
|
|
94
110
|
min_length=min_length,
|
|
95
111
|
max_length=max_length,
|
|
112
|
+
pattern=pattern,
|
|
96
113
|
regex=regex,
|
|
97
114
|
deprecated=deprecated,
|
|
98
115
|
example=example,
|
|
@@ -109,6 +126,7 @@ class Query(Param):
|
|
|
109
126
|
self,
|
|
110
127
|
default: Any = Undefined,
|
|
111
128
|
*,
|
|
129
|
+
annotation: Optional[Type[Any]] = None,
|
|
112
130
|
alias: Optional[str] = None,
|
|
113
131
|
title: Optional[str] = None,
|
|
114
132
|
description: Optional[str] = None,
|
|
@@ -118,6 +136,7 @@ class Query(Param):
|
|
|
118
136
|
le: Optional[float] = None,
|
|
119
137
|
min_length: Optional[int] = None,
|
|
120
138
|
max_length: Optional[int] = None,
|
|
139
|
+
pattern: Optional[str] = None,
|
|
121
140
|
regex: Optional[str] = None,
|
|
122
141
|
example: Any = Undefined,
|
|
123
142
|
examples: Optional[Dict[str, Any]] = None,
|
|
@@ -127,6 +146,7 @@ class Query(Param):
|
|
|
127
146
|
):
|
|
128
147
|
super().__init__(
|
|
129
148
|
default=default,
|
|
149
|
+
annotation=annotation,
|
|
130
150
|
alias=alias,
|
|
131
151
|
title=title,
|
|
132
152
|
description=description,
|
|
@@ -136,6 +156,7 @@ class Query(Param):
|
|
|
136
156
|
le=le,
|
|
137
157
|
min_length=min_length,
|
|
138
158
|
max_length=max_length,
|
|
159
|
+
pattern=pattern,
|
|
139
160
|
regex=regex,
|
|
140
161
|
deprecated=deprecated,
|
|
141
162
|
example=example,
|
|
@@ -152,6 +173,7 @@ class Header(Param):
|
|
|
152
173
|
self,
|
|
153
174
|
default: Any = Undefined,
|
|
154
175
|
*,
|
|
176
|
+
annotation: Optional[Type[Any]] = None,
|
|
155
177
|
alias: Optional[str] = None,
|
|
156
178
|
convert_underscores: bool = True,
|
|
157
179
|
title: Optional[str] = None,
|
|
@@ -162,6 +184,7 @@ class Header(Param):
|
|
|
162
184
|
le: Optional[float] = None,
|
|
163
185
|
min_length: Optional[int] = None,
|
|
164
186
|
max_length: Optional[int] = None,
|
|
187
|
+
pattern: Optional[str] = None,
|
|
165
188
|
regex: Optional[str] = None,
|
|
166
189
|
example: Any = Undefined,
|
|
167
190
|
examples: Optional[Dict[str, Any]] = None,
|
|
@@ -172,6 +195,7 @@ class Header(Param):
|
|
|
172
195
|
self.convert_underscores = convert_underscores
|
|
173
196
|
super().__init__(
|
|
174
197
|
default=default,
|
|
198
|
+
annotation=annotation,
|
|
175
199
|
alias=alias,
|
|
176
200
|
title=title,
|
|
177
201
|
description=description,
|
|
@@ -181,6 +205,7 @@ class Header(Param):
|
|
|
181
205
|
le=le,
|
|
182
206
|
min_length=min_length,
|
|
183
207
|
max_length=max_length,
|
|
208
|
+
pattern=pattern,
|
|
184
209
|
regex=regex,
|
|
185
210
|
deprecated=deprecated,
|
|
186
211
|
example=example,
|
|
@@ -197,6 +222,7 @@ class Cookie(Param):
|
|
|
197
222
|
self,
|
|
198
223
|
default: Any = Undefined,
|
|
199
224
|
*,
|
|
225
|
+
annotation: Optional[Type[Any]] = None,
|
|
200
226
|
alias: Optional[str] = None,
|
|
201
227
|
title: Optional[str] = None,
|
|
202
228
|
description: Optional[str] = None,
|
|
@@ -206,6 +232,7 @@ class Cookie(Param):
|
|
|
206
232
|
le: Optional[float] = None,
|
|
207
233
|
min_length: Optional[int] = None,
|
|
208
234
|
max_length: Optional[int] = None,
|
|
235
|
+
pattern: Optional[str] = None,
|
|
209
236
|
regex: Optional[str] = None,
|
|
210
237
|
example: Any = Undefined,
|
|
211
238
|
examples: Optional[Dict[str, Any]] = None,
|
|
@@ -215,6 +242,7 @@ class Cookie(Param):
|
|
|
215
242
|
):
|
|
216
243
|
super().__init__(
|
|
217
244
|
default=default,
|
|
245
|
+
annotation=annotation,
|
|
218
246
|
alias=alias,
|
|
219
247
|
title=title,
|
|
220
248
|
description=description,
|
|
@@ -224,6 +252,7 @@ class Cookie(Param):
|
|
|
224
252
|
le=le,
|
|
225
253
|
min_length=min_length,
|
|
226
254
|
max_length=max_length,
|
|
255
|
+
pattern=pattern,
|
|
227
256
|
regex=regex,
|
|
228
257
|
deprecated=deprecated,
|
|
229
258
|
example=example,
|
|
@@ -238,6 +267,7 @@ class Body(FieldInfo):
|
|
|
238
267
|
self,
|
|
239
268
|
default: Any = Undefined,
|
|
240
269
|
*,
|
|
270
|
+
annotation: Optional[Type[Any]] = None,
|
|
241
271
|
embed: bool = False,
|
|
242
272
|
media_type: str = "application/json",
|
|
243
273
|
alias: Optional[str] = None,
|
|
@@ -249,6 +279,7 @@ class Body(FieldInfo):
|
|
|
249
279
|
le: Optional[float] = None,
|
|
250
280
|
min_length: Optional[int] = None,
|
|
251
281
|
max_length: Optional[int] = None,
|
|
282
|
+
pattern: Optional[str] = None,
|
|
252
283
|
regex: Optional[str] = None,
|
|
253
284
|
example: Any = Undefined,
|
|
254
285
|
examples: Optional[Dict[str, Any]] = None,
|
|
@@ -257,8 +288,7 @@ class Body(FieldInfo):
|
|
|
257
288
|
self.embed = embed
|
|
258
289
|
self.media_type = media_type
|
|
259
290
|
self.example = example
|
|
260
|
-
|
|
261
|
-
super().__init__(
|
|
291
|
+
kwargs = dict(
|
|
262
292
|
default=default,
|
|
263
293
|
alias=alias,
|
|
264
294
|
title=title,
|
|
@@ -269,9 +299,20 @@ class Body(FieldInfo):
|
|
|
269
299
|
le=le,
|
|
270
300
|
min_length=min_length,
|
|
271
301
|
max_length=max_length,
|
|
272
|
-
regex=regex,
|
|
273
302
|
**extra,
|
|
274
303
|
)
|
|
304
|
+
if PYDANTIC_V2:
|
|
305
|
+
kwargs["annotation"] = annotation
|
|
306
|
+
kwargs["pattern"] = pattern or regex
|
|
307
|
+
else:
|
|
308
|
+
# TODO: pv2 figure out how to deprecate regex
|
|
309
|
+
kwargs["regex"] = pattern or regex
|
|
310
|
+
super().__init__(
|
|
311
|
+
**kwargs,
|
|
312
|
+
)
|
|
313
|
+
# TODO: pv2 decide how to handle OpenAPI examples vs JSON Schema examples
|
|
314
|
+
# and how to deprecate OpenAPI examples
|
|
315
|
+
self.examples = examples # type: ignore[assignment]
|
|
275
316
|
|
|
276
317
|
def __repr__(self) -> str:
|
|
277
318
|
return f"{self.__class__.__name__}({self.default})"
|
|
@@ -282,6 +323,7 @@ class Form(Body):
|
|
|
282
323
|
self,
|
|
283
324
|
default: Any = Undefined,
|
|
284
325
|
*,
|
|
326
|
+
annotation: Optional[Type[Any]] = None,
|
|
285
327
|
media_type: str = "application/x-www-form-urlencoded",
|
|
286
328
|
alias: Optional[str] = None,
|
|
287
329
|
title: Optional[str] = None,
|
|
@@ -292,6 +334,7 @@ class Form(Body):
|
|
|
292
334
|
le: Optional[float] = None,
|
|
293
335
|
min_length: Optional[int] = None,
|
|
294
336
|
max_length: Optional[int] = None,
|
|
337
|
+
pattern: Optional[str] = None,
|
|
295
338
|
regex: Optional[str] = None,
|
|
296
339
|
example: Any = Undefined,
|
|
297
340
|
examples: Optional[Dict[str, Any]] = None,
|
|
@@ -299,6 +342,7 @@ class Form(Body):
|
|
|
299
342
|
):
|
|
300
343
|
super().__init__(
|
|
301
344
|
default=default,
|
|
345
|
+
annotation=annotation,
|
|
302
346
|
embed=True,
|
|
303
347
|
media_type=media_type,
|
|
304
348
|
alias=alias,
|
|
@@ -310,6 +354,7 @@ class Form(Body):
|
|
|
310
354
|
le=le,
|
|
311
355
|
min_length=min_length,
|
|
312
356
|
max_length=max_length,
|
|
357
|
+
pattern=pattern,
|
|
313
358
|
regex=regex,
|
|
314
359
|
example=example,
|
|
315
360
|
examples=examples,
|
|
@@ -322,6 +367,7 @@ class File(Form):
|
|
|
322
367
|
self,
|
|
323
368
|
default: Any = Undefined,
|
|
324
369
|
*,
|
|
370
|
+
annotation: Optional[Type[Any]] = None,
|
|
325
371
|
media_type: str = "multipart/form-data",
|
|
326
372
|
alias: Optional[str] = None,
|
|
327
373
|
title: Optional[str] = None,
|
|
@@ -332,6 +378,7 @@ class File(Form):
|
|
|
332
378
|
le: Optional[float] = None,
|
|
333
379
|
min_length: Optional[int] = None,
|
|
334
380
|
max_length: Optional[int] = None,
|
|
381
|
+
pattern: Optional[str] = None,
|
|
335
382
|
regex: Optional[str] = None,
|
|
336
383
|
example: Any = Undefined,
|
|
337
384
|
examples: Optional[Dict[str, Any]] = None,
|
|
@@ -339,6 +386,7 @@ class File(Form):
|
|
|
339
386
|
):
|
|
340
387
|
super().__init__(
|
|
341
388
|
default=default,
|
|
389
|
+
annotation=annotation,
|
|
342
390
|
media_type=media_type,
|
|
343
391
|
alias=alias,
|
|
344
392
|
title=title,
|
|
@@ -349,6 +397,7 @@ class File(Form):
|
|
|
349
397
|
le=le,
|
|
350
398
|
min_length=min_length,
|
|
351
399
|
max_length=max_length,
|
|
400
|
+
pattern=pattern,
|
|
352
401
|
regex=regex,
|
|
353
402
|
example=example,
|
|
354
403
|
examples=examples,
|
fastapi/routing.py
CHANGED
|
@@ -20,6 +20,14 @@ from typing import (
|
|
|
20
20
|
)
|
|
21
21
|
|
|
22
22
|
from fastapi import params
|
|
23
|
+
from fastapi._compat import (
|
|
24
|
+
ModelField,
|
|
25
|
+
Undefined,
|
|
26
|
+
_get_model_config,
|
|
27
|
+
_model_dump,
|
|
28
|
+
_normalize_errors,
|
|
29
|
+
lenient_issubclass,
|
|
30
|
+
)
|
|
23
31
|
from fastapi.datastructures import Default, DefaultPlaceholder
|
|
24
32
|
from fastapi.dependencies.models import Dependant
|
|
25
33
|
from fastapi.dependencies.utils import (
|
|
@@ -29,13 +37,14 @@ from fastapi.dependencies.utils import (
|
|
|
29
37
|
get_typed_return_annotation,
|
|
30
38
|
solve_dependencies,
|
|
31
39
|
)
|
|
32
|
-
from fastapi.encoders import
|
|
40
|
+
from fastapi.encoders import jsonable_encoder
|
|
33
41
|
from fastapi.exceptions import (
|
|
34
42
|
FastAPIError,
|
|
35
43
|
RequestValidationError,
|
|
44
|
+
ResponseValidationError,
|
|
36
45
|
WebSocketRequestValidationError,
|
|
37
46
|
)
|
|
38
|
-
from fastapi.types import DecoratedCallable
|
|
47
|
+
from fastapi.types import DecoratedCallable, IncEx
|
|
39
48
|
from fastapi.utils import (
|
|
40
49
|
create_cloned_field,
|
|
41
50
|
create_response_field,
|
|
@@ -44,9 +53,6 @@ from fastapi.utils import (
|
|
|
44
53
|
is_body_allowed_for_status_code,
|
|
45
54
|
)
|
|
46
55
|
from pydantic import BaseModel
|
|
47
|
-
from pydantic.error_wrappers import ErrorWrapper, ValidationError
|
|
48
|
-
from pydantic.fields import ModelField, Undefined
|
|
49
|
-
from pydantic.utils import lenient_issubclass
|
|
50
56
|
from starlette import routing
|
|
51
57
|
from starlette.concurrency import run_in_threadpool
|
|
52
58
|
from starlette.exceptions import HTTPException
|
|
@@ -73,14 +79,15 @@ def _prepare_response_content(
|
|
|
73
79
|
exclude_none: bool = False,
|
|
74
80
|
) -> Any:
|
|
75
81
|
if isinstance(res, BaseModel):
|
|
76
|
-
read_with_orm_mode = getattr(res
|
|
82
|
+
read_with_orm_mode = getattr(_get_model_config(res), "read_with_orm_mode", None)
|
|
77
83
|
if read_with_orm_mode:
|
|
78
84
|
# Let from_orm extract the data from this model instead of converting
|
|
79
85
|
# it now to a dict.
|
|
80
86
|
# Otherwise there's no way to extract lazy data that requires attribute
|
|
81
87
|
# access instead of dict iteration, e.g. lazy relationships.
|
|
82
88
|
return res
|
|
83
|
-
return
|
|
89
|
+
return _model_dump(
|
|
90
|
+
res,
|
|
84
91
|
by_alias=True,
|
|
85
92
|
exclude_unset=exclude_unset,
|
|
86
93
|
exclude_defaults=exclude_defaults,
|
|
@@ -115,8 +122,8 @@ async def serialize_response(
|
|
|
115
122
|
*,
|
|
116
123
|
field: Optional[ModelField] = None,
|
|
117
124
|
response_content: Any,
|
|
118
|
-
include: Optional[
|
|
119
|
-
exclude: Optional[
|
|
125
|
+
include: Optional[IncEx] = None,
|
|
126
|
+
exclude: Optional[IncEx] = None,
|
|
120
127
|
by_alias: bool = True,
|
|
121
128
|
exclude_unset: bool = False,
|
|
122
129
|
exclude_defaults: bool = False,
|
|
@@ -125,24 +132,40 @@ async def serialize_response(
|
|
|
125
132
|
) -> Any:
|
|
126
133
|
if field:
|
|
127
134
|
errors = []
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
135
|
+
if not hasattr(field, "serialize"):
|
|
136
|
+
# pydantic v1
|
|
137
|
+
response_content = _prepare_response_content(
|
|
138
|
+
response_content,
|
|
139
|
+
exclude_unset=exclude_unset,
|
|
140
|
+
exclude_defaults=exclude_defaults,
|
|
141
|
+
exclude_none=exclude_none,
|
|
142
|
+
)
|
|
134
143
|
if is_coroutine:
|
|
135
144
|
value, errors_ = field.validate(response_content, {}, loc=("response",))
|
|
136
145
|
else:
|
|
137
146
|
value, errors_ = await run_in_threadpool(
|
|
138
147
|
field.validate, response_content, {}, loc=("response",)
|
|
139
148
|
)
|
|
140
|
-
if isinstance(errors_,
|
|
141
|
-
errors.append(errors_)
|
|
142
|
-
elif isinstance(errors_, list):
|
|
149
|
+
if isinstance(errors_, list):
|
|
143
150
|
errors.extend(errors_)
|
|
151
|
+
elif errors_:
|
|
152
|
+
errors.append(errors_)
|
|
144
153
|
if errors:
|
|
145
|
-
raise
|
|
154
|
+
raise ResponseValidationError(
|
|
155
|
+
errors=_normalize_errors(errors), body=response_content
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
if hasattr(field, "serialize"):
|
|
159
|
+
return field.serialize(
|
|
160
|
+
value,
|
|
161
|
+
include=include,
|
|
162
|
+
exclude=exclude,
|
|
163
|
+
by_alias=by_alias,
|
|
164
|
+
exclude_unset=exclude_unset,
|
|
165
|
+
exclude_defaults=exclude_defaults,
|
|
166
|
+
exclude_none=exclude_none,
|
|
167
|
+
)
|
|
168
|
+
|
|
146
169
|
return jsonable_encoder(
|
|
147
170
|
value,
|
|
148
171
|
include=include,
|
|
@@ -175,8 +198,8 @@ def get_request_handler(
|
|
|
175
198
|
status_code: Optional[int] = None,
|
|
176
199
|
response_class: Union[Type[Response], DefaultPlaceholder] = Default(JSONResponse),
|
|
177
200
|
response_field: Optional[ModelField] = None,
|
|
178
|
-
response_model_include: Optional[
|
|
179
|
-
response_model_exclude: Optional[
|
|
201
|
+
response_model_include: Optional[IncEx] = None,
|
|
202
|
+
response_model_exclude: Optional[IncEx] = None,
|
|
180
203
|
response_model_by_alias: bool = True,
|
|
181
204
|
response_model_exclude_unset: bool = False,
|
|
182
205
|
response_model_exclude_defaults: bool = False,
|
|
@@ -220,7 +243,16 @@ def get_request_handler(
|
|
|
220
243
|
body = body_bytes
|
|
221
244
|
except json.JSONDecodeError as e:
|
|
222
245
|
raise RequestValidationError(
|
|
223
|
-
[
|
|
246
|
+
[
|
|
247
|
+
{
|
|
248
|
+
"type": "json_invalid",
|
|
249
|
+
"loc": ("body", e.pos),
|
|
250
|
+
"msg": "JSON decode error",
|
|
251
|
+
"input": {},
|
|
252
|
+
"ctx": {"error": e.msg},
|
|
253
|
+
}
|
|
254
|
+
],
|
|
255
|
+
body=e.doc,
|
|
224
256
|
) from e
|
|
225
257
|
except HTTPException:
|
|
226
258
|
raise
|
|
@@ -236,7 +268,7 @@ def get_request_handler(
|
|
|
236
268
|
)
|
|
237
269
|
values, errors, background_tasks, sub_response, _ = solved_result
|
|
238
270
|
if errors:
|
|
239
|
-
raise RequestValidationError(errors, body=body)
|
|
271
|
+
raise RequestValidationError(_normalize_errors(errors), body=body)
|
|
240
272
|
else:
|
|
241
273
|
raw_response = await run_endpoint_function(
|
|
242
274
|
dependant=dependant, values=values, is_coroutine=is_coroutine
|
|
@@ -287,7 +319,7 @@ def get_websocket_app(
|
|
|
287
319
|
)
|
|
288
320
|
values, errors, _, _2, _3 = solved_result
|
|
289
321
|
if errors:
|
|
290
|
-
raise WebSocketRequestValidationError(errors)
|
|
322
|
+
raise WebSocketRequestValidationError(_normalize_errors(errors))
|
|
291
323
|
assert dependant.call is not None, "dependant.call must be a function"
|
|
292
324
|
await dependant.call(**values)
|
|
293
325
|
|
|
@@ -348,8 +380,8 @@ class APIRoute(routing.Route):
|
|
|
348
380
|
name: Optional[str] = None,
|
|
349
381
|
methods: Optional[Union[Set[str], List[str]]] = None,
|
|
350
382
|
operation_id: Optional[str] = None,
|
|
351
|
-
response_model_include: Optional[
|
|
352
|
-
response_model_exclude: Optional[
|
|
383
|
+
response_model_include: Optional[IncEx] = None,
|
|
384
|
+
response_model_exclude: Optional[IncEx] = None,
|
|
353
385
|
response_model_by_alias: bool = True,
|
|
354
386
|
response_model_exclude_unset: bool = False,
|
|
355
387
|
response_model_exclude_defaults: bool = False,
|
|
@@ -423,6 +455,7 @@ class APIRoute(routing.Route):
|
|
|
423
455
|
# would pass the validation and be returned as is.
|
|
424
456
|
# By being a new field, no inheritance will be passed as is. A new model
|
|
425
457
|
# will be always created.
|
|
458
|
+
# TODO: remove when deprecating Pydantic v1
|
|
426
459
|
self.secure_cloned_response_field: Optional[
|
|
427
460
|
ModelField
|
|
428
461
|
] = create_cloned_field(self.response_field)
|
|
@@ -569,8 +602,8 @@ class APIRouter(routing.Router):
|
|
|
569
602
|
deprecated: Optional[bool] = None,
|
|
570
603
|
methods: Optional[Union[Set[str], List[str]]] = None,
|
|
571
604
|
operation_id: Optional[str] = None,
|
|
572
|
-
response_model_include: Optional[
|
|
573
|
-
response_model_exclude: Optional[
|
|
605
|
+
response_model_include: Optional[IncEx] = None,
|
|
606
|
+
response_model_exclude: Optional[IncEx] = None,
|
|
574
607
|
response_model_by_alias: bool = True,
|
|
575
608
|
response_model_exclude_unset: bool = False,
|
|
576
609
|
response_model_exclude_defaults: bool = False,
|
|
@@ -650,8 +683,8 @@ class APIRouter(routing.Router):
|
|
|
650
683
|
deprecated: Optional[bool] = None,
|
|
651
684
|
methods: Optional[List[str]] = None,
|
|
652
685
|
operation_id: Optional[str] = None,
|
|
653
|
-
response_model_include: Optional[
|
|
654
|
-
response_model_exclude: Optional[
|
|
686
|
+
response_model_include: Optional[IncEx] = None,
|
|
687
|
+
response_model_exclude: Optional[IncEx] = None,
|
|
655
688
|
response_model_by_alias: bool = True,
|
|
656
689
|
response_model_exclude_unset: bool = False,
|
|
657
690
|
response_model_exclude_defaults: bool = False,
|
|
@@ -877,8 +910,8 @@ class APIRouter(routing.Router):
|
|
|
877
910
|
responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
|
|
878
911
|
deprecated: Optional[bool] = None,
|
|
879
912
|
operation_id: Optional[str] = None,
|
|
880
|
-
response_model_include: Optional[
|
|
881
|
-
response_model_exclude: Optional[
|
|
913
|
+
response_model_include: Optional[IncEx] = None,
|
|
914
|
+
response_model_exclude: Optional[IncEx] = None,
|
|
882
915
|
response_model_by_alias: bool = True,
|
|
883
916
|
response_model_exclude_unset: bool = False,
|
|
884
917
|
response_model_exclude_defaults: bool = False,
|
|
@@ -933,8 +966,8 @@ class APIRouter(routing.Router):
|
|
|
933
966
|
responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
|
|
934
967
|
deprecated: Optional[bool] = None,
|
|
935
968
|
operation_id: Optional[str] = None,
|
|
936
|
-
response_model_include: Optional[
|
|
937
|
-
response_model_exclude: Optional[
|
|
969
|
+
response_model_include: Optional[IncEx] = None,
|
|
970
|
+
response_model_exclude: Optional[IncEx] = None,
|
|
938
971
|
response_model_by_alias: bool = True,
|
|
939
972
|
response_model_exclude_unset: bool = False,
|
|
940
973
|
response_model_exclude_defaults: bool = False,
|
|
@@ -989,8 +1022,8 @@ class APIRouter(routing.Router):
|
|
|
989
1022
|
responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
|
|
990
1023
|
deprecated: Optional[bool] = None,
|
|
991
1024
|
operation_id: Optional[str] = None,
|
|
992
|
-
response_model_include: Optional[
|
|
993
|
-
response_model_exclude: Optional[
|
|
1025
|
+
response_model_include: Optional[IncEx] = None,
|
|
1026
|
+
response_model_exclude: Optional[IncEx] = None,
|
|
994
1027
|
response_model_by_alias: bool = True,
|
|
995
1028
|
response_model_exclude_unset: bool = False,
|
|
996
1029
|
response_model_exclude_defaults: bool = False,
|
|
@@ -1045,8 +1078,8 @@ class APIRouter(routing.Router):
|
|
|
1045
1078
|
responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
|
|
1046
1079
|
deprecated: Optional[bool] = None,
|
|
1047
1080
|
operation_id: Optional[str] = None,
|
|
1048
|
-
response_model_include: Optional[
|
|
1049
|
-
response_model_exclude: Optional[
|
|
1081
|
+
response_model_include: Optional[IncEx] = None,
|
|
1082
|
+
response_model_exclude: Optional[IncEx] = None,
|
|
1050
1083
|
response_model_by_alias: bool = True,
|
|
1051
1084
|
response_model_exclude_unset: bool = False,
|
|
1052
1085
|
response_model_exclude_defaults: bool = False,
|
|
@@ -1101,8 +1134,8 @@ class APIRouter(routing.Router):
|
|
|
1101
1134
|
responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
|
|
1102
1135
|
deprecated: Optional[bool] = None,
|
|
1103
1136
|
operation_id: Optional[str] = None,
|
|
1104
|
-
response_model_include: Optional[
|
|
1105
|
-
response_model_exclude: Optional[
|
|
1137
|
+
response_model_include: Optional[IncEx] = None,
|
|
1138
|
+
response_model_exclude: Optional[IncEx] = None,
|
|
1106
1139
|
response_model_by_alias: bool = True,
|
|
1107
1140
|
response_model_exclude_unset: bool = False,
|
|
1108
1141
|
response_model_exclude_defaults: bool = False,
|
|
@@ -1157,8 +1190,8 @@ class APIRouter(routing.Router):
|
|
|
1157
1190
|
responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
|
|
1158
1191
|
deprecated: Optional[bool] = None,
|
|
1159
1192
|
operation_id: Optional[str] = None,
|
|
1160
|
-
response_model_include: Optional[
|
|
1161
|
-
response_model_exclude: Optional[
|
|
1193
|
+
response_model_include: Optional[IncEx] = None,
|
|
1194
|
+
response_model_exclude: Optional[IncEx] = None,
|
|
1162
1195
|
response_model_by_alias: bool = True,
|
|
1163
1196
|
response_model_exclude_unset: bool = False,
|
|
1164
1197
|
response_model_exclude_defaults: bool = False,
|
|
@@ -1213,8 +1246,8 @@ class APIRouter(routing.Router):
|
|
|
1213
1246
|
responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
|
|
1214
1247
|
deprecated: Optional[bool] = None,
|
|
1215
1248
|
operation_id: Optional[str] = None,
|
|
1216
|
-
response_model_include: Optional[
|
|
1217
|
-
response_model_exclude: Optional[
|
|
1249
|
+
response_model_include: Optional[IncEx] = None,
|
|
1250
|
+
response_model_exclude: Optional[IncEx] = None,
|
|
1218
1251
|
response_model_by_alias: bool = True,
|
|
1219
1252
|
response_model_exclude_unset: bool = False,
|
|
1220
1253
|
response_model_exclude_defaults: bool = False,
|
|
@@ -1269,8 +1302,8 @@ class APIRouter(routing.Router):
|
|
|
1269
1302
|
responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
|
|
1270
1303
|
deprecated: Optional[bool] = None,
|
|
1271
1304
|
operation_id: Optional[str] = None,
|
|
1272
|
-
response_model_include: Optional[
|
|
1273
|
-
response_model_exclude: Optional[
|
|
1305
|
+
response_model_include: Optional[IncEx] = None,
|
|
1306
|
+
response_model_exclude: Optional[IncEx] = None,
|
|
1274
1307
|
response_model_by_alias: bool = True,
|
|
1275
1308
|
response_model_exclude_unset: bool = False,
|
|
1276
1309
|
response_model_exclude_defaults: bool = False,
|