fastapi 0.99.0__py3-none-any.whl → 0.100.0__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 +616 -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 +90 -12
- fastapi/exceptions.py +20 -8
- fastapi/openapi/constants.py +1 -0
- fastapi/openapi/models.py +223 -72
- fastapi/openapi/utils.py +84 -40
- fastapi/param_functions.py +247 -16
- fastapi/params.py +347 -34
- fastapi/routing.py +84 -47
- fastapi/security/oauth2.py +16 -12
- fastapi/types.py +9 -1
- fastapi/utils.py +66 -60
- {fastapi-0.99.0.dist-info → fastapi-0.100.0.dist-info}/METADATA +7 -3
- {fastapi-0.99.0.dist-info → fastapi-0.100.0.dist-info}/RECORD +21 -20
- {fastapi-0.99.0.dist-info → fastapi-0.100.0.dist-info}/WHEEL +0 -0
- {fastapi-0.99.0.dist-info → fastapi-0.100.0.dist-info}/licenses/LICENSE +0 -0
fastapi/openapi/utils.py
CHANGED
|
@@ -1,35 +1,37 @@
|
|
|
1
1
|
import http.client
|
|
2
2
|
import inspect
|
|
3
3
|
import warnings
|
|
4
|
-
from enum import Enum
|
|
5
4
|
from typing import Any, Dict, List, Optional, Sequence, Set, Tuple, Type, Union, cast
|
|
6
5
|
|
|
7
6
|
from fastapi import routing
|
|
7
|
+
from fastapi._compat import (
|
|
8
|
+
GenerateJsonSchema,
|
|
9
|
+
JsonSchemaValue,
|
|
10
|
+
ModelField,
|
|
11
|
+
Undefined,
|
|
12
|
+
get_compat_model_name_map,
|
|
13
|
+
get_definitions,
|
|
14
|
+
get_schema_from_model_field,
|
|
15
|
+
lenient_issubclass,
|
|
16
|
+
)
|
|
8
17
|
from fastapi.datastructures import DefaultPlaceholder
|
|
9
18
|
from fastapi.dependencies.models import Dependant
|
|
10
19
|
from fastapi.dependencies.utils import get_flat_dependant, get_flat_params
|
|
11
20
|
from fastapi.encoders import jsonable_encoder
|
|
12
|
-
from fastapi.openapi.constants import METHODS_WITH_BODY, REF_PREFIX
|
|
21
|
+
from fastapi.openapi.constants import METHODS_WITH_BODY, REF_PREFIX, REF_TEMPLATE
|
|
13
22
|
from fastapi.openapi.models import OpenAPI
|
|
14
23
|
from fastapi.params import Body, Param
|
|
15
24
|
from fastapi.responses import Response
|
|
25
|
+
from fastapi.types import ModelNameMap
|
|
16
26
|
from fastapi.utils import (
|
|
17
27
|
deep_dict_update,
|
|
18
28
|
generate_operation_id_for_path,
|
|
19
|
-
get_model_definitions,
|
|
20
29
|
is_body_allowed_for_status_code,
|
|
21
30
|
)
|
|
22
|
-
from pydantic import BaseModel
|
|
23
|
-
from pydantic.fields import ModelField, Undefined
|
|
24
|
-
from pydantic.schema import (
|
|
25
|
-
field_schema,
|
|
26
|
-
get_flat_models_from_fields,
|
|
27
|
-
get_model_name_map,
|
|
28
|
-
)
|
|
29
|
-
from pydantic.utils import lenient_issubclass
|
|
30
31
|
from starlette.responses import JSONResponse
|
|
31
32
|
from starlette.routing import BaseRoute
|
|
32
33
|
from starlette.status import HTTP_422_UNPROCESSABLE_ENTITY
|
|
34
|
+
from typing_extensions import Literal
|
|
33
35
|
|
|
34
36
|
validation_error_definition = {
|
|
35
37
|
"title": "ValidationError",
|
|
@@ -88,7 +90,11 @@ def get_openapi_security_definitions(
|
|
|
88
90
|
def get_openapi_operation_parameters(
|
|
89
91
|
*,
|
|
90
92
|
all_route_params: Sequence[ModelField],
|
|
91
|
-
|
|
93
|
+
schema_generator: GenerateJsonSchema,
|
|
94
|
+
model_name_map: ModelNameMap,
|
|
95
|
+
field_mapping: Dict[
|
|
96
|
+
Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
|
|
97
|
+
],
|
|
92
98
|
) -> List[Dict[str, Any]]:
|
|
93
99
|
parameters = []
|
|
94
100
|
for param in all_route_params:
|
|
@@ -96,13 +102,17 @@ def get_openapi_operation_parameters(
|
|
|
96
102
|
field_info = cast(Param, field_info)
|
|
97
103
|
if not field_info.include_in_schema:
|
|
98
104
|
continue
|
|
105
|
+
param_schema = get_schema_from_model_field(
|
|
106
|
+
field=param,
|
|
107
|
+
schema_generator=schema_generator,
|
|
108
|
+
model_name_map=model_name_map,
|
|
109
|
+
field_mapping=field_mapping,
|
|
110
|
+
)
|
|
99
111
|
parameter = {
|
|
100
112
|
"name": param.alias,
|
|
101
113
|
"in": field_info.in_.value,
|
|
102
114
|
"required": param.required,
|
|
103
|
-
"schema":
|
|
104
|
-
param, model_name_map=model_name_map, ref_prefix=REF_PREFIX
|
|
105
|
-
)[0],
|
|
115
|
+
"schema": param_schema,
|
|
106
116
|
}
|
|
107
117
|
if field_info.description:
|
|
108
118
|
parameter["description"] = field_info.description
|
|
@@ -117,13 +127,20 @@ def get_openapi_operation_parameters(
|
|
|
117
127
|
def get_openapi_operation_request_body(
|
|
118
128
|
*,
|
|
119
129
|
body_field: Optional[ModelField],
|
|
120
|
-
|
|
130
|
+
schema_generator: GenerateJsonSchema,
|
|
131
|
+
model_name_map: ModelNameMap,
|
|
132
|
+
field_mapping: Dict[
|
|
133
|
+
Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
|
|
134
|
+
],
|
|
121
135
|
) -> Optional[Dict[str, Any]]:
|
|
122
136
|
if not body_field:
|
|
123
137
|
return None
|
|
124
138
|
assert isinstance(body_field, ModelField)
|
|
125
|
-
body_schema
|
|
126
|
-
body_field,
|
|
139
|
+
body_schema = get_schema_from_model_field(
|
|
140
|
+
field=body_field,
|
|
141
|
+
schema_generator=schema_generator,
|
|
142
|
+
model_name_map=model_name_map,
|
|
143
|
+
field_mapping=field_mapping,
|
|
127
144
|
)
|
|
128
145
|
field_info = cast(Body, body_field.field_info)
|
|
129
146
|
request_media_type = field_info.media_type
|
|
@@ -186,7 +203,14 @@ def get_openapi_operation_metadata(
|
|
|
186
203
|
|
|
187
204
|
|
|
188
205
|
def get_openapi_path(
|
|
189
|
-
*,
|
|
206
|
+
*,
|
|
207
|
+
route: routing.APIRoute,
|
|
208
|
+
operation_ids: Set[str],
|
|
209
|
+
schema_generator: GenerateJsonSchema,
|
|
210
|
+
model_name_map: ModelNameMap,
|
|
211
|
+
field_mapping: Dict[
|
|
212
|
+
Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
|
|
213
|
+
],
|
|
190
214
|
) -> Tuple[Dict[str, Any], Dict[str, Any], Dict[str, Any]]:
|
|
191
215
|
path = {}
|
|
192
216
|
security_schemes: Dict[str, Any] = {}
|
|
@@ -214,7 +238,10 @@ def get_openapi_path(
|
|
|
214
238
|
security_schemes.update(security_definitions)
|
|
215
239
|
all_route_params = get_flat_params(route.dependant)
|
|
216
240
|
operation_parameters = get_openapi_operation_parameters(
|
|
217
|
-
all_route_params=all_route_params,
|
|
241
|
+
all_route_params=all_route_params,
|
|
242
|
+
schema_generator=schema_generator,
|
|
243
|
+
model_name_map=model_name_map,
|
|
244
|
+
field_mapping=field_mapping,
|
|
218
245
|
)
|
|
219
246
|
parameters.extend(operation_parameters)
|
|
220
247
|
if parameters:
|
|
@@ -232,7 +259,10 @@ def get_openapi_path(
|
|
|
232
259
|
operation["parameters"] = list(all_parameters.values())
|
|
233
260
|
if method in METHODS_WITH_BODY:
|
|
234
261
|
request_body_oai = get_openapi_operation_request_body(
|
|
235
|
-
body_field=route.body_field,
|
|
262
|
+
body_field=route.body_field,
|
|
263
|
+
schema_generator=schema_generator,
|
|
264
|
+
model_name_map=model_name_map,
|
|
265
|
+
field_mapping=field_mapping,
|
|
236
266
|
)
|
|
237
267
|
if request_body_oai:
|
|
238
268
|
operation["requestBody"] = request_body_oai
|
|
@@ -246,8 +276,10 @@ def get_openapi_path(
|
|
|
246
276
|
cb_definitions,
|
|
247
277
|
) = get_openapi_path(
|
|
248
278
|
route=callback,
|
|
249
|
-
model_name_map=model_name_map,
|
|
250
279
|
operation_ids=operation_ids,
|
|
280
|
+
schema_generator=schema_generator,
|
|
281
|
+
model_name_map=model_name_map,
|
|
282
|
+
field_mapping=field_mapping,
|
|
251
283
|
)
|
|
252
284
|
callbacks[callback.name] = {callback.path: cb_path}
|
|
253
285
|
operation["callbacks"] = callbacks
|
|
@@ -273,10 +305,11 @@ def get_openapi_path(
|
|
|
273
305
|
response_schema = {"type": "string"}
|
|
274
306
|
if lenient_issubclass(current_response_class, JSONResponse):
|
|
275
307
|
if route.response_field:
|
|
276
|
-
response_schema
|
|
277
|
-
route.response_field,
|
|
308
|
+
response_schema = get_schema_from_model_field(
|
|
309
|
+
field=route.response_field,
|
|
310
|
+
schema_generator=schema_generator,
|
|
278
311
|
model_name_map=model_name_map,
|
|
279
|
-
|
|
312
|
+
field_mapping=field_mapping,
|
|
280
313
|
)
|
|
281
314
|
else:
|
|
282
315
|
response_schema = {}
|
|
@@ -305,8 +338,11 @@ def get_openapi_path(
|
|
|
305
338
|
field = route.response_fields.get(additional_status_code)
|
|
306
339
|
additional_field_schema: Optional[Dict[str, Any]] = None
|
|
307
340
|
if field:
|
|
308
|
-
additional_field_schema
|
|
309
|
-
field
|
|
341
|
+
additional_field_schema = get_schema_from_model_field(
|
|
342
|
+
field=field,
|
|
343
|
+
schema_generator=schema_generator,
|
|
344
|
+
model_name_map=model_name_map,
|
|
345
|
+
field_mapping=field_mapping,
|
|
310
346
|
)
|
|
311
347
|
media_type = route_response_media_type or "application/json"
|
|
312
348
|
additional_schema = (
|
|
@@ -352,13 +388,13 @@ def get_openapi_path(
|
|
|
352
388
|
return path, security_schemes, definitions
|
|
353
389
|
|
|
354
390
|
|
|
355
|
-
def
|
|
391
|
+
def get_fields_from_routes(
|
|
356
392
|
routes: Sequence[BaseRoute],
|
|
357
|
-
) ->
|
|
393
|
+
) -> List[ModelField]:
|
|
358
394
|
body_fields_from_routes: List[ModelField] = []
|
|
359
395
|
responses_from_routes: List[ModelField] = []
|
|
360
396
|
request_fields_from_routes: List[ModelField] = []
|
|
361
|
-
callback_flat_models:
|
|
397
|
+
callback_flat_models: List[ModelField] = []
|
|
362
398
|
for route in routes:
|
|
363
399
|
if getattr(route, "include_in_schema", None) and isinstance(
|
|
364
400
|
route, routing.APIRoute
|
|
@@ -373,13 +409,12 @@ def get_flat_models_from_routes(
|
|
|
373
409
|
if route.response_fields:
|
|
374
410
|
responses_from_routes.extend(route.response_fields.values())
|
|
375
411
|
if route.callbacks:
|
|
376
|
-
callback_flat_models
|
|
412
|
+
callback_flat_models.extend(get_fields_from_routes(route.callbacks))
|
|
377
413
|
params = get_flat_params(route.dependant)
|
|
378
414
|
request_fields_from_routes.extend(params)
|
|
379
415
|
|
|
380
|
-
flat_models = callback_flat_models
|
|
381
|
-
body_fields_from_routes + responses_from_routes + request_fields_from_routes
|
|
382
|
-
known_models=set(),
|
|
416
|
+
flat_models = callback_flat_models + list(
|
|
417
|
+
body_fields_from_routes + responses_from_routes + request_fields_from_routes
|
|
383
418
|
)
|
|
384
419
|
return flat_models
|
|
385
420
|
|
|
@@ -417,15 +452,22 @@ def get_openapi(
|
|
|
417
452
|
paths: Dict[str, Dict[str, Any]] = {}
|
|
418
453
|
webhook_paths: Dict[str, Dict[str, Any]] = {}
|
|
419
454
|
operation_ids: Set[str] = set()
|
|
420
|
-
|
|
421
|
-
model_name_map =
|
|
422
|
-
|
|
423
|
-
|
|
455
|
+
all_fields = get_fields_from_routes(list(routes or []) + list(webhooks or []))
|
|
456
|
+
model_name_map = get_compat_model_name_map(all_fields)
|
|
457
|
+
schema_generator = GenerateJsonSchema(ref_template=REF_TEMPLATE)
|
|
458
|
+
field_mapping, definitions = get_definitions(
|
|
459
|
+
fields=all_fields,
|
|
460
|
+
schema_generator=schema_generator,
|
|
461
|
+
model_name_map=model_name_map,
|
|
424
462
|
)
|
|
425
463
|
for route in routes or []:
|
|
426
464
|
if isinstance(route, routing.APIRoute):
|
|
427
465
|
result = get_openapi_path(
|
|
428
|
-
route=route,
|
|
466
|
+
route=route,
|
|
467
|
+
operation_ids=operation_ids,
|
|
468
|
+
schema_generator=schema_generator,
|
|
469
|
+
model_name_map=model_name_map,
|
|
470
|
+
field_mapping=field_mapping,
|
|
429
471
|
)
|
|
430
472
|
if result:
|
|
431
473
|
path, security_schemes, path_definitions = result
|
|
@@ -441,8 +483,10 @@ def get_openapi(
|
|
|
441
483
|
if isinstance(webhook, routing.APIRoute):
|
|
442
484
|
result = get_openapi_path(
|
|
443
485
|
route=webhook,
|
|
444
|
-
model_name_map=model_name_map,
|
|
445
486
|
operation_ids=operation_ids,
|
|
487
|
+
schema_generator=schema_generator,
|
|
488
|
+
model_name_map=model_name_map,
|
|
489
|
+
field_mapping=field_mapping,
|
|
446
490
|
)
|
|
447
491
|
if result:
|
|
448
492
|
path, security_schemes, path_definitions = result
|