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 CHANGED
@@ -1,6 +1,6 @@
1
1
  """FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
2
2
 
3
- __version__ = "0.118.2"
3
+ __version__ = "0.119.0"
4
4
 
5
5
  from starlette import status as status
6
6
 
@@ -0,0 +1,50 @@
1
+ from .main import BaseConfig as BaseConfig
2
+ from .main import PydanticSchemaGenerationError as PydanticSchemaGenerationError
3
+ from .main import RequiredParam as RequiredParam
4
+ from .main import Undefined as Undefined
5
+ from .main import UndefinedType as UndefinedType
6
+ from .main import Url as Url
7
+ from .main import Validator as Validator
8
+ from .main import _get_model_config as _get_model_config
9
+ from .main import _is_error_wrapper as _is_error_wrapper
10
+ from .main import _is_model_class as _is_model_class
11
+ from .main import _is_model_field as _is_model_field
12
+ from .main import _is_undefined as _is_undefined
13
+ from .main import _model_dump as _model_dump
14
+ from .main import _model_rebuild as _model_rebuild
15
+ from .main import copy_field_info as copy_field_info
16
+ from .main import create_body_model as create_body_model
17
+ from .main import evaluate_forwardref as evaluate_forwardref
18
+ from .main import get_annotation_from_field_info as get_annotation_from_field_info
19
+ from .main import get_cached_model_fields as get_cached_model_fields
20
+ from .main import get_compat_model_name_map as get_compat_model_name_map
21
+ from .main import get_definitions as get_definitions
22
+ from .main import get_missing_field_error as get_missing_field_error
23
+ from .main import get_schema_from_model_field as get_schema_from_model_field
24
+ from .main import is_bytes_field as is_bytes_field
25
+ from .main import is_bytes_sequence_field as is_bytes_sequence_field
26
+ from .main import is_scalar_field as is_scalar_field
27
+ from .main import is_scalar_sequence_field as is_scalar_sequence_field
28
+ from .main import is_sequence_field as is_sequence_field
29
+ from .main import serialize_sequence_value as serialize_sequence_value
30
+ from .main import (
31
+ with_info_plain_validator_function as with_info_plain_validator_function,
32
+ )
33
+ from .model_field import ModelField as ModelField
34
+ from .shared import PYDANTIC_V2 as PYDANTIC_V2
35
+ from .shared import PYDANTIC_VERSION_MINOR_TUPLE as PYDANTIC_VERSION_MINOR_TUPLE
36
+ from .shared import annotation_is_pydantic_v1 as annotation_is_pydantic_v1
37
+ from .shared import field_annotation_is_scalar as field_annotation_is_scalar
38
+ from .shared import (
39
+ is_uploadfile_or_nonable_uploadfile_annotation as is_uploadfile_or_nonable_uploadfile_annotation,
40
+ )
41
+ from .shared import (
42
+ is_uploadfile_sequence_annotation as is_uploadfile_sequence_annotation,
43
+ )
44
+ from .shared import lenient_issubclass as lenient_issubclass
45
+ from .shared import sequence_types as sequence_types
46
+ from .shared import value_is_sequence as value_is_sequence
47
+ from .v1 import CoreSchema as CoreSchema
48
+ from .v1 import GetJsonSchemaHandler as GetJsonSchemaHandler
49
+ from .v1 import JsonSchemaValue as JsonSchemaValue
50
+ from .v1 import _normalize_errors as _normalize_errors
@@ -0,0 +1,305 @@
1
+ from functools import lru_cache
2
+ from typing import (
3
+ Any,
4
+ Dict,
5
+ List,
6
+ Sequence,
7
+ Tuple,
8
+ Type,
9
+ )
10
+
11
+ from fastapi._compat import v1
12
+ from fastapi._compat.shared import PYDANTIC_V2, lenient_issubclass
13
+ from fastapi.types import ModelNameMap
14
+ from pydantic import BaseModel
15
+ from typing_extensions import Literal
16
+
17
+ from .model_field import ModelField
18
+
19
+ if PYDANTIC_V2:
20
+ from .v2 import BaseConfig as BaseConfig
21
+ from .v2 import FieldInfo as FieldInfo
22
+ from .v2 import PydanticSchemaGenerationError as PydanticSchemaGenerationError
23
+ from .v2 import RequiredParam as RequiredParam
24
+ from .v2 import Undefined as Undefined
25
+ from .v2 import UndefinedType as UndefinedType
26
+ from .v2 import Url as Url
27
+ from .v2 import Validator as Validator
28
+ from .v2 import evaluate_forwardref as evaluate_forwardref
29
+ from .v2 import get_missing_field_error as get_missing_field_error
30
+ from .v2 import (
31
+ with_info_plain_validator_function as with_info_plain_validator_function,
32
+ )
33
+ else:
34
+ from .v1 import BaseConfig as BaseConfig # type: ignore[assignment]
35
+ from .v1 import FieldInfo as FieldInfo
36
+ from .v1 import ( # type: ignore[assignment]
37
+ PydanticSchemaGenerationError as PydanticSchemaGenerationError,
38
+ )
39
+ from .v1 import RequiredParam as RequiredParam
40
+ from .v1 import Undefined as Undefined
41
+ from .v1 import UndefinedType as UndefinedType
42
+ from .v1 import Url as Url # type: ignore[assignment]
43
+ from .v1 import Validator as Validator
44
+ from .v1 import evaluate_forwardref as evaluate_forwardref
45
+ from .v1 import get_missing_field_error as get_missing_field_error
46
+ from .v1 import ( # type: ignore[assignment]
47
+ with_info_plain_validator_function as with_info_plain_validator_function,
48
+ )
49
+
50
+
51
+ @lru_cache
52
+ def get_cached_model_fields(model: Type[BaseModel]) -> List[ModelField]:
53
+ if lenient_issubclass(model, v1.BaseModel):
54
+ return v1.get_model_fields(model)
55
+ else:
56
+ from . import v2
57
+
58
+ return v2.get_model_fields(model) # type: ignore[return-value]
59
+
60
+
61
+ def _is_undefined(value: object) -> bool:
62
+ if isinstance(value, v1.UndefinedType):
63
+ return True
64
+ elif PYDANTIC_V2:
65
+ from . import v2
66
+
67
+ return isinstance(value, v2.UndefinedType)
68
+ return False
69
+
70
+
71
+ def _get_model_config(model: BaseModel) -> Any:
72
+ if isinstance(model, v1.BaseModel):
73
+ return v1._get_model_config(model)
74
+ elif PYDANTIC_V2:
75
+ from . import v2
76
+
77
+ return v2._get_model_config(model)
78
+
79
+
80
+ def _model_dump(
81
+ model: BaseModel, mode: Literal["json", "python"] = "json", **kwargs: Any
82
+ ) -> Any:
83
+ if isinstance(model, v1.BaseModel):
84
+ return v1._model_dump(model, mode=mode, **kwargs)
85
+ elif PYDANTIC_V2:
86
+ from . import v2
87
+
88
+ return v2._model_dump(model, mode=mode, **kwargs)
89
+
90
+
91
+ def _is_error_wrapper(exc: Exception) -> bool:
92
+ if isinstance(exc, v1.ErrorWrapper):
93
+ return True
94
+ elif PYDANTIC_V2:
95
+ from . import v2
96
+
97
+ return isinstance(exc, v2.ErrorWrapper)
98
+ return False
99
+
100
+
101
+ def copy_field_info(*, field_info: FieldInfo, annotation: Any) -> FieldInfo:
102
+ if isinstance(field_info, v1.FieldInfo):
103
+ return v1.copy_field_info(field_info=field_info, annotation=annotation)
104
+ else:
105
+ assert PYDANTIC_V2
106
+ from . import v2
107
+
108
+ return v2.copy_field_info(field_info=field_info, annotation=annotation)
109
+
110
+
111
+ def create_body_model(
112
+ *, fields: Sequence[ModelField], model_name: str
113
+ ) -> Type[BaseModel]:
114
+ if fields and isinstance(fields[0], v1.ModelField):
115
+ return v1.create_body_model(fields=fields, model_name=model_name)
116
+ else:
117
+ assert PYDANTIC_V2
118
+ from . import v2
119
+
120
+ return v2.create_body_model(fields=fields, model_name=model_name) # type: ignore[arg-type]
121
+
122
+
123
+ def get_annotation_from_field_info(
124
+ annotation: Any, field_info: FieldInfo, field_name: str
125
+ ) -> Any:
126
+ if isinstance(field_info, v1.FieldInfo):
127
+ return v1.get_annotation_from_field_info(
128
+ annotation=annotation, field_info=field_info, field_name=field_name
129
+ )
130
+ else:
131
+ assert PYDANTIC_V2
132
+ from . import v2
133
+
134
+ return v2.get_annotation_from_field_info(
135
+ annotation=annotation, field_info=field_info, field_name=field_name
136
+ )
137
+
138
+
139
+ def is_bytes_field(field: ModelField) -> bool:
140
+ if isinstance(field, v1.ModelField):
141
+ return v1.is_bytes_field(field)
142
+ else:
143
+ assert PYDANTIC_V2
144
+ from . import v2
145
+
146
+ return v2.is_bytes_field(field) # type: ignore[arg-type]
147
+
148
+
149
+ def is_bytes_sequence_field(field: ModelField) -> bool:
150
+ if isinstance(field, v1.ModelField):
151
+ return v1.is_bytes_sequence_field(field)
152
+ else:
153
+ assert PYDANTIC_V2
154
+ from . import v2
155
+
156
+ return v2.is_bytes_sequence_field(field) # type: ignore[arg-type]
157
+
158
+
159
+ def is_scalar_field(field: ModelField) -> bool:
160
+ if isinstance(field, v1.ModelField):
161
+ return v1.is_scalar_field(field)
162
+ else:
163
+ assert PYDANTIC_V2
164
+ from . import v2
165
+
166
+ return v2.is_scalar_field(field) # type: ignore[arg-type]
167
+
168
+
169
+ def is_scalar_sequence_field(field: ModelField) -> bool:
170
+ if isinstance(field, v1.ModelField):
171
+ return v1.is_scalar_sequence_field(field)
172
+ else:
173
+ assert PYDANTIC_V2
174
+ from . import v2
175
+
176
+ return v2.is_scalar_sequence_field(field) # type: ignore[arg-type]
177
+
178
+
179
+ def is_sequence_field(field: ModelField) -> bool:
180
+ if isinstance(field, v1.ModelField):
181
+ return v1.is_sequence_field(field)
182
+ else:
183
+ assert PYDANTIC_V2
184
+ from . import v2
185
+
186
+ return v2.is_sequence_field(field) # type: ignore[arg-type]
187
+
188
+
189
+ def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]:
190
+ if isinstance(field, v1.ModelField):
191
+ return v1.serialize_sequence_value(field=field, value=value)
192
+ else:
193
+ assert PYDANTIC_V2
194
+ from . import v2
195
+
196
+ return v2.serialize_sequence_value(field=field, value=value) # type: ignore[arg-type]
197
+
198
+
199
+ def _model_rebuild(model: Type[BaseModel]) -> None:
200
+ if lenient_issubclass(model, v1.BaseModel):
201
+ v1._model_rebuild(model)
202
+ elif PYDANTIC_V2:
203
+ from . import v2
204
+
205
+ v2._model_rebuild(model)
206
+
207
+
208
+ def get_compat_model_name_map(fields: List[ModelField]) -> ModelNameMap:
209
+ v1_model_fields = [field for field in fields if isinstance(field, v1.ModelField)]
210
+ v1_flat_models = v1.get_flat_models_from_fields(v1_model_fields, known_models=set()) # type: ignore[attr-defined]
211
+ all_flat_models = v1_flat_models
212
+ if PYDANTIC_V2:
213
+ from . import v2
214
+
215
+ v2_model_fields = [
216
+ field for field in fields if isinstance(field, v2.ModelField)
217
+ ]
218
+ v2_flat_models = v2.get_flat_models_from_fields(
219
+ v2_model_fields, known_models=set()
220
+ )
221
+ all_flat_models = all_flat_models.union(v2_flat_models)
222
+
223
+ model_name_map = v2.get_model_name_map(all_flat_models)
224
+ return model_name_map
225
+ model_name_map = v1.get_model_name_map(all_flat_models)
226
+ return model_name_map
227
+
228
+
229
+ def get_definitions(
230
+ *,
231
+ fields: List[ModelField],
232
+ model_name_map: ModelNameMap,
233
+ separate_input_output_schemas: bool = True,
234
+ ) -> Tuple[
235
+ Dict[Tuple[ModelField, Literal["validation", "serialization"]], v1.JsonSchemaValue],
236
+ Dict[str, Dict[str, Any]],
237
+ ]:
238
+ v1_fields = [field for field in fields if isinstance(field, v1.ModelField)]
239
+ v1_field_maps, v1_definitions = v1.get_definitions(
240
+ fields=v1_fields,
241
+ model_name_map=model_name_map,
242
+ separate_input_output_schemas=separate_input_output_schemas,
243
+ )
244
+ if not PYDANTIC_V2:
245
+ return v1_field_maps, v1_definitions
246
+ else:
247
+ from . import v2
248
+
249
+ v2_fields = [field for field in fields if isinstance(field, v2.ModelField)]
250
+ v2_field_maps, v2_definitions = v2.get_definitions(
251
+ fields=v2_fields,
252
+ model_name_map=model_name_map,
253
+ separate_input_output_schemas=separate_input_output_schemas,
254
+ )
255
+ all_definitions = {**v1_definitions, **v2_definitions}
256
+ all_field_maps = {**v1_field_maps, **v2_field_maps}
257
+ return all_field_maps, all_definitions
258
+
259
+
260
+ def get_schema_from_model_field(
261
+ *,
262
+ field: ModelField,
263
+ model_name_map: ModelNameMap,
264
+ field_mapping: Dict[
265
+ Tuple[ModelField, Literal["validation", "serialization"]], v1.JsonSchemaValue
266
+ ],
267
+ separate_input_output_schemas: bool = True,
268
+ ) -> Dict[str, Any]:
269
+ if isinstance(field, v1.ModelField):
270
+ return v1.get_schema_from_model_field(
271
+ field=field,
272
+ model_name_map=model_name_map,
273
+ field_mapping=field_mapping,
274
+ separate_input_output_schemas=separate_input_output_schemas,
275
+ )
276
+ else:
277
+ assert PYDANTIC_V2
278
+ from . import v2
279
+
280
+ return v2.get_schema_from_model_field(
281
+ field=field, # type: ignore[arg-type]
282
+ model_name_map=model_name_map,
283
+ field_mapping=field_mapping, # type: ignore[arg-type]
284
+ separate_input_output_schemas=separate_input_output_schemas,
285
+ )
286
+
287
+
288
+ def _is_model_field(value: Any) -> bool:
289
+ if isinstance(value, v1.ModelField):
290
+ return True
291
+ elif PYDANTIC_V2:
292
+ from . import v2
293
+
294
+ return isinstance(value, v2.ModelField)
295
+ return False
296
+
297
+
298
+ def _is_model_class(value: Any) -> bool:
299
+ if lenient_issubclass(value, v1.BaseModel):
300
+ return True
301
+ elif PYDANTIC_V2:
302
+ from . import v2
303
+
304
+ return lenient_issubclass(value, v2.BaseModel) # type: ignore[attr-defined]
305
+ return False
@@ -0,0 +1,53 @@
1
+ from typing import (
2
+ Any,
3
+ Dict,
4
+ List,
5
+ Tuple,
6
+ Union,
7
+ )
8
+
9
+ from fastapi.types import IncEx
10
+ from pydantic.fields import FieldInfo
11
+ from typing_extensions import Literal, Protocol
12
+
13
+
14
+ class ModelField(Protocol):
15
+ field_info: "FieldInfo"
16
+ name: str
17
+ mode: Literal["validation", "serialization"] = "validation"
18
+ _version: Literal["v1", "v2"] = "v1"
19
+
20
+ @property
21
+ def alias(self) -> str: ...
22
+
23
+ @property
24
+ def required(self) -> bool: ...
25
+
26
+ @property
27
+ def default(self) -> Any: ...
28
+
29
+ @property
30
+ def type_(self) -> Any: ...
31
+
32
+ def get_default(self) -> Any: ...
33
+
34
+ def validate(
35
+ self,
36
+ value: Any,
37
+ values: Dict[str, Any] = {}, # noqa: B006
38
+ *,
39
+ loc: Tuple[Union[int, str], ...] = (),
40
+ ) -> Tuple[Any, Union[List[Dict[str, Any]], None]]: ...
41
+
42
+ def serialize(
43
+ self,
44
+ value: Any,
45
+ *,
46
+ mode: Literal["json", "python"] = "json",
47
+ include: Union[IncEx, None] = None,
48
+ exclude: Union[IncEx, None] = None,
49
+ by_alias: bool = True,
50
+ exclude_unset: bool = False,
51
+ exclude_defaults: bool = False,
52
+ exclude_none: bool = False,
53
+ ) -> Any: ...
@@ -0,0 +1,209 @@
1
+ import sys
2
+ import types
3
+ import typing
4
+ from collections import deque
5
+ from dataclasses import is_dataclass
6
+ from typing import (
7
+ Any,
8
+ Deque,
9
+ FrozenSet,
10
+ List,
11
+ Mapping,
12
+ Sequence,
13
+ Set,
14
+ Tuple,
15
+ Type,
16
+ Union,
17
+ )
18
+
19
+ from fastapi._compat import v1
20
+ from fastapi.types import UnionType
21
+ from pydantic import BaseModel
22
+ from pydantic.version import VERSION as PYDANTIC_VERSION
23
+ from starlette.datastructures import UploadFile
24
+ from typing_extensions import Annotated, get_args, get_origin
25
+
26
+ # Copy from Pydantic v2, compatible with v1
27
+ if sys.version_info < (3, 9):
28
+ # Pydantic no longer supports Python 3.8, this might be incorrect, but the code
29
+ # this is used for is also never reached in this codebase, as it's a copy of
30
+ # Pydantic's lenient_issubclass, just for compatibility with v1
31
+ # TODO: remove when dropping support for Python 3.8
32
+ WithArgsTypes: Tuple[Any, ...] = ()
33
+ elif sys.version_info < (3, 10):
34
+ WithArgsTypes: tuple[Any, ...] = (typing._GenericAlias, types.GenericAlias) # type: ignore[attr-defined]
35
+ else:
36
+ WithArgsTypes: tuple[Any, ...] = (
37
+ typing._GenericAlias, # type: ignore[attr-defined]
38
+ types.GenericAlias,
39
+ types.UnionType,
40
+ ) # pyright: ignore[reportAttributeAccessIssue]
41
+
42
+ PYDANTIC_VERSION_MINOR_TUPLE = tuple(int(x) for x in PYDANTIC_VERSION.split(".")[:2])
43
+ PYDANTIC_V2 = PYDANTIC_VERSION_MINOR_TUPLE[0] == 2
44
+
45
+
46
+ sequence_annotation_to_type = {
47
+ Sequence: list,
48
+ List: list,
49
+ list: list,
50
+ Tuple: tuple,
51
+ tuple: tuple,
52
+ Set: set,
53
+ set: set,
54
+ FrozenSet: frozenset,
55
+ frozenset: frozenset,
56
+ Deque: deque,
57
+ deque: deque,
58
+ }
59
+
60
+ sequence_types = tuple(sequence_annotation_to_type.keys())
61
+
62
+ Url: Type[Any]
63
+
64
+
65
+ # Copy of Pydantic v2, compatible with v1
66
+ def lenient_issubclass(
67
+ cls: Any, class_or_tuple: Union[Type[Any], Tuple[Type[Any], ...], None]
68
+ ) -> bool:
69
+ try:
70
+ return isinstance(cls, type) and issubclass(cls, class_or_tuple) # type: ignore[arg-type]
71
+ except TypeError: # pragma: no cover
72
+ if isinstance(cls, WithArgsTypes):
73
+ return False
74
+ raise # pragma: no cover
75
+
76
+
77
+ def _annotation_is_sequence(annotation: Union[Type[Any], None]) -> bool:
78
+ if lenient_issubclass(annotation, (str, bytes)):
79
+ return False
80
+ return lenient_issubclass(annotation, sequence_types) # type: ignore[arg-type]
81
+
82
+
83
+ def field_annotation_is_sequence(annotation: Union[Type[Any], None]) -> bool:
84
+ origin = get_origin(annotation)
85
+ if origin is Union or origin is UnionType:
86
+ for arg in get_args(annotation):
87
+ if field_annotation_is_sequence(arg):
88
+ return True
89
+ return False
90
+ return _annotation_is_sequence(annotation) or _annotation_is_sequence(
91
+ get_origin(annotation)
92
+ )
93
+
94
+
95
+ def value_is_sequence(value: Any) -> bool:
96
+ return isinstance(value, sequence_types) and not isinstance(value, (str, bytes)) # type: ignore[arg-type]
97
+
98
+
99
+ def _annotation_is_complex(annotation: Union[Type[Any], None]) -> bool:
100
+ return (
101
+ lenient_issubclass(annotation, (BaseModel, v1.BaseModel, Mapping, UploadFile))
102
+ or _annotation_is_sequence(annotation)
103
+ or is_dataclass(annotation)
104
+ )
105
+
106
+
107
+ def field_annotation_is_complex(annotation: Union[Type[Any], None]) -> bool:
108
+ origin = get_origin(annotation)
109
+ if origin is Union or origin is UnionType:
110
+ return any(field_annotation_is_complex(arg) for arg in get_args(annotation))
111
+
112
+ if origin is Annotated:
113
+ return field_annotation_is_complex(get_args(annotation)[0])
114
+
115
+ return (
116
+ _annotation_is_complex(annotation)
117
+ or _annotation_is_complex(origin)
118
+ or hasattr(origin, "__pydantic_core_schema__")
119
+ or hasattr(origin, "__get_pydantic_core_schema__")
120
+ )
121
+
122
+
123
+ def field_annotation_is_scalar(annotation: Any) -> bool:
124
+ # handle Ellipsis here to make tuple[int, ...] work nicely
125
+ return annotation is Ellipsis or not field_annotation_is_complex(annotation)
126
+
127
+
128
+ def field_annotation_is_scalar_sequence(annotation: Union[Type[Any], None]) -> bool:
129
+ origin = get_origin(annotation)
130
+ if origin is Union or origin is UnionType:
131
+ at_least_one_scalar_sequence = False
132
+ for arg in get_args(annotation):
133
+ if field_annotation_is_scalar_sequence(arg):
134
+ at_least_one_scalar_sequence = True
135
+ continue
136
+ elif not field_annotation_is_scalar(arg):
137
+ return False
138
+ return at_least_one_scalar_sequence
139
+ return field_annotation_is_sequence(annotation) and all(
140
+ field_annotation_is_scalar(sub_annotation)
141
+ for sub_annotation in get_args(annotation)
142
+ )
143
+
144
+
145
+ def is_bytes_or_nonable_bytes_annotation(annotation: Any) -> bool:
146
+ if lenient_issubclass(annotation, bytes):
147
+ return True
148
+ origin = get_origin(annotation)
149
+ if origin is Union or origin is UnionType:
150
+ for arg in get_args(annotation):
151
+ if lenient_issubclass(arg, bytes):
152
+ return True
153
+ return False
154
+
155
+
156
+ def is_uploadfile_or_nonable_uploadfile_annotation(annotation: Any) -> bool:
157
+ if lenient_issubclass(annotation, UploadFile):
158
+ return True
159
+ origin = get_origin(annotation)
160
+ if origin is Union or origin is UnionType:
161
+ for arg in get_args(annotation):
162
+ if lenient_issubclass(arg, UploadFile):
163
+ return True
164
+ return False
165
+
166
+
167
+ def is_bytes_sequence_annotation(annotation: Any) -> bool:
168
+ origin = get_origin(annotation)
169
+ if origin is Union or origin is UnionType:
170
+ at_least_one = False
171
+ for arg in get_args(annotation):
172
+ if is_bytes_sequence_annotation(arg):
173
+ at_least_one = True
174
+ continue
175
+ return at_least_one
176
+ return field_annotation_is_sequence(annotation) and all(
177
+ is_bytes_or_nonable_bytes_annotation(sub_annotation)
178
+ for sub_annotation in get_args(annotation)
179
+ )
180
+
181
+
182
+ def is_uploadfile_sequence_annotation(annotation: Any) -> bool:
183
+ origin = get_origin(annotation)
184
+ if origin is Union or origin is UnionType:
185
+ at_least_one = False
186
+ for arg in get_args(annotation):
187
+ if is_uploadfile_sequence_annotation(arg):
188
+ at_least_one = True
189
+ continue
190
+ return at_least_one
191
+ return field_annotation_is_sequence(annotation) and all(
192
+ is_uploadfile_or_nonable_uploadfile_annotation(sub_annotation)
193
+ for sub_annotation in get_args(annotation)
194
+ )
195
+
196
+
197
+ def annotation_is_pydantic_v1(annotation: Any) -> bool:
198
+ if lenient_issubclass(annotation, v1.BaseModel):
199
+ return True
200
+ origin = get_origin(annotation)
201
+ if origin is Union or origin is UnionType:
202
+ for arg in get_args(annotation):
203
+ if lenient_issubclass(arg, v1.BaseModel):
204
+ return True
205
+ if field_annotation_is_sequence(annotation):
206
+ for sub_annotation in get_args(annotation):
207
+ if annotation_is_pydantic_v1(sub_annotation):
208
+ return True
209
+ return False