Merge branch 'custom-append-slash-redirect' of https://github.com/dstufft/pyramid into dstufft-custom-append-slash-redirect
| | |
| | | explicitly different from ``request.response``. This does not change the |
| | | API of a renderer. See https://github.com/Pylons/pyramid/pull/1563 |
| | | |
| | | - ``Configurator().add_notfound_view()`` will now accept anything that |
| | | implements the ``IResponse`` interface and will use that as the response |
| | | class instead of the default ``HTTPFound``. |
| | | |
| | | Bug Fixes |
| | | --------- |
| | | |
| | |
| | | - Geoffrey T. Dairiki, 2015/02/06 |
| | | |
| | | - David Glick, 2015/02/12 |
| | | |
| | | - Donald Stufft, 2015/03/15 |
| | |
| | | application, this view will be invoked if the value of ``PATH_INFO`` does not |
| | | already end in a slash, and if the value of ``PATH_INFO`` *plus* a slash |
| | | matches any route's pattern. In this case it does an HTTP redirect to the |
| | | slash-appended ``PATH_INFO``. |
| | | slash-appended ``PATH_INFO``. In addition you may pass anything that implements |
| | | :class:`pyramid.interfaces.IResponse` which will then be used in place of the |
| | | default class (:class:`pyramid.httpexceptions.HTTPFound`). |
| | | |
| | | Let's use an example. If the following routes are configured in your |
| | | application: |
| | |
| | | head of ``tutorial/tutorial/views.py``: |
| | | |
| | | .. literalinclude:: src/authorization/tutorial/views.py |
| | | :lines: 6-13,15-17 |
| | | :lines: 6-17 |
| | | :linenos: |
| | | :emphasize-lines: 3,6-9,11 |
| | | :emphasize-lines: 3,6-11 |
| | | :language: python |
| | | |
| | | (Only the highlighted lines, with other necessary modifications, |
| | |
| | | Pyramid will return the result of the view callable provided as |
| | | ``view``, as normal. |
| | | |
| | | If ``append_slash`` implements IResponse then that will be used as the |
| | | response class instead of the default of ``HTTPFound``. |
| | | |
| | | .. versionadded:: 1.3 |
| | | .. versionchanged:: 1.6 |
| | | """ |
| | | for arg in ('name', 'permission', 'context', 'for_', 'http_cache'): |
| | | if arg in predicates: |
| | |
| | | settings.update(predicates) |
| | | if append_slash: |
| | | view = self._derive_view(view, attr=attr, renderer=renderer) |
| | | view = AppendSlashNotFoundViewFactory(view) |
| | | if IResponse.implementedBy(append_slash): |
| | | view = AppendSlashNotFoundViewFactory( |
| | | view, redirect_class=append_slash, |
| | | ) |
| | | else: |
| | | view = AppendSlashNotFoundViewFactory(view) |
| | | settings['view'] = view |
| | | else: |
| | | settings['attr'] = attr |
| | |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import implementedBy |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.httpexceptions import HTTPNotFound |
| | | from pyramid.httpexceptions import HTTPFound, HTTPNotFound |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_route('foo', '/foo/') |
| | | def view(request): return Response('OK') |
| | |
| | | ctx_iface=implementedBy(HTTPNotFound), |
| | | request_iface=IRequest) |
| | | result = view(None, request) |
| | | self.assertTrue(isinstance(result, HTTPFound)) |
| | | self.assertEqual(result.location, '/scriptname/foo/?a=1&b=2') |
| | | |
| | | def test_add_notfound_view_append_slash_custom_response(self): |
| | | from pyramid.response import Response |
| | | from pyramid.renderers import null_renderer |
| | | from zope.interface import implementedBy |
| | | from pyramid.interfaces import IRequest |
| | | from pyramid.httpexceptions import HTTPMovedPermanently, HTTPNotFound |
| | | config = self._makeOne(autocommit=True) |
| | | config.add_route('foo', '/foo/') |
| | | def view(request): return Response('OK') |
| | | config.add_notfound_view( |
| | | view, renderer=null_renderer,append_slash=HTTPMovedPermanently |
| | | ) |
| | | request = self._makeRequest(config) |
| | | request.environ['PATH_INFO'] = '/foo' |
| | | request.query_string = 'a=1&b=2' |
| | | request.path = '/scriptname/foo' |
| | | view = self._getViewCallable(config, |
| | | ctx_iface=implementedBy(HTTPNotFound), |
| | | request_iface=IRequest) |
| | | result = view(None, request) |
| | | self.assertTrue(isinstance(result, HTTPMovedPermanently)) |
| | | self.assertEqual(result.location, '/scriptname/foo/?a=1&b=2') |
| | | |
| | | def test_add_notfound_view_with_view_defaults(self): |
| | |
| | | .. deprecated:: 1.3 |
| | | |
| | | """ |
| | | def __init__(self, notfound_view=None): |
| | | def __init__(self, notfound_view=None, redirect_class=HTTPFound): |
| | | if notfound_view is None: |
| | | notfound_view = default_exceptionresponse_view |
| | | self.notfound_view = notfound_view |
| | | self.redirect_class = redirect_class |
| | | |
| | | def __call__(self, context, request): |
| | | path = decode_path_info(request.environ['PATH_INFO'] or '/') |
| | |
| | | qs = request.query_string |
| | | if qs: |
| | | qs = '?' + qs |
| | | return HTTPFound(location=request.path+'/'+qs) |
| | | return self.redirect_class(location=request.path+'/'+qs) |
| | | return self.notfound_view(context, request) |
| | | |
| | | append_slash_notfound_view = AppendSlashNotFoundViewFactory() |
| | |
| | | |
| | | @forbidden_view_config() |
| | | def forbidden(request): |
| | | return Response('You are not allowed', status='401 Unauthorized') |
| | | return Response('You are not allowed', status='403 Forbidden') |
| | | |
| | | All arguments passed to this function have the same meaning as |
| | | :meth:`pyramid.view.view_config` and each predicate argument restricts |