Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update exception handler signature to reflect HTTPConnection #1440

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/exceptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ exception_handlers = {
app = Starlette(routes=routes, exception_handlers=exception_handlers)
```

Exception handlers have the callable signature of `handler(conn, exception) -> response` and
the conn is an `HTTPConnection` or it's subclasses either `Request` or `WebSocket` instance.

If `debug` is enabled and an error occurs, then instead of using the installed
500 handler, Starlette will respond with a traceback response.

Expand Down
19 changes: 8 additions & 11 deletions starlette/applications.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@
from starlette.middleware import Middleware
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.middleware.errors import ServerErrorMiddleware
from starlette.requests import Request
from starlette.requests import HTTPConnection
from starlette.responses import Response
from starlette.routing import BaseRoute, Router
from starlette.types import ASGIApp, Receive, Scope, Send

_TYPE_EXCEPTION_HANDLER = typing.Callable[
[HTTPConnection, Exception], typing.Union[Response, typing.Awaitable[Response]]
]


class Starlette:
"""
Expand All @@ -28,7 +32,7 @@ class Starlette:
* **exception_handlers** - A mapping of either integer status codes,
or exception class types onto callables which handle the exceptions.
Exception handler callables should be of the form
`handler(request, exc) -> response` and may be be either standard functions, or
`handler(conn, exc) -> response` and may be be either standard functions, or
async functions.
* **on_startup** - A list of callables to run on application startup.
Startup handler callables do not take any arguments, and may be be either
Expand All @@ -43,12 +47,7 @@ def __init__(
debug: bool = False,
routes: typing.Sequence[BaseRoute] = None,
middleware: typing.Sequence[Middleware] = None,
exception_handlers: typing.Mapping[
typing.Any,
typing.Callable[
[Request, Exception], typing.Union[Response, typing.Awaitable[Response]]
],
] = None,
exception_handlers: typing.Mapping[typing.Any, _TYPE_EXCEPTION_HANDLER] = None,
on_startup: typing.Sequence[typing.Callable] = None,
on_shutdown: typing.Sequence[typing.Callable] = None,
lifespan: typing.Callable[["Starlette"], typing.AsyncContextManager] = None,
Expand All @@ -73,9 +72,7 @@ def __init__(
def build_middleware_stack(self) -> ASGIApp:
debug = self.debug
error_handler = None
exception_handlers: typing.Dict[
typing.Any, typing.Callable[[Request, Exception], Response]
] = {}
exception_handlers: typing.Dict[typing.Any, _TYPE_EXCEPTION_HANDLER] = {}

for key, value in self.exception_handlers.items():
if key in (500, Exception):
Expand Down
11 changes: 6 additions & 5 deletions tests/test_exceptions.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
import pytest

from starlette.exceptions import ExceptionMiddleware, HTTPException
from starlette.requests import HTTPConnection
from starlette.responses import PlainTextResponse
from starlette.routing import Route, Router, WebSocketRoute


def raise_runtime_error(request):
def raise_runtime_error(conn: HTTPConnection):
raise RuntimeError("Yikes")


def not_acceptable(request):
def not_acceptable(conn: HTTPConnection):
raise HTTPException(status_code=406)


def no_content(request):
def no_content(conn: HTTPConnection):
raise HTTPException(status_code=204)


def not_modified(request):
def not_modified(conn: HTTPConnection):
raise HTTPException(status_code=304)


def with_headers(request):
def with_headers(conn: HTTPConnection):
raise HTTPException(status_code=200, headers={"x-potato": "always"})


Expand Down