fastapi 0.114.2__py3-none-any.whl → 0.115.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/dependencies/utils.py +79 -11
- fastapi/openapi/utils.py +52 -34
- {fastapi-0.114.2.dist-info → fastapi-0.115.0.dist-info}/METADATA +1 -1
- {fastapi-0.114.2.dist-info → fastapi-0.115.0.dist-info}/RECORD +8 -8
- {fastapi-0.114.2.dist-info → fastapi-0.115.0.dist-info}/WHEEL +0 -0
- {fastapi-0.114.2.dist-info → fastapi-0.115.0.dist-info}/entry_points.txt +0 -0
- {fastapi-0.114.2.dist-info → fastapi-0.115.0.dist-info}/licenses/LICENSE +0 -0
fastapi/__init__.py
CHANGED
fastapi/dependencies/utils.py
CHANGED
|
@@ -201,14 +201,23 @@ def get_flat_dependant(
|
|
|
201
201
|
return flat_dependant
|
|
202
202
|
|
|
203
203
|
|
|
204
|
+
def _get_flat_fields_from_params(fields: List[ModelField]) -> List[ModelField]:
|
|
205
|
+
if not fields:
|
|
206
|
+
return fields
|
|
207
|
+
first_field = fields[0]
|
|
208
|
+
if len(fields) == 1 and lenient_issubclass(first_field.type_, BaseModel):
|
|
209
|
+
fields_to_extract = get_cached_model_fields(first_field.type_)
|
|
210
|
+
return fields_to_extract
|
|
211
|
+
return fields
|
|
212
|
+
|
|
213
|
+
|
|
204
214
|
def get_flat_params(dependant: Dependant) -> List[ModelField]:
|
|
205
215
|
flat_dependant = get_flat_dependant(dependant, skip_repeats=True)
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
)
|
|
216
|
+
path_params = _get_flat_fields_from_params(flat_dependant.path_params)
|
|
217
|
+
query_params = _get_flat_fields_from_params(flat_dependant.query_params)
|
|
218
|
+
header_params = _get_flat_fields_from_params(flat_dependant.header_params)
|
|
219
|
+
cookie_params = _get_flat_fields_from_params(flat_dependant.cookie_params)
|
|
220
|
+
return path_params + query_params + header_params + cookie_params
|
|
212
221
|
|
|
213
222
|
|
|
214
223
|
def get_typed_signature(call: Callable[..., Any]) -> inspect.Signature:
|
|
@@ -479,7 +488,15 @@ def analyze_param(
|
|
|
479
488
|
field=field
|
|
480
489
|
), "Path params must be of one of the supported types"
|
|
481
490
|
elif isinstance(field_info, params.Query):
|
|
482
|
-
assert
|
|
491
|
+
assert (
|
|
492
|
+
is_scalar_field(field)
|
|
493
|
+
or is_scalar_sequence_field(field)
|
|
494
|
+
or (
|
|
495
|
+
lenient_issubclass(field.type_, BaseModel)
|
|
496
|
+
# For Pydantic v1
|
|
497
|
+
and getattr(field, "shape", 1) == 1
|
|
498
|
+
)
|
|
499
|
+
)
|
|
483
500
|
|
|
484
501
|
return ParamDetails(type_annotation=type_annotation, depends=depends, field=field)
|
|
485
502
|
|
|
@@ -686,11 +703,14 @@ def _validate_value_with_model_field(
|
|
|
686
703
|
return v_, []
|
|
687
704
|
|
|
688
705
|
|
|
689
|
-
def _get_multidict_value(
|
|
706
|
+
def _get_multidict_value(
|
|
707
|
+
field: ModelField, values: Mapping[str, Any], alias: Union[str, None] = None
|
|
708
|
+
) -> Any:
|
|
709
|
+
alias = alias or field.alias
|
|
690
710
|
if is_sequence_field(field) and isinstance(values, (ImmutableMultiDict, Headers)):
|
|
691
|
-
value = values.getlist(
|
|
711
|
+
value = values.getlist(alias)
|
|
692
712
|
else:
|
|
693
|
-
value = values.get(
|
|
713
|
+
value = values.get(alias, None)
|
|
694
714
|
if (
|
|
695
715
|
value is None
|
|
696
716
|
or (
|
|
@@ -712,7 +732,55 @@ def request_params_to_args(
|
|
|
712
732
|
received_params: Union[Mapping[str, Any], QueryParams, Headers],
|
|
713
733
|
) -> Tuple[Dict[str, Any], List[Any]]:
|
|
714
734
|
values: Dict[str, Any] = {}
|
|
715
|
-
errors = []
|
|
735
|
+
errors: List[Dict[str, Any]] = []
|
|
736
|
+
|
|
737
|
+
if not fields:
|
|
738
|
+
return values, errors
|
|
739
|
+
|
|
740
|
+
first_field = fields[0]
|
|
741
|
+
fields_to_extract = fields
|
|
742
|
+
single_not_embedded_field = False
|
|
743
|
+
if len(fields) == 1 and lenient_issubclass(first_field.type_, BaseModel):
|
|
744
|
+
fields_to_extract = get_cached_model_fields(first_field.type_)
|
|
745
|
+
single_not_embedded_field = True
|
|
746
|
+
|
|
747
|
+
params_to_process: Dict[str, Any] = {}
|
|
748
|
+
|
|
749
|
+
processed_keys = set()
|
|
750
|
+
|
|
751
|
+
for field in fields_to_extract:
|
|
752
|
+
alias = None
|
|
753
|
+
if isinstance(received_params, Headers):
|
|
754
|
+
# Handle fields extracted from a Pydantic Model for a header, each field
|
|
755
|
+
# doesn't have a FieldInfo of type Header with the default convert_underscores=True
|
|
756
|
+
convert_underscores = getattr(field.field_info, "convert_underscores", True)
|
|
757
|
+
if convert_underscores:
|
|
758
|
+
alias = (
|
|
759
|
+
field.alias
|
|
760
|
+
if field.alias != field.name
|
|
761
|
+
else field.name.replace("_", "-")
|
|
762
|
+
)
|
|
763
|
+
value = _get_multidict_value(field, received_params, alias=alias)
|
|
764
|
+
if value is not None:
|
|
765
|
+
params_to_process[field.name] = value
|
|
766
|
+
processed_keys.add(alias or field.alias)
|
|
767
|
+
processed_keys.add(field.name)
|
|
768
|
+
|
|
769
|
+
for key, value in received_params.items():
|
|
770
|
+
if key not in processed_keys:
|
|
771
|
+
params_to_process[key] = value
|
|
772
|
+
|
|
773
|
+
if single_not_embedded_field:
|
|
774
|
+
field_info = first_field.field_info
|
|
775
|
+
assert isinstance(
|
|
776
|
+
field_info, params.Param
|
|
777
|
+
), "Params must be subclasses of Param"
|
|
778
|
+
loc: Tuple[str, ...] = (field_info.in_.value,)
|
|
779
|
+
v_, errors_ = _validate_value_with_model_field(
|
|
780
|
+
field=first_field, value=params_to_process, values=values, loc=loc
|
|
781
|
+
)
|
|
782
|
+
return {first_field.name: v_}, errors_
|
|
783
|
+
|
|
716
784
|
for field in fields:
|
|
717
785
|
value = _get_multidict_value(field, received_params)
|
|
718
786
|
field_info = field.field_info
|
fastapi/openapi/utils.py
CHANGED
|
@@ -16,11 +16,15 @@ from fastapi._compat import (
|
|
|
16
16
|
)
|
|
17
17
|
from fastapi.datastructures import DefaultPlaceholder
|
|
18
18
|
from fastapi.dependencies.models import Dependant
|
|
19
|
-
from fastapi.dependencies.utils import
|
|
19
|
+
from fastapi.dependencies.utils import (
|
|
20
|
+
_get_flat_fields_from_params,
|
|
21
|
+
get_flat_dependant,
|
|
22
|
+
get_flat_params,
|
|
23
|
+
)
|
|
20
24
|
from fastapi.encoders import jsonable_encoder
|
|
21
25
|
from fastapi.openapi.constants import METHODS_WITH_BODY, REF_PREFIX, REF_TEMPLATE
|
|
22
26
|
from fastapi.openapi.models import OpenAPI
|
|
23
|
-
from fastapi.params import Body,
|
|
27
|
+
from fastapi.params import Body, ParamTypes
|
|
24
28
|
from fastapi.responses import Response
|
|
25
29
|
from fastapi.types import ModelNameMap
|
|
26
30
|
from fastapi.utils import (
|
|
@@ -87,9 +91,9 @@ def get_openapi_security_definitions(
|
|
|
87
91
|
return security_definitions, operation_security
|
|
88
92
|
|
|
89
93
|
|
|
90
|
-
def
|
|
94
|
+
def _get_openapi_operation_parameters(
|
|
91
95
|
*,
|
|
92
|
-
|
|
96
|
+
dependant: Dependant,
|
|
93
97
|
schema_generator: GenerateJsonSchema,
|
|
94
98
|
model_name_map: ModelNameMap,
|
|
95
99
|
field_mapping: Dict[
|
|
@@ -98,33 +102,47 @@ def get_openapi_operation_parameters(
|
|
|
98
102
|
separate_input_output_schemas: bool = True,
|
|
99
103
|
) -> List[Dict[str, Any]]:
|
|
100
104
|
parameters = []
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
"
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
105
|
+
flat_dependant = get_flat_dependant(dependant, skip_repeats=True)
|
|
106
|
+
path_params = _get_flat_fields_from_params(flat_dependant.path_params)
|
|
107
|
+
query_params = _get_flat_fields_from_params(flat_dependant.query_params)
|
|
108
|
+
header_params = _get_flat_fields_from_params(flat_dependant.header_params)
|
|
109
|
+
cookie_params = _get_flat_fields_from_params(flat_dependant.cookie_params)
|
|
110
|
+
parameter_groups = [
|
|
111
|
+
(ParamTypes.path, path_params),
|
|
112
|
+
(ParamTypes.query, query_params),
|
|
113
|
+
(ParamTypes.header, header_params),
|
|
114
|
+
(ParamTypes.cookie, cookie_params),
|
|
115
|
+
]
|
|
116
|
+
for param_type, param_group in parameter_groups:
|
|
117
|
+
for param in param_group:
|
|
118
|
+
field_info = param.field_info
|
|
119
|
+
# field_info = cast(Param, field_info)
|
|
120
|
+
if not getattr(field_info, "include_in_schema", True):
|
|
121
|
+
continue
|
|
122
|
+
param_schema = get_schema_from_model_field(
|
|
123
|
+
field=param,
|
|
124
|
+
schema_generator=schema_generator,
|
|
125
|
+
model_name_map=model_name_map,
|
|
126
|
+
field_mapping=field_mapping,
|
|
127
|
+
separate_input_output_schemas=separate_input_output_schemas,
|
|
128
|
+
)
|
|
129
|
+
parameter = {
|
|
130
|
+
"name": param.alias,
|
|
131
|
+
"in": param_type.value,
|
|
132
|
+
"required": param.required,
|
|
133
|
+
"schema": param_schema,
|
|
134
|
+
}
|
|
135
|
+
if field_info.description:
|
|
136
|
+
parameter["description"] = field_info.description
|
|
137
|
+
openapi_examples = getattr(field_info, "openapi_examples", None)
|
|
138
|
+
example = getattr(field_info, "example", None)
|
|
139
|
+
if openapi_examples:
|
|
140
|
+
parameter["examples"] = jsonable_encoder(openapi_examples)
|
|
141
|
+
elif example != Undefined:
|
|
142
|
+
parameter["example"] = jsonable_encoder(example)
|
|
143
|
+
if getattr(field_info, "deprecated", None):
|
|
144
|
+
parameter["deprecated"] = True
|
|
145
|
+
parameters.append(parameter)
|
|
128
146
|
return parameters
|
|
129
147
|
|
|
130
148
|
|
|
@@ -247,9 +265,8 @@ def get_openapi_path(
|
|
|
247
265
|
operation.setdefault("security", []).extend(operation_security)
|
|
248
266
|
if security_definitions:
|
|
249
267
|
security_schemes.update(security_definitions)
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
all_route_params=all_route_params,
|
|
268
|
+
operation_parameters = _get_openapi_operation_parameters(
|
|
269
|
+
dependant=route.dependant,
|
|
253
270
|
schema_generator=schema_generator,
|
|
254
271
|
model_name_map=model_name_map,
|
|
255
272
|
field_mapping=field_mapping,
|
|
@@ -379,6 +396,7 @@ def get_openapi_path(
|
|
|
379
396
|
deep_dict_update(openapi_response, process_response)
|
|
380
397
|
openapi_response["description"] = description
|
|
381
398
|
http422 = str(HTTP_422_UNPROCESSABLE_ENTITY)
|
|
399
|
+
all_route_params = get_flat_params(route.dependant)
|
|
382
400
|
if (all_route_params or route.body_field) and not any(
|
|
383
401
|
status in operation["responses"]
|
|
384
402
|
for status in [http422, "4XX", "default"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: fastapi
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.115.0
|
|
4
4
|
Summary: FastAPI framework, high performance, easy to learn, fast to code, ready for production
|
|
5
5
|
Author-Email: =?utf-8?q?Sebasti=C3=A1n_Ram=C3=ADrez?= <tiangolo@gmail.com>
|
|
6
6
|
Classifier: Intended Audience :: Information Technology
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
fastapi-0.
|
|
2
|
-
fastapi-0.
|
|
3
|
-
fastapi-0.
|
|
4
|
-
fastapi-0.
|
|
5
|
-
fastapi/__init__.py,sha256=
|
|
1
|
+
fastapi-0.115.0.dist-info/METADATA,sha256=ooXztPJg9fxh1kZsyXVFKVLEyPDuMUVqS0N7t6uRi94,27227
|
|
2
|
+
fastapi-0.115.0.dist-info/WHEEL,sha256=rSwsxJWe3vzyR5HCwjWXQruDgschpei4h_giTm0dJVE,90
|
|
3
|
+
fastapi-0.115.0.dist-info/entry_points.txt,sha256=Nn2-rs4A5_lQZko2b9QqCKQx9Irx0agGbxq3QLgjBxQ,46
|
|
4
|
+
fastapi-0.115.0.dist-info/licenses/LICENSE,sha256=Tsif_IFIW5f-xYSy1KlhAy7v_oNEU4lP2cEnSQbMdE4,1086
|
|
5
|
+
fastapi/__init__.py,sha256=xZXaU_wxKQRFq4Cl6laXFZnFy_nuVDvmwxHB43HlgaE,1081
|
|
6
6
|
fastapi/__main__.py,sha256=bKePXLdO4SsVSM6r9SVoLickJDcR2c0cTOxZRKq26YQ,37
|
|
7
7
|
fastapi/_compat.py,sha256=N4y7exHYWpWytEwsDU31YHDXoJRvHxREx2qNS3bF85o,23876
|
|
8
8
|
fastapi/applications.py,sha256=Ix-o9pQAWhEDf9J0Q1hZ0nBB1uP72c-Y3oiYzvrwqiM,176316
|
|
@@ -12,7 +12,7 @@ fastapi/concurrency.py,sha256=AYLnS4judDUmXsNRICtoKSP0prfYDcS8ehBtYW9JhQQ,1403
|
|
|
12
12
|
fastapi/datastructures.py,sha256=b2PEz77XGq-u3Ur1Inwk0AGjOsQZO49yF9C7IPJ15cY,5766
|
|
13
13
|
fastapi/dependencies/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
14
|
fastapi/dependencies/models.py,sha256=Pjl6vx-4nZ5Tta9kJa3-RfQKkXtCpS09-FhMgs9eWNs,1507
|
|
15
|
-
fastapi/dependencies/utils.py,sha256=
|
|
15
|
+
fastapi/dependencies/utils.py,sha256=EnZ_n4CEK3fTqylgr9m3skxmzvFUflleoT1ESCH865k,35172
|
|
16
16
|
fastapi/encoders.py,sha256=LvwYmFeOz4tVwvgBoC5rvZnbr7hZr73KGrU8O7zSptU,11068
|
|
17
17
|
fastapi/exception_handlers.py,sha256=MBrIOA-ugjJDivIi4rSsUJBdTsjuzN76q4yh0q1COKw,1332
|
|
18
18
|
fastapi/exceptions.py,sha256=taNixuFEXb67lI1bnX1ubq8y8TseJ4yoPlWjyP0fTzk,4969
|
|
@@ -27,7 +27,7 @@ fastapi/openapi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
|
27
27
|
fastapi/openapi/constants.py,sha256=adGzmis1L1HJRTE3kJ5fmHS_Noq6tIY6pWv_SFzoFDU,153
|
|
28
28
|
fastapi/openapi/docs.py,sha256=XcQq-ZbQdC5sI0gIGu5MoHK1q-OFaqws7-ORTo6sjY4,10348
|
|
29
29
|
fastapi/openapi/models.py,sha256=PqkxQiqcEgjKuhfUIWPZPQcyTcubtUCB3vcObLsB7VE,15397
|
|
30
|
-
fastapi/openapi/utils.py,sha256=
|
|
30
|
+
fastapi/openapi/utils.py,sha256=vpbAzWpuNaJL_ocBxt4jp0GUUwrDKNB1anyoAx69fhA,23177
|
|
31
31
|
fastapi/param_functions.py,sha256=uQzNlihlhM80u4Xbstz__D3L3yxpTqLmsC-Hra1WfqE,64018
|
|
32
32
|
fastapi/params.py,sha256=XC025dCSObp7fXhOPYo-jwXQRGZ9CwlfNRq2cLh_dRk,28186
|
|
33
33
|
fastapi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -47,4 +47,4 @@ fastapi/testclient.py,sha256=nBvaAmX66YldReJNZXPOk1sfuo2Q6hs8bOvIaCep6LQ,66
|
|
|
47
47
|
fastapi/types.py,sha256=nFb36sK3DSoqoyo7Miwy3meKK5UdFBgkAgLSzQlUVyI,383
|
|
48
48
|
fastapi/utils.py,sha256=y8Bj5ttMaI9tS4D60OUgXqKnktBr99NdYUnHHV9LgoY,7948
|
|
49
49
|
fastapi/websockets.py,sha256=419uncYObEKZG0YcrXscfQQYLSWoE10jqxVMetGdR98,222
|
|
50
|
-
fastapi-0.
|
|
50
|
+
fastapi-0.115.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|