Chris McDonough
2013-08-30 97ed56d766298ee042305ff8712df5f1fc3fbe3a
allow exception view registrations for HTTPException to override default exception view; closes #985
6 files modified
45 ■■■■ changed files
CHANGES.txt 5 ●●●●● patch | view | raw | blame | history
pyramid/httpexceptions.py 15 ●●●● patch | view | raw | blame | history
pyramid/tests/pkgs/exceptionviewapp/__init__.py 8 ●●●●● patch | view | raw | blame | history
pyramid/tests/pkgs/exceptionviewapp/views.py 7 ●●●●● patch | view | raw | blame | history
pyramid/tests/test_httpexceptions.py 6 ●●●● patch | view | raw | blame | history
pyramid/tests/test_integration.py 4 ●●●● patch | view | raw | blame | history
CHANGES.txt
@@ -163,6 +163,11 @@
Bug Fixes
---------
- It was not possible to use ``pyramid.httpexceptions.HTTPException`` as
  the ``context`` of an exception view as very general catchall for
  http-related exceptions when you wanted that exception view to override the
  default exception view.  See https://github.com/Pylons/pyramid/issues/985
- When the ``pyramid.reload_templates`` setting was true, and a Chameleon 
  template was reloaded, and the renderer specification named a macro 
  (e.g. ``foo#macroname.pt``), renderings of the template after the template
pyramid/httpexceptions.py
@@ -149,11 +149,8 @@
            value = text_type(value)
    return value
class HTTPException(Exception): # bw compat
    """ Base class for all :term:`exception response` objects."""
@implementer(IExceptionResponse)
class WSGIHTTPException(Response, HTTPException):
class HTTPException(Response, Exception):
    ## You should set in subclasses:
    # code = 200
@@ -253,7 +250,7 @@
                'html_comment':html_comment,
                }
            body_tmpl = self.body_template_obj
            if WSGIHTTPException.body_template_obj is not body_tmpl:
            if HTTPException.body_template_obj is not body_tmpl:
                # Custom template; add headers to args
                for k, v in environ.items():
                    if (not k.startswith('wsgi.')) and ('.' in k):
@@ -289,7 +286,9 @@
        self.prepare(environ)
        return Response.__call__(self, environ, start_response)
class HTTPError(WSGIHTTPException):
WSGIHTTPException = HTTPException # b/c post 1.5
class HTTPError(HTTPException):
    """
    base class for exceptions with status codes in the 400s and 500s
@@ -297,7 +296,7 @@
    and that any work in progress should not be committed.  
    """
class HTTPRedirection(WSGIHTTPException):
class HTTPRedirection(HTTPException):
    """
    base class for exceptions with status codes in the 300s (redirections)
@@ -307,7 +306,7 @@
    condition.
    """
class HTTPOk(WSGIHTTPException):
class HTTPOk(HTTPException):
    """
    Base class for exceptions with status codes in the 200s (successful
    responses)
pyramid/tests/pkgs/exceptionviewapp/__init__.py
@@ -1,5 +1,8 @@
from pyramid.httpexceptions import HTTPException
def includeme(config):
    config.add_route('route_raise_exception', 'route_raise_exception')
    config.add_route('route_raise_httpexception', 'route_raise_httpexception')
    config.add_route('route_raise_exception2', 'route_raise_exception2',
                     factory='.models.route_factory')
    config.add_route('route_raise_exception3', 'route_raise_exception3',
@@ -21,3 +24,8 @@
                    route_name='route_raise_exception4')
    config.add_view('.views.whoa', context='.models.AnException',
                    route_name='route_raise_exception4')
    config.add_view('.views.raise_httpexception',
                    route_name='route_raise_httpexception')
    config.add_view('.views.catch_httpexception', context=HTTPException)
pyramid/tests/pkgs/exceptionviewapp/views.py
@@ -1,5 +1,6 @@
from webob import Response
from .models import AnException
from pyramid.httpexceptions import HTTPBadRequest
def no(request):
    return Response('no')
@@ -15,3 +16,9 @@
def raise_exception(request):
    raise AnException()
def raise_httpexception(request):
    raise HTTPBadRequest
def catch_httpexception(request):
    return Response('caught')
pyramid/tests/test_httpexceptions.py
@@ -57,10 +57,10 @@
        duo = DummyUnicodeObject()
        self.assertEqual(self._callFUT(duo), text_('42'))
class TestWSGIHTTPException(unittest.TestCase):
class TestHTTPException(unittest.TestCase):
    def _getTargetClass(self):
        from pyramid.httpexceptions import WSGIHTTPException
        return WSGIHTTPException
        from pyramid.httpexceptions import HTTPException
        return HTTPException
    def _getTargetSubclass(self, code='200', title='OK',
                           explanation='explanation', empty_body=False):
pyramid/tests/test_integration.py
@@ -465,6 +465,10 @@
        res = self.testapp.get('/route_raise_exception4', status=200)
        self.assertTrue(b'whoa' in res.body)
    def test_raise_httpexception(self):
        res = self.testapp.get('/route_raise_httpexception', status=200)
        self.assertTrue(b'caught' in res.body)
class TestConflictApp(unittest.TestCase):
    package = 'pyramid.tests.pkgs.conflictapp'
    def _makeConfig(self):