types-PyYAML==6.0.12.10
types-dataclasses==0.6.6
pytest==7.4.0
-trio==0.22.1
-anyio@git+https://github.com/agronholm/anyio.git
+trio==0.21.0
+anyio==3.7.1
# Documentation
mkdocs==1.4.3
import functools
import sys
import typing
+from contextlib import contextmanager
if sys.version_info >= (3, 10): # pragma: no cover
from typing import TypeGuard
else: # pragma: no cover
from typing_extensions import TypeGuard
+has_exceptiongroups = True
+if sys.version_info < (3, 11): # pragma: no cover
+ try:
+ from exceptiongroup import BaseExceptionGroup
+ except ImportError:
+ has_exceptiongroups = False
+
T = typing.TypeVar("T")
AwaitableCallable = typing.Callable[..., typing.Awaitable[T]]
async def __aexit__(self, *args: typing.Any) -> typing.Union[None, bool]:
await self.entered.close()
return None
+
+
+@contextmanager
+def collapse_excgroups() -> typing.Generator[None, None, None]:
+ try:
+ yield
+ except BaseException as exc:
+ if has_exceptiongroups:
+ while isinstance(exc, BaseExceptionGroup) and len(exc.exceptions) == 1:
+ exc = exc.exceptions[0] # pragma: no cover
+
+ raise exc
-import sys
import typing
-from contextlib import contextmanager
import anyio
from anyio.abc import ObjectReceiveStream, ObjectSendStream
+from starlette._utils import collapse_excgroups
from starlette.background import BackgroundTask
from starlette.requests import ClientDisconnect, Request
from starlette.responses import ContentStream, Response, StreamingResponse
from starlette.types import ASGIApp, Message, Receive, Scope, Send
-if sys.version_info < (3, 11): # pragma: no cover
- from exceptiongroup import BaseExceptionGroup
-
RequestResponseEndpoint = typing.Callable[[Request], typing.Awaitable[Response]]
DispatchFunction = typing.Callable[
[Request, RequestResponseEndpoint], typing.Awaitable[Response]
T = typing.TypeVar("T")
-@contextmanager
-def _convert_excgroups() -> typing.Generator[None, None, None]:
- try:
- yield
- except BaseException as exc:
- while isinstance(exc, BaseExceptionGroup) and len(exc.exceptions) == 1:
- exc = exc.exceptions[0]
-
- raise exc
-
-
class _CachedRequest(Request):
"""
If the user calls Request.body() from their dispatch function
response.raw_headers = message["headers"]
return response
- with _convert_excgroups():
+ with collapse_excgroups():
async with anyio.create_task_group() as task_group:
response = await self.dispatch_func(request, call_next)
await response(scope, wrapped_receive, send)
import pytest
+from starlette._utils import collapse_excgroups
from starlette.middleware.wsgi import WSGIMiddleware, build_environ
-if sys.version_info < (3, 11): # pragma: no cover
- from exceptiongroup import ExceptionGroup
-
def hello_world(environ, start_response):
status = "200 OK"
# The HTTP protocol implementations would catch this error and return 500.
app = WSGIMiddleware(raise_exception)
client = test_client_factory(app)
- with pytest.raises(ExceptionGroup) as exc:
+ with pytest.raises(RuntimeError), collapse_excgroups():
client.get("/")
- assert len(exc.value.exceptions) == 1
- assert isinstance(exc.value.exceptions[0], RuntimeError)
-
def test_wsgi_exc_info(test_client_factory):
# Note that we're testing the WSGI app directly here.