fastapi 0.96.1__py3-none-any.whl → 0.100.0b1__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,9 +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
33
- from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError
34
- from fastapi.types import DecoratedCallable
40
+ from fastapi.encoders import jsonable_encoder
41
+ from fastapi.exceptions import (
42
+ FastAPIError,
43
+ RequestValidationError,
44
+ ResponseValidationError,
45
+ WebSocketRequestValidationError,
46
+ )
47
+ from fastapi.types import DecoratedCallable, IncEx
35
48
  from fastapi.utils import (
36
49
  create_cloned_field,
37
50
  create_response_field,
@@ -40,23 +53,20 @@ from fastapi.utils import (
40
53
  is_body_allowed_for_status_code,
41
54
  )
42
55
  from pydantic import BaseModel
43
- from pydantic.error_wrappers import ErrorWrapper, ValidationError
44
- from pydantic.fields import ModelField, Undefined
45
- from pydantic.utils import lenient_issubclass
46
56
  from starlette import routing
47
57
  from starlette.concurrency import run_in_threadpool
48
58
  from starlette.exceptions import HTTPException
49
59
  from starlette.requests import Request
50
60
  from starlette.responses import JSONResponse, Response
51
- from starlette.routing import BaseRoute, Match
52
- from starlette.routing import Mount as Mount # noqa
53
61
  from starlette.routing import (
62
+ BaseRoute,
63
+ Match,
54
64
  compile_path,
55
65
  get_name,
56
66
  request_response,
57
67
  websocket_session,
58
68
  )
59
- from starlette.status import WS_1008_POLICY_VIOLATION
69
+ from starlette.routing import Mount as Mount # noqa
60
70
  from starlette.types import ASGIApp, Lifespan, Scope
61
71
  from starlette.websockets import WebSocket
62
72
 
@@ -69,14 +79,15 @@ def _prepare_response_content(
69
79
  exclude_none: bool = False,
70
80
  ) -> Any:
71
81
  if isinstance(res, BaseModel):
72
- 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)
73
83
  if read_with_orm_mode:
74
84
  # Let from_orm extract the data from this model instead of converting
75
85
  # it now to a dict.
76
86
  # Otherwise there's no way to extract lazy data that requires attribute
77
87
  # access instead of dict iteration, e.g. lazy relationships.
78
88
  return res
79
- return res.dict(
89
+ return _model_dump(
90
+ res,
80
91
  by_alias=True,
81
92
  exclude_unset=exclude_unset,
82
93
  exclude_defaults=exclude_defaults,
@@ -111,8 +122,8 @@ async def serialize_response(
111
122
  *,
112
123
  field: Optional[ModelField] = None,
113
124
  response_content: Any,
114
- include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
115
- exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
125
+ include: Optional[IncEx] = None,
126
+ exclude: Optional[IncEx] = None,
116
127
  by_alias: bool = True,
117
128
  exclude_unset: bool = False,
118
129
  exclude_defaults: bool = False,
@@ -121,24 +132,40 @@ async def serialize_response(
121
132
  ) -> Any:
122
133
  if field:
123
134
  errors = []
124
- response_content = _prepare_response_content(
125
- response_content,
126
- exclude_unset=exclude_unset,
127
- exclude_defaults=exclude_defaults,
128
- exclude_none=exclude_none,
129
- )
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
+ )
130
143
  if is_coroutine:
131
144
  value, errors_ = field.validate(response_content, {}, loc=("response",))
132
145
  else:
133
146
  value, errors_ = await run_in_threadpool(
134
147
  field.validate, response_content, {}, loc=("response",)
135
148
  )
136
- if isinstance(errors_, ErrorWrapper):
137
- errors.append(errors_)
138
- elif isinstance(errors_, list):
149
+ if isinstance(errors_, list):
139
150
  errors.extend(errors_)
151
+ elif errors_:
152
+ errors.append(errors_)
140
153
  if errors:
141
- 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
+
142
169
  return jsonable_encoder(
143
170
  value,
144
171
  include=include,
@@ -171,8 +198,8 @@ def get_request_handler(
171
198
  status_code: Optional[int] = None,
172
199
  response_class: Union[Type[Response], DefaultPlaceholder] = Default(JSONResponse),
173
200
  response_field: Optional[ModelField] = None,
174
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
175
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
201
+ response_model_include: Optional[IncEx] = None,
202
+ response_model_exclude: Optional[IncEx] = None,
176
203
  response_model_by_alias: bool = True,
177
204
  response_model_exclude_unset: bool = False,
178
205
  response_model_exclude_defaults: bool = False,
@@ -216,7 +243,16 @@ def get_request_handler(
216
243
  body = body_bytes
217
244
  except json.JSONDecodeError as e:
218
245
  raise RequestValidationError(
219
- [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,
220
256
  ) from e
221
257
  except HTTPException:
222
258
  raise
@@ -232,7 +268,7 @@ def get_request_handler(
232
268
  )
233
269
  values, errors, background_tasks, sub_response, _ = solved_result
234
270
  if errors:
235
- raise RequestValidationError(errors, body=body)
271
+ raise RequestValidationError(_normalize_errors(errors), body=body)
236
272
  else:
237
273
  raw_response = await run_endpoint_function(
238
274
  dependant=dependant, values=values, is_coroutine=is_coroutine
@@ -283,8 +319,7 @@ def get_websocket_app(
283
319
  )
284
320
  values, errors, _, _2, _3 = solved_result
285
321
  if errors:
286
- await websocket.close(code=WS_1008_POLICY_VIOLATION)
287
- raise WebSocketRequestValidationError(errors)
322
+ raise WebSocketRequestValidationError(_normalize_errors(errors))
288
323
  assert dependant.call is not None, "dependant.call must be a function"
289
324
  await dependant.call(**values)
290
325
 
@@ -298,13 +333,21 @@ class APIWebSocketRoute(routing.WebSocketRoute):
298
333
  endpoint: Callable[..., Any],
299
334
  *,
300
335
  name: Optional[str] = None,
336
+ dependencies: Optional[Sequence[params.Depends]] = None,
301
337
  dependency_overrides_provider: Optional[Any] = None,
302
338
  ) -> None:
303
339
  self.path = path
304
340
  self.endpoint = endpoint
305
341
  self.name = get_name(endpoint) if name is None else name
342
+ self.dependencies = list(dependencies or [])
306
343
  self.path_regex, self.path_format, self.param_convertors = compile_path(path)
307
344
  self.dependant = get_dependant(path=self.path_format, call=self.endpoint)
345
+ for depends in self.dependencies[::-1]:
346
+ self.dependant.dependencies.insert(
347
+ 0,
348
+ get_parameterless_sub_dependant(depends=depends, path=self.path_format),
349
+ )
350
+
308
351
  self.app = websocket_session(
309
352
  get_websocket_app(
310
353
  dependant=self.dependant,
@@ -337,8 +380,8 @@ class APIRoute(routing.Route):
337
380
  name: Optional[str] = None,
338
381
  methods: Optional[Union[Set[str], List[str]]] = None,
339
382
  operation_id: Optional[str] = None,
340
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
341
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
383
+ response_model_include: Optional[IncEx] = None,
384
+ response_model_exclude: Optional[IncEx] = None,
342
385
  response_model_by_alias: bool = True,
343
386
  response_model_exclude_unset: bool = False,
344
387
  response_model_exclude_defaults: bool = False,
@@ -412,16 +455,14 @@ class APIRoute(routing.Route):
412
455
  # would pass the validation and be returned as is.
413
456
  # By being a new field, no inheritance will be passed as is. A new model
414
457
  # will be always created.
458
+ # TODO: remove when deprecating Pydantic v1
415
459
  self.secure_cloned_response_field: Optional[
416
460
  ModelField
417
461
  ] = create_cloned_field(self.response_field)
418
462
  else:
419
463
  self.response_field = None # type: ignore
420
464
  self.secure_cloned_response_field = None
421
- if dependencies:
422
- self.dependencies = list(dependencies)
423
- else:
424
- self.dependencies = []
465
+ self.dependencies = list(dependencies or [])
425
466
  self.description = description or inspect.cleandoc(self.endpoint.__doc__ or "")
426
467
  # if a "form feed" character (page break) is found in the description text,
427
468
  # truncate description text to the content preceding the first "form feed"
@@ -516,7 +557,7 @@ class APIRouter(routing.Router):
516
557
  ), "A path prefix must not end with '/', as the routes will start with '/'"
517
558
  self.prefix = prefix
518
559
  self.tags: List[Union[str, Enum]] = tags or []
519
- self.dependencies = list(dependencies or []) or []
560
+ self.dependencies = list(dependencies or [])
520
561
  self.deprecated = deprecated
521
562
  self.include_in_schema = include_in_schema
522
563
  self.responses = responses or {}
@@ -561,8 +602,8 @@ class APIRouter(routing.Router):
561
602
  deprecated: Optional[bool] = None,
562
603
  methods: Optional[Union[Set[str], List[str]]] = None,
563
604
  operation_id: Optional[str] = None,
564
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
565
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
605
+ response_model_include: Optional[IncEx] = None,
606
+ response_model_exclude: Optional[IncEx] = None,
566
607
  response_model_by_alias: bool = True,
567
608
  response_model_exclude_unset: bool = False,
568
609
  response_model_exclude_defaults: bool = False,
@@ -642,8 +683,8 @@ class APIRouter(routing.Router):
642
683
  deprecated: Optional[bool] = None,
643
684
  methods: Optional[List[str]] = None,
644
685
  operation_id: Optional[str] = None,
645
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
646
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
686
+ response_model_include: Optional[IncEx] = None,
687
+ response_model_exclude: Optional[IncEx] = None,
647
688
  response_model_by_alias: bool = True,
648
689
  response_model_exclude_unset: bool = False,
649
690
  response_model_exclude_defaults: bool = False,
@@ -690,21 +731,37 @@ class APIRouter(routing.Router):
690
731
  return decorator
691
732
 
692
733
  def add_api_websocket_route(
693
- self, path: str, endpoint: Callable[..., Any], name: Optional[str] = None
734
+ self,
735
+ path: str,
736
+ endpoint: Callable[..., Any],
737
+ name: Optional[str] = None,
738
+ *,
739
+ dependencies: Optional[Sequence[params.Depends]] = None,
694
740
  ) -> None:
741
+ current_dependencies = self.dependencies.copy()
742
+ if dependencies:
743
+ current_dependencies.extend(dependencies)
744
+
695
745
  route = APIWebSocketRoute(
696
746
  self.prefix + path,
697
747
  endpoint=endpoint,
698
748
  name=name,
749
+ dependencies=current_dependencies,
699
750
  dependency_overrides_provider=self.dependency_overrides_provider,
700
751
  )
701
752
  self.routes.append(route)
702
753
 
703
754
  def websocket(
704
- self, path: str, name: Optional[str] = None
755
+ self,
756
+ path: str,
757
+ name: Optional[str] = None,
758
+ *,
759
+ dependencies: Optional[Sequence[params.Depends]] = None,
705
760
  ) -> Callable[[DecoratedCallable], DecoratedCallable]:
706
761
  def decorator(func: DecoratedCallable) -> DecoratedCallable:
707
- self.add_api_websocket_route(path, func, name=name)
762
+ self.add_api_websocket_route(
763
+ path, func, name=name, dependencies=dependencies
764
+ )
708
765
  return func
709
766
 
710
767
  return decorator
@@ -744,7 +801,7 @@ class APIRouter(routing.Router):
744
801
  path = getattr(r, "path") # noqa: B009
745
802
  name = getattr(r, "name", "unknown")
746
803
  if path is not None and not path:
747
- raise Exception(
804
+ raise FastAPIError(
748
805
  f"Prefix and path cannot be both empty (path operation: {name})"
749
806
  )
750
807
  if responses is None:
@@ -819,8 +876,16 @@ class APIRouter(routing.Router):
819
876
  name=route.name,
820
877
  )
821
878
  elif isinstance(route, APIWebSocketRoute):
879
+ current_dependencies = []
880
+ if dependencies:
881
+ current_dependencies.extend(dependencies)
882
+ if route.dependencies:
883
+ current_dependencies.extend(route.dependencies)
822
884
  self.add_api_websocket_route(
823
- prefix + route.path, route.endpoint, name=route.name
885
+ prefix + route.path,
886
+ route.endpoint,
887
+ dependencies=current_dependencies,
888
+ name=route.name,
824
889
  )
825
890
  elif isinstance(route, routing.WebSocketRoute):
826
891
  self.add_websocket_route(
@@ -845,8 +910,8 @@ class APIRouter(routing.Router):
845
910
  responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
846
911
  deprecated: Optional[bool] = None,
847
912
  operation_id: Optional[str] = None,
848
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
849
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
913
+ response_model_include: Optional[IncEx] = None,
914
+ response_model_exclude: Optional[IncEx] = None,
850
915
  response_model_by_alias: bool = True,
851
916
  response_model_exclude_unset: bool = False,
852
917
  response_model_exclude_defaults: bool = False,
@@ -901,8 +966,8 @@ class APIRouter(routing.Router):
901
966
  responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
902
967
  deprecated: Optional[bool] = None,
903
968
  operation_id: Optional[str] = None,
904
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
905
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
969
+ response_model_include: Optional[IncEx] = None,
970
+ response_model_exclude: Optional[IncEx] = None,
906
971
  response_model_by_alias: bool = True,
907
972
  response_model_exclude_unset: bool = False,
908
973
  response_model_exclude_defaults: bool = False,
@@ -957,8 +1022,8 @@ class APIRouter(routing.Router):
957
1022
  responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
958
1023
  deprecated: Optional[bool] = None,
959
1024
  operation_id: Optional[str] = None,
960
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
961
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1025
+ response_model_include: Optional[IncEx] = None,
1026
+ response_model_exclude: Optional[IncEx] = None,
962
1027
  response_model_by_alias: bool = True,
963
1028
  response_model_exclude_unset: bool = False,
964
1029
  response_model_exclude_defaults: bool = False,
@@ -1013,8 +1078,8 @@ class APIRouter(routing.Router):
1013
1078
  responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
1014
1079
  deprecated: Optional[bool] = None,
1015
1080
  operation_id: Optional[str] = None,
1016
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1017
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1081
+ response_model_include: Optional[IncEx] = None,
1082
+ response_model_exclude: Optional[IncEx] = None,
1018
1083
  response_model_by_alias: bool = True,
1019
1084
  response_model_exclude_unset: bool = False,
1020
1085
  response_model_exclude_defaults: bool = False,
@@ -1069,8 +1134,8 @@ class APIRouter(routing.Router):
1069
1134
  responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
1070
1135
  deprecated: Optional[bool] = None,
1071
1136
  operation_id: Optional[str] = None,
1072
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1073
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1137
+ response_model_include: Optional[IncEx] = None,
1138
+ response_model_exclude: Optional[IncEx] = None,
1074
1139
  response_model_by_alias: bool = True,
1075
1140
  response_model_exclude_unset: bool = False,
1076
1141
  response_model_exclude_defaults: bool = False,
@@ -1125,8 +1190,8 @@ class APIRouter(routing.Router):
1125
1190
  responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
1126
1191
  deprecated: Optional[bool] = None,
1127
1192
  operation_id: Optional[str] = None,
1128
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1129
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1193
+ response_model_include: Optional[IncEx] = None,
1194
+ response_model_exclude: Optional[IncEx] = None,
1130
1195
  response_model_by_alias: bool = True,
1131
1196
  response_model_exclude_unset: bool = False,
1132
1197
  response_model_exclude_defaults: bool = False,
@@ -1181,8 +1246,8 @@ class APIRouter(routing.Router):
1181
1246
  responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
1182
1247
  deprecated: Optional[bool] = None,
1183
1248
  operation_id: Optional[str] = None,
1184
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1185
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1249
+ response_model_include: Optional[IncEx] = None,
1250
+ response_model_exclude: Optional[IncEx] = None,
1186
1251
  response_model_by_alias: bool = True,
1187
1252
  response_model_exclude_unset: bool = False,
1188
1253
  response_model_exclude_defaults: bool = False,
@@ -1237,8 +1302,8 @@ class APIRouter(routing.Router):
1237
1302
  responses: Optional[Dict[Union[int, str], Dict[str, Any]]] = None,
1238
1303
  deprecated: Optional[bool] = None,
1239
1304
  operation_id: Optional[str] = None,
1240
- response_model_include: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1241
- response_model_exclude: Optional[Union[SetIntStr, DictIntStrAny]] = None,
1305
+ response_model_include: Optional[IncEx] = None,
1306
+ response_model_exclude: Optional[IncEx] = None,
1242
1307
  response_model_by_alias: bool = True,
1243
1308
  response_model_exclude_unset: bool = False,
1244
1309
  response_model_exclude_defaults: bool = False,
@@ -21,7 +21,9 @@ class APIKeyQuery(APIKeyBase):
21
21
  auto_error: bool = True,
22
22
  ):
23
23
  self.model: APIKey = APIKey(
24
- **{"in": APIKeyIn.query}, name=name, description=description
24
+ **{"in": APIKeyIn.query}, # type: ignore[arg-type]
25
+ name=name,
26
+ description=description,
25
27
  )
26
28
  self.scheme_name = scheme_name or self.__class__.__name__
27
29
  self.auto_error = auto_error
@@ -48,7 +50,9 @@ class APIKeyHeader(APIKeyBase):
48
50
  auto_error: bool = True,
49
51
  ):
50
52
  self.model: APIKey = APIKey(
51
- **{"in": APIKeyIn.header}, name=name, description=description
53
+ **{"in": APIKeyIn.header}, # type: ignore[arg-type]
54
+ name=name,
55
+ description=description,
52
56
  )
53
57
  self.scheme_name = scheme_name or self.__class__.__name__
54
58
  self.auto_error = auto_error
@@ -75,7 +79,9 @@ class APIKeyCookie(APIKeyBase):
75
79
  auto_error: bool = True,
76
80
  ):
77
81
  self.model: APIKey = APIKey(
78
- **{"in": APIKeyIn.cookie}, name=name, description=description
82
+ **{"in": APIKeyIn.cookie}, # type: ignore[arg-type]
83
+ name=name,
84
+ description=description,
79
85
  )
80
86
  self.scheme_name = scheme_name or self.__class__.__name__
81
87
  self.auto_error = auto_error
@@ -1,4 +1,4 @@
1
- from typing import Any, Dict, List, Optional, Union
1
+ from typing import Any, Dict, List, Optional, Union, cast
2
2
 
3
3
  from fastapi.exceptions import HTTPException
4
4
  from fastapi.openapi.models import OAuth2 as OAuth2Model
@@ -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,
@@ -121,7 +125,9 @@ class OAuth2(SecurityBase):
121
125
  description: Optional[str] = None,
122
126
  auto_error: bool = True,
123
127
  ):
124
- self.model = OAuth2Model(flows=flows, description=description)
128
+ self.model = OAuth2Model(
129
+ flows=cast(OAuthFlowsModel, flows), description=description
130
+ )
125
131
  self.scheme_name = scheme_name or self.__class__.__name__
126
132
  self.auto_error = auto_error
127
133
 
@@ -148,7 +154,9 @@ class OAuth2PasswordBearer(OAuth2):
148
154
  ):
149
155
  if not scopes:
150
156
  scopes = {}
151
- flows = OAuthFlowsModel(password={"tokenUrl": tokenUrl, "scopes": scopes})
157
+ flows = OAuthFlowsModel(
158
+ password=cast(Any, {"tokenUrl": tokenUrl, "scopes": scopes})
159
+ )
152
160
  super().__init__(
153
161
  flows=flows,
154
162
  scheme_name=scheme_name,
@@ -185,12 +193,15 @@ class OAuth2AuthorizationCodeBearer(OAuth2):
185
193
  if not scopes:
186
194
  scopes = {}
187
195
  flows = OAuthFlowsModel(
188
- authorizationCode={
189
- "authorizationUrl": authorizationUrl,
190
- "tokenUrl": tokenUrl,
191
- "refreshUrl": refreshUrl,
192
- "scopes": scopes,
193
- }
196
+ authorizationCode=cast(
197
+ Any,
198
+ {
199
+ "authorizationUrl": authorizationUrl,
200
+ "tokenUrl": tokenUrl,
201
+ "refreshUrl": refreshUrl,
202
+ "scopes": scopes,
203
+ },
204
+ )
194
205
  )
195
206
  super().__init__(
196
207
  flows=flows,
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]]