fastapi 0.117.1__py3-none-any.whl → 0.118.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of fastapi might be problematic. Click here for more details.
- fastapi/__init__.py +1 -1
- fastapi/applications.py +52 -1
- fastapi/middleware/asyncexitstack.py +18 -0
- fastapi/routing.py +199 -130
- fastapi/security/oauth2.py +2 -2
- {fastapi-0.117.1.dist-info → fastapi-0.118.0.dist-info}/METADATA +1 -1
- {fastapi-0.117.1.dist-info → fastapi-0.118.0.dist-info}/RECORD +10 -9
- {fastapi-0.117.1.dist-info → fastapi-0.118.0.dist-info}/WHEEL +0 -0
- {fastapi-0.117.1.dist-info → fastapi-0.118.0.dist-info}/entry_points.txt +0 -0
- {fastapi-0.117.1.dist-info → fastapi-0.118.0.dist-info}/licenses/LICENSE +0 -0
fastapi/__init__.py
CHANGED
fastapi/applications.py
CHANGED
|
@@ -22,6 +22,7 @@ from fastapi.exception_handlers import (
|
|
|
22
22
|
)
|
|
23
23
|
from fastapi.exceptions import RequestValidationError, WebSocketRequestValidationError
|
|
24
24
|
from fastapi.logger import logger
|
|
25
|
+
from fastapi.middleware.asyncexitstack import AsyncExitStackMiddleware
|
|
25
26
|
from fastapi.openapi.docs import (
|
|
26
27
|
get_redoc_html,
|
|
27
28
|
get_swagger_ui_html,
|
|
@@ -36,10 +37,12 @@ from starlette.datastructures import State
|
|
|
36
37
|
from starlette.exceptions import HTTPException
|
|
37
38
|
from starlette.middleware import Middleware
|
|
38
39
|
from starlette.middleware.base import BaseHTTPMiddleware
|
|
40
|
+
from starlette.middleware.errors import ServerErrorMiddleware
|
|
41
|
+
from starlette.middleware.exceptions import ExceptionMiddleware
|
|
39
42
|
from starlette.requests import Request
|
|
40
43
|
from starlette.responses import HTMLResponse, JSONResponse, Response
|
|
41
44
|
from starlette.routing import BaseRoute
|
|
42
|
-
from starlette.types import ASGIApp, Lifespan, Receive, Scope, Send
|
|
45
|
+
from starlette.types import ASGIApp, ExceptionHandler, Lifespan, Receive, Scope, Send
|
|
43
46
|
from typing_extensions import Annotated, Doc, deprecated
|
|
44
47
|
|
|
45
48
|
AppType = TypeVar("AppType", bound="FastAPI")
|
|
@@ -990,6 +993,54 @@ class FastAPI(Starlette):
|
|
|
990
993
|
self.middleware_stack: Union[ASGIApp, None] = None
|
|
991
994
|
self.setup()
|
|
992
995
|
|
|
996
|
+
def build_middleware_stack(self) -> ASGIApp:
|
|
997
|
+
# Duplicate/override from Starlette to add AsyncExitStackMiddleware
|
|
998
|
+
# inside of ExceptionMiddleware, inside of custom user middlewares
|
|
999
|
+
debug = self.debug
|
|
1000
|
+
error_handler = None
|
|
1001
|
+
exception_handlers: dict[Any, ExceptionHandler] = {}
|
|
1002
|
+
|
|
1003
|
+
for key, value in self.exception_handlers.items():
|
|
1004
|
+
if key in (500, Exception):
|
|
1005
|
+
error_handler = value
|
|
1006
|
+
else:
|
|
1007
|
+
exception_handlers[key] = value
|
|
1008
|
+
|
|
1009
|
+
middleware = (
|
|
1010
|
+
[Middleware(ServerErrorMiddleware, handler=error_handler, debug=debug)]
|
|
1011
|
+
+ self.user_middleware
|
|
1012
|
+
+ [
|
|
1013
|
+
Middleware(
|
|
1014
|
+
ExceptionMiddleware, handlers=exception_handlers, debug=debug
|
|
1015
|
+
),
|
|
1016
|
+
# Add FastAPI-specific AsyncExitStackMiddleware for closing files.
|
|
1017
|
+
# Before this was also used for closing dependencies with yield but
|
|
1018
|
+
# those now have their own AsyncExitStack, to properly support
|
|
1019
|
+
# streaming responses while keeping compatibility with the previous
|
|
1020
|
+
# versions (as of writing 0.117.1) that allowed doing
|
|
1021
|
+
# except HTTPException inside a dependency with yield.
|
|
1022
|
+
# This needs to happen after user middlewares because those create a
|
|
1023
|
+
# new contextvars context copy by using a new AnyIO task group.
|
|
1024
|
+
# This AsyncExitStack preserves the context for contextvars, not
|
|
1025
|
+
# strictly necessary for closing files but it was one of the original
|
|
1026
|
+
# intentions.
|
|
1027
|
+
# If the AsyncExitStack lived outside of the custom middlewares and
|
|
1028
|
+
# contextvars were set, for example in a dependency with 'yield'
|
|
1029
|
+
# in that internal contextvars context, the values would not be
|
|
1030
|
+
# available in the outer context of the AsyncExitStack.
|
|
1031
|
+
# By placing the middleware and the AsyncExitStack here, inside all
|
|
1032
|
+
# user middlewares, the same context is used.
|
|
1033
|
+
# This is currently not needed, only for closing files, but used to be
|
|
1034
|
+
# important when dependencies with yield were closed here.
|
|
1035
|
+
Middleware(AsyncExitStackMiddleware),
|
|
1036
|
+
]
|
|
1037
|
+
)
|
|
1038
|
+
|
|
1039
|
+
app = self.router
|
|
1040
|
+
for cls, args, kwargs in reversed(middleware):
|
|
1041
|
+
app = cls(app, *args, **kwargs)
|
|
1042
|
+
return app
|
|
1043
|
+
|
|
993
1044
|
def openapi(self) -> Dict[str, Any]:
|
|
994
1045
|
"""
|
|
995
1046
|
Generate the OpenAPI schema of the application. This is called by FastAPI
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from contextlib import AsyncExitStack
|
|
2
|
+
|
|
3
|
+
from starlette.types import ASGIApp, Receive, Scope, Send
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# Used mainly to close files after the request is done, dependencies are closed
|
|
7
|
+
# in their own AsyncExitStack
|
|
8
|
+
class AsyncExitStackMiddleware:
|
|
9
|
+
def __init__(
|
|
10
|
+
self, app: ASGIApp, context_name: str = "fastapi_middleware_astack"
|
|
11
|
+
) -> None:
|
|
12
|
+
self.app = app
|
|
13
|
+
self.context_name = context_name
|
|
14
|
+
|
|
15
|
+
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
|
|
16
|
+
async with AsyncExitStack() as stack:
|
|
17
|
+
scope[self.context_name] = stack
|
|
18
|
+
await self.app(scope, receive, send)
|
fastapi/routing.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import dataclasses
|
|
2
2
|
import email.message
|
|
3
|
+
import functools
|
|
3
4
|
import inspect
|
|
4
5
|
import json
|
|
5
6
|
import sys
|
|
@@ -8,6 +9,7 @@ from enum import Enum, IntEnum
|
|
|
8
9
|
from typing import (
|
|
9
10
|
Any,
|
|
10
11
|
AsyncIterator,
|
|
12
|
+
Awaitable,
|
|
11
13
|
Callable,
|
|
12
14
|
Collection,
|
|
13
15
|
Coroutine,
|
|
@@ -59,6 +61,8 @@ from fastapi.utils import (
|
|
|
59
61
|
)
|
|
60
62
|
from pydantic import BaseModel
|
|
61
63
|
from starlette import routing
|
|
64
|
+
from starlette._exception_handler import wrap_app_handling_exceptions
|
|
65
|
+
from starlette._utils import is_async_callable
|
|
62
66
|
from starlette.concurrency import run_in_threadpool
|
|
63
67
|
from starlette.exceptions import HTTPException
|
|
64
68
|
from starlette.requests import Request
|
|
@@ -68,11 +72,9 @@ from starlette.routing import (
|
|
|
68
72
|
Match,
|
|
69
73
|
compile_path,
|
|
70
74
|
get_name,
|
|
71
|
-
request_response,
|
|
72
|
-
websocket_session,
|
|
73
75
|
)
|
|
74
76
|
from starlette.routing import Mount as Mount # noqa
|
|
75
|
-
from starlette.types import AppType, ASGIApp, Lifespan, Scope
|
|
77
|
+
from starlette.types import AppType, ASGIApp, Lifespan, Receive, Scope, Send
|
|
76
78
|
from starlette.websockets import WebSocket
|
|
77
79
|
from typing_extensions import Annotated, Doc, deprecated
|
|
78
80
|
|
|
@@ -82,6 +84,73 @@ else: # pragma: no cover
|
|
|
82
84
|
from asyncio import iscoroutinefunction
|
|
83
85
|
|
|
84
86
|
|
|
87
|
+
# Copy of starlette.routing.request_response modified to include the
|
|
88
|
+
# dependencies' AsyncExitStack
|
|
89
|
+
def request_response(
|
|
90
|
+
func: Callable[[Request], Union[Awaitable[Response], Response]],
|
|
91
|
+
) -> ASGIApp:
|
|
92
|
+
"""
|
|
93
|
+
Takes a function or coroutine `func(request) -> response`,
|
|
94
|
+
and returns an ASGI application.
|
|
95
|
+
"""
|
|
96
|
+
f: Callable[[Request], Awaitable[Response]] = (
|
|
97
|
+
func if is_async_callable(func) else functools.partial(run_in_threadpool, func) # type:ignore
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
async def app(scope: Scope, receive: Receive, send: Send) -> None:
|
|
101
|
+
request = Request(scope, receive, send)
|
|
102
|
+
|
|
103
|
+
async def app(scope: Scope, receive: Receive, send: Send) -> None:
|
|
104
|
+
# Starts customization
|
|
105
|
+
response_awaited = False
|
|
106
|
+
async with AsyncExitStack() as stack:
|
|
107
|
+
scope["fastapi_inner_astack"] = stack
|
|
108
|
+
# Same as in Starlette
|
|
109
|
+
response = await f(request)
|
|
110
|
+
await response(scope, receive, send)
|
|
111
|
+
# Continues customization
|
|
112
|
+
response_awaited = True
|
|
113
|
+
if not response_awaited:
|
|
114
|
+
raise FastAPIError(
|
|
115
|
+
"Response not awaited. There's a high chance that the "
|
|
116
|
+
"application code is raising an exception and a dependency with yield "
|
|
117
|
+
"has a block with a bare except, or a block with except Exception, "
|
|
118
|
+
"and is not raising the exception again. Read more about it in the "
|
|
119
|
+
"docs: https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-with-yield/#dependencies-with-yield-and-except"
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
# Same as in Starlette
|
|
123
|
+
await wrap_app_handling_exceptions(app, request)(scope, receive, send)
|
|
124
|
+
|
|
125
|
+
return app
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
# Copy of starlette.routing.websocket_session modified to include the
|
|
129
|
+
# dependencies' AsyncExitStack
|
|
130
|
+
def websocket_session(
|
|
131
|
+
func: Callable[[WebSocket], Awaitable[None]],
|
|
132
|
+
) -> ASGIApp:
|
|
133
|
+
"""
|
|
134
|
+
Takes a coroutine `func(session)`, and returns an ASGI application.
|
|
135
|
+
"""
|
|
136
|
+
# assert asyncio.iscoroutinefunction(func), "WebSocket endpoints must be async"
|
|
137
|
+
|
|
138
|
+
async def app(scope: Scope, receive: Receive, send: Send) -> None:
|
|
139
|
+
session = WebSocket(scope, receive=receive, send=send)
|
|
140
|
+
|
|
141
|
+
async def app(scope: Scope, receive: Receive, send: Send) -> None:
|
|
142
|
+
# Starts customization
|
|
143
|
+
async with AsyncExitStack() as stack:
|
|
144
|
+
scope["fastapi_inner_astack"] = stack
|
|
145
|
+
# Same as in Starlette
|
|
146
|
+
await func(session)
|
|
147
|
+
|
|
148
|
+
# Same as in Starlette
|
|
149
|
+
await wrap_app_handling_exceptions(app, session)(scope, receive, send)
|
|
150
|
+
|
|
151
|
+
return app
|
|
152
|
+
|
|
153
|
+
|
|
85
154
|
def _prepare_response_content(
|
|
86
155
|
res: Any,
|
|
87
156
|
*,
|
|
@@ -246,119 +315,120 @@ def get_request_handler(
|
|
|
246
315
|
|
|
247
316
|
async def app(request: Request) -> Response:
|
|
248
317
|
response: Union[Response, None] = None
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
318
|
+
file_stack = request.scope.get("fastapi_middleware_astack")
|
|
319
|
+
assert isinstance(file_stack, AsyncExitStack), (
|
|
320
|
+
"fastapi_middleware_astack not found in request scope"
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
# Read body and auto-close files
|
|
324
|
+
try:
|
|
325
|
+
body: Any = None
|
|
326
|
+
if body_field:
|
|
327
|
+
if is_body_form:
|
|
328
|
+
body = await request.form()
|
|
329
|
+
file_stack.push_async_callback(body.close)
|
|
330
|
+
else:
|
|
331
|
+
body_bytes = await request.body()
|
|
332
|
+
if body_bytes:
|
|
333
|
+
json_body: Any = Undefined
|
|
334
|
+
content_type_value = request.headers.get("content-type")
|
|
335
|
+
if not content_type_value:
|
|
336
|
+
json_body = await request.json()
|
|
337
|
+
else:
|
|
338
|
+
message = email.message.Message()
|
|
339
|
+
message["content-type"] = content_type_value
|
|
340
|
+
if message.get_content_maintype() == "application":
|
|
341
|
+
subtype = message.get_content_subtype()
|
|
342
|
+
if subtype == "json" or subtype.endswith("+json"):
|
|
343
|
+
json_body = await request.json()
|
|
344
|
+
if json_body != Undefined:
|
|
345
|
+
body = json_body
|
|
346
|
+
else:
|
|
347
|
+
body = body_bytes
|
|
348
|
+
except json.JSONDecodeError as e:
|
|
349
|
+
validation_error = RequestValidationError(
|
|
350
|
+
[
|
|
351
|
+
{
|
|
352
|
+
"type": "json_invalid",
|
|
353
|
+
"loc": ("body", e.pos),
|
|
354
|
+
"msg": "JSON decode error",
|
|
355
|
+
"input": {},
|
|
356
|
+
"ctx": {"error": e.msg},
|
|
357
|
+
}
|
|
358
|
+
],
|
|
359
|
+
body=e.doc,
|
|
360
|
+
)
|
|
361
|
+
raise validation_error from e
|
|
362
|
+
except HTTPException:
|
|
363
|
+
# If a middleware raises an HTTPException, it should be raised again
|
|
364
|
+
raise
|
|
365
|
+
except Exception as e:
|
|
366
|
+
http_error = HTTPException(
|
|
367
|
+
status_code=400, detail="There was an error parsing the body"
|
|
368
|
+
)
|
|
369
|
+
raise http_error from e
|
|
370
|
+
|
|
371
|
+
# Solve dependencies and run path operation function, auto-closing dependencies
|
|
372
|
+
errors: List[Any] = []
|
|
373
|
+
async_exit_stack = request.scope.get("fastapi_inner_astack")
|
|
374
|
+
assert isinstance(async_exit_stack, AsyncExitStack), (
|
|
375
|
+
"fastapi_inner_astack not found in request scope"
|
|
376
|
+
)
|
|
377
|
+
solved_result = await solve_dependencies(
|
|
378
|
+
request=request,
|
|
379
|
+
dependant=dependant,
|
|
380
|
+
body=body,
|
|
381
|
+
dependency_overrides_provider=dependency_overrides_provider,
|
|
382
|
+
async_exit_stack=async_exit_stack,
|
|
383
|
+
embed_body_fields=embed_body_fields,
|
|
384
|
+
)
|
|
385
|
+
errors = solved_result.errors
|
|
386
|
+
if not errors:
|
|
387
|
+
raw_response = await run_endpoint_function(
|
|
388
|
+
dependant=dependant,
|
|
389
|
+
values=solved_result.values,
|
|
390
|
+
is_coroutine=is_coroutine,
|
|
391
|
+
)
|
|
392
|
+
if isinstance(raw_response, Response):
|
|
393
|
+
if raw_response.background is None:
|
|
394
|
+
raw_response.background = solved_result.background_tasks
|
|
395
|
+
response = raw_response
|
|
396
|
+
else:
|
|
397
|
+
response_args: Dict[str, Any] = {
|
|
398
|
+
"background": solved_result.background_tasks
|
|
399
|
+
}
|
|
400
|
+
# If status_code was set, use it, otherwise use the default from the
|
|
401
|
+
# response class, in the case of redirect it's 307
|
|
402
|
+
current_status_code = (
|
|
403
|
+
status_code if status_code else solved_result.response.status_code
|
|
305
404
|
)
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
}
|
|
321
|
-
# If status_code was set, use it, otherwise use the default from the
|
|
322
|
-
# response class, in the case of redirect it's 307
|
|
323
|
-
current_status_code = (
|
|
324
|
-
status_code
|
|
325
|
-
if status_code
|
|
326
|
-
else solved_result.response.status_code
|
|
327
|
-
)
|
|
328
|
-
if current_status_code is not None:
|
|
329
|
-
response_args["status_code"] = current_status_code
|
|
330
|
-
if solved_result.response.status_code:
|
|
331
|
-
response_args["status_code"] = (
|
|
332
|
-
solved_result.response.status_code
|
|
333
|
-
)
|
|
334
|
-
content = await serialize_response(
|
|
335
|
-
field=response_field,
|
|
336
|
-
response_content=raw_response,
|
|
337
|
-
include=response_model_include,
|
|
338
|
-
exclude=response_model_exclude,
|
|
339
|
-
by_alias=response_model_by_alias,
|
|
340
|
-
exclude_unset=response_model_exclude_unset,
|
|
341
|
-
exclude_defaults=response_model_exclude_defaults,
|
|
342
|
-
exclude_none=response_model_exclude_none,
|
|
343
|
-
is_coroutine=is_coroutine,
|
|
344
|
-
)
|
|
345
|
-
response = actual_response_class(content, **response_args)
|
|
346
|
-
if not is_body_allowed_for_status_code(response.status_code):
|
|
347
|
-
response.body = b""
|
|
348
|
-
response.headers.raw.extend(solved_result.response.headers.raw)
|
|
349
|
-
if errors:
|
|
350
|
-
validation_error = RequestValidationError(
|
|
351
|
-
_normalize_errors(errors), body=body
|
|
405
|
+
if current_status_code is not None:
|
|
406
|
+
response_args["status_code"] = current_status_code
|
|
407
|
+
if solved_result.response.status_code:
|
|
408
|
+
response_args["status_code"] = solved_result.response.status_code
|
|
409
|
+
content = await serialize_response(
|
|
410
|
+
field=response_field,
|
|
411
|
+
response_content=raw_response,
|
|
412
|
+
include=response_model_include,
|
|
413
|
+
exclude=response_model_exclude,
|
|
414
|
+
by_alias=response_model_by_alias,
|
|
415
|
+
exclude_unset=response_model_exclude_unset,
|
|
416
|
+
exclude_defaults=response_model_exclude_defaults,
|
|
417
|
+
exclude_none=response_model_exclude_none,
|
|
418
|
+
is_coroutine=is_coroutine,
|
|
352
419
|
)
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
"docs: https://fastapi.tiangolo.com/tutorial/dependencies/dependencies-with-yield/#dependencies-with-yield-and-except"
|
|
420
|
+
response = actual_response_class(content, **response_args)
|
|
421
|
+
if not is_body_allowed_for_status_code(response.status_code):
|
|
422
|
+
response.body = b""
|
|
423
|
+
response.headers.raw.extend(solved_result.response.headers.raw)
|
|
424
|
+
if errors:
|
|
425
|
+
validation_error = RequestValidationError(
|
|
426
|
+
_normalize_errors(errors), body=body
|
|
361
427
|
)
|
|
428
|
+
raise validation_error
|
|
429
|
+
|
|
430
|
+
# Return response
|
|
431
|
+
assert response
|
|
362
432
|
return response
|
|
363
433
|
|
|
364
434
|
return app
|
|
@@ -370,24 +440,23 @@ def get_websocket_app(
|
|
|
370
440
|
embed_body_fields: bool = False,
|
|
371
441
|
) -> Callable[[WebSocket], Coroutine[Any, Any, Any]]:
|
|
372
442
|
async def app(websocket: WebSocket) -> None:
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
443
|
+
async_exit_stack = websocket.scope.get("fastapi_inner_astack")
|
|
444
|
+
assert isinstance(async_exit_stack, AsyncExitStack), (
|
|
445
|
+
"fastapi_inner_astack not found in request scope"
|
|
446
|
+
)
|
|
447
|
+
solved_result = await solve_dependencies(
|
|
448
|
+
request=websocket,
|
|
449
|
+
dependant=dependant,
|
|
450
|
+
dependency_overrides_provider=dependency_overrides_provider,
|
|
451
|
+
async_exit_stack=async_exit_stack,
|
|
452
|
+
embed_body_fields=embed_body_fields,
|
|
453
|
+
)
|
|
454
|
+
if solved_result.errors:
|
|
455
|
+
raise WebSocketRequestValidationError(
|
|
456
|
+
_normalize_errors(solved_result.errors)
|
|
384
457
|
)
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
_normalize_errors(solved_result.errors)
|
|
388
|
-
)
|
|
389
|
-
assert dependant.call is not None, "dependant.call must be a function"
|
|
390
|
-
await dependant.call(**solved_result.values)
|
|
458
|
+
assert dependant.call is not None, "dependant.call must be a function"
|
|
459
|
+
await dependant.call(**solved_result.values)
|
|
391
460
|
|
|
392
461
|
return app
|
|
393
462
|
|
fastapi/security/oauth2.py
CHANGED
|
@@ -89,7 +89,7 @@ class OAuth2PasswordRequestForm:
|
|
|
89
89
|
Doc(
|
|
90
90
|
"""
|
|
91
91
|
`password` string. The OAuth2 spec requires the exact field name
|
|
92
|
-
`password
|
|
92
|
+
`password`.
|
|
93
93
|
"""
|
|
94
94
|
),
|
|
95
95
|
],
|
|
@@ -243,7 +243,7 @@ class OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm):
|
|
|
243
243
|
Doc(
|
|
244
244
|
"""
|
|
245
245
|
`password` string. The OAuth2 spec requires the exact field name
|
|
246
|
-
`password
|
|
246
|
+
`password`.
|
|
247
247
|
"""
|
|
248
248
|
),
|
|
249
249
|
],
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: fastapi
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.118.0
|
|
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
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
fastapi-0.
|
|
2
|
-
fastapi-0.
|
|
3
|
-
fastapi-0.
|
|
4
|
-
fastapi-0.
|
|
5
|
-
fastapi/__init__.py,sha256=
|
|
1
|
+
fastapi-0.118.0.dist-info/METADATA,sha256=RU7sXRYZDFARbkSSsO8GPrY7UfY76lmfqw9KZ2vXT6g,28135
|
|
2
|
+
fastapi-0.118.0.dist-info/WHEEL,sha256=9P2ygRxDrTJz3gsagc0Z96ukrxjr-LFBGOgv3AuKlCA,90
|
|
3
|
+
fastapi-0.118.0.dist-info/entry_points.txt,sha256=GCf-WbIZxyGT4MUmrPGj1cOHYZoGsNPHAvNkT6hnGeA,61
|
|
4
|
+
fastapi-0.118.0.dist-info/licenses/LICENSE,sha256=Tsif_IFIW5f-xYSy1KlhAy7v_oNEU4lP2cEnSQbMdE4,1086
|
|
5
|
+
fastapi/__init__.py,sha256=SlrlRcZQncT3o5Yip5GQIOvht2J2uCLN1rY2m_TPfuA,1081
|
|
6
6
|
fastapi/__main__.py,sha256=bKePXLdO4SsVSM6r9SVoLickJDcR2c0cTOxZRKq26YQ,37
|
|
7
7
|
fastapi/_compat.py,sha256=EQyNY-qrN3cjwI1r69JVAROc2lQCvi6W1we6_7jx_gc,24274
|
|
8
|
-
fastapi/applications.py,sha256=
|
|
8
|
+
fastapi/applications.py,sha256=nLbGcVdmCxXsl4aTSuP0WVS_XGY7wXBL3vC7nqlplmA,180276
|
|
9
9
|
fastapi/background.py,sha256=rouLirxUANrcYC824MSMypXL_Qb2HYg2YZqaiEqbEKI,1768
|
|
10
10
|
fastapi/cli.py,sha256=OYhZb0NR_deuT5ofyPF2NoNBzZDNOP8Salef2nk-HqA,418
|
|
11
11
|
fastapi/concurrency.py,sha256=MirfowoSpkMQZ8j_g0ZxaQKpV6eB3G-dB5TgcXCrgEA,1424
|
|
@@ -18,6 +18,7 @@ fastapi/exception_handlers.py,sha256=YVcT8Zy021VYYeecgdyh5YEUjEIHKcLspbkSf4OfbJI
|
|
|
18
18
|
fastapi/exceptions.py,sha256=taNixuFEXb67lI1bnX1ubq8y8TseJ4yoPlWjyP0fTzk,4969
|
|
19
19
|
fastapi/logger.py,sha256=I9NNi3ov8AcqbsbC9wl1X-hdItKgYt2XTrx1f99Zpl4,54
|
|
20
20
|
fastapi/middleware/__init__.py,sha256=oQDxiFVcc1fYJUOIFvphnK7pTT5kktmfL32QXpBFvvo,58
|
|
21
|
+
fastapi/middleware/asyncexitstack.py,sha256=RKGlQpGzg3GLosqVhrxBy_NCZ9qJS7zQeNHt5Y3x-00,637
|
|
21
22
|
fastapi/middleware/cors.py,sha256=ynwjWQZoc_vbhzZ3_ZXceoaSrslHFHPdoM52rXr0WUU,79
|
|
22
23
|
fastapi/middleware/gzip.py,sha256=xM5PcsH8QlAimZw4VDvcmTnqQamslThsfe3CVN2voa0,79
|
|
23
24
|
fastapi/middleware/httpsredirect.py,sha256=rL8eXMnmLijwVkH7_400zHri1AekfeBd6D6qs8ix950,115
|
|
@@ -33,12 +34,12 @@ fastapi/params.py,sha256=g450axUBQgQJODdtM7WBxZbQj9Z64inFvadrgHikBbU,28237
|
|
|
33
34
|
fastapi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
34
35
|
fastapi/requests.py,sha256=zayepKFcienBllv3snmWI20Gk0oHNVLU4DDhqXBb4LU,142
|
|
35
36
|
fastapi/responses.py,sha256=QNQQlwpKhQoIPZTTWkpc9d_QGeGZ_aVQPaDV3nQ8m7c,1761
|
|
36
|
-
fastapi/routing.py,sha256=
|
|
37
|
+
fastapi/routing.py,sha256=tK_d2K_0kP-rcbAmjjlR0mZMR170QkBITvwHWPq7eiQ,178409
|
|
37
38
|
fastapi/security/__init__.py,sha256=bO8pNmxqVRXUjfl2mOKiVZLn0FpBQ61VUYVjmppnbJw,881
|
|
38
39
|
fastapi/security/api_key.py,sha256=di-0gQ8MKugi2YfmlMoDHk-QMF_vnLGJRFOA6tcZ7fA,9016
|
|
39
40
|
fastapi/security/base.py,sha256=dl4pvbC-RxjfbWgPtCWd8MVU-7CB2SZ22rJDXVCXO6c,141
|
|
40
41
|
fastapi/security/http.py,sha256=rWR2x-5CUsjWmRucYthwRig6MG1o-boyrr4Xo-PuuxU,13606
|
|
41
|
-
fastapi/security/oauth2.py,sha256=
|
|
42
|
+
fastapi/security/oauth2.py,sha256=rKHIUHq29367Qpe0Ez5Gcu1yIIM6SMw7nEfh15gBNIQ,22036
|
|
42
43
|
fastapi/security/open_id_connect_url.py,sha256=8vizZ2tGqEp1ur8SwtVgyHJhGAJ5AqahgcvSpaIioDI,2722
|
|
43
44
|
fastapi/security/utils.py,sha256=bd8T0YM7UQD5ATKucr1bNtAvz_Y3__dVNAv5UebiPvc,293
|
|
44
45
|
fastapi/staticfiles.py,sha256=iirGIt3sdY2QZXd36ijs3Cj-T0FuGFda3cd90kM9Ikw,69
|
|
@@ -47,4 +48,4 @@ fastapi/testclient.py,sha256=nBvaAmX66YldReJNZXPOk1sfuo2Q6hs8bOvIaCep6LQ,66
|
|
|
47
48
|
fastapi/types.py,sha256=nFb36sK3DSoqoyo7Miwy3meKK5UdFBgkAgLSzQlUVyI,383
|
|
48
49
|
fastapi/utils.py,sha256=S59stPvKPUJ7MSkke3FaegSyig_4Uwhd32jnLiMF1jE,8032
|
|
49
50
|
fastapi/websockets.py,sha256=419uncYObEKZG0YcrXscfQQYLSWoE10jqxVMetGdR98,222
|
|
50
|
-
fastapi-0.
|
|
51
|
+
fastapi-0.118.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|