fastapi 0.105.0__py3-none-any.whl → 0.106.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 +0 -52
- fastapi/concurrency.py +0 -1
- fastapi/dependencies/utils.py +4 -5
- fastapi/routing.py +133 -98
- {fastapi-0.105.0.dist-info → fastapi-0.106.0.dist-info}/METADATA +1 -1
- {fastapi-0.105.0.dist-info → fastapi-0.106.0.dist-info}/RECORD +9 -10
- {fastapi-0.105.0.dist-info → fastapi-0.106.0.dist-info}/WHEEL +1 -1
- fastapi/middleware/asyncexitstack.py +0 -25
- {fastapi-0.105.0.dist-info → fastapi-0.106.0.dist-info}/licenses/LICENSE +0 -0
fastapi/__init__.py
CHANGED
fastapi/applications.py
CHANGED
|
@@ -22,7 +22,6 @@ 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
|
|
26
25
|
from fastapi.openapi.docs import (
|
|
27
26
|
get_redoc_html,
|
|
28
27
|
get_swagger_ui_html,
|
|
@@ -37,8 +36,6 @@ from starlette.datastructures import State
|
|
|
37
36
|
from starlette.exceptions import HTTPException
|
|
38
37
|
from starlette.middleware import Middleware
|
|
39
38
|
from starlette.middleware.base import BaseHTTPMiddleware
|
|
40
|
-
from starlette.middleware.errors import ServerErrorMiddleware
|
|
41
|
-
from starlette.middleware.exceptions import ExceptionMiddleware
|
|
42
39
|
from starlette.requests import Request
|
|
43
40
|
from starlette.responses import HTMLResponse, JSONResponse, Response
|
|
44
41
|
from starlette.routing import BaseRoute
|
|
@@ -966,55 +963,6 @@ class FastAPI(Starlette):
|
|
|
966
963
|
self.middleware_stack: Union[ASGIApp, None] = None
|
|
967
964
|
self.setup()
|
|
968
965
|
|
|
969
|
-
def build_middleware_stack(self) -> ASGIApp:
|
|
970
|
-
# Duplicate/override from Starlette to add AsyncExitStackMiddleware
|
|
971
|
-
# inside of ExceptionMiddleware, inside of custom user middlewares
|
|
972
|
-
debug = self.debug
|
|
973
|
-
error_handler = None
|
|
974
|
-
exception_handlers = {}
|
|
975
|
-
|
|
976
|
-
for key, value in self.exception_handlers.items():
|
|
977
|
-
if key in (500, Exception):
|
|
978
|
-
error_handler = value
|
|
979
|
-
else:
|
|
980
|
-
exception_handlers[key] = value
|
|
981
|
-
|
|
982
|
-
middleware = (
|
|
983
|
-
[Middleware(ServerErrorMiddleware, handler=error_handler, debug=debug)]
|
|
984
|
-
+ self.user_middleware
|
|
985
|
-
+ [
|
|
986
|
-
Middleware(
|
|
987
|
-
ExceptionMiddleware, handlers=exception_handlers, debug=debug
|
|
988
|
-
),
|
|
989
|
-
# Add FastAPI-specific AsyncExitStackMiddleware for dependencies with
|
|
990
|
-
# contextvars.
|
|
991
|
-
# This needs to happen after user middlewares because those create a
|
|
992
|
-
# new contextvars context copy by using a new AnyIO task group.
|
|
993
|
-
# The initial part of dependencies with 'yield' is executed in the
|
|
994
|
-
# FastAPI code, inside all the middlewares. However, the teardown part
|
|
995
|
-
# (after 'yield') is executed in the AsyncExitStack in this middleware.
|
|
996
|
-
# If the AsyncExitStack lived outside of the custom middlewares and
|
|
997
|
-
# contextvars were set in a dependency with 'yield' in that internal
|
|
998
|
-
# contextvars context, the values would not be available in the
|
|
999
|
-
# outer context of the AsyncExitStack.
|
|
1000
|
-
# By placing the middleware and the AsyncExitStack here, inside all
|
|
1001
|
-
# user middlewares, the code before and after 'yield' in dependencies
|
|
1002
|
-
# with 'yield' is executed in the same contextvars context. Thus, all values
|
|
1003
|
-
# set in contextvars before 'yield' are still available after 'yield,' as
|
|
1004
|
-
# expected.
|
|
1005
|
-
# Additionally, by having this AsyncExitStack here, after the
|
|
1006
|
-
# ExceptionMiddleware, dependencies can now catch handled exceptions,
|
|
1007
|
-
# e.g. HTTPException, to customize the teardown code (e.g. DB session
|
|
1008
|
-
# rollback).
|
|
1009
|
-
Middleware(AsyncExitStackMiddleware),
|
|
1010
|
-
]
|
|
1011
|
-
)
|
|
1012
|
-
|
|
1013
|
-
app = self.router
|
|
1014
|
-
for cls, options in reversed(middleware):
|
|
1015
|
-
app = cls(app=app, **options)
|
|
1016
|
-
return app
|
|
1017
|
-
|
|
1018
966
|
def openapi(self) -> Dict[str, Any]:
|
|
1019
967
|
"""
|
|
1020
968
|
Generate the OpenAPI schema of the application. This is called by FastAPI
|
fastapi/concurrency.py
CHANGED
fastapi/dependencies/utils.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import inspect
|
|
2
|
-
from contextlib import contextmanager
|
|
2
|
+
from contextlib import AsyncExitStack, contextmanager
|
|
3
3
|
from copy import deepcopy
|
|
4
4
|
from typing import (
|
|
5
5
|
Any,
|
|
@@ -46,7 +46,6 @@ from fastapi._compat import (
|
|
|
46
46
|
)
|
|
47
47
|
from fastapi.background import BackgroundTasks
|
|
48
48
|
from fastapi.concurrency import (
|
|
49
|
-
AsyncExitStack,
|
|
50
49
|
asynccontextmanager,
|
|
51
50
|
contextmanager_in_threadpool,
|
|
52
51
|
)
|
|
@@ -529,6 +528,7 @@ async def solve_dependencies(
|
|
|
529
528
|
response: Optional[Response] = None,
|
|
530
529
|
dependency_overrides_provider: Optional[Any] = None,
|
|
531
530
|
dependency_cache: Optional[Dict[Tuple[Callable[..., Any], Tuple[str]], Any]] = None,
|
|
531
|
+
async_exit_stack: AsyncExitStack,
|
|
532
532
|
) -> Tuple[
|
|
533
533
|
Dict[str, Any],
|
|
534
534
|
List[Any],
|
|
@@ -575,6 +575,7 @@ async def solve_dependencies(
|
|
|
575
575
|
response=response,
|
|
576
576
|
dependency_overrides_provider=dependency_overrides_provider,
|
|
577
577
|
dependency_cache=dependency_cache,
|
|
578
|
+
async_exit_stack=async_exit_stack,
|
|
578
579
|
)
|
|
579
580
|
(
|
|
580
581
|
sub_values,
|
|
@@ -590,10 +591,8 @@ async def solve_dependencies(
|
|
|
590
591
|
if sub_dependant.use_cache and sub_dependant.cache_key in dependency_cache:
|
|
591
592
|
solved = dependency_cache[sub_dependant.cache_key]
|
|
592
593
|
elif is_gen_callable(call) or is_async_gen_callable(call):
|
|
593
|
-
stack = request.scope.get("fastapi_astack")
|
|
594
|
-
assert isinstance(stack, AsyncExitStack)
|
|
595
594
|
solved = await solve_generator(
|
|
596
|
-
call=call, stack=
|
|
595
|
+
call=call, stack=async_exit_stack, sub_values=sub_values
|
|
597
596
|
)
|
|
598
597
|
elif is_coroutine_callable(call):
|
|
599
598
|
solved = await call(**sub_values)
|
fastapi/routing.py
CHANGED
|
@@ -216,95 +216,124 @@ def get_request_handler(
|
|
|
216
216
|
actual_response_class = response_class
|
|
217
217
|
|
|
218
218
|
async def app(request: Request) -> Response:
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
219
|
+
exception_to_reraise: Optional[Exception] = None
|
|
220
|
+
response: Union[Response, None] = None
|
|
221
|
+
async with AsyncExitStack() as async_exit_stack:
|
|
222
|
+
# TODO: remove this scope later, after a few releases
|
|
223
|
+
# This scope fastapi_astack is no longer used by FastAPI, kept for
|
|
224
|
+
# compatibility, just in case
|
|
225
|
+
request.scope["fastapi_astack"] = async_exit_stack
|
|
226
|
+
try:
|
|
227
|
+
body: Any = None
|
|
228
|
+
if body_field:
|
|
229
|
+
if is_body_form:
|
|
230
|
+
body = await request.form()
|
|
231
|
+
async_exit_stack.push_async_callback(body.close)
|
|
232
|
+
else:
|
|
233
|
+
body_bytes = await request.body()
|
|
234
|
+
if body_bytes:
|
|
235
|
+
json_body: Any = Undefined
|
|
236
|
+
content_type_value = request.headers.get("content-type")
|
|
237
|
+
if not content_type_value:
|
|
238
|
+
json_body = await request.json()
|
|
239
|
+
else:
|
|
240
|
+
message = email.message.Message()
|
|
241
|
+
message["content-type"] = content_type_value
|
|
242
|
+
if message.get_content_maintype() == "application":
|
|
243
|
+
subtype = message.get_content_subtype()
|
|
244
|
+
if subtype == "json" or subtype.endswith("+json"):
|
|
245
|
+
json_body = await request.json()
|
|
246
|
+
if json_body != Undefined:
|
|
247
|
+
body = json_body
|
|
248
|
+
else:
|
|
249
|
+
body = body_bytes
|
|
250
|
+
except json.JSONDecodeError as e:
|
|
251
|
+
validation_error = RequestValidationError(
|
|
252
|
+
[
|
|
253
|
+
{
|
|
254
|
+
"type": "json_invalid",
|
|
255
|
+
"loc": ("body", e.pos),
|
|
256
|
+
"msg": "JSON decode error",
|
|
257
|
+
"input": {},
|
|
258
|
+
"ctx": {"error": e.msg},
|
|
259
|
+
}
|
|
260
|
+
],
|
|
261
|
+
body=e.doc,
|
|
262
|
+
)
|
|
263
|
+
exception_to_reraise = validation_error
|
|
264
|
+
raise validation_error from e
|
|
265
|
+
except HTTPException as e:
|
|
266
|
+
exception_to_reraise = e
|
|
267
|
+
raise
|
|
268
|
+
except Exception as e:
|
|
269
|
+
http_error = HTTPException(
|
|
270
|
+
status_code=400, detail="There was an error parsing the body"
|
|
271
|
+
)
|
|
272
|
+
exception_to_reraise = http_error
|
|
273
|
+
raise http_error from e
|
|
274
|
+
try:
|
|
275
|
+
solved_result = await solve_dependencies(
|
|
276
|
+
request=request,
|
|
277
|
+
dependant=dependant,
|
|
278
|
+
body=body,
|
|
279
|
+
dependency_overrides_provider=dependency_overrides_provider,
|
|
280
|
+
async_exit_stack=async_exit_stack,
|
|
281
|
+
)
|
|
282
|
+
values, errors, background_tasks, sub_response, _ = solved_result
|
|
283
|
+
except Exception as e:
|
|
284
|
+
exception_to_reraise = e
|
|
285
|
+
raise e
|
|
286
|
+
if errors:
|
|
287
|
+
validation_error = RequestValidationError(
|
|
288
|
+
_normalize_errors(errors), body=body
|
|
289
|
+
)
|
|
290
|
+
exception_to_reraise = validation_error
|
|
291
|
+
raise validation_error
|
|
292
|
+
else:
|
|
293
|
+
try:
|
|
294
|
+
raw_response = await run_endpoint_function(
|
|
295
|
+
dependant=dependant, values=values, is_coroutine=is_coroutine
|
|
296
|
+
)
|
|
297
|
+
except Exception as e:
|
|
298
|
+
exception_to_reraise = e
|
|
299
|
+
raise e
|
|
300
|
+
if isinstance(raw_response, Response):
|
|
301
|
+
if raw_response.background is None:
|
|
302
|
+
raw_response.background = background_tasks
|
|
303
|
+
response = raw_response
|
|
227
304
|
else:
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
if
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
except Exception as e:
|
|
261
|
-
raise HTTPException(
|
|
262
|
-
status_code=400, detail="There was an error parsing the body"
|
|
263
|
-
) from e
|
|
264
|
-
solved_result = await solve_dependencies(
|
|
265
|
-
request=request,
|
|
266
|
-
dependant=dependant,
|
|
267
|
-
body=body,
|
|
268
|
-
dependency_overrides_provider=dependency_overrides_provider,
|
|
269
|
-
)
|
|
270
|
-
values, errors, background_tasks, sub_response, _ = solved_result
|
|
271
|
-
if errors:
|
|
272
|
-
raise RequestValidationError(_normalize_errors(errors), body=body)
|
|
273
|
-
else:
|
|
274
|
-
raw_response = await run_endpoint_function(
|
|
275
|
-
dependant=dependant, values=values, is_coroutine=is_coroutine
|
|
276
|
-
)
|
|
277
|
-
|
|
278
|
-
if isinstance(raw_response, Response):
|
|
279
|
-
if raw_response.background is None:
|
|
280
|
-
raw_response.background = background_tasks
|
|
281
|
-
return raw_response
|
|
282
|
-
response_args: Dict[str, Any] = {"background": background_tasks}
|
|
283
|
-
# If status_code was set, use it, otherwise use the default from the
|
|
284
|
-
# response class, in the case of redirect it's 307
|
|
285
|
-
current_status_code = (
|
|
286
|
-
status_code if status_code else sub_response.status_code
|
|
287
|
-
)
|
|
288
|
-
if current_status_code is not None:
|
|
289
|
-
response_args["status_code"] = current_status_code
|
|
290
|
-
if sub_response.status_code:
|
|
291
|
-
response_args["status_code"] = sub_response.status_code
|
|
292
|
-
content = await serialize_response(
|
|
293
|
-
field=response_field,
|
|
294
|
-
response_content=raw_response,
|
|
295
|
-
include=response_model_include,
|
|
296
|
-
exclude=response_model_exclude,
|
|
297
|
-
by_alias=response_model_by_alias,
|
|
298
|
-
exclude_unset=response_model_exclude_unset,
|
|
299
|
-
exclude_defaults=response_model_exclude_defaults,
|
|
300
|
-
exclude_none=response_model_exclude_none,
|
|
301
|
-
is_coroutine=is_coroutine,
|
|
302
|
-
)
|
|
303
|
-
response = actual_response_class(content, **response_args)
|
|
304
|
-
if not is_body_allowed_for_status_code(response.status_code):
|
|
305
|
-
response.body = b""
|
|
306
|
-
response.headers.raw.extend(sub_response.headers.raw)
|
|
307
|
-
return response
|
|
305
|
+
response_args: Dict[str, Any] = {"background": background_tasks}
|
|
306
|
+
# If status_code was set, use it, otherwise use the default from the
|
|
307
|
+
# response class, in the case of redirect it's 307
|
|
308
|
+
current_status_code = (
|
|
309
|
+
status_code if status_code else sub_response.status_code
|
|
310
|
+
)
|
|
311
|
+
if current_status_code is not None:
|
|
312
|
+
response_args["status_code"] = current_status_code
|
|
313
|
+
if sub_response.status_code:
|
|
314
|
+
response_args["status_code"] = sub_response.status_code
|
|
315
|
+
content = await serialize_response(
|
|
316
|
+
field=response_field,
|
|
317
|
+
response_content=raw_response,
|
|
318
|
+
include=response_model_include,
|
|
319
|
+
exclude=response_model_exclude,
|
|
320
|
+
by_alias=response_model_by_alias,
|
|
321
|
+
exclude_unset=response_model_exclude_unset,
|
|
322
|
+
exclude_defaults=response_model_exclude_defaults,
|
|
323
|
+
exclude_none=response_model_exclude_none,
|
|
324
|
+
is_coroutine=is_coroutine,
|
|
325
|
+
)
|
|
326
|
+
response = actual_response_class(content, **response_args)
|
|
327
|
+
if not is_body_allowed_for_status_code(response.status_code):
|
|
328
|
+
response.body = b""
|
|
329
|
+
response.headers.raw.extend(sub_response.headers.raw)
|
|
330
|
+
# This exception was possibly handled by the dependency but it should
|
|
331
|
+
# still bubble up so that the ServerErrorMiddleware can return a 500
|
|
332
|
+
# or the ExceptionMiddleware can catch and handle any other exceptions
|
|
333
|
+
if exception_to_reraise:
|
|
334
|
+
raise exception_to_reraise
|
|
335
|
+
assert response is not None, "An error occurred while generating the request"
|
|
336
|
+
return response
|
|
308
337
|
|
|
309
338
|
return app
|
|
310
339
|
|
|
@@ -313,16 +342,22 @@ def get_websocket_app(
|
|
|
313
342
|
dependant: Dependant, dependency_overrides_provider: Optional[Any] = None
|
|
314
343
|
) -> Callable[[WebSocket], Coroutine[Any, Any, Any]]:
|
|
315
344
|
async def app(websocket: WebSocket) -> None:
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
345
|
+
async with AsyncExitStack() as async_exit_stack:
|
|
346
|
+
# TODO: remove this scope later, after a few releases
|
|
347
|
+
# This scope fastapi_astack is no longer used by FastAPI, kept for
|
|
348
|
+
# compatibility, just in case
|
|
349
|
+
websocket.scope["fastapi_astack"] = async_exit_stack
|
|
350
|
+
solved_result = await solve_dependencies(
|
|
351
|
+
request=websocket,
|
|
352
|
+
dependant=dependant,
|
|
353
|
+
dependency_overrides_provider=dependency_overrides_provider,
|
|
354
|
+
async_exit_stack=async_exit_stack,
|
|
355
|
+
)
|
|
356
|
+
values, errors, _, _2, _3 = solved_result
|
|
357
|
+
if errors:
|
|
358
|
+
raise WebSocketRequestValidationError(_normalize_errors(errors))
|
|
359
|
+
assert dependant.call is not None, "dependant.call must be a function"
|
|
360
|
+
await dependant.call(**values)
|
|
326
361
|
|
|
327
362
|
return app
|
|
328
363
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: fastapi
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.106.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/
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
fastapi/__init__.py,sha256=
|
|
1
|
+
fastapi/__init__.py,sha256=7JbocWwEkmJC10EiyLujBbEG9V3fhU-JKWgGzp3lmwk,1081
|
|
2
2
|
fastapi/_compat.py,sha256=i_LwkpFVbNCuraFRbc1UmNNocX63BAwjjBXgF59JJVQ,23027
|
|
3
|
-
fastapi/applications.py,sha256=
|
|
3
|
+
fastapi/applications.py,sha256=nUoSz0Lhif39vAw9KATzFH2Xjz73kftOMCiwq6osNfg,176375
|
|
4
4
|
fastapi/background.py,sha256=F1tsrJKfDZaRchNgF9ykB2PcRaPBJTbL4htN45TJAIc,1799
|
|
5
|
-
fastapi/concurrency.py,sha256=
|
|
5
|
+
fastapi/concurrency.py,sha256=AYLnS4judDUmXsNRICtoKSP0prfYDcS8ehBtYW9JhQQ,1403
|
|
6
6
|
fastapi/datastructures.py,sha256=FF1s2g6cAQ5XxlNToB3scgV94Zf3DjdzcaI7ToaTrmg,5797
|
|
7
7
|
fastapi/encoders.py,sha256=90lbmIW8NZjpPVzbgKhpY49B7TFqa7hrdQDQa70SM9U,11024
|
|
8
8
|
fastapi/exception_handlers.py,sha256=MBrIOA-ugjJDivIi4rSsUJBdTsjuzN76q4yh0q1COKw,1332
|
|
@@ -13,7 +13,7 @@ fastapi/params.py,sha256=LzjihAvODd3w7-GddraUyVtH1xfwR9smIoQn-Z_g4mg,27807
|
|
|
13
13
|
fastapi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
14
|
fastapi/requests.py,sha256=zayepKFcienBllv3snmWI20Gk0oHNVLU4DDhqXBb4LU,142
|
|
15
15
|
fastapi/responses.py,sha256=QNQQlwpKhQoIPZTTWkpc9d_QGeGZ_aVQPaDV3nQ8m7c,1761
|
|
16
|
-
fastapi/routing.py,sha256=
|
|
16
|
+
fastapi/routing.py,sha256=YTWD3Cfwq1RxHN0-9WJSD9J4W3SSh52oKxYUud2XtcY,174483
|
|
17
17
|
fastapi/staticfiles.py,sha256=iirGIt3sdY2QZXd36ijs3Cj-T0FuGFda3cd90kM9Ikw,69
|
|
18
18
|
fastapi/templating.py,sha256=4zsuTWgcjcEainMJFAlW6-gnslm6AgOS1SiiDWfmQxk,76
|
|
19
19
|
fastapi/testclient.py,sha256=nBvaAmX66YldReJNZXPOk1sfuo2Q6hs8bOvIaCep6LQ,66
|
|
@@ -22,9 +22,8 @@ fastapi/utils.py,sha256=rpSasHpgooPIfe67yU3HzOMDv7PtxiG9x6K-bhu6Z18,8193
|
|
|
22
22
|
fastapi/websockets.py,sha256=419uncYObEKZG0YcrXscfQQYLSWoE10jqxVMetGdR98,222
|
|
23
23
|
fastapi/dependencies/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
24
|
fastapi/dependencies/models.py,sha256=-n-YCxzgVBkurQi49qOTooT71v_oeAhHJ-qQFonxh5o,2494
|
|
25
|
-
fastapi/dependencies/utils.py,sha256=
|
|
25
|
+
fastapi/dependencies/utils.py,sha256=IUY-uZmp56BUZuEiHtTQT0iGNF5ASIst7AzFMzA_As8,30158
|
|
26
26
|
fastapi/middleware/__init__.py,sha256=oQDxiFVcc1fYJUOIFvphnK7pTT5kktmfL32QXpBFvvo,58
|
|
27
|
-
fastapi/middleware/asyncexitstack.py,sha256=LvMyVI1QdmWNWYPZqx295VFavssUfVpUsonPOsMWz1E,1035
|
|
28
27
|
fastapi/middleware/cors.py,sha256=ynwjWQZoc_vbhzZ3_ZXceoaSrslHFHPdoM52rXr0WUU,79
|
|
29
28
|
fastapi/middleware/gzip.py,sha256=xM5PcsH8QlAimZw4VDvcmTnqQamslThsfe3CVN2voa0,79
|
|
30
29
|
fastapi/middleware/httpsredirect.py,sha256=rL8eXMnmLijwVkH7_400zHri1AekfeBd6D6qs8ix950,115
|
|
@@ -42,7 +41,7 @@ fastapi/security/http.py,sha256=_YdhSRRUCGydVDUILygWg0VlkPA28t_gjcy_axD3eOk,1353
|
|
|
42
41
|
fastapi/security/oauth2.py,sha256=QAUOE2f6KXbXjkrJIIYCOugI6-R0g9EECZ5t8eN9nA4,21612
|
|
43
42
|
fastapi/security/open_id_connect_url.py,sha256=Mb8wFxrRh4CrsFW0RcjBEQLASPHGDtZRP6c2dCrspAg,2753
|
|
44
43
|
fastapi/security/utils.py,sha256=bd8T0YM7UQD5ATKucr1bNtAvz_Y3__dVNAv5UebiPvc,293
|
|
45
|
-
fastapi-0.
|
|
46
|
-
fastapi-0.
|
|
47
|
-
fastapi-0.
|
|
48
|
-
fastapi-0.
|
|
44
|
+
fastapi-0.106.0.dist-info/METADATA,sha256=m8-HdxWfRji5ynzlkoOQaAAxR1k1mkpt7UQXcxpUZmk,24944
|
|
45
|
+
fastapi-0.106.0.dist-info/WHEEL,sha256=mRYSEL3Ih6g5a_CVMIcwiF__0Ae4_gLYh01YFNwiq1k,87
|
|
46
|
+
fastapi-0.106.0.dist-info/licenses/LICENSE,sha256=Tsif_IFIW5f-xYSy1KlhAy7v_oNEU4lP2cEnSQbMdE4,1086
|
|
47
|
+
fastapi-0.106.0.dist-info/RECORD,,
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
from typing import Optional
|
|
2
|
-
|
|
3
|
-
from fastapi.concurrency import AsyncExitStack
|
|
4
|
-
from starlette.types import ASGIApp, Receive, Scope, Send
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class AsyncExitStackMiddleware:
|
|
8
|
-
def __init__(self, app: ASGIApp, context_name: str = "fastapi_astack") -> None:
|
|
9
|
-
self.app = app
|
|
10
|
-
self.context_name = context_name
|
|
11
|
-
|
|
12
|
-
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
|
|
13
|
-
dependency_exception: Optional[Exception] = None
|
|
14
|
-
async with AsyncExitStack() as stack:
|
|
15
|
-
scope[self.context_name] = stack
|
|
16
|
-
try:
|
|
17
|
-
await self.app(scope, receive, send)
|
|
18
|
-
except Exception as e:
|
|
19
|
-
dependency_exception = e
|
|
20
|
-
raise e
|
|
21
|
-
if dependency_exception:
|
|
22
|
-
# This exception was possibly handled by the dependency but it should
|
|
23
|
-
# still bubble up so that the ServerErrorMiddleware can return a 500
|
|
24
|
-
# or the ExceptionMiddleware can catch and handle any other exceptions
|
|
25
|
-
raise dependency_exception
|
|
File without changes
|