fastapi 0.99.0__py3-none-any.whl → 0.100.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/routing.py CHANGED
@@ -20,6 +20,14 @@ from typing import (
20
20
  )
21
21
 
22
22
  from fastapi import params
23
+ from fastapi._compat import (
24
+ ModelField,
25
+ Undefined,
26
+ _get_model_config,
27
+ _model_dump,
28
+ _normalize_errors,
29
+ lenient_issubclass,
30
+ )
23
31
  from fastapi.datastructures import Default, DefaultPlaceholder
24
32
  from fastapi.dependencies.models import Dependant
25
33
  from fastapi.dependencies.utils import (
@@ -29,13 +37,14 @@ from fastapi.dependencies.utils import (
29
37
  get_typed_return_annotation,
30
38
  solve_dependencies,
31
39
  )
32
- from fastapi.encoders import DictIntStrAny, SetIntStr, jsonable_encoder
40
+ from fastapi.encoders import jsonable_encoder
33
41
  from fastapi.exceptions import (
34
42
  FastAPIError,
35
43
  RequestValidationError,
44
+ ResponseValidationError,
36
45
  WebSocketRequestValidationError,
37
46
  )
38
- from fastapi.types import DecoratedCallable
47
+ from fastapi.types import DecoratedCallable, IncEx
39
48
  from fastapi.utils import (
40
49
  create_cloned_field,
41
50
  create_response_field,
@@ -44,9 +53,6 @@ from fastapi.utils import (
44
53
  is_body_allowed_for_status_code,
45
54
  )
46
55
  from pydantic import BaseModel
47
- from pydantic.error_wrappers import ErrorWrapper, ValidationError
48
- from pydantic.fields import ModelField, Undefined
49
- from pydantic.utils import lenient_issubclass
50
56
  from starlette import routing
51
57
  from starlette.concurrency import run_in_threadpool
52
58
  from starlette.exceptions import HTTPException
@@ -73,14 +79,15 @@ def _prepare_response_content(
73
79
  exclude_none: bool = False,
74
80
  ) -> Any:
75
81
  if isinstance(res, BaseModel):
76
- read_with_orm_mode = getattr(res.__config__, "read_with_orm_mode", None)
82
+ read_with_orm_mode = getattr(_get_model_config(res), "read_with_orm_mode", None)
77
83
  if read_with_orm_mode:
78
84
  # Let from_orm extract the data from this model instead of converting
79
85
  # it now to a dict.
80
86
  # Otherwise there's no way to extract lazy data that requires attribute
81
87
  # access instead of dict iteration, e.g. lazy relationships.
82
88
  return res
83
- return res.dict(
89
+ return _model_dump(
90
+ res,
84
91
  by_alias=True,
85
92
  exclude_unset=exclude_unset,
86
93
  exclude_defaults=exclude_defaults,
@@ -115,8 +122,8 @@ async def serialize_response(
115
122
  *,
116
123
  field: Optional[ModelField] = None,
117
124
  response_content: Any,
118
- include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
119
- exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
125
+ include: Optional[IncEx] = None,
126
+ exclude: Optional[IncEx] = None,
120
127
  by_alias: bool = True,
121
128
  exclude_unset: bool = False,
122
129
  exclude_defaults: bool = False,
@@ -125,24 +132,40 @@ async def serialize_response(
125
132
  ) -> Any:
126
133
  if field:
127
134
  errors = []
128
- response_content = _prepare_response_content(
129
- response_content,
130
- exclude_unset=exclude_unset,
131
- exclude_defaults=exclude_defaults,
132
- exclude_none=exclude_none,
133
- )
135
+ if not hasattr(field, "serialize"):
136
+ # pydantic v1
137
+ response_content = _prepare_response_content(
138
+ response_content,
139
+ exclude_unset=exclude_unset,
140
+ exclude_defaults=exclude_defaults,
141
+ exclude_none=exclude_none,
142
+ )
134
143
  if is_coroutine:
135
144
  value, errors_ = field.validate(response_content, {}, loc=("response",))
136
145
  else:
137
146
  value, errors_ = await run_in_threadpool(
138
147
  field.validate, response_content, {}, loc=("response",)
139
148
  )
140
- if isinstance(errors_, ErrorWrapper):
141
- errors.append(errors_)
142
- elif isinstance(errors_, list):
149
+ if isinstance(errors_, list):
143
150
  errors.extend(errors_)
151
+ elif errors_:
152
+ errors.append(errors_)
144
153
  if errors:
145
- raise ValidationError(errors, field.type_)
154
+ raise ResponseValidationError(
155
+ errors=_normalize_errors(errors), body=response_content
156
+ )
157
+
158
+ if hasattr(field, "serialize"):
159
+ return field.serialize(
160
+ value,
161
+ include=include,
162
+ exclude=exclude,
163
+ by_alias=by_alias,
164
+ exclude_unset=exclude_unset,
165
+ exclude_defaults=exclude_defaults,
166
+ exclude_none=exclude_none,
167
+ )
168
+
146
169
  return jsonable_encoder(
147
170
  value,
148
171
  include=include,
@@ -175,8 +198,8 @@ def get_request_handler(
175
198
  status_code: Optional[int] = None,
176
199
  response_class: Union[Type[Response], DefaultPlaceholder] = Default(JSONResponse),
177
200
  response_field: Optional[ModelField] = None,
178
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
179
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
201
+ response_model_include: Optional[IncEx] = None,
202
+ response_model_exclude: Optional[IncEx] = None,
180
203
  response_model_by_alias: bool = True,
181
204
  response_model_exclude_unset: bool = False,
182
205
  response_model_exclude_defaults: bool = False,
@@ -220,7 +243,16 @@ def get_request_handler(
220
243
  body = body_bytes
221
244
  except json.JSONDecodeError as e:
222
245
  raise RequestValidationError(
223
- [ErrorWrapper(e, ("body", e.pos))], body=e.doc
246
+ [
247
+ {
248
+ "type": "json_invalid",
249
+ "loc": ("body", e.pos),
250
+ "msg": "JSON decode error",
251
+ "input": {},
252
+ "ctx": {"error": e.msg},
253
+ }
254
+ ],
255
+ body=e.doc,
224
256
  ) from e
225
257
  except HTTPException:
226
258
  raise
@@ -236,7 +268,7 @@ def get_request_handler(
236
268
  )
237
269
  values, errors, background_tasks, sub_response, _ = solved_result
238
270
  if errors:
239
- raise RequestValidationError(errors, body=body)
271
+ raise RequestValidationError(_normalize_errors(errors), body=body)
240
272
  else:
241
273
  raw_response = await run_endpoint_function(
242
274
  dependant=dependant, values=values, is_coroutine=is_coroutine
@@ -287,7 +319,7 @@ def get_websocket_app(
287
319
  )
288
320
  values, errors, _, _2, _3 = solved_result
289
321
  if errors:
290
- raise WebSocketRequestValidationError(errors)
322
+ raise WebSocketRequestValidationError(_normalize_errors(errors))
291
323
  assert dependant.call is not None, "dependant.call must be a function"
292
324
  await dependant.call(**values)
293
325
 
@@ -348,8 +380,8 @@ class APIRoute(routing.Route):
348
380
  name: Optional[str] = None,
349
381
  methods: Optional[Union[Set[str], List[str]]] = None,
350
382
  operation_id: Optional[str] = None,
351
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
352
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
383
+ response_model_include: Optional[IncEx] = None,
384
+ response_model_exclude: Optional[IncEx] = None,
353
385
  response_model_by_alias: bool = True,
354
386
  response_model_exclude_unset: bool = False,
355
387
  response_model_exclude_defaults: bool = False,
@@ -414,7 +446,11 @@ class APIRoute(routing.Route):
414
446
  ), f"Status code {status_code} must not have a response body"
415
447
  response_name = "Response_" + self.unique_id
416
448
  self.response_field = create_response_field(
417
- name=response_name, type_=self.response_model
449
+ name=response_name,
450
+ type_=self.response_model,
451
+ # TODO: This should actually set mode='serialization', just, that changes the schemas
452
+ # mode="serialization",
453
+ mode="validation",
418
454
  )
419
455
  # Create a clone of the field, so that a Pydantic submodel is not returned
420
456
  # as is just because it's an instance of a subclass of a more limited class
@@ -423,6 +459,7 @@ class APIRoute(routing.Route):
423
459
  # would pass the validation and be returned as is.
424
460
  # By being a new field, no inheritance will be passed as is. A new model
425
461
  # will be always created.
462
+ # TODO: remove when deprecating Pydantic v1
426
463
  self.secure_cloned_response_field: Optional[
427
464
  ModelField
428
465
  ] = create_cloned_field(self.response_field)
@@ -569,8 +606,8 @@ class APIRouter(routing.Router):
569
606
  deprecated: Optional[bool] = None,
570
607
  methods: Optional[Union[Set[str], List[str]]] = None,
571
608
  operation_id: Optional[str] = None,
572
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
573
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
609
+ response_model_include: Optional[IncEx] = None,
610
+ response_model_exclude: Optional[IncEx] = None,
574
611
  response_model_by_alias: bool = True,
575
612
  response_model_exclude_unset: bool = False,
576
613
  response_model_exclude_defaults: bool = False,
@@ -650,8 +687,8 @@ class APIRouter(routing.Router):
650
687
  deprecated: Optional[bool] = None,
651
688
  methods: Optional[List[str]] = None,
652
689
  operation_id: Optional[str] = None,
653
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
654
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
690
+ response_model_include: Optional[IncEx] = None,
691
+ response_model_exclude: Optional[IncEx] = None,
655
692
  response_model_by_alias: bool = True,
656
693
  response_model_exclude_unset: bool = False,
657
694
  response_model_exclude_defaults: bool = False,
@@ -877,8 +914,8 @@ class APIRouter(routing.Router):
877
914
  responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
878
915
  deprecated: Optional[bool] = None,
879
916
  operation_id: Optional[str] = None,
880
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
881
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
917
+ response_model_include: Optional[IncEx] = None,
918
+ response_model_exclude: Optional[IncEx] = None,
882
919
  response_model_by_alias: bool = True,
883
920
  response_model_exclude_unset: bool = False,
884
921
  response_model_exclude_defaults: bool = False,
@@ -933,8 +970,8 @@ class APIRouter(routing.Router):
933
970
  responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
934
971
  deprecated: Optional[bool] = None,
935
972
  operation_id: Optional[str] = None,
936
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
937
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
973
+ response_model_include: Optional[IncEx] = None,
974
+ response_model_exclude: Optional[IncEx] = None,
938
975
  response_model_by_alias: bool = True,
939
976
  response_model_exclude_unset: bool = False,
940
977
  response_model_exclude_defaults: bool = False,
@@ -989,8 +1026,8 @@ class APIRouter(routing.Router):
989
1026
  responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
990
1027
  deprecated: Optional[bool] = None,
991
1028
  operation_id: Optional[str] = None,
992
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
993
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1029
+ response_model_include: Optional[IncEx] = None,
1030
+ response_model_exclude: Optional[IncEx] = None,
994
1031
  response_model_by_alias: bool = True,
995
1032
  response_model_exclude_unset: bool = False,
996
1033
  response_model_exclude_defaults: bool = False,
@@ -1045,8 +1082,8 @@ class APIRouter(routing.Router):
1045
1082
  responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
1046
1083
  deprecated: Optional[bool] = None,
1047
1084
  operation_id: Optional[str] = None,
1048
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1049
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1085
+ response_model_include: Optional[IncEx] = None,
1086
+ response_model_exclude: Optional[IncEx] = None,
1050
1087
  response_model_by_alias: bool = True,
1051
1088
  response_model_exclude_unset: bool = False,
1052
1089
  response_model_exclude_defaults: bool = False,
@@ -1101,8 +1138,8 @@ class APIRouter(routing.Router):
1101
1138
  responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
1102
1139
  deprecated: Optional[bool] = None,
1103
1140
  operation_id: Optional[str] = None,
1104
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1105
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1141
+ response_model_include: Optional[IncEx] = None,
1142
+ response_model_exclude: Optional[IncEx] = None,
1106
1143
  response_model_by_alias: bool = True,
1107
1144
  response_model_exclude_unset: bool = False,
1108
1145
  response_model_exclude_defaults: bool = False,
@@ -1157,8 +1194,8 @@ class APIRouter(routing.Router):
1157
1194
  responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
1158
1195
  deprecated: Optional[bool] = None,
1159
1196
  operation_id: Optional[str] = None,
1160
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1161
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1197
+ response_model_include: Optional[IncEx] = None,
1198
+ response_model_exclude: Optional[IncEx] = None,
1162
1199
  response_model_by_alias: bool = True,
1163
1200
  response_model_exclude_unset: bool = False,
1164
1201
  response_model_exclude_defaults: bool = False,
@@ -1213,8 +1250,8 @@ class APIRouter(routing.Router):
1213
1250
  responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
1214
1251
  deprecated: Optional[bool] = None,
1215
1252
  operation_id: Optional[str] = None,
1216
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1217
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1253
+ response_model_include: Optional[IncEx] = None,
1254
+ response_model_exclude: Optional[IncEx] = None,
1218
1255
  response_model_by_alias: bool = True,
1219
1256
  response_model_exclude_unset: bool = False,
1220
1257
  response_model_exclude_defaults: bool = False,
@@ -1269,8 +1306,8 @@ class APIRouter(routing.Router):
1269
1306
  responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
1270
1307
  deprecated: Optional[bool] = None,
1271
1308
  operation_id: Optional[str] = None,
1272
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1273
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1309
+ response_model_include: Optional[IncEx] = None,
1310
+ response_model_exclude: Optional[IncEx] = None,
1274
1311
  response_model_by_alias: bool = True,
1275
1312
  response_model_exclude_unset: bool = False,
1276
1313
  response_model_exclude_defaults: bool = False,
@@ -9,6 +9,9 @@ from fastapi.security.utils import get_authorization_scheme_param
9
9
  from starlette.requests import Request
10
10
  from starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN
11
11
 
12
+ # TODO: import from typing when deprecating Python 3.9
13
+ from typing_extensions import Annotated
14
+
12
15
 
13
16
  class OAuth2PasswordRequestForm:
14
17
  """
@@ -45,12 +48,13 @@ class OAuth2PasswordRequestForm:
45
48
 
46
49
  def __init__(
47
50
  self,
48
- grant_type: str = Form(default=None, regex="password"),
49
- username: str = Form(),
50
- password: str = Form(),
51
- scope: str = Form(default=""),
52
- client_id: Optional[str] = Form(default=None),
53
- client_secret: Optional[str] = Form(default=None),
51
+ *,
52
+ grant_type: Annotated[Union[str, None], Form(pattern="password")] = None,
53
+ username: Annotated[str, Form()],
54
+ password: Annotated[str, Form()],
55
+ scope: Annotated[str, Form()] = "",
56
+ client_id: Annotated[Union[str, None], Form()] = None,
57
+ client_secret: Annotated[Union[str, None], Form()] = None,
54
58
  ):
55
59
  self.grant_type = grant_type
56
60
  self.username = username
@@ -95,12 +99,12 @@ class OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm):
95
99
 
96
100
  def __init__(
97
101
  self,
98
- grant_type: str = Form(regex="password"),
99
- username: str = Form(),
100
- password: str = Form(),
101
- scope: str = Form(default=""),
102
- client_id: Optional[str] = Form(default=None),
103
- client_secret: Optional[str] = Form(default=None),
102
+ grant_type: Annotated[str, Form(pattern="password")],
103
+ username: Annotated[str, Form()],
104
+ password: Annotated[str, Form()],
105
+ scope: Annotated[str, Form()] = "",
106
+ client_id: Annotated[Union[str, None], Form()] = None,
107
+ client_secret: Annotated[Union[str, None], Form()] = None,
104
108
  ):
105
109
  super().__init__(
106
110
  grant_type=grant_type,
fastapi/types.py CHANGED
@@ -1,3 +1,11 @@
1
- from typing import Any, Callable, TypeVar
1
+ import types
2
+ from enum import Enum
3
+ from typing import Any, Callable, Dict, Set, Type, TypeVar, Union
4
+
5
+ from pydantic import BaseModel
2
6
 
3
7
  DecoratedCallable = TypeVar("DecoratedCallable", bound=Callable[..., Any])
8
+ UnionType = getattr(types, "UnionType", Union)
9
+ NoneType = getattr(types, "UnionType", None)
10
+ ModelNameMap = Dict[Union[Type[BaseModel], Type[Enum]], str]
11
+ IncEx = Union[Set[int], Set[str], Dict[int, Any], Dict[str, Any]]
fastapi/utils.py CHANGED
@@ -1,7 +1,6 @@
1
1
  import re
2
2
  import warnings
3
3
  from dataclasses import is_dataclass
4
- from enum import Enum
5
4
  from typing import (
6
5
  TYPE_CHECKING,
7
6
  Any,
@@ -16,13 +15,20 @@ from typing import (
16
15
  from weakref import WeakKeyDictionary
17
16
 
18
17
  import fastapi
18
+ from fastapi._compat import (
19
+ PYDANTIC_V2,
20
+ BaseConfig,
21
+ ModelField,
22
+ PydanticSchemaGenerationError,
23
+ Undefined,
24
+ UndefinedType,
25
+ Validator,
26
+ lenient_issubclass,
27
+ )
19
28
  from fastapi.datastructures import DefaultPlaceholder, DefaultType
20
- from fastapi.openapi.constants import REF_PREFIX
21
- from pydantic import BaseConfig, BaseModel, create_model
22
- from pydantic.class_validators import Validator
23
- from pydantic.fields import FieldInfo, ModelField, UndefinedType
24
- from pydantic.schema import model_process_schema
25
- from pydantic.utils import lenient_issubclass
29
+ from pydantic import BaseModel, create_model
30
+ from pydantic.fields import FieldInfo
31
+ from typing_extensions import Literal
26
32
 
27
33
  if TYPE_CHECKING: # pragma: nocover
28
34
  from .routing import APIRoute
@@ -50,24 +56,6 @@ def is_body_allowed_for_status_code(status_code: Union[int, str, None]) -> bool:
50
56
  return not (current_status_code < 200 or current_status_code in {204, 304})
51
57
 
52
58
 
53
- def get_model_definitions(
54
- *,
55
- flat_models: Set[Union[Type[BaseModel], Type[Enum]]],
56
- model_name_map: Dict[Union[Type[BaseModel], Type[Enum]], str],
57
- ) -> Dict[str, Any]:
58
- definitions: Dict[str, Dict[str, Any]] = {}
59
- for model in flat_models:
60
- m_schema, m_definitions, m_nested_models = model_process_schema(
61
- model, model_name_map=model_name_map, ref_prefix=REF_PREFIX
62
- )
63
- definitions.update(m_definitions)
64
- model_name = model_name_map[model]
65
- if "description" in m_schema:
66
- m_schema["description"] = m_schema["description"].split("\f")[0]
67
- definitions[model_name] = m_schema
68
- return definitions
69
-
70
-
71
59
  def get_path_param_names(path: str) -> Set[str]:
72
60
  return set(re.findall("{(.*?)}", path))
73
61
 
@@ -76,30 +64,40 @@ def create_response_field(
76
64
  name: str,
77
65
  type_: Type[Any],
78
66
  class_validators: Optional[Dict[str, Validator]] = None,
79
- default: Optional[Any] = None,
80
- required: Union[bool, UndefinedType] = True,
67
+ default: Optional[Any] = Undefined,
68
+ required: Union[bool, UndefinedType] = Undefined,
81
69
  model_config: Type[BaseConfig] = BaseConfig,
82
70
  field_info: Optional[FieldInfo] = None,
83
71
  alias: Optional[str] = None,
72
+ mode: Literal["validation", "serialization"] = "validation",
84
73
  ) -> ModelField:
85
74
  """
86
75
  Create a new response field. Raises if type_ is invalid.
87
76
  """
88
77
  class_validators = class_validators or {}
89
- field_info = field_info or FieldInfo()
90
-
91
- try:
92
- return ModelField(
93
- name=name,
94
- type_=type_,
95
- class_validators=class_validators,
96
- default=default,
97
- required=required,
98
- model_config=model_config,
99
- alias=alias,
100
- field_info=field_info,
78
+ if PYDANTIC_V2:
79
+ field_info = field_info or FieldInfo(
80
+ annotation=type_, default=default, alias=alias
81
+ )
82
+ else:
83
+ field_info = field_info or FieldInfo()
84
+ kwargs = {"name": name, "field_info": field_info}
85
+ if PYDANTIC_V2:
86
+ kwargs.update({"mode": mode})
87
+ else:
88
+ kwargs.update(
89
+ {
90
+ "type_": type_,
91
+ "class_validators": class_validators,
92
+ "default": default,
93
+ "required": required,
94
+ "model_config": model_config,
95
+ "alias": alias,
96
+ }
101
97
  )
102
- except RuntimeError:
98
+ try:
99
+ return ModelField(**kwargs) # type: ignore[arg-type]
100
+ except (RuntimeError, PydanticSchemaGenerationError):
103
101
  raise fastapi.exceptions.FastAPIError(
104
102
  "Invalid args for response field! Hint: "
105
103
  f"check that {type_} is a valid Pydantic field type. "
@@ -116,6 +114,8 @@ def create_cloned_field(
116
114
  *,
117
115
  cloned_types: Optional[MutableMapping[Type[BaseModel], Type[BaseModel]]] = None,
118
116
  ) -> ModelField:
117
+ if PYDANTIC_V2:
118
+ return field
119
119
  # cloned_types caches already cloned types to support recursive models and improve
120
120
  # performance by avoiding unecessary cloning
121
121
  if cloned_types is None:
@@ -136,30 +136,30 @@ def create_cloned_field(
136
136
  f, cloned_types=cloned_types
137
137
  )
138
138
  new_field = create_response_field(name=field.name, type_=use_type)
139
- new_field.has_alias = field.has_alias
140
- new_field.alias = field.alias
141
- new_field.class_validators = field.class_validators
142
- new_field.default = field.default
143
- new_field.required = field.required
144
- new_field.model_config = field.model_config
139
+ new_field.has_alias = field.has_alias # type: ignore[attr-defined]
140
+ new_field.alias = field.alias # type: ignore[misc]
141
+ new_field.class_validators = field.class_validators # type: ignore[attr-defined]
142
+ new_field.default = field.default # type: ignore[misc]
143
+ new_field.required = field.required # type: ignore[misc]
144
+ new_field.model_config = field.model_config # type: ignore[attr-defined]
145
145
  new_field.field_info = field.field_info
146
- new_field.allow_none = field.allow_none
147
- new_field.validate_always = field.validate_always
148
- if field.sub_fields:
149
- new_field.sub_fields = [
146
+ new_field.allow_none = field.allow_none # type: ignore[attr-defined]
147
+ new_field.validate_always = field.validate_always # type: ignore[attr-defined]
148
+ if field.sub_fields: # type: ignore[attr-defined]
149
+ new_field.sub_fields = [ # type: ignore[attr-defined]
150
150
  create_cloned_field(sub_field, cloned_types=cloned_types)
151
- for sub_field in field.sub_fields
151
+ for sub_field in field.sub_fields # type: ignore[attr-defined]
152
152
  ]
153
- if field.key_field:
154
- new_field.key_field = create_cloned_field(
155
- field.key_field, cloned_types=cloned_types
153
+ if field.key_field: # type: ignore[attr-defined]
154
+ new_field.key_field = create_cloned_field( # type: ignore[attr-defined]
155
+ field.key_field, cloned_types=cloned_types # type: ignore[attr-defined]
156
156
  )
157
- new_field.validators = field.validators
158
- new_field.pre_validators = field.pre_validators
159
- new_field.post_validators = field.post_validators
160
- new_field.parse_json = field.parse_json
161
- new_field.shape = field.shape
162
- new_field.populate_validators()
157
+ new_field.validators = field.validators # type: ignore[attr-defined]
158
+ new_field.pre_validators = field.pre_validators # type: ignore[attr-defined]
159
+ new_field.post_validators = field.post_validators # type: ignore[attr-defined]
160
+ new_field.parse_json = field.parse_json # type: ignore[attr-defined]
161
+ new_field.shape = field.shape # type: ignore[attr-defined]
162
+ new_field.populate_validators() # type: ignore[attr-defined]
163
163
  return new_field
164
164
 
165
165
 
@@ -220,3 +220,9 @@ def get_value_or_default(
220
220
  if not isinstance(item, DefaultPlaceholder):
221
221
  return item
222
222
  return first_item
223
+
224
+
225
+ def match_pydantic_error_url(error_type: str) -> Any:
226
+ from dirty_equals import IsStr
227
+
228
+ return IsStr(regex=rf"^https://errors\.pydantic\.dev/.*/v/{error_type}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: fastapi
3
- Version: 0.99.0
3
+ Version: 0.100.0
4
4
  Summary: FastAPI framework, high performance, easy to learn, fast to code, ready for production
5
5
  Project-URL: Homepage, https://github.com/tiangolo/fastapi
6
6
  Project-URL: Documentation, https://fastapi.tiangolo.com/
@@ -36,15 +36,17 @@ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
36
36
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
37
37
  Classifier: Typing :: Typed
38
38
  Requires-Python: >=3.7
39
- Requires-Dist: pydantic!=1.8,!=1.8.1,<2.0.0,>=1.7.4
39
+ Requires-Dist: pydantic!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,<3.0.0,>=1.7.4
40
40
  Requires-Dist: starlette<0.28.0,>=0.27.0
41
41
  Requires-Dist: typing-extensions>=4.5.0
42
42
  Provides-Extra: all
43
- Requires-Dist: email-validator>=1.1.1; extra == 'all'
43
+ Requires-Dist: email-validator>=2.0.0; extra == 'all'
44
44
  Requires-Dist: httpx>=0.23.0; extra == 'all'
45
45
  Requires-Dist: itsdangerous>=1.1.0; extra == 'all'
46
46
  Requires-Dist: jinja2>=2.11.2; extra == 'all'
47
47
  Requires-Dist: orjson>=3.2.1; extra == 'all'
48
+ Requires-Dist: pydantic-extra-types>=2.0.0; extra == 'all'
49
+ Requires-Dist: pydantic-settings>=2.0.0; extra == 'all'
48
50
  Requires-Dist: python-multipart>=0.0.5; extra == 'all'
49
51
  Requires-Dist: pyyaml>=5.3.1; extra == 'all'
50
52
  Requires-Dist: ujson!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,>=4.0.1; extra == 'all'
@@ -500,6 +502,8 @@ To understand more about it, see the section <a href="https://fastapi.tiangolo.c
500
502
  Used by Pydantic:
501
503
 
502
504
  * <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - for email validation.
505
+ * <a href="https://docs.pydantic.dev/latest/usage/pydantic_settings/" target="_blank"><code>pydantic-settings</code></a> - for settings management.
506
+ * <a href="https://docs.pydantic.dev/latest/usage/types/extra_types/extra_types/" target="_blank"><code>pydantic-extra-types</code></a> - for extra types to be used with Pydantic.
503
507
 
504
508
  Used by Starlette:
505
509
 
@@ -1,27 +1,28 @@
1
- fastapi/__init__.py,sha256=HRoaTz7Z0V5fn_LEIFueYVCI33l4z9GS9ruLzoa_FCc,1080
2
- fastapi/applications.py,sha256=xV95gsMsnOqsezXnBEBpL9Yb7prwd0s9c-be8EmEa4w,40588
1
+ fastapi/__init__.py,sha256=cdUs7opWotDE2bN3Mgml7gFtCBbmNhXm5KvrkggJ8-0,1081
2
+ fastapi/_compat.py,sha256=lc_zD5IiWpKQTo83OFziqSBUWmsH2pqOzJVCPx8fCjw,22213
3
+ fastapi/applications.py,sha256=CAjthLITFb8scqk9jTK8d7rKuy_6nGJEkhTWcfph-xI,40021
3
4
  fastapi/background.py,sha256=HtN5_pJJrOdalSbuGSMKJAPNWUU5h7rY_BXXubu7-IQ,76
4
5
  fastapi/concurrency.py,sha256=h7ZhZG8cEiVx6an1txcB2RKpjW6_xmHwFo9E3vUiMQA,1468
5
- fastapi/datastructures.py,sha256=oW6xuU0C-sBwbcyXI-MlBO0tSS4BSPB2lYUa1yCw8-A,1905
6
- fastapi/encoders.py,sha256=VsFE_5xOv9c53-qctpTQf4xsscrJhmZZJdif1-1WTjs,5976
6
+ fastapi/datastructures.py,sha256=iWyfPvU6gZuFPHUC1RzRQP6VnLqYWnD75no5uLIxB48,2793
7
+ fastapi/encoders.py,sha256=uvI5zloRkzjlXJ-VnwvPJS5lD7j9n-MYhAoEXNrpV9k,8056
7
8
  fastapi/exception_handlers.py,sha256=MBrIOA-ugjJDivIi4rSsUJBdTsjuzN76q4yh0q1COKw,1332
8
- fastapi/exceptions.py,sha256=rYONIZZhCPYCrA8XTNMQ07GVsGBSN7LipSLsoFB3JMk,1205
9
+ fastapi/exceptions.py,sha256=B-KRexbd3Vtf_cP_YYY9ZocPGoGn1F2UvJ41Cdi0_3k,1400
9
10
  fastapi/logger.py,sha256=I9NNi3ov8AcqbsbC9wl1X-hdItKgYt2XTrx1f99Zpl4,54
10
- fastapi/param_functions.py,sha256=LOzbtY0eqmivGM_-MgzvQoCZim0WMQNO60JDFyQi3Do,8981
11
- fastapi/params.py,sha256=kmLpzYZ7uYI_jGxZJtgtPPrV1n4nbQQEykeLAyTyG48,13207
11
+ fastapi/param_functions.py,sha256=ycrVFfSANRCgaAaRT7pC9_5okx_e4D0L8NUz6wTUKAw,18411
12
+ fastapi/params.py,sha256=yxRVq1uY-afW839YdE34gsQbVrF02hz-t7lEW3yfxM8,26883
12
13
  fastapi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
14
  fastapi/requests.py,sha256=zayepKFcienBllv3snmWI20Gk0oHNVLU4DDhqXBb4LU,142
14
15
  fastapi/responses.py,sha256=on95e4CfSRyNz7MEjqFuzsP-eW8kHWTxEl_Z-Vzb7lA,1242
15
- fastapi/routing.py,sha256=ENL3MNsSqlqo5Io7AGj0g7reX59PhfwIRsfQTEsTIhc,56490
16
+ fastapi/routing.py,sha256=bhsAPsSHTpINdtUrYoH-_bEy5E9iXfvVCW9p4KpRKxI,56905
16
17
  fastapi/staticfiles.py,sha256=iirGIt3sdY2QZXd36ijs3Cj-T0FuGFda3cd90kM9Ikw,69
17
18
  fastapi/templating.py,sha256=4zsuTWgcjcEainMJFAlW6-gnslm6AgOS1SiiDWfmQxk,76
18
19
  fastapi/testclient.py,sha256=nBvaAmX66YldReJNZXPOk1sfuo2Q6hs8bOvIaCep6LQ,66
19
- fastapi/types.py,sha256=r6MngTHzkZOP9lzXgduje9yeZe5EInWAzCLuRJlhIuE,118
20
- fastapi/utils.py,sha256=ROfkxh6erG_hGkmTNGE4gD36D_dZ33R5jL8GOjzHGPM,7652
20
+ fastapi/types.py,sha256=WZJ1jvm1MCwIrxxRYxKwtXS9HqcGk0RnCbLzrMZh-lI,428
21
+ fastapi/utils.py,sha256=_vUwlqa4dq8M0Rl3Pro051teIccx36Z4hgecGH8F_oA,8179
21
22
  fastapi/websockets.py,sha256=419uncYObEKZG0YcrXscfQQYLSWoE10jqxVMetGdR98,222
22
23
  fastapi/dependencies/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
23
- fastapi/dependencies/models.py,sha256=zNbioxICuOeb-9ADDVQ45hUHOC0PBtPVEfVU3f1l_nc,2494
24
- fastapi/dependencies/utils.py,sha256=hDn1Uz6g_CiSrQikwA8WrYs_vH-Og5kG2a1qFFc6ZpA,30908
24
+ fastapi/dependencies/models.py,sha256=-n-YCxzgVBkurQi49qOTooT71v_oeAhHJ-qQFonxh5o,2494
25
+ fastapi/dependencies/utils.py,sha256=ffWJykKesqKxA_YVmrNhKogCF33AfZ2by0Tzfr_JlvY,29721
25
26
  fastapi/middleware/__init__.py,sha256=oQDxiFVcc1fYJUOIFvphnK7pTT5kktmfL32QXpBFvvo,58
26
27
  fastapi/middleware/asyncexitstack.py,sha256=LvMyVI1QdmWNWYPZqx295VFavssUfVpUsonPOsMWz1E,1035
27
28
  fastapi/middleware/cors.py,sha256=ynwjWQZoc_vbhzZ3_ZXceoaSrslHFHPdoM52rXr0WUU,79
@@ -30,18 +31,18 @@ fastapi/middleware/httpsredirect.py,sha256=rL8eXMnmLijwVkH7_400zHri1AekfeBd6D6qs
30
31
  fastapi/middleware/trustedhost.py,sha256=eE5XGRxGa7c5zPnMJDGp3BxaL25k5iVQlhnv-Pk0Pss,109
31
32
  fastapi/middleware/wsgi.py,sha256=Z3Ue-7wni4lUZMvH3G9ek__acgYdJstbnpZX_HQAboY,79
32
33
  fastapi/openapi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
- fastapi/openapi/constants.py,sha256=mWxYBjED6PU-tQ9X227Qkq2SsW2cv-C1jYFKt63xxEs,107
34
+ fastapi/openapi/constants.py,sha256=adGzmis1L1HJRTE3kJ5fmHS_Noq6tIY6pWv_SFzoFDU,153
34
35
  fastapi/openapi/docs.py,sha256=HbP76-u4A45BrL4WjLMhA3MBVI9xMx7XiMyDRS_ZO0E,6532
35
- fastapi/openapi/models.py,sha256=_jNDuzJqCKRAkiw3EvQw48OPzhYsyhCOxnvgCkg-uOA,14447
36
- fastapi/openapi/utils.py,sha256=JWM8ApZ2Ij6m7VSalKrzU2MYfNQY-nrpi2FunaushM8,19576
36
+ fastapi/openapi/models.py,sha256=G_yoz3jFjCDZVE5xW0vcQPXRljtqhnbGR8oogEnr-Hc,17733
37
+ fastapi/openapi/utils.py,sha256=2c-l7jCmOpL3k6hiQwEmW5HS0uTczaEhzOXeHRUTv9E,21047
37
38
  fastapi/security/__init__.py,sha256=bO8pNmxqVRXUjfl2mOKiVZLn0FpBQ61VUYVjmppnbJw,881
38
39
  fastapi/security/api_key.py,sha256=92kxZjj9OuIvQCUpLszP9qlILRgx6hCh1x-bZdhmQDU,2939
39
40
  fastapi/security/base.py,sha256=dl4pvbC-RxjfbWgPtCWd8MVU-7CB2SZ22rJDXVCXO6c,141
40
41
  fastapi/security/http.py,sha256=VbTm1k6t6EjJAnCnYVquSOmSK7fATdKRgq0-TgC7FnQ,5964
41
- fastapi/security/oauth2.py,sha256=I0DyRHEmfn_Up8vpYl3H8EV0dTdl5T1S3ib8EtRqfMI,8360
42
+ fastapi/security/oauth2.py,sha256=fXQdWuTtUKSZ9Lyrj9fDuQoXAmXTd9AVFDrrwStJKX0,8579
42
43
  fastapi/security/open_id_connect_url.py,sha256=GKK84g6OZbOFCEZJyd27pGjpaClGxeZrYOemUzyhfbU,1141
43
44
  fastapi/security/utils.py,sha256=bd8T0YM7UQD5ATKucr1bNtAvz_Y3__dVNAv5UebiPvc,293
44
- fastapi-0.99.0.dist-info/METADATA,sha256=ZyovzFXOT4X6PNOEd1GkFOIu98W7Iby-XWDYLnvMdQ0,23001
45
- fastapi-0.99.0.dist-info/WHEEL,sha256=KGYbc1zXlYddvwxnNty23BeaKzh7YuoSIvIMO4jEhvw,87
46
- fastapi-0.99.0.dist-info/licenses/LICENSE,sha256=Tsif_IFIW5f-xYSy1KlhAy7v_oNEU4lP2cEnSQbMdE4,1086
47
- fastapi-0.99.0.dist-info/RECORD,,
45
+ fastapi-0.100.0.dist-info/METADATA,sha256=0copRVgfwPRo1J78FqTMFv5X022nfOI8Wvwr-8Cd6JA,23461
46
+ fastapi-0.100.0.dist-info/WHEEL,sha256=KGYbc1zXlYddvwxnNty23BeaKzh7YuoSIvIMO4jEhvw,87
47
+ fastapi-0.100.0.dist-info/licenses/LICENSE,sha256=Tsif_IFIW5f-xYSy1KlhAy7v_oNEU4lP2cEnSQbMdE4,1086
48
+ fastapi-0.100.0.dist-info/RECORD,,