fastapi 0.118.2__py3-none-any.whl → 0.119.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/__init__.py +50 -0
- fastapi/_compat/main.py +305 -0
- fastapi/_compat/model_field.py +53 -0
- fastapi/_compat/shared.py +209 -0
- fastapi/_compat/v1.py +334 -0
- fastapi/_compat/v2.py +459 -0
- fastapi/datastructures.py +6 -7
- fastapi/dependencies/utils.py +72 -33
- fastapi/encoders.py +11 -4
- fastapi/openapi/utils.py +5 -18
- fastapi/routing.py +4 -2
- fastapi/temp_pydantic_v1_params.py +724 -0
- fastapi/utils.py +62 -36
- {fastapi-0.118.2.dist-info → fastapi-0.119.0.dist-info}/METADATA +2 -1
- {fastapi-0.118.2.dist-info → fastapi-0.119.0.dist-info}/RECORD +19 -13
- fastapi/_compat.py +0 -680
- {fastapi-0.118.2.dist-info → fastapi-0.119.0.dist-info}/WHEEL +0 -0
- {fastapi-0.118.2.dist-info → fastapi-0.119.0.dist-info}/entry_points.txt +0 -0
- {fastapi-0.118.2.dist-info → fastapi-0.119.0.dist-info}/licenses/LICENSE +0 -0
fastapi/dependencies/utils.py
CHANGED
|
@@ -23,11 +23,11 @@ import anyio
|
|
|
23
23
|
from fastapi import params
|
|
24
24
|
from fastapi._compat import (
|
|
25
25
|
PYDANTIC_V2,
|
|
26
|
-
ErrorWrapper,
|
|
27
26
|
ModelField,
|
|
28
27
|
RequiredParam,
|
|
29
28
|
Undefined,
|
|
30
|
-
|
|
29
|
+
_is_error_wrapper,
|
|
30
|
+
_is_model_class,
|
|
31
31
|
copy_field_info,
|
|
32
32
|
create_body_model,
|
|
33
33
|
evaluate_forwardref,
|
|
@@ -45,8 +45,10 @@ from fastapi._compat import (
|
|
|
45
45
|
lenient_issubclass,
|
|
46
46
|
sequence_types,
|
|
47
47
|
serialize_sequence_value,
|
|
48
|
+
v1,
|
|
48
49
|
value_is_sequence,
|
|
49
50
|
)
|
|
51
|
+
from fastapi._compat.shared import annotation_is_pydantic_v1
|
|
50
52
|
from fastapi.background import BackgroundTasks
|
|
51
53
|
from fastapi.concurrency import (
|
|
52
54
|
asynccontextmanager,
|
|
@@ -74,6 +76,8 @@ from starlette.responses import Response
|
|
|
74
76
|
from starlette.websockets import WebSocket
|
|
75
77
|
from typing_extensions import Annotated, get_args, get_origin
|
|
76
78
|
|
|
79
|
+
from .. import temp_pydantic_v1_params
|
|
80
|
+
|
|
77
81
|
if sys.version_info >= (3, 13): # pragma: no cover
|
|
78
82
|
from inspect import iscoroutinefunction
|
|
79
83
|
else: # pragma: no cover
|
|
@@ -219,7 +223,7 @@ def _get_flat_fields_from_params(fields: List[ModelField]) -> List[ModelField]:
|
|
|
219
223
|
if not fields:
|
|
220
224
|
return fields
|
|
221
225
|
first_field = fields[0]
|
|
222
|
-
if len(fields) == 1 and
|
|
226
|
+
if len(fields) == 1 and _is_model_class(first_field.type_):
|
|
223
227
|
fields_to_extract = get_cached_model_fields(first_field.type_)
|
|
224
228
|
return fields_to_extract
|
|
225
229
|
return fields
|
|
@@ -315,7 +319,9 @@ def get_dependant(
|
|
|
315
319
|
)
|
|
316
320
|
continue
|
|
317
321
|
assert param_details.field is not None
|
|
318
|
-
if isinstance(
|
|
322
|
+
if isinstance(
|
|
323
|
+
param_details.field.field_info, (params.Body, temp_pydantic_v1_params.Body)
|
|
324
|
+
):
|
|
319
325
|
dependant.body_params.append(param_details.field)
|
|
320
326
|
else:
|
|
321
327
|
add_param_to_fields(field=param_details.field, dependant=dependant)
|
|
@@ -374,28 +380,38 @@ def analyze_param(
|
|
|
374
380
|
fastapi_annotations = [
|
|
375
381
|
arg
|
|
376
382
|
for arg in annotated_args[1:]
|
|
377
|
-
if isinstance(arg, (FieldInfo, params.Depends))
|
|
383
|
+
if isinstance(arg, (FieldInfo, v1.FieldInfo, params.Depends))
|
|
378
384
|
]
|
|
379
385
|
fastapi_specific_annotations = [
|
|
380
386
|
arg
|
|
381
387
|
for arg in fastapi_annotations
|
|
382
|
-
if isinstance(
|
|
388
|
+
if isinstance(
|
|
389
|
+
arg,
|
|
390
|
+
(
|
|
391
|
+
params.Param,
|
|
392
|
+
temp_pydantic_v1_params.Param,
|
|
393
|
+
params.Body,
|
|
394
|
+
temp_pydantic_v1_params.Body,
|
|
395
|
+
params.Depends,
|
|
396
|
+
),
|
|
397
|
+
)
|
|
383
398
|
]
|
|
384
399
|
if fastapi_specific_annotations:
|
|
385
|
-
fastapi_annotation: Union[FieldInfo, params.Depends, None] = (
|
|
400
|
+
fastapi_annotation: Union[FieldInfo, v1.FieldInfo, params.Depends, None] = (
|
|
386
401
|
fastapi_specific_annotations[-1]
|
|
387
402
|
)
|
|
388
403
|
else:
|
|
389
404
|
fastapi_annotation = None
|
|
390
405
|
# Set default for Annotated FieldInfo
|
|
391
|
-
if isinstance(fastapi_annotation, FieldInfo):
|
|
406
|
+
if isinstance(fastapi_annotation, (FieldInfo, v1.FieldInfo)):
|
|
392
407
|
# Copy `field_info` because we mutate `field_info.default` below.
|
|
393
408
|
field_info = copy_field_info(
|
|
394
409
|
field_info=fastapi_annotation, annotation=use_annotation
|
|
395
410
|
)
|
|
396
|
-
assert
|
|
397
|
-
|
|
398
|
-
|
|
411
|
+
assert field_info.default in {
|
|
412
|
+
Undefined,
|
|
413
|
+
v1.Undefined,
|
|
414
|
+
} or field_info.default in {RequiredParam, v1.RequiredParam}, (
|
|
399
415
|
f"`{field_info.__class__.__name__}` default value cannot be set in"
|
|
400
416
|
f" `Annotated` for {param_name!r}. Set the default value with `=` instead."
|
|
401
417
|
)
|
|
@@ -419,14 +435,15 @@ def analyze_param(
|
|
|
419
435
|
)
|
|
420
436
|
depends = value
|
|
421
437
|
# Get FieldInfo from default value
|
|
422
|
-
elif isinstance(value, FieldInfo):
|
|
438
|
+
elif isinstance(value, (FieldInfo, v1.FieldInfo)):
|
|
423
439
|
assert field_info is None, (
|
|
424
440
|
"Cannot specify FastAPI annotations in `Annotated` and default value"
|
|
425
441
|
f" together for {param_name!r}"
|
|
426
442
|
)
|
|
427
443
|
field_info = value
|
|
428
444
|
if PYDANTIC_V2:
|
|
429
|
-
field_info
|
|
445
|
+
if isinstance(field_info, FieldInfo):
|
|
446
|
+
field_info.annotation = type_annotation
|
|
430
447
|
|
|
431
448
|
# Get Depends from type annotation
|
|
432
449
|
if depends is not None and depends.dependency is None:
|
|
@@ -463,7 +480,14 @@ def analyze_param(
|
|
|
463
480
|
) or is_uploadfile_sequence_annotation(type_annotation):
|
|
464
481
|
field_info = params.File(annotation=use_annotation, default=default_value)
|
|
465
482
|
elif not field_annotation_is_scalar(annotation=type_annotation):
|
|
466
|
-
|
|
483
|
+
if annotation_is_pydantic_v1(use_annotation):
|
|
484
|
+
field_info = temp_pydantic_v1_params.Body(
|
|
485
|
+
annotation=use_annotation, default=default_value
|
|
486
|
+
)
|
|
487
|
+
else:
|
|
488
|
+
field_info = params.Body(
|
|
489
|
+
annotation=use_annotation, default=default_value
|
|
490
|
+
)
|
|
467
491
|
else:
|
|
468
492
|
field_info = params.Query(annotation=use_annotation, default=default_value)
|
|
469
493
|
|
|
@@ -472,12 +496,14 @@ def analyze_param(
|
|
|
472
496
|
if field_info is not None:
|
|
473
497
|
# Handle field_info.in_
|
|
474
498
|
if is_path_param:
|
|
475
|
-
assert isinstance(
|
|
499
|
+
assert isinstance(
|
|
500
|
+
field_info, (params.Path, temp_pydantic_v1_params.Path)
|
|
501
|
+
), (
|
|
476
502
|
f"Cannot use `{field_info.__class__.__name__}` for path param"
|
|
477
503
|
f" {param_name!r}"
|
|
478
504
|
)
|
|
479
505
|
elif (
|
|
480
|
-
isinstance(field_info, params.Param)
|
|
506
|
+
isinstance(field_info, (params.Param, temp_pydantic_v1_params.Param))
|
|
481
507
|
and getattr(field_info, "in_", None) is None
|
|
482
508
|
):
|
|
483
509
|
field_info.in_ = params.ParamTypes.query
|
|
@@ -486,7 +512,7 @@ def analyze_param(
|
|
|
486
512
|
field_info,
|
|
487
513
|
param_name,
|
|
488
514
|
)
|
|
489
|
-
if isinstance(field_info, params.Form):
|
|
515
|
+
if isinstance(field_info, (params.Form, temp_pydantic_v1_params.Form)):
|
|
490
516
|
ensure_multipart_is_installed()
|
|
491
517
|
if not field_info.alias and getattr(field_info, "convert_underscores", None):
|
|
492
518
|
alias = param_name.replace("_", "-")
|
|
@@ -498,19 +524,19 @@ def analyze_param(
|
|
|
498
524
|
type_=use_annotation_from_field_info,
|
|
499
525
|
default=field_info.default,
|
|
500
526
|
alias=alias,
|
|
501
|
-
required=field_info.default in (RequiredParam, Undefined),
|
|
527
|
+
required=field_info.default in (RequiredParam, v1.RequiredParam, Undefined),
|
|
502
528
|
field_info=field_info,
|
|
503
529
|
)
|
|
504
530
|
if is_path_param:
|
|
505
531
|
assert is_scalar_field(field=field), (
|
|
506
532
|
"Path params must be of one of the supported types"
|
|
507
533
|
)
|
|
508
|
-
elif isinstance(field_info, params.Query):
|
|
534
|
+
elif isinstance(field_info, (params.Query, temp_pydantic_v1_params.Query)):
|
|
509
535
|
assert (
|
|
510
536
|
is_scalar_field(field)
|
|
511
537
|
or is_scalar_sequence_field(field)
|
|
512
538
|
or (
|
|
513
|
-
|
|
539
|
+
_is_model_class(field.type_)
|
|
514
540
|
# For Pydantic v1
|
|
515
541
|
and getattr(field, "shape", 1) == 1
|
|
516
542
|
)
|
|
@@ -712,10 +738,10 @@ def _validate_value_with_model_field(
|
|
|
712
738
|
else:
|
|
713
739
|
return deepcopy(field.default), []
|
|
714
740
|
v_, errors_ = field.validate(value, values, loc=loc)
|
|
715
|
-
if
|
|
741
|
+
if _is_error_wrapper(errors_): # type: ignore[arg-type]
|
|
716
742
|
return None, [errors_]
|
|
717
743
|
elif isinstance(errors_, list):
|
|
718
|
-
new_errors = _regenerate_error_with_loc(errors=errors_, loc_prefix=())
|
|
744
|
+
new_errors = v1._regenerate_error_with_loc(errors=errors_, loc_prefix=())
|
|
719
745
|
return None, new_errors
|
|
720
746
|
else:
|
|
721
747
|
return v_, []
|
|
@@ -732,7 +758,7 @@ def _get_multidict_value(
|
|
|
732
758
|
if (
|
|
733
759
|
value is None
|
|
734
760
|
or (
|
|
735
|
-
isinstance(field.field_info, params.Form)
|
|
761
|
+
isinstance(field.field_info, (params.Form, temp_pydantic_v1_params.Form))
|
|
736
762
|
and isinstance(value, str) # For type checks
|
|
737
763
|
and value == ""
|
|
738
764
|
)
|
|
@@ -798,7 +824,7 @@ def request_params_to_args(
|
|
|
798
824
|
|
|
799
825
|
if single_not_embedded_field:
|
|
800
826
|
field_info = first_field.field_info
|
|
801
|
-
assert isinstance(field_info, params.Param), (
|
|
827
|
+
assert isinstance(field_info, (params.Param, temp_pydantic_v1_params.Param)), (
|
|
802
828
|
"Params must be subclasses of Param"
|
|
803
829
|
)
|
|
804
830
|
loc: Tuple[str, ...] = (field_info.in_.value,)
|
|
@@ -810,7 +836,7 @@ def request_params_to_args(
|
|
|
810
836
|
for field in fields:
|
|
811
837
|
value = _get_multidict_value(field, received_params)
|
|
812
838
|
field_info = field.field_info
|
|
813
|
-
assert isinstance(field_info, params.Param), (
|
|
839
|
+
assert isinstance(field_info, (params.Param, temp_pydantic_v1_params.Param)), (
|
|
814
840
|
"Params must be subclasses of Param"
|
|
815
841
|
)
|
|
816
842
|
loc = (field_info.in_.value, field.alias)
|
|
@@ -837,7 +863,7 @@ def is_union_of_base_models(field_type: Any) -> bool:
|
|
|
837
863
|
union_args = get_args(field_type)
|
|
838
864
|
|
|
839
865
|
for arg in union_args:
|
|
840
|
-
if not
|
|
866
|
+
if not _is_model_class(arg):
|
|
841
867
|
return False
|
|
842
868
|
|
|
843
869
|
return True
|
|
@@ -859,8 +885,8 @@ def _should_embed_body_fields(fields: List[ModelField]) -> bool:
|
|
|
859
885
|
# If it's a Form (or File) field, it has to be a BaseModel (or a union of BaseModels) to be top level
|
|
860
886
|
# otherwise it has to be embedded, so that the key value pair can be extracted
|
|
861
887
|
if (
|
|
862
|
-
isinstance(first_field.field_info, params.Form)
|
|
863
|
-
and not
|
|
888
|
+
isinstance(first_field.field_info, (params.Form, temp_pydantic_v1_params.Form))
|
|
889
|
+
and not _is_model_class(first_field.type_)
|
|
864
890
|
and not is_union_of_base_models(first_field.type_)
|
|
865
891
|
):
|
|
866
892
|
return True
|
|
@@ -877,14 +903,14 @@ async def _extract_form_body(
|
|
|
877
903
|
value = _get_multidict_value(field, received_body)
|
|
878
904
|
field_info = field.field_info
|
|
879
905
|
if (
|
|
880
|
-
isinstance(field_info, params.File)
|
|
906
|
+
isinstance(field_info, (params.File, temp_pydantic_v1_params.File))
|
|
881
907
|
and is_bytes_field(field)
|
|
882
908
|
and isinstance(value, UploadFile)
|
|
883
909
|
):
|
|
884
910
|
value = await value.read()
|
|
885
911
|
elif (
|
|
886
912
|
is_bytes_sequence_field(field)
|
|
887
|
-
and isinstance(field_info, params.File)
|
|
913
|
+
and isinstance(field_info, (params.File, temp_pydantic_v1_params.File))
|
|
888
914
|
and value_is_sequence(value)
|
|
889
915
|
):
|
|
890
916
|
# For types
|
|
@@ -925,7 +951,7 @@ async def request_body_to_args(
|
|
|
925
951
|
|
|
926
952
|
if (
|
|
927
953
|
single_not_embedded_field
|
|
928
|
-
and
|
|
954
|
+
and _is_model_class(first_field.type_)
|
|
929
955
|
and isinstance(received_body, FormData)
|
|
930
956
|
):
|
|
931
957
|
fields_to_extract = get_cached_model_fields(first_field.type_)
|
|
@@ -990,15 +1016,28 @@ def get_body_field(
|
|
|
990
1016
|
BodyFieldInfo_kwargs["default"] = None
|
|
991
1017
|
if any(isinstance(f.field_info, params.File) for f in flat_dependant.body_params):
|
|
992
1018
|
BodyFieldInfo: Type[params.Body] = params.File
|
|
1019
|
+
elif any(
|
|
1020
|
+
isinstance(f.field_info, temp_pydantic_v1_params.File)
|
|
1021
|
+
for f in flat_dependant.body_params
|
|
1022
|
+
):
|
|
1023
|
+
BodyFieldInfo: Type[temp_pydantic_v1_params.Body] = temp_pydantic_v1_params.File # type: ignore[no-redef]
|
|
993
1024
|
elif any(isinstance(f.field_info, params.Form) for f in flat_dependant.body_params):
|
|
994
1025
|
BodyFieldInfo = params.Form
|
|
1026
|
+
elif any(
|
|
1027
|
+
isinstance(f.field_info, temp_pydantic_v1_params.Form)
|
|
1028
|
+
for f in flat_dependant.body_params
|
|
1029
|
+
):
|
|
1030
|
+
BodyFieldInfo = temp_pydantic_v1_params.Form # type: ignore[assignment]
|
|
995
1031
|
else:
|
|
996
|
-
|
|
1032
|
+
if annotation_is_pydantic_v1(BodyModel):
|
|
1033
|
+
BodyFieldInfo = temp_pydantic_v1_params.Body # type: ignore[assignment]
|
|
1034
|
+
else:
|
|
1035
|
+
BodyFieldInfo = params.Body
|
|
997
1036
|
|
|
998
1037
|
body_param_media_types = [
|
|
999
1038
|
f.field_info.media_type
|
|
1000
1039
|
for f in flat_dependant.body_params
|
|
1001
|
-
if isinstance(f.field_info, params.Body)
|
|
1040
|
+
if isinstance(f.field_info, (params.Body, temp_pydantic_v1_params.Body))
|
|
1002
1041
|
]
|
|
1003
1042
|
if len(set(body_param_media_types)) == 1:
|
|
1004
1043
|
BodyFieldInfo_kwargs["media_type"] = body_param_media_types[0]
|
fastapi/encoders.py
CHANGED
|
@@ -17,6 +17,7 @@ from types import GeneratorType
|
|
|
17
17
|
from typing import Any, Callable, Dict, List, Optional, Tuple, Type, Union
|
|
18
18
|
from uuid import UUID
|
|
19
19
|
|
|
20
|
+
from fastapi._compat import v1
|
|
20
21
|
from fastapi.types import IncEx
|
|
21
22
|
from pydantic import BaseModel
|
|
22
23
|
from pydantic.color import Color
|
|
@@ -24,7 +25,7 @@ from pydantic.networks import AnyUrl, NameEmail
|
|
|
24
25
|
from pydantic.types import SecretBytes, SecretStr
|
|
25
26
|
from typing_extensions import Annotated, Doc
|
|
26
27
|
|
|
27
|
-
from ._compat import
|
|
28
|
+
from ._compat import Url, _is_undefined, _model_dump
|
|
28
29
|
|
|
29
30
|
|
|
30
31
|
# Taken from Pydantic v1 as is
|
|
@@ -58,6 +59,7 @@ def decimal_encoder(dec_value: Decimal) -> Union[int, float]:
|
|
|
58
59
|
ENCODERS_BY_TYPE: Dict[Type[Any], Callable[[Any], Any]] = {
|
|
59
60
|
bytes: lambda o: o.decode(),
|
|
60
61
|
Color: str,
|
|
62
|
+
v1.Color: str,
|
|
61
63
|
datetime.date: isoformat,
|
|
62
64
|
datetime.datetime: isoformat,
|
|
63
65
|
datetime.time: isoformat,
|
|
@@ -74,14 +76,19 @@ ENCODERS_BY_TYPE: Dict[Type[Any], Callable[[Any], Any]] = {
|
|
|
74
76
|
IPv6Interface: str,
|
|
75
77
|
IPv6Network: str,
|
|
76
78
|
NameEmail: str,
|
|
79
|
+
v1.NameEmail: str,
|
|
77
80
|
Path: str,
|
|
78
81
|
Pattern: lambda o: o.pattern,
|
|
79
82
|
SecretBytes: str,
|
|
83
|
+
v1.SecretBytes: str,
|
|
80
84
|
SecretStr: str,
|
|
85
|
+
v1.SecretStr: str,
|
|
81
86
|
set: list,
|
|
82
87
|
UUID: str,
|
|
83
88
|
Url: str,
|
|
89
|
+
v1.Url: str,
|
|
84
90
|
AnyUrl: str,
|
|
91
|
+
v1.AnyUrl: str,
|
|
85
92
|
}
|
|
86
93
|
|
|
87
94
|
|
|
@@ -213,10 +220,10 @@ def jsonable_encoder(
|
|
|
213
220
|
include = set(include)
|
|
214
221
|
if exclude is not None and not isinstance(exclude, (set, dict)):
|
|
215
222
|
exclude = set(exclude)
|
|
216
|
-
if isinstance(obj, BaseModel):
|
|
223
|
+
if isinstance(obj, (BaseModel, v1.BaseModel)):
|
|
217
224
|
# TODO: remove when deprecating Pydantic v1
|
|
218
225
|
encoders: Dict[Any, Any] = {}
|
|
219
|
-
if
|
|
226
|
+
if isinstance(obj, v1.BaseModel):
|
|
220
227
|
encoders = getattr(obj.__config__, "json_encoders", {}) # type: ignore[attr-defined]
|
|
221
228
|
if custom_encoder:
|
|
222
229
|
encoders = {**encoders, **custom_encoder}
|
|
@@ -260,7 +267,7 @@ def jsonable_encoder(
|
|
|
260
267
|
return str(obj)
|
|
261
268
|
if isinstance(obj, (str, int, float, type(None))):
|
|
262
269
|
return obj
|
|
263
|
-
if
|
|
270
|
+
if _is_undefined(obj):
|
|
264
271
|
return None
|
|
265
272
|
if isinstance(obj, dict):
|
|
266
273
|
encoded_dict = {}
|
fastapi/openapi/utils.py
CHANGED
|
@@ -5,7 +5,6 @@ from typing import Any, Dict, List, Optional, Sequence, Set, Tuple, Type, Union,
|
|
|
5
5
|
|
|
6
6
|
from fastapi import routing
|
|
7
7
|
from fastapi._compat import (
|
|
8
|
-
GenerateJsonSchema,
|
|
9
8
|
JsonSchemaValue,
|
|
10
9
|
ModelField,
|
|
11
10
|
Undefined,
|
|
@@ -22,7 +21,7 @@ from fastapi.dependencies.utils import (
|
|
|
22
21
|
get_flat_params,
|
|
23
22
|
)
|
|
24
23
|
from fastapi.encoders import jsonable_encoder
|
|
25
|
-
from fastapi.openapi.constants import METHODS_WITH_BODY, REF_PREFIX
|
|
24
|
+
from fastapi.openapi.constants import METHODS_WITH_BODY, REF_PREFIX
|
|
26
25
|
from fastapi.openapi.models import OpenAPI
|
|
27
26
|
from fastapi.params import Body, ParamTypes
|
|
28
27
|
from fastapi.responses import Response
|
|
@@ -37,6 +36,8 @@ from starlette.responses import JSONResponse
|
|
|
37
36
|
from starlette.routing import BaseRoute
|
|
38
37
|
from typing_extensions import Literal
|
|
39
38
|
|
|
39
|
+
from .._compat import _is_model_field
|
|
40
|
+
|
|
40
41
|
validation_error_definition = {
|
|
41
42
|
"title": "ValidationError",
|
|
42
43
|
"type": "object",
|
|
@@ -94,7 +95,6 @@ def get_openapi_security_definitions(
|
|
|
94
95
|
def _get_openapi_operation_parameters(
|
|
95
96
|
*,
|
|
96
97
|
dependant: Dependant,
|
|
97
|
-
schema_generator: GenerateJsonSchema,
|
|
98
98
|
model_name_map: ModelNameMap,
|
|
99
99
|
field_mapping: Dict[
|
|
100
100
|
Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
|
|
@@ -128,7 +128,6 @@ def _get_openapi_operation_parameters(
|
|
|
128
128
|
continue
|
|
129
129
|
param_schema = get_schema_from_model_field(
|
|
130
130
|
field=param,
|
|
131
|
-
schema_generator=schema_generator,
|
|
132
131
|
model_name_map=model_name_map,
|
|
133
132
|
field_mapping=field_mapping,
|
|
134
133
|
separate_input_output_schemas=separate_input_output_schemas,
|
|
@@ -169,7 +168,6 @@ def _get_openapi_operation_parameters(
|
|
|
169
168
|
def get_openapi_operation_request_body(
|
|
170
169
|
*,
|
|
171
170
|
body_field: Optional[ModelField],
|
|
172
|
-
schema_generator: GenerateJsonSchema,
|
|
173
171
|
model_name_map: ModelNameMap,
|
|
174
172
|
field_mapping: Dict[
|
|
175
173
|
Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
|
|
@@ -178,10 +176,9 @@ def get_openapi_operation_request_body(
|
|
|
178
176
|
) -> Optional[Dict[str, Any]]:
|
|
179
177
|
if not body_field:
|
|
180
178
|
return None
|
|
181
|
-
assert
|
|
179
|
+
assert _is_model_field(body_field)
|
|
182
180
|
body_schema = get_schema_from_model_field(
|
|
183
181
|
field=body_field,
|
|
184
|
-
schema_generator=schema_generator,
|
|
185
182
|
model_name_map=model_name_map,
|
|
186
183
|
field_mapping=field_mapping,
|
|
187
184
|
separate_input_output_schemas=separate_input_output_schemas,
|
|
@@ -254,7 +251,6 @@ def get_openapi_path(
|
|
|
254
251
|
*,
|
|
255
252
|
route: routing.APIRoute,
|
|
256
253
|
operation_ids: Set[str],
|
|
257
|
-
schema_generator: GenerateJsonSchema,
|
|
258
254
|
model_name_map: ModelNameMap,
|
|
259
255
|
field_mapping: Dict[
|
|
260
256
|
Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
|
|
@@ -287,7 +283,6 @@ def get_openapi_path(
|
|
|
287
283
|
security_schemes.update(security_definitions)
|
|
288
284
|
operation_parameters = _get_openapi_operation_parameters(
|
|
289
285
|
dependant=route.dependant,
|
|
290
|
-
schema_generator=schema_generator,
|
|
291
286
|
model_name_map=model_name_map,
|
|
292
287
|
field_mapping=field_mapping,
|
|
293
288
|
separate_input_output_schemas=separate_input_output_schemas,
|
|
@@ -309,7 +304,6 @@ def get_openapi_path(
|
|
|
309
304
|
if method in METHODS_WITH_BODY:
|
|
310
305
|
request_body_oai = get_openapi_operation_request_body(
|
|
311
306
|
body_field=route.body_field,
|
|
312
|
-
schema_generator=schema_generator,
|
|
313
307
|
model_name_map=model_name_map,
|
|
314
308
|
field_mapping=field_mapping,
|
|
315
309
|
separate_input_output_schemas=separate_input_output_schemas,
|
|
@@ -327,7 +321,6 @@ def get_openapi_path(
|
|
|
327
321
|
) = get_openapi_path(
|
|
328
322
|
route=callback,
|
|
329
323
|
operation_ids=operation_ids,
|
|
330
|
-
schema_generator=schema_generator,
|
|
331
324
|
model_name_map=model_name_map,
|
|
332
325
|
field_mapping=field_mapping,
|
|
333
326
|
separate_input_output_schemas=separate_input_output_schemas,
|
|
@@ -358,7 +351,6 @@ def get_openapi_path(
|
|
|
358
351
|
if route.response_field:
|
|
359
352
|
response_schema = get_schema_from_model_field(
|
|
360
353
|
field=route.response_field,
|
|
361
|
-
schema_generator=schema_generator,
|
|
362
354
|
model_name_map=model_name_map,
|
|
363
355
|
field_mapping=field_mapping,
|
|
364
356
|
separate_input_output_schemas=separate_input_output_schemas,
|
|
@@ -392,7 +384,6 @@ def get_openapi_path(
|
|
|
392
384
|
if field:
|
|
393
385
|
additional_field_schema = get_schema_from_model_field(
|
|
394
386
|
field=field,
|
|
395
|
-
schema_generator=schema_generator,
|
|
396
387
|
model_name_map=model_name_map,
|
|
397
388
|
field_mapping=field_mapping,
|
|
398
389
|
separate_input_output_schemas=separate_input_output_schemas,
|
|
@@ -454,7 +445,7 @@ def get_fields_from_routes(
|
|
|
454
445
|
route, routing.APIRoute
|
|
455
446
|
):
|
|
456
447
|
if route.body_field:
|
|
457
|
-
assert
|
|
448
|
+
assert _is_model_field(route.body_field), (
|
|
458
449
|
"A request body must be a Pydantic Field"
|
|
459
450
|
)
|
|
460
451
|
body_fields_from_routes.append(route.body_field)
|
|
@@ -510,10 +501,8 @@ def get_openapi(
|
|
|
510
501
|
operation_ids: Set[str] = set()
|
|
511
502
|
all_fields = get_fields_from_routes(list(routes or []) + list(webhooks or []))
|
|
512
503
|
model_name_map = get_compat_model_name_map(all_fields)
|
|
513
|
-
schema_generator = GenerateJsonSchema(ref_template=REF_TEMPLATE)
|
|
514
504
|
field_mapping, definitions = get_definitions(
|
|
515
505
|
fields=all_fields,
|
|
516
|
-
schema_generator=schema_generator,
|
|
517
506
|
model_name_map=model_name_map,
|
|
518
507
|
separate_input_output_schemas=separate_input_output_schemas,
|
|
519
508
|
)
|
|
@@ -522,7 +511,6 @@ def get_openapi(
|
|
|
522
511
|
result = get_openapi_path(
|
|
523
512
|
route=route,
|
|
524
513
|
operation_ids=operation_ids,
|
|
525
|
-
schema_generator=schema_generator,
|
|
526
514
|
model_name_map=model_name_map,
|
|
527
515
|
field_mapping=field_mapping,
|
|
528
516
|
separate_input_output_schemas=separate_input_output_schemas,
|
|
@@ -542,7 +530,6 @@ def get_openapi(
|
|
|
542
530
|
result = get_openapi_path(
|
|
543
531
|
route=webhook,
|
|
544
532
|
operation_ids=operation_ids,
|
|
545
|
-
schema_generator=schema_generator,
|
|
546
533
|
model_name_map=model_name_map,
|
|
547
534
|
field_mapping=field_mapping,
|
|
548
535
|
separate_input_output_schemas=separate_input_output_schemas,
|
fastapi/routing.py
CHANGED
|
@@ -24,7 +24,7 @@ from typing import (
|
|
|
24
24
|
Union,
|
|
25
25
|
)
|
|
26
26
|
|
|
27
|
-
from fastapi import params
|
|
27
|
+
from fastapi import params, temp_pydantic_v1_params
|
|
28
28
|
from fastapi._compat import (
|
|
29
29
|
ModelField,
|
|
30
30
|
Undefined,
|
|
@@ -307,7 +307,9 @@ def get_request_handler(
|
|
|
307
307
|
) -> Callable[[Request], Coroutine[Any, Any, Response]]:
|
|
308
308
|
assert dependant.call is not None, "dependant.call must be a function"
|
|
309
309
|
is_coroutine = iscoroutinefunction(dependant.call)
|
|
310
|
-
is_body_form = body_field and isinstance(
|
|
310
|
+
is_body_form = body_field and isinstance(
|
|
311
|
+
body_field.field_info, (params.Form, temp_pydantic_v1_params.Form)
|
|
312
|
+
)
|
|
311
313
|
if isinstance(response_class, DefaultPlaceholder):
|
|
312
314
|
actual_response_class: Type[Response] = response_class.value
|
|
313
315
|
else:
|