Exceptions, HTTP Errors, and Redirects¶
Issuing redirects and HTTP errors¶
Here's how to send redirects and HTTP errors in Pyramid compared to Pylons:
1# Pylons -- in controller action
2from pylons.controllers.util import abort, redirect
3abort(404) # Not Found
4abort(403) # Forbidden
5abort(400) # Bad request; e.g., invalid query parameter
6abort(500) # Internal server error
7redirect(url("section1")) # Redirect (default 302 Found)
8
9# Pyramid -- in view code
10import pyramid.httpexceptions as exc
11raise exc.exception_response(404) # Not Found
12raise exc.HTTPNotFound() # Same thing
13return exc.HTTPNotFound() # Same thing
14raise exc.HTTPForbidden()
15raise exc.HTTPBadRequest()
16raise exc.HTTPInternalServerError()
17raise exc.HTTPFound(request.route_url("section1")) # Redirect
The pyramid.httpexceptions
module has classes for all official HTTP
statuses. These classes inherit from both Response
and Exception
, so
you can either return them or raise them. Raising HTTP exceptions can make
your code structurally more readable. It's particularly useful in
subroutines where it can cut through several calling stack frames that would
otherwise each need an if
to pass the error condition through.
Exception rules:
Pyramid internally raises
HTTPNotFound
if no route matches the request, or if no view matches the route and request. It raisesHTTPForbidden
if the request is denied based on the current authorization policy.If an uncaught exception occurs during request processing, Pyramid will catch it and look for an "exception view" that matches it. An exception view is one whose context argument is the exception's class, an ancestor of it, or an interface it implements. All other view predicates must also match; e.g., if a 'route_name' argument is specified, it must match the actual route name. (Thus an exception view is typically registered without a route name.) The view is called with the exception object as its context, and whatever response the view returns will be sent to the browser. You can thus use an exception view to customize the error screen shown to the user.
If no matching exception view is found, HTTP exceptions are their own response so they are sent to the browser. Standard HTTPExceptions have a simple error message and layout; subclasses can customize this.
Non-HTTPException responses propagate to the WSGI server. If the debug toolbar tween is enabled, it will catch the exception and display the interactive traceback. Otherwise the WSGI server will catch it and send its own "500 Internal Server Error" screen.
Here are the most popular HTTP exceptions:
Class |
Code |
Location |
Meaning |
---|---|---|---|
HTTPMovedPermanently |
301 |
Y |
Permanent redirect; client should change bookmarks. |
HTTPFound |
302 |
Y |
Temporary redirect. 1 |
HTTPSeeOther |
303 |
Y |
Temporary redirect; client should use GET. 1 |
HTTPTemporaryRedirect |
307 |
Y |
Temporary redirect. 1 |
HTTPClientError |
400 |
N |
General user error; e.g., invalid query param. |
HTTPUnauthorized |
401 |
N |
User must authenticate. |
HTTPForbidden |
403 |
N |
Authorization failure, or general refusal. |
HTTPNotFound |
404 |
N |
The URL is not recognized. |
HTTPGone |
410 |
N |
The resource formerly at this URL is permanently gone; client should delete bookmarks. |
HTTPInternalServerError |
500 |
N |
The server could not process the request due to an internal error. |
The constructor args for classes with a "Y" in the location column are
(location="", detail=None, headers=None, comment=None, ...)
. Otherwise the
constructor args are (detail=None, headers=None, comment=None, ...)
.
The location
argument is optional at the Python level, but the HTTP spec
requires a location that's an absolute URL, so it's effectively required.
The detail
argument may be a plain-text string which will be incorporated
into the error screen. headers
may be a list of HTTP headers (name-value
tuples) to add to the response. comment
may be a plain-text string which is
not shown to the user. (XXX Is it logged?)
Exception views¶
You can register an exception view for any exception class, although it's most
commonly used with HTTPNotFound
or HTTPForbidden
. Here's an example of
an exception view with a custom exception, borrowed from the Pyramid manual:
1from pyramid.response import Response
2
3class ValidationFailure(Exception):
4 pass
5
6@view_config(context=ValidationFailure)
7def failed_validation(exc, request):
8 # If the view has two formal arguments, the first is the context.
9 # The context is always available as ``request.context`` too.
10 msg = exc.args[0] if exc.args else ""
11 response = Response('Failed validation: %s' % msg)
12 response.status_int = 500
13 return response
For convenience, Pyramid has special decorators and configurator methods to
register a "Not Found" view or a "Forbidden" view. @notfound_view_config
and @forbidden_view_config
(defined in pyramid.view
) takes care of the
context argument for you.
Additionally, @notfound_view_config
accepts an append_slash
argument,
which can be used to enforce a trailing-slash convention. If your site defines
all its routes to end in a slash and you set append_slash=True
, then when
a slashless request doesn't match any route, Pyramid try again with a slash
appended to the request URL. If that matches a route, Pyramid will issue a
redirect to it. This is useful only for sites that prefer a trailing slash
("/dir/" and "/dir/a/"). Other sites prefer not to have a trailing slash
("/dir" and "/dir/a"), and there are no special features for this.