fastapi 0.119.0__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 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.119.0"
3
+ __version__ = "0.119.1"
4
4
 
5
5
  from starlette import status as status
6
6
 
@@ -30,6 +30,10 @@ from .main import serialize_sequence_value as serialize_sequence_value
30
30
  from .main import (
31
31
  with_info_plain_validator_function as with_info_plain_validator_function,
32
32
  )
33
+ from .may_v1 import CoreSchema as CoreSchema
34
+ from .may_v1 import GetJsonSchemaHandler as GetJsonSchemaHandler
35
+ from .may_v1 import JsonSchemaValue as JsonSchemaValue
36
+ from .may_v1 import _normalize_errors as _normalize_errors
33
37
  from .model_field import ModelField as ModelField
34
38
  from .shared import PYDANTIC_V2 as PYDANTIC_V2
35
39
  from .shared import PYDANTIC_VERSION_MINOR_TUPLE as PYDANTIC_VERSION_MINOR_TUPLE
@@ -44,7 +48,3 @@ from .shared import (
44
48
  from .shared import lenient_issubclass as lenient_issubclass
45
49
  from .shared import sequence_types as sequence_types
46
50
  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
fastapi/_compat/main.py CHANGED
@@ -1,3 +1,4 @@
1
+ import sys
1
2
  from functools import lru_cache
2
3
  from typing import (
3
4
  Any,
@@ -8,7 +9,7 @@ from typing import (
8
9
  Type,
9
10
  )
10
11
 
11
- from fastapi._compat import v1
12
+ from fastapi._compat import may_v1
12
13
  from fastapi._compat.shared import PYDANTIC_V2, lenient_issubclass
13
14
  from fastapi.types import ModelNameMap
14
15
  from pydantic import BaseModel
@@ -50,7 +51,9 @@ else:
50
51
 
51
52
  @lru_cache
52
53
  def get_cached_model_fields(model: Type[BaseModel]) -> List[ModelField]:
53
- if lenient_issubclass(model, v1.BaseModel):
54
+ if lenient_issubclass(model, may_v1.BaseModel):
55
+ from fastapi._compat import v1
56
+
54
57
  return v1.get_model_fields(model)
55
58
  else:
56
59
  from . import v2
@@ -59,7 +62,7 @@ def get_cached_model_fields(model: Type[BaseModel]) -> List[ModelField]:
59
62
 
60
63
 
61
64
  def _is_undefined(value: object) -> bool:
62
- if isinstance(value, v1.UndefinedType):
65
+ if isinstance(value, may_v1.UndefinedType):
63
66
  return True
64
67
  elif PYDANTIC_V2:
65
68
  from . import v2
@@ -69,7 +72,9 @@ def _is_undefined(value: object) -> bool:
69
72
 
70
73
 
71
74
  def _get_model_config(model: BaseModel) -> Any:
72
- if isinstance(model, v1.BaseModel):
75
+ if isinstance(model, may_v1.BaseModel):
76
+ from fastapi._compat import v1
77
+
73
78
  return v1._get_model_config(model)
74
79
  elif PYDANTIC_V2:
75
80
  from . import v2
@@ -80,7 +85,9 @@ def _get_model_config(model: BaseModel) -> Any:
80
85
  def _model_dump(
81
86
  model: BaseModel, mode: Literal["json", "python"] = "json", **kwargs: Any
82
87
  ) -> Any:
83
- if isinstance(model, v1.BaseModel):
88
+ if isinstance(model, may_v1.BaseModel):
89
+ from fastapi._compat import v1
90
+
84
91
  return v1._model_dump(model, mode=mode, **kwargs)
85
92
  elif PYDANTIC_V2:
86
93
  from . import v2
@@ -89,7 +96,7 @@ def _model_dump(
89
96
 
90
97
 
91
98
  def _is_error_wrapper(exc: Exception) -> bool:
92
- if isinstance(exc, v1.ErrorWrapper):
99
+ if isinstance(exc, may_v1.ErrorWrapper):
93
100
  return True
94
101
  elif PYDANTIC_V2:
95
102
  from . import v2
@@ -99,7 +106,9 @@ def _is_error_wrapper(exc: Exception) -> bool:
99
106
 
100
107
 
101
108
  def copy_field_info(*, field_info: FieldInfo, annotation: Any) -> FieldInfo:
102
- if isinstance(field_info, v1.FieldInfo):
109
+ if isinstance(field_info, may_v1.FieldInfo):
110
+ from fastapi._compat import v1
111
+
103
112
  return v1.copy_field_info(field_info=field_info, annotation=annotation)
104
113
  else:
105
114
  assert PYDANTIC_V2
@@ -111,7 +120,9 @@ def copy_field_info(*, field_info: FieldInfo, annotation: Any) -> FieldInfo:
111
120
  def create_body_model(
112
121
  *, fields: Sequence[ModelField], model_name: str
113
122
  ) -> Type[BaseModel]:
114
- if fields and isinstance(fields[0], v1.ModelField):
123
+ if fields and isinstance(fields[0], may_v1.ModelField):
124
+ from fastapi._compat import v1
125
+
115
126
  return v1.create_body_model(fields=fields, model_name=model_name)
116
127
  else:
117
128
  assert PYDANTIC_V2
@@ -123,7 +134,9 @@ def create_body_model(
123
134
  def get_annotation_from_field_info(
124
135
  annotation: Any, field_info: FieldInfo, field_name: str
125
136
  ) -> Any:
126
- if isinstance(field_info, v1.FieldInfo):
137
+ if isinstance(field_info, may_v1.FieldInfo):
138
+ from fastapi._compat import v1
139
+
127
140
  return v1.get_annotation_from_field_info(
128
141
  annotation=annotation, field_info=field_info, field_name=field_name
129
142
  )
@@ -137,7 +150,9 @@ def get_annotation_from_field_info(
137
150
 
138
151
 
139
152
  def is_bytes_field(field: ModelField) -> bool:
140
- if isinstance(field, v1.ModelField):
153
+ if isinstance(field, may_v1.ModelField):
154
+ from fastapi._compat import v1
155
+
141
156
  return v1.is_bytes_field(field)
142
157
  else:
143
158
  assert PYDANTIC_V2
@@ -147,7 +162,9 @@ def is_bytes_field(field: ModelField) -> bool:
147
162
 
148
163
 
149
164
  def is_bytes_sequence_field(field: ModelField) -> bool:
150
- if isinstance(field, v1.ModelField):
165
+ if isinstance(field, may_v1.ModelField):
166
+ from fastapi._compat import v1
167
+
151
168
  return v1.is_bytes_sequence_field(field)
152
169
  else:
153
170
  assert PYDANTIC_V2
@@ -157,7 +174,9 @@ def is_bytes_sequence_field(field: ModelField) -> bool:
157
174
 
158
175
 
159
176
  def is_scalar_field(field: ModelField) -> bool:
160
- if isinstance(field, v1.ModelField):
177
+ if isinstance(field, may_v1.ModelField):
178
+ from fastapi._compat import v1
179
+
161
180
  return v1.is_scalar_field(field)
162
181
  else:
163
182
  assert PYDANTIC_V2
@@ -167,7 +186,9 @@ def is_scalar_field(field: ModelField) -> bool:
167
186
 
168
187
 
169
188
  def is_scalar_sequence_field(field: ModelField) -> bool:
170
- if isinstance(field, v1.ModelField):
189
+ if isinstance(field, may_v1.ModelField):
190
+ from fastapi._compat import v1
191
+
171
192
  return v1.is_scalar_sequence_field(field)
172
193
  else:
173
194
  assert PYDANTIC_V2
@@ -177,7 +198,9 @@ def is_scalar_sequence_field(field: ModelField) -> bool:
177
198
 
178
199
 
179
200
  def is_sequence_field(field: ModelField) -> bool:
180
- if isinstance(field, v1.ModelField):
201
+ if isinstance(field, may_v1.ModelField):
202
+ from fastapi._compat import v1
203
+
181
204
  return v1.is_sequence_field(field)
182
205
  else:
183
206
  assert PYDANTIC_V2
@@ -187,7 +210,9 @@ def is_sequence_field(field: ModelField) -> bool:
187
210
 
188
211
 
189
212
  def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]:
190
- if isinstance(field, v1.ModelField):
213
+ if isinstance(field, may_v1.ModelField):
214
+ from fastapi._compat import v1
215
+
191
216
  return v1.serialize_sequence_value(field=field, value=value)
192
217
  else:
193
218
  assert PYDANTIC_V2
@@ -197,7 +222,9 @@ def serialize_sequence_value(*, field: ModelField, value: Any) -> Sequence[Any]:
197
222
 
198
223
 
199
224
  def _model_rebuild(model: Type[BaseModel]) -> None:
200
- if lenient_issubclass(model, v1.BaseModel):
225
+ if lenient_issubclass(model, may_v1.BaseModel):
226
+ from fastapi._compat import v1
227
+
201
228
  v1._model_rebuild(model)
202
229
  elif PYDANTIC_V2:
203
230
  from . import v2
@@ -206,9 +233,18 @@ def _model_rebuild(model: Type[BaseModel]) -> None:
206
233
 
207
234
 
208
235
  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
236
+ v1_model_fields = [
237
+ field for field in fields if isinstance(field, may_v1.ModelField)
238
+ ]
239
+ if v1_model_fields:
240
+ from fastapi._compat import v1
241
+
242
+ v1_flat_models = v1.get_flat_models_from_fields(
243
+ v1_model_fields, known_models=set()
244
+ )
245
+ all_flat_models = v1_flat_models
246
+ else:
247
+ all_flat_models = set()
212
248
  if PYDANTIC_V2:
213
249
  from . import v2
214
250
 
@@ -222,6 +258,8 @@ def get_compat_model_name_map(fields: List[ModelField]) -> ModelNameMap:
222
258
 
223
259
  model_name_map = v2.get_model_name_map(all_flat_models)
224
260
  return model_name_map
261
+ from fastapi._compat import v1
262
+
225
263
  model_name_map = v1.get_model_name_map(all_flat_models)
226
264
  return model_name_map
227
265
 
@@ -232,17 +270,35 @@ def get_definitions(
232
270
  model_name_map: ModelNameMap,
233
271
  separate_input_output_schemas: bool = True,
234
272
  ) -> Tuple[
235
- Dict[Tuple[ModelField, Literal["validation", "serialization"]], v1.JsonSchemaValue],
273
+ Dict[
274
+ Tuple[ModelField, Literal["validation", "serialization"]],
275
+ may_v1.JsonSchemaValue,
276
+ ],
236
277
  Dict[str, Dict[str, Any]],
237
278
  ]:
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
279
+ if sys.version_info < (3, 14):
280
+ v1_fields = [field for field in fields if isinstance(field, may_v1.ModelField)]
281
+ v1_field_maps, v1_definitions = may_v1.get_definitions(
282
+ fields=v1_fields,
283
+ model_name_map=model_name_map,
284
+ separate_input_output_schemas=separate_input_output_schemas,
285
+ )
286
+ if not PYDANTIC_V2:
287
+ return v1_field_maps, v1_definitions
288
+ else:
289
+ from . import v2
290
+
291
+ v2_fields = [field for field in fields if isinstance(field, v2.ModelField)]
292
+ v2_field_maps, v2_definitions = v2.get_definitions(
293
+ fields=v2_fields,
294
+ model_name_map=model_name_map,
295
+ separate_input_output_schemas=separate_input_output_schemas,
296
+ )
297
+ all_definitions = {**v1_definitions, **v2_definitions}
298
+ all_field_maps = {**v1_field_maps, **v2_field_maps}
299
+ return all_field_maps, all_definitions
300
+
301
+ # Pydantic v1 is not supported since Python 3.14
246
302
  else:
247
303
  from . import v2
248
304
 
@@ -252,9 +308,7 @@ def get_definitions(
252
308
  model_name_map=model_name_map,
253
309
  separate_input_output_schemas=separate_input_output_schemas,
254
310
  )
255
- all_definitions = {**v1_definitions, **v2_definitions}
256
- all_field_maps = {**v1_field_maps, **v2_field_maps}
257
- return all_field_maps, all_definitions
311
+ return v2_field_maps, v2_definitions
258
312
 
259
313
 
260
314
  def get_schema_from_model_field(
@@ -262,11 +316,14 @@ def get_schema_from_model_field(
262
316
  field: ModelField,
263
317
  model_name_map: ModelNameMap,
264
318
  field_mapping: Dict[
265
- Tuple[ModelField, Literal["validation", "serialization"]], v1.JsonSchemaValue
319
+ Tuple[ModelField, Literal["validation", "serialization"]],
320
+ may_v1.JsonSchemaValue,
266
321
  ],
267
322
  separate_input_output_schemas: bool = True,
268
323
  ) -> Dict[str, Any]:
269
- if isinstance(field, v1.ModelField):
324
+ if isinstance(field, may_v1.ModelField):
325
+ from fastapi._compat import v1
326
+
270
327
  return v1.get_schema_from_model_field(
271
328
  field=field,
272
329
  model_name_map=model_name_map,
@@ -286,7 +343,7 @@ def get_schema_from_model_field(
286
343
 
287
344
 
288
345
  def _is_model_field(value: Any) -> bool:
289
- if isinstance(value, v1.ModelField):
346
+ if isinstance(value, may_v1.ModelField):
290
347
  return True
291
348
  elif PYDANTIC_V2:
292
349
  from . import v2
@@ -296,7 +353,7 @@ def _is_model_field(value: Any) -> bool:
296
353
 
297
354
 
298
355
  def _is_model_class(value: Any) -> bool:
299
- if lenient_issubclass(value, v1.BaseModel):
356
+ if lenient_issubclass(value, may_v1.BaseModel):
300
357
  return True
301
358
  elif PYDANTIC_V2:
302
359
  from . import v2
@@ -0,0 +1,123 @@
1
+ import sys
2
+ from typing import Any, Dict, List, Literal, Sequence, Tuple, Type, Union
3
+
4
+ from fastapi.types import ModelNameMap
5
+
6
+ if sys.version_info >= (3, 14):
7
+
8
+ class AnyUrl:
9
+ pass
10
+
11
+ class BaseConfig:
12
+ pass
13
+
14
+ class BaseModel:
15
+ pass
16
+
17
+ class Color:
18
+ pass
19
+
20
+ class CoreSchema:
21
+ pass
22
+
23
+ class ErrorWrapper:
24
+ pass
25
+
26
+ class FieldInfo:
27
+ pass
28
+
29
+ class GetJsonSchemaHandler:
30
+ pass
31
+
32
+ class JsonSchemaValue:
33
+ pass
34
+
35
+ class ModelField:
36
+ pass
37
+
38
+ class NameEmail:
39
+ pass
40
+
41
+ class RequiredParam:
42
+ pass
43
+
44
+ class SecretBytes:
45
+ pass
46
+
47
+ class SecretStr:
48
+ pass
49
+
50
+ class Undefined:
51
+ pass
52
+
53
+ class UndefinedType:
54
+ pass
55
+
56
+ class Url:
57
+ pass
58
+
59
+ from .v2 import ValidationError, create_model
60
+
61
+ def get_definitions(
62
+ *,
63
+ fields: List[ModelField],
64
+ model_name_map: ModelNameMap,
65
+ separate_input_output_schemas: bool = True,
66
+ ) -> Tuple[
67
+ Dict[
68
+ Tuple[ModelField, Literal["validation", "serialization"]], JsonSchemaValue
69
+ ],
70
+ Dict[str, Dict[str, Any]],
71
+ ]:
72
+ return {}, {} # pragma: no cover
73
+
74
+
75
+ else:
76
+ from .v1 import AnyUrl as AnyUrl
77
+ from .v1 import BaseConfig as BaseConfig
78
+ from .v1 import BaseModel as BaseModel
79
+ from .v1 import Color as Color
80
+ from .v1 import CoreSchema as CoreSchema
81
+ from .v1 import ErrorWrapper as ErrorWrapper
82
+ from .v1 import FieldInfo as FieldInfo
83
+ from .v1 import GetJsonSchemaHandler as GetJsonSchemaHandler
84
+ from .v1 import JsonSchemaValue as JsonSchemaValue
85
+ from .v1 import ModelField as ModelField
86
+ from .v1 import NameEmail as NameEmail
87
+ from .v1 import RequiredParam as RequiredParam
88
+ from .v1 import SecretBytes as SecretBytes
89
+ from .v1 import SecretStr as SecretStr
90
+ from .v1 import Undefined as Undefined
91
+ from .v1 import UndefinedType as UndefinedType
92
+ from .v1 import Url as Url
93
+ from .v1 import ValidationError, create_model
94
+ from .v1 import get_definitions as get_definitions
95
+
96
+
97
+ RequestErrorModel: Type[BaseModel] = create_model("Request")
98
+
99
+
100
+ def _normalize_errors(errors: Sequence[Any]) -> List[Dict[str, Any]]:
101
+ use_errors: List[Any] = []
102
+ for error in errors:
103
+ if isinstance(error, ErrorWrapper):
104
+ new_errors = ValidationError( # type: ignore[call-arg]
105
+ errors=[error], model=RequestErrorModel
106
+ ).errors()
107
+ use_errors.extend(new_errors)
108
+ elif isinstance(error, list):
109
+ use_errors.extend(_normalize_errors(error))
110
+ else:
111
+ use_errors.append(error)
112
+ return use_errors
113
+
114
+
115
+ def _regenerate_error_with_loc(
116
+ *, errors: Sequence[Any], loc_prefix: Tuple[Union[str, int], ...]
117
+ ) -> List[Dict[str, Any]]:
118
+ updated_loc_errors: List[Any] = [
119
+ {**err, "loc": loc_prefix + err.get("loc", ())}
120
+ for err in _normalize_errors(errors)
121
+ ]
122
+
123
+ return updated_loc_errors
fastapi/_compat/shared.py CHANGED
@@ -16,7 +16,7 @@ from typing import (
16
16
  Union,
17
17
  )
18
18
 
19
- from fastapi._compat import v1
19
+ from fastapi._compat import may_v1
20
20
  from fastapi.types import UnionType
21
21
  from pydantic import BaseModel
22
22
  from pydantic.version import VERSION as PYDANTIC_VERSION
@@ -98,7 +98,9 @@ def value_is_sequence(value: Any) -> bool:
98
98
 
99
99
  def _annotation_is_complex(annotation: Union[Type[Any], None]) -> bool:
100
100
  return (
101
- lenient_issubclass(annotation, (BaseModel, v1.BaseModel, Mapping, UploadFile))
101
+ lenient_issubclass(
102
+ annotation, (BaseModel, may_v1.BaseModel, Mapping, UploadFile)
103
+ )
102
104
  or _annotation_is_sequence(annotation)
103
105
  or is_dataclass(annotation)
104
106
  )
@@ -195,12 +197,12 @@ def is_uploadfile_sequence_annotation(annotation: Any) -> bool:
195
197
 
196
198
 
197
199
  def annotation_is_pydantic_v1(annotation: Any) -> bool:
198
- if lenient_issubclass(annotation, v1.BaseModel):
200
+ if lenient_issubclass(annotation, may_v1.BaseModel):
199
201
  return True
200
202
  origin = get_origin(annotation)
201
203
  if origin is Union or origin is UnionType:
202
204
  for arg in get_args(annotation):
203
- if lenient_issubclass(arg, v1.BaseModel):
205
+ if lenient_issubclass(arg, may_v1.BaseModel):
204
206
  return True
205
207
  if field_annotation_is_sequence(annotation):
206
208
  for sub_annotation in get_args(annotation):
fastapi/_compat/v1.py CHANGED
@@ -54,13 +54,15 @@ if not PYDANTIC_V2:
54
54
  from pydantic.schema import TypeModelSet as TypeModelSet
55
55
  from pydantic.schema import (
56
56
  field_schema,
57
- get_flat_models_from_fields,
58
57
  model_process_schema,
59
58
  )
60
59
  from pydantic.schema import (
61
60
  get_annotation_from_field_info as get_annotation_from_field_info,
62
61
  )
63
62
  from pydantic.schema import get_flat_models_from_field as get_flat_models_from_field
63
+ from pydantic.schema import (
64
+ get_flat_models_from_fields as get_flat_models_from_fields,
65
+ )
64
66
  from pydantic.schema import get_model_name_map as get_model_name_map
65
67
  from pydantic.types import SecretBytes as SecretBytes
66
68
  from pydantic.types import SecretStr as SecretStr
@@ -99,7 +101,6 @@ else:
99
101
  from pydantic.v1.schema import TypeModelSet as TypeModelSet
100
102
  from pydantic.v1.schema import (
101
103
  field_schema,
102
- get_flat_models_from_fields,
103
104
  model_process_schema,
104
105
  )
105
106
  from pydantic.v1.schema import (
@@ -108,6 +109,9 @@ else:
108
109
  from pydantic.v1.schema import (
109
110
  get_flat_models_from_field as get_flat_models_from_field,
110
111
  )
112
+ from pydantic.v1.schema import (
113
+ get_flat_models_from_fields as get_flat_models_from_fields,
114
+ )
111
115
  from pydantic.v1.schema import get_model_name_map as get_model_name_map
112
116
  from pydantic.v1.types import ( # type: ignore[assignment]
113
117
  SecretBytes as SecretBytes,
@@ -215,32 +219,6 @@ def is_pv1_scalar_sequence_field(field: ModelField) -> bool:
215
219
  return False
216
220
 
217
221
 
218
- def _normalize_errors(errors: Sequence[Any]) -> List[Dict[str, Any]]:
219
- use_errors: List[Any] = []
220
- for error in errors:
221
- if isinstance(error, ErrorWrapper):
222
- new_errors = ValidationError( # type: ignore[call-arg]
223
- errors=[error], model=RequestErrorModel
224
- ).errors()
225
- use_errors.extend(new_errors)
226
- elif isinstance(error, list):
227
- use_errors.extend(_normalize_errors(error))
228
- else:
229
- use_errors.append(error)
230
- return use_errors
231
-
232
-
233
- def _regenerate_error_with_loc(
234
- *, errors: Sequence[Any], loc_prefix: Tuple[Union[str, int], ...]
235
- ) -> List[Dict[str, Any]]:
236
- updated_loc_errors: List[Any] = [
237
- {**err, "loc": loc_prefix + err.get("loc", ())}
238
- for err in _normalize_errors(errors)
239
- ]
240
-
241
- return updated_loc_errors
242
-
243
-
244
222
  def _model_rebuild(model: Type[BaseModel]) -> None:
245
223
  model.update_forward_refs()
246
224
 
fastapi/_compat/v2.py CHANGED
@@ -15,7 +15,7 @@ from typing import (
15
15
  cast,
16
16
  )
17
17
 
18
- from fastapi._compat import shared, v1
18
+ from fastapi._compat import may_v1, shared
19
19
  from fastapi.openapi.constants import REF_TEMPLATE
20
20
  from fastapi.types import IncEx, ModelNameMap
21
21
  from pydantic import BaseModel, TypeAdapter, create_model
@@ -116,7 +116,7 @@ class ModelField:
116
116
  None,
117
117
  )
118
118
  except ValidationError as exc:
119
- return None, v1._regenerate_error_with_loc(
119
+ return None, may_v1._regenerate_error_with_loc(
120
120
  errors=exc.errors(include_url=False), loc_prefix=loc
121
121
  )
122
122
 
fastapi/applications.py CHANGED
@@ -75,7 +75,7 @@ class FastAPI(Starlette):
75
75
  errors.
76
76
 
77
77
  Read more in the
78
- [Starlette docs for Applications](https://www.starlette.io/applications/#instantiating-the-application).
78
+ [Starlette docs for Applications](https://www.starlette.dev/applications/#instantiating-the-application).
79
79
  """
80
80
  ),
81
81
  ] = False,
@@ -938,7 +938,7 @@ class FastAPI(Starlette):
938
938
  This is simply inherited from Starlette.
939
939
 
940
940
  Read more about it in the
941
- [Starlette docs for Applications](https://www.starlette.io/applications/#storing-state-on-the-app-instance).
941
+ [Starlette docs for Applications](https://www.starlette.dev/applications/#storing-state-on-the-app-instance).
942
942
  """
943
943
  ),
944
944
  ] = State()
@@ -43,9 +43,9 @@ 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
- v1,
49
49
  value_is_sequence,
50
50
  )
51
51
  from fastapi._compat.shared import annotation_is_pydantic_v1
@@ -380,7 +380,7 @@ def analyze_param(
380
380
  fastapi_annotations = [
381
381
  arg
382
382
  for arg in annotated_args[1:]
383
- if isinstance(arg, (FieldInfo, v1.FieldInfo, params.Depends))
383
+ if isinstance(arg, (FieldInfo, may_v1.FieldInfo, params.Depends))
384
384
  ]
385
385
  fastapi_specific_annotations = [
386
386
  arg
@@ -397,21 +397,21 @@ def analyze_param(
397
397
  )
398
398
  ]
399
399
  if fastapi_specific_annotations:
400
- fastapi_annotation: Union[FieldInfo, v1.FieldInfo, params.Depends, None] = (
401
- fastapi_specific_annotations[-1]
402
- )
400
+ fastapi_annotation: Union[
401
+ FieldInfo, may_v1.FieldInfo, params.Depends, None
402
+ ] = fastapi_specific_annotations[-1]
403
403
  else:
404
404
  fastapi_annotation = None
405
405
  # Set default for Annotated FieldInfo
406
- if isinstance(fastapi_annotation, (FieldInfo, v1.FieldInfo)):
406
+ if isinstance(fastapi_annotation, (FieldInfo, may_v1.FieldInfo)):
407
407
  # Copy `field_info` because we mutate `field_info.default` below.
408
408
  field_info = copy_field_info(
409
409
  field_info=fastapi_annotation, annotation=use_annotation
410
410
  )
411
411
  assert field_info.default in {
412
412
  Undefined,
413
- v1.Undefined,
414
- } or field_info.default in {RequiredParam, v1.RequiredParam}, (
413
+ may_v1.Undefined,
414
+ } or field_info.default in {RequiredParam, may_v1.RequiredParam}, (
415
415
  f"`{field_info.__class__.__name__}` default value cannot be set in"
416
416
  f" `Annotated` for {param_name!r}. Set the default value with `=` instead."
417
417
  )
@@ -435,7 +435,7 @@ def analyze_param(
435
435
  )
436
436
  depends = value
437
437
  # Get FieldInfo from default value
438
- elif isinstance(value, (FieldInfo, v1.FieldInfo)):
438
+ elif isinstance(value, (FieldInfo, may_v1.FieldInfo)):
439
439
  assert field_info is None, (
440
440
  "Cannot specify FastAPI annotations in `Annotated` and default value"
441
441
  f" together for {param_name!r}"
@@ -524,7 +524,8 @@ def analyze_param(
524
524
  type_=use_annotation_from_field_info,
525
525
  default=field_info.default,
526
526
  alias=alias,
527
- required=field_info.default in (RequiredParam, v1.RequiredParam, Undefined),
527
+ required=field_info.default
528
+ in (RequiredParam, may_v1.RequiredParam, Undefined),
528
529
  field_info=field_info,
529
530
  )
530
531
  if is_path_param:
@@ -741,7 +742,7 @@ def _validate_value_with_model_field(
741
742
  if _is_error_wrapper(errors_): # type: ignore[arg-type]
742
743
  return None, [errors_]
743
744
  elif isinstance(errors_, list):
744
- new_errors = v1._regenerate_error_with_loc(errors=errors_, loc_prefix=())
745
+ new_errors = may_v1._regenerate_error_with_loc(errors=errors_, loc_prefix=())
745
746
  return None, new_errors
746
747
  else:
747
748
  return v_, []
fastapi/encoders.py CHANGED
@@ -17,7 +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
+ from fastapi._compat import may_v1
21
21
  from fastapi.types import IncEx
22
22
  from pydantic import BaseModel
23
23
  from pydantic.color import Color
@@ -59,7 +59,7 @@ def decimal_encoder(dec_value: Decimal) -> Union[int, float]:
59
59
  ENCODERS_BY_TYPE: Dict[Type[Any], Callable[[Any], Any]] = {
60
60
  bytes: lambda o: o.decode(),
61
61
  Color: str,
62
- v1.Color: str,
62
+ may_v1.Color: str,
63
63
  datetime.date: isoformat,
64
64
  datetime.datetime: isoformat,
65
65
  datetime.time: isoformat,
@@ -76,19 +76,19 @@ ENCODERS_BY_TYPE: Dict[Type[Any], Callable[[Any], Any]] = {
76
76
  IPv6Interface: str,
77
77
  IPv6Network: str,
78
78
  NameEmail: str,
79
- v1.NameEmail: str,
79
+ may_v1.NameEmail: str,
80
80
  Path: str,
81
81
  Pattern: lambda o: o.pattern,
82
82
  SecretBytes: str,
83
- v1.SecretBytes: str,
83
+ may_v1.SecretBytes: str,
84
84
  SecretStr: str,
85
- v1.SecretStr: str,
85
+ may_v1.SecretStr: str,
86
86
  set: list,
87
87
  UUID: str,
88
88
  Url: str,
89
- v1.Url: str,
89
+ may_v1.Url: str,
90
90
  AnyUrl: str,
91
- v1.AnyUrl: str,
91
+ may_v1.AnyUrl: str,
92
92
  }
93
93
 
94
94
 
@@ -220,10 +220,10 @@ def jsonable_encoder(
220
220
  include = set(include)
221
221
  if exclude is not None and not isinstance(exclude, (set, dict)):
222
222
  exclude = set(exclude)
223
- if isinstance(obj, (BaseModel, v1.BaseModel)):
223
+ if isinstance(obj, (BaseModel, may_v1.BaseModel)):
224
224
  # TODO: remove when deprecating Pydantic v1
225
225
  encoders: Dict[Any, Any] = {}
226
- if isinstance(obj, v1.BaseModel):
226
+ if isinstance(obj, may_v1.BaseModel):
227
227
  encoders = getattr(obj.__config__, "json_encoders", {}) # type: ignore[attr-defined]
228
228
  if custom_encoder:
229
229
  encoders = {**encoders, **custom_encoder}
@@ -5,8 +5,8 @@ from fastapi.openapi.models import Example
5
5
  from fastapi.params import ParamTypes
6
6
  from typing_extensions import Annotated, deprecated
7
7
 
8
+ from ._compat.may_v1 import FieldInfo, Undefined
8
9
  from ._compat.shared import PYDANTIC_VERSION_MINOR_TUPLE
9
- from ._compat.v1 import FieldInfo, Undefined
10
10
 
11
11
  _Unset: Any = Undefined
12
12
 
fastapi/utils.py CHANGED
@@ -25,7 +25,7 @@ from fastapi._compat import (
25
25
  Validator,
26
26
  annotation_is_pydantic_v1,
27
27
  lenient_issubclass,
28
- v1,
28
+ may_v1,
29
29
  )
30
30
  from fastapi.datastructures import DefaultPlaceholder, DefaultType
31
31
  from pydantic import BaseModel
@@ -87,8 +87,8 @@ def create_model_field(
87
87
  ) -> ModelField:
88
88
  class_validators = class_validators or {}
89
89
 
90
- v1_model_config = v1.BaseConfig
91
- v1_field_info = field_info or v1.FieldInfo()
90
+ v1_model_config = may_v1.BaseConfig
91
+ v1_field_info = field_info or may_v1.FieldInfo()
92
92
  v1_kwargs = {
93
93
  "name": name,
94
94
  "field_info": v1_field_info,
@@ -102,9 +102,11 @@ def create_model_field(
102
102
 
103
103
  if (
104
104
  annotation_is_pydantic_v1(type_)
105
- or isinstance(field_info, v1.FieldInfo)
105
+ or isinstance(field_info, may_v1.FieldInfo)
106
106
  or version == "1"
107
107
  ):
108
+ from fastapi._compat import v1
109
+
108
110
  try:
109
111
  return v1.ModelField(**v1_kwargs) # type: ignore[no-any-return]
110
112
  except RuntimeError:
@@ -122,6 +124,8 @@ def create_model_field(
122
124
  raise fastapi.exceptions.FastAPIError(_invalid_args_message) from None
123
125
  # Pydantic v2 is not installed, but it's not a Pydantic v1 ModelField, it could be
124
126
  # a Pydantic v1 type, like a constrained int
127
+ from fastapi._compat import v1
128
+
125
129
  try:
126
130
  return v1.ModelField(**v1_kwargs) # type: ignore[no-any-return]
127
131
  except RuntimeError:
@@ -138,6 +142,9 @@ def create_cloned_field(
138
142
 
139
143
  if isinstance(field, v2.ModelField):
140
144
  return field
145
+
146
+ from fastapi._compat import v1
147
+
141
148
  # cloned_types caches already cloned types to support recursive models and improve
142
149
  # performance by avoiding unnecessary cloning
143
150
  if cloned_types is None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fastapi
3
- Version: 0.119.0
3
+ Version: 0.119.1
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
@@ -198,7 +198,7 @@ If you are building a <abbr title="Command Line Interface">CLI</abbr> app to be
198
198
 
199
199
  FastAPI stands on the shoulders of giants:
200
200
 
201
- * <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a> for the web parts.
201
+ * <a href="https://www.starlette.dev/" class="external-link" target="_blank">Starlette</a> for the web parts.
202
202
  * <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> for the data parts.
203
203
 
204
204
  ## Installation
@@ -304,7 +304,7 @@ INFO: Application startup complete.
304
304
  <details markdown="1">
305
305
  <summary>About the command <code>fastapi dev main.py</code>...</summary>
306
306
 
307
- The command `fastapi dev` reads your `main.py` file, detects the **FastAPI** app in it, and starts a server using <a href="https://www.uvicorn.org" class="external-link" target="_blank">Uvicorn</a>.
307
+ The command `fastapi dev` reads your `main.py` file, detects the **FastAPI** app in it, and starts a server using <a href="https://www.uvicorn.dev" class="external-link" target="_blank">Uvicorn</a>.
308
308
 
309
309
  By default, `fastapi dev` will start with auto-reload enabled for local development.
310
310
 
@@ -545,7 +545,7 @@ Used by Starlette:
545
545
 
546
546
  Used by FastAPI:
547
547
 
548
- * <a href="https://www.uvicorn.org" target="_blank"><code>uvicorn</code></a> - for the server that loads and serves your application. This includes `uvicorn[standard]`, which includes some dependencies (e.g. `uvloop`) needed for high performance serving.
548
+ * <a href="https://www.uvicorn.dev" target="_blank"><code>uvicorn</code></a> - for the server that loads and serves your application. This includes `uvicorn[standard]`, which includes some dependencies (e.g. `uvloop`) needed for high performance serving.
549
549
  * `fastapi-cli[standard]` - to provide the `fastapi` command.
550
550
  * This includes `fastapi-cloud-cli`, which allows you to deploy your FastAPI application to <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>.
551
551
 
@@ -1,24 +1,25 @@
1
- fastapi-0.119.0.dist-info/METADATA,sha256=9RzosSkC2zNwdliJ2_sosixubAhbDq4t-tyvZDMDlwg,28186
2
- fastapi-0.119.0.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
3
- fastapi-0.119.0.dist-info/entry_points.txt,sha256=GCf-WbIZxyGT4MUmrPGj1cOHYZoGsNPHAvNkT6hnGeA,61
4
- fastapi-0.119.0.dist-info/licenses/LICENSE,sha256=Tsif_IFIW5f-xYSy1KlhAy7v_oNEU4lP2cEnSQbMdE4,1086
5
- fastapi/__init__.py,sha256=q4QtrQP-eBRDVvKeyEyir7ClYWTW2YcB7JMBaMQOGbI,1081
1
+ fastapi-0.119.1.dist-info/METADATA,sha256=rY8zpZZCl9O5sa04bbHX9LNu4OzUSNK_wFz5Q_bw0us,28187
2
+ fastapi-0.119.1.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
3
+ fastapi-0.119.1.dist-info/entry_points.txt,sha256=GCf-WbIZxyGT4MUmrPGj1cOHYZoGsNPHAvNkT6hnGeA,61
4
+ fastapi-0.119.1.dist-info/licenses/LICENSE,sha256=Tsif_IFIW5f-xYSy1KlhAy7v_oNEU4lP2cEnSQbMdE4,1086
5
+ fastapi/__init__.py,sha256=zO_apwJ-xWFAMpLy76jnXPRx1spS5KMoM7cF7mk8bgA,1081
6
6
  fastapi/__main__.py,sha256=bKePXLdO4SsVSM6r9SVoLickJDcR2c0cTOxZRKq26YQ,37
7
- fastapi/_compat/__init__.py,sha256=WHnNsyqIJDrQL4XFQnnGVzaasRiJ3tP7aLWbtaJmj9k,2702
8
- fastapi/_compat/main.py,sha256=zWbuXdKsPWU2A23x1UYwpAFbAG7PPJLkv5l6rFz2EJo,9577
7
+ fastapi/_compat/__init__.py,sha256=8fa5XmM6_whr6YWuCs7KDdKR_gZ_AMmaxYW7GDn0eng,2718
8
+ fastapi/_compat/main.py,sha256=WDixlh9_5nfFuwWvbYQJNi8l5nDZdfbl2nMyTriG65c,10978
9
+ fastapi/_compat/may_v1.py,sha256=uiZpZTEVHBlD_Q3WYUW_BNW24X3yk_OwvHhCgPwTUco,2979
9
10
  fastapi/_compat/model_field.py,sha256=SrSoXEcloGXKAqjR8UDW2869RPgLRFdWTuVgTBhX_Gw,1190
10
- fastapi/_compat/shared.py,sha256=T8bSTUX_NQX0i5-i25C2GY7hQV6q2jDvNzWW2j3t57k,6992
11
- fastapi/_compat/v1.py,sha256=yhBcElJKJTgnMUEKWH2NJfUcm5zpRouUk4AgVHGNBs8,11015
12
- fastapi/_compat/v2.py,sha256=2Y8u4LGo9qlbGablSfLt2HN-qy9mdEdWm8XjQCS-rVI,15830
13
- fastapi/applications.py,sha256=nLbGcVdmCxXsl4aTSuP0WVS_XGY7wXBL3vC7nqlplmA,180276
11
+ fastapi/_compat/shared.py,sha256=KPOKDRBmM4mzGLdRZwDyrTIph6Eud9Vb2vil1dxNdV0,7030
12
+ fastapi/_compat/v1.py,sha256=v_YLzo8uyr0HeA7QxNbgaSb332kCcBK9-9PZmOHGkq8,10325
13
+ fastapi/_compat/v2.py,sha256=AcWbeOlPPFwxj0bRXtVe-A4Lio9ovCR7STd-qS5aqOk,15838
14
+ fastapi/applications.py,sha256=loHPnnTLs4mkV5Cbeota0_MnYMGHaepU4HR9VDdrwUQ,180278
14
15
  fastapi/background.py,sha256=rouLirxUANrcYC824MSMypXL_Qb2HYg2YZqaiEqbEKI,1768
15
16
  fastapi/cli.py,sha256=OYhZb0NR_deuT5ofyPF2NoNBzZDNOP8Salef2nk-HqA,418
16
17
  fastapi/concurrency.py,sha256=MirfowoSpkMQZ8j_g0ZxaQKpV6eB3G-dB5TgcXCrgEA,1424
17
18
  fastapi/datastructures.py,sha256=hM5DM_PtV7rL54VHtLk0dA9RHeAm9IzBd5TrRqc9tSs,5788
18
19
  fastapi/dependencies/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
20
  fastapi/dependencies/models.py,sha256=Pjl6vx-4nZ5Tta9kJa3-RfQKkXtCpS09-FhMgs9eWNs,1507
20
- fastapi/dependencies/utils.py,sha256=Zu-cYUeRm3vHXpcRlp3SSGpAlvY9qy_6w47zV7xs4ms,38587
21
- fastapi/encoders.py,sha256=rWunWAUY41X5ubkwdNewqL9T-zSTxtdUd7QwoqdgNio,11282
21
+ fastapi/dependencies/utils.py,sha256=weAsXzD81nWm5U0LEa3xnXo9VWMmcFfttQ73vC1M0kw,38633
22
+ fastapi/encoders.py,sha256=nv7xTKPQOFTziC85lTHxO0WwuKugpUjEc26HXO-QHHo,11318
22
23
  fastapi/exception_handlers.py,sha256=YVcT8Zy021VYYeecgdyh5YEUjEIHKcLspbkSf4OfbJI,1275
23
24
  fastapi/exceptions.py,sha256=taNixuFEXb67lI1bnX1ubq8y8TseJ4yoPlWjyP0fTzk,4969
24
25
  fastapi/logger.py,sha256=I9NNi3ov8AcqbsbC9wl1X-hdItKgYt2XTrx1f99Zpl4,54
@@ -48,10 +49,10 @@ fastapi/security/oauth2.py,sha256=rKHIUHq29367Qpe0Ez5Gcu1yIIM6SMw7nEfh15gBNIQ,22
48
49
  fastapi/security/open_id_connect_url.py,sha256=8vizZ2tGqEp1ur8SwtVgyHJhGAJ5AqahgcvSpaIioDI,2722
49
50
  fastapi/security/utils.py,sha256=bd8T0YM7UQD5ATKucr1bNtAvz_Y3__dVNAv5UebiPvc,293
50
51
  fastapi/staticfiles.py,sha256=iirGIt3sdY2QZXd36ijs3Cj-T0FuGFda3cd90kM9Ikw,69
51
- fastapi/temp_pydantic_v1_params.py,sha256=DjlXo_wtbNERtLj4jLNMoytb9y4TIpKxKnk-mx93WKY,26526
52
+ fastapi/temp_pydantic_v1_params.py,sha256=c9uTBAryfdbgEmAiuJ9BmnmFzYiFZK52z3dDKX4PSRY,26530
52
53
  fastapi/templating.py,sha256=4zsuTWgcjcEainMJFAlW6-gnslm6AgOS1SiiDWfmQxk,76
53
54
  fastapi/testclient.py,sha256=nBvaAmX66YldReJNZXPOk1sfuo2Q6hs8bOvIaCep6LQ,66
54
55
  fastapi/types.py,sha256=nFb36sK3DSoqoyo7Miwy3meKK5UdFBgkAgLSzQlUVyI,383
55
- fastapi/utils.py,sha256=CmeQxdHE9c-_R5Fl_xRT-Uapbm9dHDVYbrB_LAX8MiI,8881
56
+ fastapi/utils.py,sha256=Nedm_1OJnL12uHJ85HTPCO-AHfwxCtXObFpBi_0X4xQ,9010
56
57
  fastapi/websockets.py,sha256=419uncYObEKZG0YcrXscfQQYLSWoE10jqxVMetGdR98,222
57
- fastapi-0.119.0.dist-info/RECORD,,
58
+ fastapi-0.119.1.dist-info/RECORD,,