fastapi 0.118.3__py3-none-any.whl → 0.119.1__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 +362 -0
- fastapi/_compat/may_v1.py +123 -0
- fastapi/_compat/model_field.py +53 -0
- fastapi/_compat/shared.py +211 -0
- fastapi/_compat/v1.py +312 -0
- fastapi/_compat/v2.py +459 -0
- fastapi/applications.py +2 -2
- fastapi/datastructures.py +6 -7
- fastapi/dependencies/utils.py +75 -35
- 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 +69 -36
- {fastapi-0.118.3.dist-info → fastapi-0.119.1.dist-info}/METADATA +4 -4
- {fastapi-0.118.3.dist-info → fastapi-0.119.1.dist-info}/RECORD +21 -14
- fastapi/_compat.py +0 -680
- {fastapi-0.118.3.dist-info → fastapi-0.119.1.dist-info}/WHEEL +0 -0
- {fastapi-0.118.3.dist-info → fastapi-0.119.1.dist-info}/entry_points.txt +0 -0
- {fastapi-0.118.3.dist-info → fastapi-0.119.1.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,
|
|
@@ -43,10 +43,12 @@ from fastapi._compat import (
|
|
|
43
43
|
is_uploadfile_or_nonable_uploadfile_annotation,
|
|
44
44
|
is_uploadfile_sequence_annotation,
|
|
45
45
|
lenient_issubclass,
|
|
46
|
+
may_v1,
|
|
46
47
|
sequence_types,
|
|
47
48
|
serialize_sequence_value,
|
|
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, may_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[
|
|
386
|
-
|
|
387
|
-
|
|
400
|
+
fastapi_annotation: Union[
|
|
401
|
+
FieldInfo, may_v1.FieldInfo, params.Depends, None
|
|
402
|
+
] = fastapi_specific_annotations[-1]
|
|
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, may_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
|
+
may_v1.Undefined,
|
|
414
|
+
} or field_info.default in {RequiredParam, may_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, may_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,20 @@ 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
|
|
527
|
+
required=field_info.default
|
|
528
|
+
in (RequiredParam, may_v1.RequiredParam, Undefined),
|
|
502
529
|
field_info=field_info,
|
|
503
530
|
)
|
|
504
531
|
if is_path_param:
|
|
505
532
|
assert is_scalar_field(field=field), (
|
|
506
533
|
"Path params must be of one of the supported types"
|
|
507
534
|
)
|
|
508
|
-
elif isinstance(field_info, params.Query):
|
|
535
|
+
elif isinstance(field_info, (params.Query, temp_pydantic_v1_params.Query)):
|
|
509
536
|
assert (
|
|
510
537
|
is_scalar_field(field)
|
|
511
538
|
or is_scalar_sequence_field(field)
|
|
512
539
|
or (
|
|
513
|
-
|
|
540
|
+
_is_model_class(field.type_)
|
|
514
541
|
# For Pydantic v1
|
|
515
542
|
and getattr(field, "shape", 1) == 1
|
|
516
543
|
)
|
|
@@ -712,10 +739,10 @@ def _validate_value_with_model_field(
|
|
|
712
739
|
else:
|
|
713
740
|
return deepcopy(field.default), []
|
|
714
741
|
v_, errors_ = field.validate(value, values, loc=loc)
|
|
715
|
-
if
|
|
742
|
+
if _is_error_wrapper(errors_): # type: ignore[arg-type]
|
|
716
743
|
return None, [errors_]
|
|
717
744
|
elif isinstance(errors_, list):
|
|
718
|
-
new_errors = _regenerate_error_with_loc(errors=errors_, loc_prefix=())
|
|
745
|
+
new_errors = may_v1._regenerate_error_with_loc(errors=errors_, loc_prefix=())
|
|
719
746
|
return None, new_errors
|
|
720
747
|
else:
|
|
721
748
|
return v_, []
|
|
@@ -732,7 +759,7 @@ def _get_multidict_value(
|
|
|
732
759
|
if (
|
|
733
760
|
value is None
|
|
734
761
|
or (
|
|
735
|
-
isinstance(field.field_info, params.Form)
|
|
762
|
+
isinstance(field.field_info, (params.Form, temp_pydantic_v1_params.Form))
|
|
736
763
|
and isinstance(value, str) # For type checks
|
|
737
764
|
and value == ""
|
|
738
765
|
)
|
|
@@ -798,7 +825,7 @@ def request_params_to_args(
|
|
|
798
825
|
|
|
799
826
|
if single_not_embedded_field:
|
|
800
827
|
field_info = first_field.field_info
|
|
801
|
-
assert isinstance(field_info, params.Param), (
|
|
828
|
+
assert isinstance(field_info, (params.Param, temp_pydantic_v1_params.Param)), (
|
|
802
829
|
"Params must be subclasses of Param"
|
|
803
830
|
)
|
|
804
831
|
loc: Tuple[str, ...] = (field_info.in_.value,)
|
|
@@ -810,7 +837,7 @@ def request_params_to_args(
|
|
|
810
837
|
for field in fields:
|
|
811
838
|
value = _get_multidict_value(field, received_params)
|
|
812
839
|
field_info = field.field_info
|
|
813
|
-
assert isinstance(field_info, params.Param), (
|
|
840
|
+
assert isinstance(field_info, (params.Param, temp_pydantic_v1_params.Param)), (
|
|
814
841
|
"Params must be subclasses of Param"
|
|
815
842
|
)
|
|
816
843
|
loc = (field_info.in_.value, field.alias)
|
|
@@ -837,7 +864,7 @@ def is_union_of_base_models(field_type: Any) -> bool:
|
|
|
837
864
|
union_args = get_args(field_type)
|
|
838
865
|
|
|
839
866
|
for arg in union_args:
|
|
840
|
-
if not
|
|
867
|
+
if not _is_model_class(arg):
|
|
841
868
|
return False
|
|
842
869
|
|
|
843
870
|
return True
|
|
@@ -859,8 +886,8 @@ def _should_embed_body_fields(fields: List[ModelField]) -> bool:
|
|
|
859
886
|
# If it's a Form (or File) field, it has to be a BaseModel (or a union of BaseModels) to be top level
|
|
860
887
|
# otherwise it has to be embedded, so that the key value pair can be extracted
|
|
861
888
|
if (
|
|
862
|
-
isinstance(first_field.field_info, params.Form)
|
|
863
|
-
and not
|
|
889
|
+
isinstance(first_field.field_info, (params.Form, temp_pydantic_v1_params.Form))
|
|
890
|
+
and not _is_model_class(first_field.type_)
|
|
864
891
|
and not is_union_of_base_models(first_field.type_)
|
|
865
892
|
):
|
|
866
893
|
return True
|
|
@@ -877,14 +904,14 @@ async def _extract_form_body(
|
|
|
877
904
|
value = _get_multidict_value(field, received_body)
|
|
878
905
|
field_info = field.field_info
|
|
879
906
|
if (
|
|
880
|
-
isinstance(field_info, params.File)
|
|
907
|
+
isinstance(field_info, (params.File, temp_pydantic_v1_params.File))
|
|
881
908
|
and is_bytes_field(field)
|
|
882
909
|
and isinstance(value, UploadFile)
|
|
883
910
|
):
|
|
884
911
|
value = await value.read()
|
|
885
912
|
elif (
|
|
886
913
|
is_bytes_sequence_field(field)
|
|
887
|
-
and isinstance(field_info, params.File)
|
|
914
|
+
and isinstance(field_info, (params.File, temp_pydantic_v1_params.File))
|
|
888
915
|
and value_is_sequence(value)
|
|
889
916
|
):
|
|
890
917
|
# For types
|
|
@@ -925,7 +952,7 @@ async def request_body_to_args(
|
|
|
925
952
|
|
|
926
953
|
if (
|
|
927
954
|
single_not_embedded_field
|
|
928
|
-
and
|
|
955
|
+
and _is_model_class(first_field.type_)
|
|
929
956
|
and isinstance(received_body, FormData)
|
|
930
957
|
):
|
|
931
958
|
fields_to_extract = get_cached_model_fields(first_field.type_)
|
|
@@ -990,15 +1017,28 @@ def get_body_field(
|
|
|
990
1017
|
BodyFieldInfo_kwargs["default"] = None
|
|
991
1018
|
if any(isinstance(f.field_info, params.File) for f in flat_dependant.body_params):
|
|
992
1019
|
BodyFieldInfo: Type[params.Body] = params.File
|
|
1020
|
+
elif any(
|
|
1021
|
+
isinstance(f.field_info, temp_pydantic_v1_params.File)
|
|
1022
|
+
for f in flat_dependant.body_params
|
|
1023
|
+
):
|
|
1024
|
+
BodyFieldInfo: Type[temp_pydantic_v1_params.Body] = temp_pydantic_v1_params.File # type: ignore[no-redef]
|
|
993
1025
|
elif any(isinstance(f.field_info, params.Form) for f in flat_dependant.body_params):
|
|
994
1026
|
BodyFieldInfo = params.Form
|
|
1027
|
+
elif any(
|
|
1028
|
+
isinstance(f.field_info, temp_pydantic_v1_params.Form)
|
|
1029
|
+
for f in flat_dependant.body_params
|
|
1030
|
+
):
|
|
1031
|
+
BodyFieldInfo = temp_pydantic_v1_params.Form # type: ignore[assignment]
|
|
995
1032
|
else:
|
|
996
|
-
|
|
1033
|
+
if annotation_is_pydantic_v1(BodyModel):
|
|
1034
|
+
BodyFieldInfo = temp_pydantic_v1_params.Body # type: ignore[assignment]
|
|
1035
|
+
else:
|
|
1036
|
+
BodyFieldInfo = params.Body
|
|
997
1037
|
|
|
998
1038
|
body_param_media_types = [
|
|
999
1039
|
f.field_info.media_type
|
|
1000
1040
|
for f in flat_dependant.body_params
|
|
1001
|
-
if isinstance(f.field_info, params.Body)
|
|
1041
|
+
if isinstance(f.field_info, (params.Body, temp_pydantic_v1_params.Body))
|
|
1002
1042
|
]
|
|
1003
1043
|
if len(set(body_param_media_types)) == 1:
|
|
1004
1044
|
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 may_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
|
+
may_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
|
+
may_v1.NameEmail: str,
|
|
77
80
|
Path: str,
|
|
78
81
|
Pattern: lambda o: o.pattern,
|
|
79
82
|
SecretBytes: str,
|
|
83
|
+
may_v1.SecretBytes: str,
|
|
80
84
|
SecretStr: str,
|
|
85
|
+
may_v1.SecretStr: str,
|
|
81
86
|
set: list,
|
|
82
87
|
UUID: str,
|
|
83
88
|
Url: str,
|
|
89
|
+
may_v1.Url: str,
|
|
84
90
|
AnyUrl: str,
|
|
91
|
+
may_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, may_v1.BaseModel)):
|
|
217
224
|
# TODO: remove when deprecating Pydantic v1
|
|
218
225
|
encoders: Dict[Any, Any] = {}
|
|
219
|
-
if
|
|
226
|
+
if isinstance(obj, may_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:
|