From 1ffb8e3cc21603b29ccd78152f82cca7f61a09b1 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Mon, 16 May 2011 02:11:56 -0400 Subject: - Added API docs for ``pyramid.httpexceptions.abort`` and ``pyramid.httpexceptions.redirect``. - Added "HTTP Exceptions" section to Views narrative chapter including a description of ``pyramid.httpexceptions.abort``; adjusted redirect section to note ``pyramid.httpexceptions.redirect``. - A default exception view for the context ``webob.exc.HTTPException`` (aka ``pyramid.httpexceptions.HTTPException``) is now registered by default. This means that an instance of any exception class imported from ``pyramid.httpexceptions`` (such as ``HTTPFound``) can now be raised from within view code; when raised, this exception view will render the exception to a response. - New functions named ``pyramid.httpexceptions.abort`` and ``pyramid.httpexceptions.redirect`` perform the equivalent of their Pylons brethren when an HTTP exception handler is registered. These functions take advantage of the newly registered exception view for ``webob.exc.HTTPException``. - The Configurator now accepts an additional keyword argument named ``httpexception_view``. By default, this argument is populated with a default exception view function that will be used when an HTTP exception is raised. When ``None`` is passed for this value, an exception view for HTTP exceptions will not be registered. Passing ``None`` returns the behavior of raising an HTTP exception to that of Pyramid 1.0 (the exception will propagate to middleware and to the WSGI server). --- docs/narr/views.rst | 249 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 179 insertions(+), 70 deletions(-) (limited to 'docs/narr') diff --git a/docs/narr/views.rst b/docs/narr/views.rst index 5c9bd91af..465cd3c0d 100644 --- a/docs/narr/views.rst +++ b/docs/narr/views.rst @@ -51,14 +51,14 @@ the request object contains everything your application needs to know about the specific HTTP request being made. A view callable's ultimate responsibility is to create a :mod:`Pyramid` -:term:`Response` object. This can be done by creating the response -object in the view callable code and returning it directly, as we will -be doing in this chapter. However, if a view callable does not return a -response itself, it can be configured to use a :term:`renderer` that -converts its return value into a :term:`Response` object. Using -renderers is the common way that templates are used with view callables -to generate markup. See the :ref:`renderers_chapter` chapter for -details. +:term:`Response` object. This can be done by creating the response object in +the view callable code and returning it directly, as we will be doing in this +chapter. However, if a view callable does not return a response itself, it +can be configured to use a :term:`renderer` that converts its return value +into a :term:`Response` object. Using renderers is the common way that +templates are used with view callables to generate markup: see the +:ref:`renderers_chapter` chapter for details. In some cases, a response may +also be generated by raising an exception within a view callable. .. index:: single: view calling convention @@ -234,8 +234,8 @@ You don't need to always use :class:`~pyramid.response.Response` to represent a response. :app:`Pyramid` provides a range of different "exception" classes which can act as response objects too. For example, an instance of the class :class:`pyramid.httpexceptions.HTTPFound` is also a valid response object -(see :ref:`http_redirect`). A view can actually return any object that has -the following attributes. +(see :ref:`http_exceptions` and ref:`http_redirect`). A view can actually +return any object that has the following attributes. status The HTTP status code (including the name) for the response as a string. @@ -254,46 +254,6 @@ app_iter These attributes form the structure of the "Pyramid Response interface". -.. index:: - single: view http redirect - single: http redirect (from a view) - -.. _http_redirect: - -Using a View Callable to Do an HTTP Redirect --------------------------------------------- - -You can issue an HTTP redirect from within a view by returning a particular -kind of response. - -.. code-block:: python - :linenos: - - from pyramid.httpexceptions import HTTPFound - - def myview(request): - return HTTPFound(location='http://example.com') - -All exception types from the :mod:`pyramid.httpexceptions` module implement -the :term:`Response` interface; any can be returned as the response from a -view. See :mod:`pyramid.httpexceptions` for the documentation for the -``HTTPFound`` exception; it also includes other response types that imply -other HTTP response codes, such as ``HTTPUnauthorized`` for ``401 -Unauthorized``. - -.. note:: - - Although exception types from the :mod:`pyramid.httpexceptions` module are - in fact bona fide Python :class:`Exception` types, the :app:`Pyramid` view - machinery expects them to be *returned* by a view callable rather than - *raised*. - - It is possible, however, in Python 2.5 and above, to configure an - *exception view* to catch these exceptions, and return an appropriate - :class:`~pyramid.response.Response`. The simplest such view could just - catch and return the original exception. See :ref:`exception_views` for - more details. - .. index:: single: view exceptions @@ -304,13 +264,21 @@ Using Special Exceptions In View Callables Usually when a Python exception is raised within a view callable, :app:`Pyramid` allows the exception to propagate all the way out to the -:term:`WSGI` server which invoked the application. +:term:`WSGI` server which invoked the application. It is usually caught and +logged there. -However, for convenience, two special exceptions exist which are always -handled by :app:`Pyramid` itself. These are -:exc:`pyramid.exceptions.NotFound` and :exc:`pyramid.exceptions.Forbidden`. -Both are exception classes which accept a single positional constructor -argument: a ``message``. +However, for convenience, a special set of exceptions exists. When one of +these exceptions is raised within a view callable, it will always cause +:app:`Pyramid` to generate a response. Two categories of special exceptions +exist: internal exceptions and HTTP exceptions. + +Internal Exceptions +~~~~~~~~~~~~~~~~~~~ + +:exc:`pyramid.exceptions.NotFound` and :exc:`pyramid.exceptions.Forbidden` +are exceptions often raised by Pyramid itself when it (respectively) cannot +find a view to service a request or when authorization was forbidden by a +security policy. However, they can also be raised by application developers. If :exc:`~pyramid.exceptions.NotFound` is raised within view code, the result of the :term:`Not Found View` will be returned to the user agent which @@ -320,22 +288,100 @@ If :exc:`~pyramid.exceptions.Forbidden` is raised within view code, the result of the :term:`Forbidden View` will be returned to the user agent which performed the request. -In all cases, the message provided to the exception constructor is made -available to the view which :app:`Pyramid` invokes as +Both are exception classes which accept a single positional constructor +argument: a ``message``. In all cases, the message provided to the exception +constructor is made available to the view which :app:`Pyramid` invokes as ``request.exception.args[0]``. +An example: + +.. code-block:: python + :linenos: + + from pyramid.exceptions import NotFound + + def aview(request): + raise NotFound('not found!') + +Internal exceptions may not be *returned* in order to generate a response, +they must always be *raised*. + +.. index:: + single: HTTP exceptions + +.. _http_exceptions: + +HTTP Exceptions +~~~~~~~~~~~~~~~ + +All exception classes documented in the :mod:`pyramid.httpexceptions` module +implement the :term:`Response` interface; an instance of any of these classes +can be returned or raised from within a view. The instance will be used as +as the view's response. + +For example, the :class:`pyramid.httpexceptions.HTTPUnauthorized` exception +can be raised. This will cause a response to be generated with a ``401 +Unauthorized`` status: + +.. code-block:: python + :linenos: + + from pyramid.httpexceptions import HTTPUnauthorized + + def aview(request): + raise HTTPUnauthorized() + +A shortcut for importing and raising an HTTP exception is the +:func:`pyramid.httpexceptions.abort` function. This function accepts an HTTP +status code and raises the corresponding HTTP exception. For example, to +raise HTTPUnauthorized, instead of the above, you could do: + +.. code-block:: python + :linenos: + + from pyramid.httpexceptions import abort + + def aview(request): + abort(401) + +This is the case because ``401`` is the HTTP status code for "HTTP +Unauthorized". Therefore, ``abort(401)`` is functionally equivalent to +``raise HTTPUnauthorized()``. Other exceptions in +:mod:`pyramid.httpexceptions` can be raised via +:func:`pyramid.httpexceptions.abort` as well, as long as the status code +associated with the exception is provided to the function. + +An HTTP exception, instead of being raised, can alternately be *returned* +(HTTP exceptions are also valid response objects): + +.. code-block:: python + :linenos: + + from pyramid.httpexceptions import HTTPUnauthorized + + def aview(request): + return HTTPUnauthorized() + +Note that :class:`pyramid.exceptions.NotFound` is *not* the same as +:class:`pyramid.httpexceptions.HTTPNotFound`. If the latter is raised, the +:term:`Not Found view` will *not* be called automatically. Likewise, +:class:`pyramid.exceptions.Foribdden` is not the same exception as +:class:`pyramid.httpexceptions.HTTPForbidden`. If the latter is raised, the +:term:`Forbidden view` will not be called automatically. + .. index:: single: exception views .. _exception_views: -Exception Views ---------------- +Custom Exception Views +---------------------- -The machinery which allows the special :exc:`~pyramid.exceptions.NotFound` and -:exc:`~pyramid.exceptions.Forbidden` exceptions to be caught by specialized -views as described in :ref:`special_exceptions_in_callables` can also be used -by application developers to convert arbitrary exceptions to responses. +The machinery which allows :exc:`~pyramid.exceptions.NotFound`, +:exc:`~pyramid.exceptions.Forbidden` and HTTP exceptions to be caught by +specialized views as described in :ref:`special_exceptions_in_callables` can +also be used by application developers to convert arbitrary exceptions to +responses. To register a view that should be called whenever a particular exception is raised from with :app:`Pyramid` view code, use the exception class or one of @@ -359,6 +405,7 @@ raises a ``helloworld.exceptions.ValidationFailure`` exception: .. code-block:: python :linenos: + from pyramid.view import view_config from helloworld.exceptions import ValidationFailure @view_config(context=ValidationFailure) @@ -380,12 +427,13 @@ exception view registration: :linenos: from pyramid.view import view_config - from pyramid.exceptions import NotFound - from pyramid.httpexceptions import HTTPNotFound + from helloworld.exceptions import ValidationFailure - @view_config(context=NotFound, route_name='home') - def notfound_view(request): - return HTTPNotFound() + @view_config(context=ValidationFailure, route_name='home') + def failed_validation(exc, request): + response = Response('Failed validation: %s' % exc.msg) + response.status_int = 500 + return response The above exception view names the ``route_name`` of ``home``, meaning that it will only be called when the route matched has a name of ``home``. You @@ -407,7 +455,68 @@ exception views which have a name will be ignored. can use an exception as ``context`` for a normal view. Exception views can be configured with any view registration mechanism: -``@view_config`` decorator, ZCML, or imperative ``add_view`` styles. +``@view_config`` decorator or imperative ``add_view`` styles. + +.. index:: + single: view http redirect + single: http redirect (from a view) + +.. _http_redirect: + +Using a View Callable to Do an HTTP Redirect +-------------------------------------------- + +Two methods exist to redirect to another URL from within a view callable: a +short form and a long form. The short form should be preferred when +possible. + +Short Form +~~~~~~~~~~ + +You can issue an HTTP redirect from within a view callable by using the +:func:`pyramid.httpexceptions.redirect` function. This function raises an +:class:`pyramid.httpexceptions.HTTPFound` exception (a "302"), which is +caught by an exception handler and turned into a response. + +.. code-block:: python + :linenos: + + from pyramid.httpexceptions import redirect + + def myview(request): + redirect('http://example.com') + +Long Form +~~~~~~~~~ + +You can issue an HTTP redirect from within a view "by hand" instead of +relying on the :func:`pyramid.httpexceptions.redirect` function to do it for +you. + +To do so, you can *return* a :class:`pyramid.httpexceptions.HTTPFound` +instance. + +.. code-block:: python + :linenos: + + from pyramid.httpexceptions import HTTPFound + + def myview(request): + return HTTPFound(location='http://example.com') + +Or, alternately, you can *raise* an HTTPFound exception instead of returning +one. + +.. code-block:: python + :linenos: + + from pyramid.httpexceptions import HTTPFound + + def myview(request): + raise HTTPFound(location='http://example.com') + +The above form of generating a response by raising HTTPFound is completely +equivalent to ``redirect('http://example.com')``. .. index:: single: unicode, views, and forms -- cgit v1.2.3 From e1e0df9ff85d5d31b355527549e0b5654cce3af9 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Mon, 16 May 2011 02:19:37 -0400 Subject: typo --- docs/narr/views.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr') diff --git a/docs/narr/views.rst b/docs/narr/views.rst index 465cd3c0d..66e9919e2 100644 --- a/docs/narr/views.rst +++ b/docs/narr/views.rst @@ -365,7 +365,7 @@ An HTTP exception, instead of being raised, can alternately be *returned* Note that :class:`pyramid.exceptions.NotFound` is *not* the same as :class:`pyramid.httpexceptions.HTTPNotFound`. If the latter is raised, the :term:`Not Found view` will *not* be called automatically. Likewise, -:class:`pyramid.exceptions.Foribdden` is not the same exception as +:class:`pyramid.exceptions.Forbidden` is not the same exception as :class:`pyramid.httpexceptions.HTTPForbidden`. If the latter is raised, the :term:`Forbidden view` will not be called automatically. -- cgit v1.2.3 From a7e625785f65c41e5a6dc017b31bd0d74821474e Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Tue, 31 May 2011 14:40:05 -0400 Subject: the canonical import location for HTTP exceptions/responses is now pyramid.response --- docs/narr/hooks.rst | 48 +++++++++++++-------------- docs/narr/renderers.rst | 31 ++++++++++++------ docs/narr/router.rst | 53 +++++++++++++++--------------- docs/narr/testing.rst | 13 ++++---- docs/narr/urldispatch.rst | 6 ++-- docs/narr/views.rst | 82 +++++++++++++++++++++-------------------------- docs/narr/webob.rst | 36 ++++----------------- 7 files changed, 124 insertions(+), 145 deletions(-) (limited to 'docs/narr') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 7e3fe0a5c..d620b5672 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -21,7 +21,7 @@ configuration. The :term:`not found view` callable is a view callable like any other. The :term:`view configuration` which causes it to be a "not found" view consists -only of naming the :exc:`pyramid.exceptions.NotFound` class as the +only of naming the :exc:`pyramid.response.HTTPNotFound` class as the ``context`` of the view configuration. If your application uses :term:`imperative configuration`, you can replace @@ -31,9 +31,9 @@ method to register an "exception view": .. code-block:: python :linenos: - from pyramid.exceptions import NotFound + from pyramid.response import HTTPNotFound from helloworld.views import notfound_view - config.add_view(notfound_view, context=NotFound) + config.add_view(notfound_view, context=HTTPNotFound) Replace ``helloworld.views.notfound_view`` with a reference to the :term:`view callable` you want to use to represent the Not Found view. @@ -42,7 +42,7 @@ Like any other view, the notfound view must accept at least a ``request`` parameter, or both ``context`` and ``request``. The ``request`` is the current :term:`request` representing the denied action. The ``context`` (if used in the call signature) will be the instance of the -:exc:`~pyramid.exceptions.NotFound` exception that caused the view to be +:exc:`~pyramid.response.HTTPNotFound` exception that caused the view to be called. Here's some sample code that implements a minimal NotFound view callable: @@ -50,25 +50,25 @@ Here's some sample code that implements a minimal NotFound view callable: .. code-block:: python :linenos: - from pyramid.httpexceptions import HTTPNotFound + from pyramid.response import HTTPNotFound def notfound_view(request): return HTTPNotFound() .. note:: When a NotFound view callable is invoked, it is passed a - :term:`request`. The ``exception`` attribute of the request will - be an instance of the :exc:`~pyramid.exceptions.NotFound` - exception that caused the not found view to be called. The value - of ``request.exception.args[0]`` will be a value explaining why the - not found error was raised. This message will be different when - the ``debug_notfound`` environment setting is true than it is when - it is false. + :term:`request`. The ``exception`` attribute of the request will be an + instance of the :exc:`~pyramid.response.HTTPNotFound` exception that + caused the not found view to be called. The value of + ``request.exception.args[0]`` will be a value explaining why the not found + error was raised. This message will be different when the + ``debug_notfound`` environment setting is true than it is when it is + false. .. warning:: When a NotFound view callable accepts an argument list as described in :ref:`request_and_context_view_definitions`, the ``context`` passed as the first argument to the view callable will be the - :exc:`~pyramid.exceptions.NotFound` exception instance. If available, the - resource context will still be available as ``request.context``. + :exc:`~pyramid.response.HTTPNotFound` exception instance. If available, + the resource context will still be available as ``request.context``. .. index:: single: forbidden view @@ -85,7 +85,7 @@ the view which generates it can be overridden as necessary. The :term:`forbidden view` callable is a view callable like any other. The :term:`view configuration` which causes it to be a "not found" view consists -only of naming the :exc:`pyramid.exceptions.Forbidden` class as the +only of naming the :exc:`pyramid.response.HTTPForbidden` class as the ``context`` of the view configuration. You can replace the forbidden view by using the @@ -96,8 +96,8 @@ view": :linenos: from helloworld.views import forbidden_view - from pyramid.exceptions import Forbidden - config.add_view(forbidden_view, context=Forbidden) + from pyramid.response import HTTPForbidden + config.add_view(forbidden_view, context=HTTPForbidden) Replace ``helloworld.views.forbidden_view`` with a reference to the Python :term:`view callable` you want to use to represent the Forbidden view. @@ -121,13 +121,13 @@ Here's some sample code that implements a minimal forbidden view: return Response('forbidden') .. note:: When a forbidden view callable is invoked, it is passed a - :term:`request`. The ``exception`` attribute of the request will - be an instance of the :exc:`~pyramid.exceptions.Forbidden` - exception that caused the forbidden view to be called. The value - of ``request.exception.args[0]`` will be a value explaining why the - forbidden was raised. This message will be different when the - ``debug_authorization`` environment setting is true than it is when - it is false. + :term:`request`. The ``exception`` attribute of the request will be an + instance of the :exc:`~pyramid.response.HTTPForbidden` exception that + caused the forbidden view to be called. The value of + ``request.exception.args[0]`` will be a value explaining why the forbidden + was raised. This message will be different when the + ``debug_authorization`` environment setting is true than it is when it is + false. .. index:: single: request factory diff --git a/docs/narr/renderers.rst b/docs/narr/renderers.rst index c3533648b..c7a3d7837 100644 --- a/docs/narr/renderers.rst +++ b/docs/narr/renderers.rst @@ -73,30 +73,43 @@ When this configuration is added to an application, the which renders view return values to a :term:`JSON` response serialization. Other built-in renderers include renderers which use the :term:`Chameleon` -templating language to render a dictionary to a response. +templating language to render a dictionary to a response. Additional +renderers can be added by developers to the system as necessary (see +:ref:`adding_and_overriding_renderers`). + +Views which use a renderer can vary non-body response attributes (such as +headers and the HTTP status code) by attaching a property to the +``request.response`` attribute See :ref:`request_response_attr`. If the :term:`view callable` associated with a :term:`view configuration` returns a Response object directly (an object with the attributes ``status``, ``headerlist`` and ``app_iter``), any renderer associated with the view configuration is ignored, and the response is passed back to :app:`Pyramid` unchanged. For example, if your view callable returns an instance of the -:class:`pyramid.httpexceptions.HTTPFound` class as a response, no renderer -will be employed. +:class:`pyramid.response.HTTPFound` class as a response, no renderer will be +employed. .. code-block:: python :linenos: - from pyramid.httpexceptions import HTTPFound + from pyramid.response import HTTPFound def view(request): return HTTPFound(location='http://example.com') # any renderer avoided -Views which use a renderer can vary non-body response attributes (such as -headers and the HTTP status code) by attaching a property to the -``request.response`` attribute See :ref:`request_response_attr`. +Likewise for a "plain old response": + +.. code-block:: python + :linenos: + + from pyramid.response import Response + + def view(request): + return Response('OK') # any renderer avoided -Additional renderers can be added by developers to the system as necessary -(see :ref:`adding_and_overriding_renderers`). +Mutations to ``request.response`` in views which return a Response object +like this directly (unless that response *is* ``request.response``) will be +ignored. .. index:: single: renderers (built-in) diff --git a/docs/narr/router.rst b/docs/narr/router.rst index 11f84d4ea..44fa9835b 100644 --- a/docs/narr/router.rst +++ b/docs/narr/router.rst @@ -77,40 +77,37 @@ processing? #. A :class:`~pyramid.events.ContextFound` :term:`event` is sent to any subscribers. -#. :app:`Pyramid` looks up a :term:`view` callable using the - context, the request, and the view name. If a view callable - doesn't exist for this combination of objects (based on the type of - the context, the type of the request, and the value of the view - name, and any :term:`predicate` attributes applied to the view - configuration), :app:`Pyramid` raises a - :class:`~pyramid.exceptions.NotFound` exception, which is meant - to be caught by a surrounding exception handler. +#. :app:`Pyramid` looks up a :term:`view` callable using the context, the + request, and the view name. If a view callable doesn't exist for this + combination of objects (based on the type of the context, the type of the + request, and the value of the view name, and any :term:`predicate` + attributes applied to the view configuration), :app:`Pyramid` raises a + :class:`~pyramid.response.HTTPNotFound` exception, which is meant to be + caught by a surrounding exception handler. #. If a view callable was found, :app:`Pyramid` attempts to call the view function. -#. If an :term:`authorization policy` is in use, and the view was - protected by a :term:`permission`, :app:`Pyramid` passes the - context, the request, and the view_name to a function which - determines whether the view being asked for can be executed by the - requesting user, based on credential information in the request and - security information attached to the context. If it returns - ``True``, :app:`Pyramid` calls the view callable to obtain a - response. If it returns ``False``, it raises a - :class:`~pyramid.exceptions.Forbidden` exception, which is meant - to be called by a surrounding exception handler. +#. If an :term:`authorization policy` is in use, and the view was protected + by a :term:`permission`, :app:`Pyramid` passes the context, the request, + and the view_name to a function which determines whether the view being + asked for can be executed by the requesting user, based on credential + information in the request and security information attached to the + context. If it returns ``True``, :app:`Pyramid` calls the view callable + to obtain a response. If it returns ``False``, it raises a + :class:`~pyramid.response.HTTPForbidden` exception, which is meant to be + called by a surrounding exception handler. #. If any exception was raised within a :term:`root factory`, by - :term:`traversal`, by a :term:`view callable` or by - :app:`Pyramid` itself (such as when it raises - :class:`~pyramid.exceptions.NotFound` or - :class:`~pyramid.exceptions.Forbidden`), the router catches the - exception, and attaches it to the request as the ``exception`` - attribute. It then attempts to find a :term:`exception view` for - the exception that was caught. If it finds an exception view - callable, that callable is called, and is presumed to generate a - response. If an :term:`exception view` that matches the exception - cannot be found, the exception is reraised. + :term:`traversal`, by a :term:`view callable` or by :app:`Pyramid` itself + (such as when it raises :class:`~pyramid.response.HTTPNotFound` or + :class:`~pyramid.response.HTTPForbidden`), the router catches the + exception, and attaches it to the request as the ``exception`` attribute. + It then attempts to find a :term:`exception view` for the exception that + was caught. If it finds an exception view callable, that callable is + called, and is presumed to generate a response. If an :term:`exception + view` that matches the exception cannot be found, the exception is + reraised. #. The following steps occur only when a :term:`response` could be successfully generated by a normal :term:`view callable` or an diff --git a/docs/narr/testing.rst b/docs/narr/testing.rst index bd45388c2..862eda9f0 100644 --- a/docs/narr/testing.rst +++ b/docs/narr/testing.rst @@ -191,11 +191,11 @@ function. :linenos: from pyramid.security import has_permission - from pyramid.exceptions import Forbidden + from pyramid.response import HTTPForbidden def view_fn(request): if not has_permission('edit', request.context, request): - raise Forbidden + raise HTTPForbidden return {'greeting':'hello'} Without doing anything special during a unit test, the call to @@ -207,7 +207,7 @@ application registry is not created and populated (e.g. by initializing the configurator with an authorization policy), like when you invoke application code via a unit test, :app:`Pyramid` API functions will tend to either fail or return default results. So how do you test the branch of the code in this -view function that raises :exc:`Forbidden`? +view function that raises :exc:`HTTPForbidden`? The testing API provided by :app:`Pyramid` allows you to simulate various application registry registrations for use under a unit testing framework @@ -230,16 +230,15 @@ without needing to invoke the actual application configuration implied by its testing.tearDown() def test_view_fn_forbidden(self): - from pyramid.exceptions import Forbidden + from pyramid.response import HTTPForbidden from my.package import view_fn self.config.testing_securitypolicy(userid='hank', permissive=False) request = testing.DummyRequest() request.context = testing.DummyResource() - self.assertRaises(Forbidden, view_fn, request) + self.assertRaises(HTTPForbidden, view_fn, request) def test_view_fn_allowed(self): - from pyramid.exceptions import Forbidden from my.package import view_fn self.config.testing_securitypolicy(userid='hank', permissive=True) @@ -265,7 +264,7 @@ We call the function being tested with the manufactured request. When the function is called, :func:`pyramid.security.has_permission` will call the "dummy" authentication policy we've registered through :meth:`~pyramid.config.Configuration.testing_securitypolicy`, which denies -access. We check that the view function raises a :exc:`Forbidden` error. +access. We check that the view function raises a :exc:`HTTPForbidden` error. The second test method, named ``test_view_fn_allowed`` tests the alternate case, where the authentication policy allows access. Notice that we pass diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst index 5df1eb3af..e5228b81e 100644 --- a/docs/narr/urldispatch.rst +++ b/docs/narr/urldispatch.rst @@ -917,7 +917,7 @@ the application's startup configuration, adding the following stanza: :linenos: config.add_view('pyramid.view.append_slash_notfound_view', - context='pyramid.exceptions.NotFound') + context='pyramid.response.HTTPNotFound') See :ref:`view_module` and :ref:`changing_the_notfound_view` for more information about the slash-appending not found view and for a more general @@ -945,14 +945,14 @@ view as the first argument to its constructor. For instance: .. code-block:: python :linenos: - from pyramid.exceptions import NotFound + from pyramid.response import HTTPNotFound from pyramid.view import AppendSlashNotFoundViewFactory def notfound_view(context, request): return HTTPNotFound('It aint there, stop trying!') custom_append_slash = AppendSlashNotFoundViewFactory(notfound_view) - config.add_view(custom_append_slash, context=NotFound) + config.add_view(custom_append_slash, context=HTTPNotFound) The ``notfound_view`` supplied must adhere to the two-argument view callable calling convention of ``(context, request)`` (``context`` will be the diff --git a/docs/narr/views.rst b/docs/narr/views.rst index 66e9919e2..73a7c2e2a 100644 --- a/docs/narr/views.rst +++ b/docs/narr/views.rst @@ -233,7 +233,7 @@ implements the :term:`Response` interface is to return a You don't need to always use :class:`~pyramid.response.Response` to represent a response. :app:`Pyramid` provides a range of different "exception" classes which can act as response objects too. For example, an instance of the class -:class:`pyramid.httpexceptions.HTTPFound` is also a valid response object +:class:`pyramid.response.HTTPFound` is also a valid response object (see :ref:`http_exceptions` and ref:`http_redirect`). A view can actually return any object that has the following attributes. @@ -275,17 +275,18 @@ exist: internal exceptions and HTTP exceptions. Internal Exceptions ~~~~~~~~~~~~~~~~~~~ -:exc:`pyramid.exceptions.NotFound` and :exc:`pyramid.exceptions.Forbidden` -are exceptions often raised by Pyramid itself when it (respectively) cannot -find a view to service a request or when authorization was forbidden by a -security policy. However, they can also be raised by application developers. +:exc:`pyramid.response.HTTPNotFound` and +:exc:`pyramid.response.HTTPForbidden` are exceptions often raised by Pyramid +itself when it (respectively) cannot find a view to service a request or when +authorization was forbidden by a security policy. However, they can also be +raised by application developers. -If :exc:`~pyramid.exceptions.NotFound` is raised within view code, the result -of the :term:`Not Found View` will be returned to the user agent which +If :exc:`~pyramid.response.HTTPNotFound` is raised within view code, the +result of the :term:`Not Found View` will be returned to the user agent which performed the request. -If :exc:`~pyramid.exceptions.Forbidden` is raised within view code, the result -of the :term:`Forbidden View` will be returned to the user agent which +If :exc:`~pyramid.response.HTTPForbidden` is raised within view code, the +result of the :term:`Forbidden View` will be returned to the user agent which performed the request. Both are exception classes which accept a single positional constructor @@ -298,13 +299,10 @@ An example: .. code-block:: python :linenos: - from pyramid.exceptions import NotFound + from pyramid.response import HTTPNotFound def aview(request): - raise NotFound('not found!') - -Internal exceptions may not be *returned* in order to generate a response, -they must always be *raised*. + raise HTTPNotFound('not found!') .. index:: single: HTTP exceptions @@ -314,32 +312,33 @@ they must always be *raised*. HTTP Exceptions ~~~~~~~~~~~~~~~ -All exception classes documented in the :mod:`pyramid.httpexceptions` module -implement the :term:`Response` interface; an instance of any of these classes -can be returned or raised from within a view. The instance will be used as -as the view's response. +All classes documented in the :mod:`pyramid.response` module as inheriting +from the :class:`pryamid.response.Response` object implement the +:term:`Response` interface; an instance of any of these classes can be +returned or raised from within a view. The instance will be used as as the +view's response. -For example, the :class:`pyramid.httpexceptions.HTTPUnauthorized` exception +For example, the :class:`pyramid.response.HTTPUnauthorized` exception can be raised. This will cause a response to be generated with a ``401 Unauthorized`` status: .. code-block:: python :linenos: - from pyramid.httpexceptions import HTTPUnauthorized + from pyramid.response import HTTPUnauthorized def aview(request): raise HTTPUnauthorized() A shortcut for importing and raising an HTTP exception is the -:func:`pyramid.httpexceptions.abort` function. This function accepts an HTTP +:func:`pyramid.response.abort` function. This function accepts an HTTP status code and raises the corresponding HTTP exception. For example, to raise HTTPUnauthorized, instead of the above, you could do: .. code-block:: python :linenos: - from pyramid.httpexceptions import abort + from pyramid.response import abort def aview(request): abort(401) @@ -347,8 +346,8 @@ raise HTTPUnauthorized, instead of the above, you could do: This is the case because ``401`` is the HTTP status code for "HTTP Unauthorized". Therefore, ``abort(401)`` is functionally equivalent to ``raise HTTPUnauthorized()``. Other exceptions in -:mod:`pyramid.httpexceptions` can be raised via -:func:`pyramid.httpexceptions.abort` as well, as long as the status code +:mod:`pyramid.response` can be raised via +:func:`pyramid.response.abort` as well, as long as the status code associated with the exception is provided to the function. An HTTP exception, instead of being raised, can alternately be *returned* @@ -357,18 +356,11 @@ An HTTP exception, instead of being raised, can alternately be *returned* .. code-block:: python :linenos: - from pyramid.httpexceptions import HTTPUnauthorized + from pyramid.response import HTTPUnauthorized def aview(request): return HTTPUnauthorized() -Note that :class:`pyramid.exceptions.NotFound` is *not* the same as -:class:`pyramid.httpexceptions.HTTPNotFound`. If the latter is raised, the -:term:`Not Found view` will *not* be called automatically. Likewise, -:class:`pyramid.exceptions.Forbidden` is not the same exception as -:class:`pyramid.httpexceptions.HTTPForbidden`. If the latter is raised, the -:term:`Forbidden view` will not be called automatically. - .. index:: single: exception views @@ -377,11 +369,11 @@ Note that :class:`pyramid.exceptions.NotFound` is *not* the same as Custom Exception Views ---------------------- -The machinery which allows :exc:`~pyramid.exceptions.NotFound`, -:exc:`~pyramid.exceptions.Forbidden` and HTTP exceptions to be caught by -specialized views as described in :ref:`special_exceptions_in_callables` can -also be used by application developers to convert arbitrary exceptions to -responses. +The machinery which allows :exc:`~pyramid.response.HTTPNotFound`, +:exc:`~pyramid.response.HTTPForbidden` and other responses to be used as +exceptions and caught by specialized views as described in +:ref:`special_exceptions_in_callables` can also be used by application +developers to convert arbitrary exceptions to responses. To register a view that should be called whenever a particular exception is raised from with :app:`Pyramid` view code, use the exception class or one of @@ -474,14 +466,14 @@ Short Form ~~~~~~~~~~ You can issue an HTTP redirect from within a view callable by using the -:func:`pyramid.httpexceptions.redirect` function. This function raises an -:class:`pyramid.httpexceptions.HTTPFound` exception (a "302"), which is -caught by an exception handler and turned into a response. +:func:`pyramid.response.redirect` function. This function raises an +:class:`pyramid.response.HTTPFound` exception (a "302"), which is caught by +the default exception response handler and turned into a response. .. code-block:: python :linenos: - from pyramid.httpexceptions import redirect + from pyramid.response import redirect def myview(request): redirect('http://example.com') @@ -490,16 +482,16 @@ Long Form ~~~~~~~~~ You can issue an HTTP redirect from within a view "by hand" instead of -relying on the :func:`pyramid.httpexceptions.redirect` function to do it for +relying on the :func:`pyramid.response.redirect` function to do it for you. -To do so, you can *return* a :class:`pyramid.httpexceptions.HTTPFound` +To do so, you can *return* a :class:`pyramid.response.HTTPFound` instance. .. code-block:: python :linenos: - from pyramid.httpexceptions import HTTPFound + from pyramid.response import HTTPFound def myview(request): return HTTPFound(location='http://example.com') @@ -510,7 +502,7 @@ one. .. code-block:: python :linenos: - from pyramid.httpexceptions import HTTPFound + from pyramid.response import HTTPFound def myview(request): raise HTTPFound(location='http://example.com') diff --git a/docs/narr/webob.rst b/docs/narr/webob.rst index 072ca1c74..6cd9418ce 100644 --- a/docs/narr/webob.rst +++ b/docs/narr/webob.rst @@ -362,11 +362,11 @@ To facilitate error responses like ``404 Not Found``, the module :mod:`webob.exc` contains classes for each kind of error response. These include boring, but appropriate error bodies. The exceptions exposed by this module, when used under :app:`Pyramid`, should be imported from the -:mod:`pyramid.httpexceptions` "facade" module. This import location is merely -a facade for the original location of these exceptions: ``webob.exc``. +:mod:`pyramid.response` module. This import location contains subclasses and +replacements that mirror those in the original ``webob.exc``. -Each class is named ``pyramid.httpexceptions.HTTP*``, where ``*`` is the reason -for the error. For instance, :class:`pyramid.httpexceptions.HTTPNotFound`. It +Each class is named ``pyramid.response.HTTP*``, where ``*`` is the reason for +the error. For instance, :class:`pyramid.response.HTTPNotFound`. It subclasses :class:`pyramid.Response`, so you can manipulate the instances in the same way. A typical example is: @@ -374,40 +374,18 @@ the same way. A typical example is: .. code-block:: python :linenos: - from pyramid.httpexceptions import HTTPNotFound - from pyramid.httpexceptions import HTTPMovedPermanently + from pyramid.response import HTTPNotFound + from pyramid.response import HTTPMovedPermanently response = HTTPNotFound('There is no such resource') # or: response = HTTPMovedPermanently(location=new_url) -These are not exceptions unless you are using Python 2.5+, because -they are new-style classes which are not allowed as exceptions until -Python 2.5. To get an exception object use ``response.exception``. -You can use this like: - -.. code-block:: python - :linenos: - - from pyramid.httpexceptions import HTTPException - from pyramid.httpexceptions import HTTPNotFound - - def aview(request): - try: - # ... stuff ... - raise HTTPNotFound('No such resource').exception - except HTTPException, e: - return request.get_response(e) - -The exceptions are still WSGI applications, but you cannot set -attributes like ``content_type``, ``charset``, etc. on these exception -objects. - More Details ++++++++++++ More details about the response object API are available in the :mod:`pyramid.response` documentation. More details about exception responses -are in the :mod:`pyramid.httpexceptions` API documentation. The `WebOb +are in the :mod:`pyramid.response` API documentation. The `WebOb documentation `_ is also useful. -- cgit v1.2.3 From df15ed98612e7962e3122da52d8d5f5b9d8882b2 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 4 Jun 2011 18:43:25 -0400 Subject: - It is now possible to control how the Pyramid router calls the WSGI ``start_response`` callable and obtains the WSGI ``app_iter`` based on adapting the response object to the new ``pyramid.interfaces.IResponder`` interface. The default ``IResponder`` uses Pyramid 1.0's logic to do this. To override the responder:: from pyramid.interfaces import IResponder from pyramid.response import Response from myapp import MyResponder config.registry.registerAdapter(MyResponder, (Response,), IResponder, name='') This makes it possible to reuse response object implementations which have, for example, their own ``__call__`` expected to be used as a WSGI application (like ``pyramid.response.Response``), e.g.: class MyResponder(object): def __init__(self, response): """ Obtain a reference to the response """ self.response = response def __call__(self, request, start_response): """ Call start_response and return an app_iter """ app_iter = self.response(request.environ, start_response) return app_iter --- docs/narr/hooks.rst | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'docs/narr') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index d620b5672..aa151d281 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -521,6 +521,42 @@ The default context URL generator is available for perusal as the class `_ of the :term:`Pylons` GitHub Pyramid repository. +.. index:: + single: IResponder + +.. _using_iresponder: + +Changing How Pyramid Treats Response Objects +-------------------------------------------- + +It is possible to control how the Pyramid :term:`router` calls the WSGI +``start_response`` callable and obtains the WSGI ``app_iter`` based on +adapting the response object to the :class: `pyramid.interfaces.IResponder` +interface. The default ``IResponder`` uses the three attributes ``status``, +``headerlist``, and ``app_iter`` attached to the response object, and calls +``start_response`` with the status and headerlist, returning the +``app_iter``. To override the responder:: + + from pyramid.interfaces import IResponder + from pyramid.response import Response + from myapp import MyResponder + + config.registry.registerAdapter(MyResponder, (Response,), + IResponder, name='') + +Overriding makes it possible to reuse response object implementations which +have, for example, their own ``__call__`` expected to be used as a WSGI +application (like :class:`pyramid.response.Response`), e.g.: + + class MyResponder(object): + def __init__(self, response): + """ Obtain a reference to the response """ + self.response = response + def __call__(self, request, start_response): + """ Call start_response and return an app_iter """ + app_iter = self.response(request.environ, start_response) + return app_iter + .. index:: single: view mapper -- cgit v1.2.3 From 99edc51a3b05309c7f5d98ff96289ec51b1d7660 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 11 Jun 2011 05:35:27 -0400 Subject: - Pyramid now expects Response objects to have a __call__ method which implements the WSGI application interface instead of the three webob attrs status, headerlist and app_iter. Backwards compatibility exists for code which returns response objects that do not have a __call__. - pyramid.response.Response is no longer an exception (and therefore cannot be raised in order to generate a response). - Changed my mind about moving stuff from pyramid.httpexceptions to pyramid.response. The stuff I moved over has been moved back to pyramid.httpexceptions. --- docs/narr/hooks.rst | 42 +++++----- docs/narr/renderers.rst | 69 +++++++++++---- docs/narr/router.rst | 12 +-- docs/narr/testing.rst | 4 +- docs/narr/urldispatch.rst | 4 +- docs/narr/views.rst | 209 +++++++++++++++++++--------------------------- docs/narr/webob.rst | 23 ++--- 7 files changed, 185 insertions(+), 178 deletions(-) (limited to 'docs/narr') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index aa151d281..b6a781417 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -21,7 +21,7 @@ configuration. The :term:`not found view` callable is a view callable like any other. The :term:`view configuration` which causes it to be a "not found" view consists -only of naming the :exc:`pyramid.response.HTTPNotFound` class as the +only of naming the :exc:`pyramid.httpexceptions.HTTPNotFound` class as the ``context`` of the view configuration. If your application uses :term:`imperative configuration`, you can replace @@ -31,7 +31,7 @@ method to register an "exception view": .. code-block:: python :linenos: - from pyramid.response import HTTPNotFound + from pyramid.httpexceptions import HTTPNotFound from helloworld.views import notfound_view config.add_view(notfound_view, context=HTTPNotFound) @@ -42,22 +42,22 @@ Like any other view, the notfound view must accept at least a ``request`` parameter, or both ``context`` and ``request``. The ``request`` is the current :term:`request` representing the denied action. The ``context`` (if used in the call signature) will be the instance of the -:exc:`~pyramid.response.HTTPNotFound` exception that caused the view to be -called. +:exc:`~pyramid.httpexceptions.HTTPNotFound` exception that caused the view to +be called. Here's some sample code that implements a minimal NotFound view callable: .. code-block:: python :linenos: - from pyramid.response import HTTPNotFound + from pyramid.httpexceptions import HTTPNotFound def notfound_view(request): return HTTPNotFound() .. note:: When a NotFound view callable is invoked, it is passed a :term:`request`. The ``exception`` attribute of the request will be an - instance of the :exc:`~pyramid.response.HTTPNotFound` exception that + instance of the :exc:`~pyramid.httpexceptions.HTTPNotFound` exception that caused the not found view to be called. The value of ``request.exception.args[0]`` will be a value explaining why the not found error was raised. This message will be different when the @@ -67,8 +67,9 @@ Here's some sample code that implements a minimal NotFound view callable: .. warning:: When a NotFound view callable accepts an argument list as described in :ref:`request_and_context_view_definitions`, the ``context`` passed as the first argument to the view callable will be the - :exc:`~pyramid.response.HTTPNotFound` exception instance. If available, - the resource context will still be available as ``request.context``. + :exc:`~pyramid.httpexceptions.HTTPNotFound` exception instance. If + available, the resource context will still be available as + ``request.context``. .. index:: single: forbidden view @@ -85,7 +86,7 @@ the view which generates it can be overridden as necessary. The :term:`forbidden view` callable is a view callable like any other. The :term:`view configuration` which causes it to be a "not found" view consists -only of naming the :exc:`pyramid.response.HTTPForbidden` class as the +only of naming the :exc:`pyramid.httpexceptions.HTTPForbidden` class as the ``context`` of the view configuration. You can replace the forbidden view by using the @@ -96,7 +97,7 @@ view": :linenos: from helloworld.views import forbidden_view - from pyramid.response import HTTPForbidden + from pyramid.httpexceptions import HTTPForbidden config.add_view(forbidden_view, context=HTTPForbidden) Replace ``helloworld.views.forbidden_view`` with a reference to the Python @@ -122,8 +123,8 @@ Here's some sample code that implements a minimal forbidden view: .. note:: When a forbidden view callable is invoked, it is passed a :term:`request`. The ``exception`` attribute of the request will be an - instance of the :exc:`~pyramid.response.HTTPForbidden` exception that - caused the forbidden view to be called. The value of + instance of the :exc:`~pyramid.httpexceptions.HTTPForbidden` exception + that caused the forbidden view to be called. The value of ``request.exception.args[0]`` will be a value explaining why the forbidden was raised. This message will be different when the ``debug_authorization`` environment setting is true than it is when it is @@ -532,10 +533,10 @@ Changing How Pyramid Treats Response Objects It is possible to control how the Pyramid :term:`router` calls the WSGI ``start_response`` callable and obtains the WSGI ``app_iter`` based on adapting the response object to the :class: `pyramid.interfaces.IResponder` -interface. The default ``IResponder`` uses the three attributes ``status``, -``headerlist``, and ``app_iter`` attached to the response object, and calls -``start_response`` with the status and headerlist, returning the -``app_iter``. To override the responder:: +interface. The default responder uses the ``__call__`` method of a response +object, passing it the WSGI environ and the WSGI ``start_response`` callable +(the response is assumed to be a WSGI application). To override the +responder:: from pyramid.interfaces import IResponder from pyramid.response import Response @@ -545,8 +546,9 @@ interface. The default ``IResponder`` uses the three attributes ``status``, IResponder, name='') Overriding makes it possible to reuse response object implementations which -have, for example, their own ``__call__`` expected to be used as a WSGI -application (like :class:`pyramid.response.Response`), e.g.: +have, for example, the ``app_iter``, ``headerlist`` and ``status`` attributes +of an object returned as a response instead of trying to use the object's +``__call__`` method:: class MyResponder(object): def __init__(self, response): @@ -554,8 +556,8 @@ application (like :class:`pyramid.response.Response`), e.g.: self.response = response def __call__(self, request, start_response): """ Call start_response and return an app_iter """ - app_iter = self.response(request.environ, start_response) - return app_iter + start_response(self.response.status, self.response.headerlist) + return self.response.app_iter .. index:: single: view mapper diff --git a/docs/narr/renderers.rst b/docs/narr/renderers.rst index c7a3d7837..99ee14908 100644 --- a/docs/narr/renderers.rst +++ b/docs/narr/renderers.rst @@ -11,7 +11,6 @@ Response interface, :app:`Pyramid` will attempt to use a .. code-block:: python :linenos: - from pyramid.response import Response from pyramid.view import view_config @view_config(renderer='json') @@ -77,39 +76,52 @@ templating language to render a dictionary to a response. Additional renderers can be added by developers to the system as necessary (see :ref:`adding_and_overriding_renderers`). -Views which use a renderer can vary non-body response attributes (such as -headers and the HTTP status code) by attaching a property to the -``request.response`` attribute See :ref:`request_response_attr`. +Views which use a renderer and return a non-Response value can vary non-body +response attributes (such as headers and the HTTP status code) by attaching a +property to the ``request.response`` attribute See +:ref:`request_response_attr`. If the :term:`view callable` associated with a :term:`view configuration` -returns a Response object directly (an object with the attributes ``status``, -``headerlist`` and ``app_iter``), any renderer associated with the view +returns a Response object directly, any renderer associated with the view configuration is ignored, and the response is passed back to :app:`Pyramid` unchanged. For example, if your view callable returns an instance of the -:class:`pyramid.response.HTTPFound` class as a response, no renderer will be -employed. +:class:`pyramid.response.Response` class as a response, no renderer +will be employed. .. code-block:: python :linenos: - from pyramid.response import HTTPFound + from pyramid.response import Response + from pyramid.view import view_config + @view_config(renderer='json') def view(request): - return HTTPFound(location='http://example.com') # any renderer avoided + return Response('OK') # json renderer avoided -Likewise for a "plain old response": +Likewise for an :term:`HTTP exception` response: .. code-block:: python :linenos: - from pyramid.response import Response + from pyramid.httpexceptions import HTTPNotFound + from pyramid.view import view_config + @view_config(renderer='json') def view(request): - return Response('OK') # any renderer avoided + return HTTPFound(location='http://example.com') # json renderer avoided -Mutations to ``request.response`` in views which return a Response object -like this directly (unless that response *is* ``request.response``) will be -ignored. +You can of course also return the ``request.response`` attribute instead to +avoid rendering: + +.. code-block:: python + :linenos: + + from pyramid.view import view_config + + @view_config(renderer='json') + def view(request): + request.response.body = 'OK' + return request.response # json renderer avoided .. index:: single: renderers (built-in) @@ -377,6 +389,31 @@ callable that uses a renderer, assign the ``status`` attribute to the request.response.status = '404 Not Found' return {'URL':request.URL} +Note that mutations of ``request.response`` in views which return a Response +object directly will have no effect unless the response object returned *is* +``request.response``. For example, the following example calls +``request.response.set_cookie``, but this call will have no effect, because a +different Response object is returned. + +.. code-block:: python + :linenos: + + from pyramid.response import Response + + def view(request): + request.response.set_cookie('abc', '123') # this has no effect + return Response('OK') # because we're returning a different response + +If you mutate ``request.response`` and you'd like the mutations to have an +effect, you must return ``request.response``: + +.. code-block:: python + :linenos: + + def view(request): + request.response.set_cookie('abc', '123') + return request.response + For more information on attributes of the request, see the API documentation in :ref:`request_module`. For more information on the API of ``request.response``, see :class:`pyramid.response.Response`. diff --git a/docs/narr/router.rst b/docs/narr/router.rst index 44fa9835b..30d54767e 100644 --- a/docs/narr/router.rst +++ b/docs/narr/router.rst @@ -82,8 +82,8 @@ processing? combination of objects (based on the type of the context, the type of the request, and the value of the view name, and any :term:`predicate` attributes applied to the view configuration), :app:`Pyramid` raises a - :class:`~pyramid.response.HTTPNotFound` exception, which is meant to be - caught by a surrounding exception handler. + :class:`~pyramid.httpexceptions.HTTPNotFound` exception, which is meant to + be caught by a surrounding :term:`exception view`. #. If a view callable was found, :app:`Pyramid` attempts to call the view function. @@ -95,13 +95,13 @@ processing? information in the request and security information attached to the context. If it returns ``True``, :app:`Pyramid` calls the view callable to obtain a response. If it returns ``False``, it raises a - :class:`~pyramid.response.HTTPForbidden` exception, which is meant to be - called by a surrounding exception handler. + :class:`~pyramid.httpexceptions.HTTPForbidden` exception, which is meant + to be called by a surrounding :term:`exception view`. #. If any exception was raised within a :term:`root factory`, by :term:`traversal`, by a :term:`view callable` or by :app:`Pyramid` itself - (such as when it raises :class:`~pyramid.response.HTTPNotFound` or - :class:`~pyramid.response.HTTPForbidden`), the router catches the + (such as when it raises :class:`~pyramid.httpexceptions.HTTPNotFound` or + :class:`~pyramid.httpexceptions.HTTPForbidden`), the router catches the exception, and attaches it to the request as the ``exception`` attribute. It then attempts to find a :term:`exception view` for the exception that was caught. If it finds an exception view callable, that callable is diff --git a/docs/narr/testing.rst b/docs/narr/testing.rst index 862eda9f0..05e851fde 100644 --- a/docs/narr/testing.rst +++ b/docs/narr/testing.rst @@ -191,7 +191,7 @@ function. :linenos: from pyramid.security import has_permission - from pyramid.response import HTTPForbidden + from pyramid.httpexceptions import HTTPForbidden def view_fn(request): if not has_permission('edit', request.context, request): @@ -230,7 +230,7 @@ without needing to invoke the actual application configuration implied by its testing.tearDown() def test_view_fn_forbidden(self): - from pyramid.response import HTTPForbidden + from pyramid.httpexceptions import HTTPForbidden from my.package import view_fn self.config.testing_securitypolicy(userid='hank', permissive=False) diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst index e5228b81e..f94ed3ba8 100644 --- a/docs/narr/urldispatch.rst +++ b/docs/narr/urldispatch.rst @@ -917,7 +917,7 @@ the application's startup configuration, adding the following stanza: :linenos: config.add_view('pyramid.view.append_slash_notfound_view', - context='pyramid.response.HTTPNotFound') + context='pyramid.httpexceptions.HTTPNotFound') See :ref:`view_module` and :ref:`changing_the_notfound_view` for more information about the slash-appending not found view and for a more general @@ -945,7 +945,7 @@ view as the first argument to its constructor. For instance: .. code-block:: python :linenos: - from pyramid.response import HTTPNotFound + from pyramid.httpexceptions import HTTPNotFound from pyramid.view import AppendSlashNotFoundViewFactory def notfound_view(context, request): diff --git a/docs/narr/views.rst b/docs/narr/views.rst index 73a7c2e2a..990828f80 100644 --- a/docs/narr/views.rst +++ b/docs/narr/views.rst @@ -230,29 +230,29 @@ implements the :term:`Response` interface is to return a def view(request): return Response('OK') -You don't need to always use :class:`~pyramid.response.Response` to represent -a response. :app:`Pyramid` provides a range of different "exception" classes -which can act as response objects too. For example, an instance of the class -:class:`pyramid.response.HTTPFound` is also a valid response object -(see :ref:`http_exceptions` and ref:`http_redirect`). A view can actually -return any object that has the following attributes. - -status - The HTTP status code (including the name) for the response as a string. - E.g. ``200 OK`` or ``401 Unauthorized``. - -headerlist - A sequence of tuples representing the list of headers that should be - set in the response. E.g. ``[('Content-Type', 'text/html'), - ('Content-Length', '412')]`` - -app_iter - An iterable representing the body of the response. This can be a - list, e.g. ``['Hello - world!']`` or it can be a file-like object, or any - other sort of iterable. - -These attributes form the structure of the "Pyramid Response interface". +You don't need to use :class:`~pyramid.response.Response` to represent a +response. A view can actually return any object that has a ``__call__`` +method that implements the :term:`WSGI` application call interface. For +example, an instance of the following class could be successfully returned by +a view callable as a response object: + +.. code-block:: python + :linenos: + + class SimpleResponse(object): + def __call__(self, environ, start_response): + """ Call the ``start_response`` callback and return + an iterable """ + body = 'Hello World!' + headers = [('Content-Type', 'text/plain'), + ('Content-Length', str(len(body)))] + start_response('200 OK', headers) + return [body] + +:app:`Pyramid` provides a range of different "exception" classes which can +act as response objects too. For example, an instance of the class +:class:`pyramid.httpexceptions.HTTPFound` is also a valid response object +(see :ref:`http_exceptions` and ref:`http_redirect`). .. index:: single: view exceptions @@ -269,40 +269,8 @@ logged there. However, for convenience, a special set of exceptions exists. When one of these exceptions is raised within a view callable, it will always cause -:app:`Pyramid` to generate a response. Two categories of special exceptions -exist: internal exceptions and HTTP exceptions. - -Internal Exceptions -~~~~~~~~~~~~~~~~~~~ - -:exc:`pyramid.response.HTTPNotFound` and -:exc:`pyramid.response.HTTPForbidden` are exceptions often raised by Pyramid -itself when it (respectively) cannot find a view to service a request or when -authorization was forbidden by a security policy. However, they can also be -raised by application developers. - -If :exc:`~pyramid.response.HTTPNotFound` is raised within view code, the -result of the :term:`Not Found View` will be returned to the user agent which -performed the request. - -If :exc:`~pyramid.response.HTTPForbidden` is raised within view code, the -result of the :term:`Forbidden View` will be returned to the user agent which -performed the request. - -Both are exception classes which accept a single positional constructor -argument: a ``message``. In all cases, the message provided to the exception -constructor is made available to the view which :app:`Pyramid` invokes as -``request.exception.args[0]``. - -An example: - -.. code-block:: python - :linenos: - - from pyramid.response import HTTPNotFound - - def aview(request): - raise HTTPNotFound('not found!') +:app:`Pyramid` to generate a response. These are known as :term:`HTTP +exception` objects. .. index:: single: HTTP exceptions @@ -312,54 +280,77 @@ An example: HTTP Exceptions ~~~~~~~~~~~~~~~ -All classes documented in the :mod:`pyramid.response` module as inheriting -from the :class:`pryamid.response.Response` object implement the -:term:`Response` interface; an instance of any of these classes can be -returned or raised from within a view. The instance will be used as as the -view's response. +All classes documented in the :mod:`pyramid.httpexceptions` module documented +as inheriting from the :class:`pryamid.httpexceptions.HTTPException` are +:term:`http exception` objects. An instances of an HTTP exception object may +either be *returned* or *raised* from within view code. In either case +(return or raise) the instance will be used as as the view's response. -For example, the :class:`pyramid.response.HTTPUnauthorized` exception +For example, the :class:`pyramid.httpexceptions.HTTPUnauthorized` exception can be raised. This will cause a response to be generated with a ``401 Unauthorized`` status: .. code-block:: python :linenos: - from pyramid.response import HTTPUnauthorized + from pyramid.httpexceptions import HTTPUnauthorized def aview(request): raise HTTPUnauthorized() -A shortcut for importing and raising an HTTP exception is the -:func:`pyramid.response.abort` function. This function accepts an HTTP -status code and raises the corresponding HTTP exception. For example, to -raise HTTPUnauthorized, instead of the above, you could do: +An HTTP exception, instead of being raised, can alternately be *returned* +(HTTP exceptions are also valid response objects): .. code-block:: python :linenos: - from pyramid.response import abort + from pyramid.httpexceptions import HTTPUnauthorized def aview(request): - abort(401) - -This is the case because ``401`` is the HTTP status code for "HTTP -Unauthorized". Therefore, ``abort(401)`` is functionally equivalent to -``raise HTTPUnauthorized()``. Other exceptions in -:mod:`pyramid.response` can be raised via -:func:`pyramid.response.abort` as well, as long as the status code -associated with the exception is provided to the function. + return HTTPUnauthorized() -An HTTP exception, instead of being raised, can alternately be *returned* -(HTTP exceptions are also valid response objects): +A shortcut for creating an HTTP exception is the +:func:`pyramid.httpexceptions.responsecode` function. This function accepts +an HTTP status code and returns the corresponding HTTP exception. For +example, instead of importing and constructing a +:class:`~pyramid.httpexceptions.HTTPUnauthorized` response object, you can +use the :func:`~pyramid.httpexceptions.responsecode` function to construct +and return the same object. .. code-block:: python :linenos: - from pyramid.response import HTTPUnauthorized + from pyramid.httpexceptions import responsecode def aview(request): - return HTTPUnauthorized() + raise responsecode(401) + +This is the case because ``401`` is the HTTP status code for "HTTP +Unauthorized". Therefore, ``raise responsecode(401)`` is functionally +equivalent to ``raise HTTPUnauthorized()``. Documentation which maps each +HTTP response code to its purpose and its associated HTTP exception object is +provided within :mod:`pyramid.httpexceptions`. + +How Pyramid Uses HTTP Exceptions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +HTTP exceptions are meant to be used directly by application application +developers. However, Pyramid itself will raise two HTTP exceptions at +various points during normal operations: +:exc:`pyramid.httpexceptions.HTTPNotFound` and +:exc:`pyramid.httpexceptions.HTTPForbidden`. Pyramid will raise the +:exc:`~pyramid.httpexceptions.HTTPNotFound` exception are raised when it +cannot find a view to service a request. Pyramid will raise the +:exc:`~pyramid.httpexceptions.Forbidden` exception or when authorization was +forbidden by a security policy. + +If :exc:`~pyramid.httpexceptions.HTTPNotFound` is raised by Pyramid itself or +within view code, the result of the :term:`Not Found View` will be returned +to the user agent which performed the request. + +If :exc:`~pyramid.httpexceptions.HTTPForbidden` is raised by Pyramid itself +within view code, the result of the :term:`Forbidden View` will be returned +to the user agent which performed the request. .. index:: single: exception views @@ -369,11 +360,10 @@ An HTTP exception, instead of being raised, can alternately be *returned* Custom Exception Views ---------------------- -The machinery which allows :exc:`~pyramid.response.HTTPNotFound`, -:exc:`~pyramid.response.HTTPForbidden` and other responses to be used as -exceptions and caught by specialized views as described in -:ref:`special_exceptions_in_callables` can also be used by application -developers to convert arbitrary exceptions to responses. +The machinery which allows HTTP exceptions to be raised and caught by +specialized views as described in :ref:`special_exceptions_in_callables` can +also be used by application developers to convert arbitrary exceptions to +responses. To register a view that should be called whenever a particular exception is raised from with :app:`Pyramid` view code, use the exception class or one of @@ -409,8 +399,8 @@ raises a ``helloworld.exceptions.ValidationFailure`` exception: Assuming that a :term:`scan` was run to pick up this view registration, this view callable will be invoked whenever a ``helloworld.exceptions.ValidationFailure`` is raised by your application's -view code. The same exception raised by a custom root factory or a custom -traverser is also caught and hooked. +view code. The same exception raised by a custom root factory, a custom +traverser, or a custom view or route predicate is also caught and hooked. Other normal view predicates can also be used in combination with an exception view registration: @@ -458,57 +448,34 @@ Exception views can be configured with any view registration mechanism: Using a View Callable to Do an HTTP Redirect -------------------------------------------- -Two methods exist to redirect to another URL from within a view callable: a -short form and a long form. The short form should be preferred when -possible. - -Short Form -~~~~~~~~~~ - -You can issue an HTTP redirect from within a view callable by using the -:func:`pyramid.response.redirect` function. This function raises an -:class:`pyramid.response.HTTPFound` exception (a "302"), which is caught by -the default exception response handler and turned into a response. - -.. code-block:: python - :linenos: - - from pyramid.response import redirect - - def myview(request): - redirect('http://example.com') - -Long Form -~~~~~~~~~ - -You can issue an HTTP redirect from within a view "by hand" instead of -relying on the :func:`pyramid.response.redirect` function to do it for -you. +You can issue an HTTP redirect by using the +:class:`pyramid.httpexceptions.HTTPFound` class. Raising or returning an +instance of this class will cause the client to receive a "302 Found" +response. -To do so, you can *return* a :class:`pyramid.response.HTTPFound` +To do so, you can *return* a :class:`pyramid.httpexceptions.HTTPFound` instance. .. code-block:: python :linenos: - from pyramid.response import HTTPFound + from pyramid.httpexceptions import HTTPFound def myview(request): return HTTPFound(location='http://example.com') -Or, alternately, you can *raise* an HTTPFound exception instead of returning -one. +Alternately, you can *raise* an HTTPFound exception instead of returning one. .. code-block:: python :linenos: - from pyramid.response import HTTPFound + from pyramid.httpexceptions import HTTPFound def myview(request): raise HTTPFound(location='http://example.com') -The above form of generating a response by raising HTTPFound is completely -equivalent to ``redirect('http://example.com')``. +When the instance is raised, it is caught by the default :term:`exception +response` handler and turned into a response. .. index:: single: unicode, views, and forms diff --git a/docs/narr/webob.rst b/docs/narr/webob.rst index 6cd9418ce..70ab5eea8 100644 --- a/docs/narr/webob.rst +++ b/docs/narr/webob.rst @@ -362,20 +362,21 @@ To facilitate error responses like ``404 Not Found``, the module :mod:`webob.exc` contains classes for each kind of error response. These include boring, but appropriate error bodies. The exceptions exposed by this module, when used under :app:`Pyramid`, should be imported from the -:mod:`pyramid.response` module. This import location contains subclasses and -replacements that mirror those in the original ``webob.exc``. +:mod:`pyramid.httpexceptions` module. This import location contains +subclasses and replacements that mirror those in the original ``webob.exc``. -Each class is named ``pyramid.response.HTTP*``, where ``*`` is the reason for -the error. For instance, :class:`pyramid.response.HTTPNotFound`. It -subclasses :class:`pyramid.Response`, so you can manipulate the instances in -the same way. A typical example is: +Each class is named ``pyramid.httpexceptions.HTTP*``, where ``*`` is the +reason for the error. For instance, +:class:`pyramid.httpexceptions.HTTPNotFound` subclasses +:class:`pyramid.Response`, so you can manipulate the instances in the same +way. A typical example is: .. ignore-next-block .. code-block:: python :linenos: - from pyramid.response import HTTPNotFound - from pyramid.response import HTTPMovedPermanently + from pyramid.httpexceptions import HTTPNotFound + from pyramid.httpexceptions import HTTPMovedPermanently response = HTTPNotFound('There is no such resource') # or: @@ -385,7 +386,7 @@ More Details ++++++++++++ More details about the response object API are available in the -:mod:`pyramid.response` documentation. More details about exception responses -are in the :mod:`pyramid.response` API documentation. The `WebOb -documentation `_ is also useful. +:mod:`pyramid.response` documentation. More details about exception +responses are in the :mod:`pyramid.httpexceptions` API documentation. The +`WebOb documentation `_ is also useful. -- cgit v1.2.3 From d868fff7597c5a05acd1f5c024fc45dde9880413 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Mon, 13 Jun 2011 06:17:00 -0400 Subject: - Remove IResponder abstraction in favor of more general IResponse abstraction. - It is now possible to return an arbitrary object from a Pyramid view callable even if a renderer is not used, as long as a suitable adapter to ``pyramid.interfaces.IResponse`` is registered for the type of the returned object. See the section in the Hooks chapter of the documentation entitled "Changing How Pyramid Treats View Responses". - The Pyramid router now, by default, expects response objects returned from view callables to implement the ``pyramid.interfaces.IResponse`` interface. Unlike the Pyramid 1.0 version of this interface, objects which implement IResponse now must define a ``__call__`` method that accepts ``environ`` and ``start_response``, and which returns an ``app_iter`` iterable, among other things. Previously, it was possible to return any object which had the three WebOb ``app_iter``, ``headerlist``, and ``status`` attributes as a response, so this is a backwards incompatibility. It is possible to get backwards compatibility back by registering an adapter to IResponse from the type of object you're now returning from view callables. See the section in the Hooks chapter of the documentation entitled "Changing How Pyramid Treats View Responses". - The ``pyramid.interfaces.IResponse`` interface is now much more extensive. Previously it defined only ``app_iter``, ``status`` and ``headerlist``; now it is basically intended to directly mirror the ``webob.Response`` API, which has many methods and attributes. - Documentation changes to support above. --- docs/narr/assets.rst | 2 +- docs/narr/hooks.rst | 134 +++++++++++++++++++++++++++++++++++------------- docs/narr/renderers.rst | 2 +- docs/narr/router.rst | 6 +-- docs/narr/views.rst | 36 +++++-------- docs/narr/webob.rst | 66 ++++++++++++------------ 6 files changed, 150 insertions(+), 96 deletions(-) (limited to 'docs/narr') diff --git a/docs/narr/assets.rst b/docs/narr/assets.rst index 8d0e7058c..0d50b0106 100644 --- a/docs/narr/assets.rst +++ b/docs/narr/assets.rst @@ -358,7 +358,7 @@ do so, do things "by hand". First define the view callable. :linenos: import os - from webob import Response + from pyramid.response import Response def favicon_view(request): here = os.path.dirname(__file__) diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index b6a781417..0db8ce5e0 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -523,41 +523,103 @@ The default context URL generator is available for perusal as the class :term:`Pylons` GitHub Pyramid repository. .. index:: - single: IResponder - -.. _using_iresponder: - -Changing How Pyramid Treats Response Objects --------------------------------------------- - -It is possible to control how the Pyramid :term:`router` calls the WSGI -``start_response`` callable and obtains the WSGI ``app_iter`` based on -adapting the response object to the :class: `pyramid.interfaces.IResponder` -interface. The default responder uses the ``__call__`` method of a response -object, passing it the WSGI environ and the WSGI ``start_response`` callable -(the response is assumed to be a WSGI application). To override the -responder:: - - from pyramid.interfaces import IResponder - from pyramid.response import Response - from myapp import MyResponder - - config.registry.registerAdapter(MyResponder, (Response,), - IResponder, name='') - -Overriding makes it possible to reuse response object implementations which -have, for example, the ``app_iter``, ``headerlist`` and ``status`` attributes -of an object returned as a response instead of trying to use the object's -``__call__`` method:: - - class MyResponder(object): - def __init__(self, response): - """ Obtain a reference to the response """ - self.response = response - def __call__(self, request, start_response): - """ Call start_response and return an app_iter """ - start_response(self.response.status, self.response.headerlist) - return self.response.app_iter + single: IResponse + +.. _using_iresponse: + +Changing How Pyramid Treats View Responses +------------------------------------------ + +It is possible to control how Pyramid treats the result of calling a view +callable on a per-type basis by using a hook involving +:class:`pyramid.interfaces.IResponse`. + +.. note:: This feature is new as of Pyramid 1.1. + +Pyramid, in various places, adapts the result of calling a view callable to +the :class:`~pyramid.interfaces.IResponse` interface to ensure that the +object returned by the view callable is a "true" response object. The vast +majority of time, the result of this adaptation is the result object itself, +as view callables written by "civilians" who read the narrative documentation +contained in this manual will always return something that implements the +:class:`~pyramid.interfaces.IResponse` interface. Most typically, this will +be an instance of the :class:`pyramid.response.Response` class or a subclass. +If a civilian returns a non-Response object from a view callable that isn't +configured to use a :term:`renderer`, he will typically expect the router to +raise an error. However, you can hook Pyramid in such a way that users can +return arbitrary values from a view callable by providing an adapter which +converts the arbitrary return value into something that implements +:class:`~pyramid.interfaces.IResponse`. + +For example, if you'd like to allow view callables to return bare string +objects (without requiring a a :term:`renderer` to convert a string to a +response object), you can register an adapter which converts the string to a +Response: + +.. code-block:: python + :linenos: + + from pyramid.interfaces import IResponse + from pyramid.response import Response + + def string_response_adapter(s): + response = Response(s) + return response + + # config is an instance of pyramid.config.Configurator + + config.registry.registerAdapter(string_response_adapter, (str,), + IResponse) + +Likewise, if you want to be able to return a simplified kind of response +object from view callables, you can use the IResponse hook to register an +adapter to the more complex IResponse interface: + +.. code-block:: python + :linenos: + + from pyramid.interfaces import IResponse + from pyramid.response import Response + + class SimpleResponse(object): + def __init__(self, body): + self.body = body + + def simple_response_adapter(simple_response): + response = Response(simple_response.body) + return response + + # config is an instance of pyramid.config.Configurator + + config.registry.registerAdapter(simple_response_adapter, + (SimpleResponse,), + IResponse) + +If you want to implement your own Response object instead of using the +:class:`pyramid.response.Response` object in any capacity at all, you'll have +to make sure the object implements every attribute and method outlined in +:class:`pyramid.interfaces.IResponse` *and* you'll have to ensure that it's +marked up with ``zope.interface.implements(IResponse)``: + + from pyramid.interfaces import IResponse + from zope.interface import implements + + class MyResponse(object): + implements(IResponse) + # ... an implementation of every method and attribute + # documented in IResponse should follow ... + +When an alternate response object implementation is returned by a view +callable, if that object asserts that it implements +:class:`~pyramid.interfaces.IResponse` (via +``zope.interface.implements(IResponse)``) , an adapter needn't be registered +for the object; Pyramid will use it directly. + +An IResponse adapter for ``webob.Response`` (as opposed to +:class:`pyramid.response.Response`) is registered by Pyramid by default at +startup time, as by their nature, instances of this class (and instances of +subclasses of the class) will natively provide IResponse. The adapter +registered for ``webob.Response`` simply returns the response object. .. index:: single: view mapper @@ -628,7 +690,7 @@ A user might make use of these framework components like so: # user application - from webob import Response + from pyramid.response import Response from pyramid.config import Configurator import pyramid_handlers from paste.httpserver import serve diff --git a/docs/narr/renderers.rst b/docs/narr/renderers.rst index 99ee14908..c4a37c23d 100644 --- a/docs/narr/renderers.rst +++ b/docs/narr/renderers.rst @@ -416,7 +416,7 @@ effect, you must return ``request.response``: For more information on attributes of the request, see the API documentation in :ref:`request_module`. For more information on the API of -``request.response``, see :class:`pyramid.response.Response`. +``request.response``, see :attr:`pyramid.request.Request.response`. .. _response_prefixed_attrs: diff --git a/docs/narr/router.rst b/docs/narr/router.rst index 30d54767e..0812f7ec7 100644 --- a/docs/narr/router.rst +++ b/docs/narr/router.rst @@ -115,9 +115,9 @@ processing? any :term:`response callback` functions attached via :meth:`~pyramid.request.Request.add_response_callback`. A :class:`~pyramid.events.NewResponse` :term:`event` is then sent to any - subscribers. The response object's ``app_iter``, ``status``, and - ``headerlist`` attributes are then used to generate a WSGI response. The - response is sent back to the upstream WSGI server. + subscribers. The response object's ``__call__`` method is then used to + generate a WSGI response. The response is sent back to the upstream WSGI + server. #. :app:`Pyramid` will attempt to execute any :term:`finished callback` functions attached via diff --git a/docs/narr/views.rst b/docs/narr/views.rst index 990828f80..e3d0a37e5 100644 --- a/docs/narr/views.rst +++ b/docs/narr/views.rst @@ -230,29 +230,19 @@ implements the :term:`Response` interface is to return a def view(request): return Response('OK') -You don't need to use :class:`~pyramid.response.Response` to represent a -response. A view can actually return any object that has a ``__call__`` -method that implements the :term:`WSGI` application call interface. For -example, an instance of the following class could be successfully returned by -a view callable as a response object: - -.. code-block:: python - :linenos: - - class SimpleResponse(object): - def __call__(self, environ, start_response): - """ Call the ``start_response`` callback and return - an iterable """ - body = 'Hello World!' - headers = [('Content-Type', 'text/plain'), - ('Content-Length', str(len(body)))] - start_response('200 OK', headers) - return [body] - -:app:`Pyramid` provides a range of different "exception" classes which can -act as response objects too. For example, an instance of the class -:class:`pyramid.httpexceptions.HTTPFound` is also a valid response object -(see :ref:`http_exceptions` and ref:`http_redirect`). +:app:`Pyramid` provides a range of different "exception" classes which +inherit from :class:`pyramid.response.Response`. For example, an instance of +the class :class:`pyramid.httpexceptions.HTTPFound` is also a valid response +object because it inherits from :class:`~pyramid.response.Response`. For +examples, see :ref:`http_exceptions` and ref:`http_redirect`. + +You can also return objects from view callables that aren't instances of (or +instances of classes which are subclasses of) +:class:`pyramid.response.Response` in various circumstances. This can be +helpful when writing tests and when attempting to share code between view +callables. See :ref:`renderers_chapter` for the common way to allow for +this. A much less common way to allow for view callables to return +non-Response objects is documented in :ref:`using_iresponse`. .. index:: single: view exceptions diff --git a/docs/narr/webob.rst b/docs/narr/webob.rst index 70ab5eea8..0ff8e1de7 100644 --- a/docs/narr/webob.rst +++ b/docs/narr/webob.rst @@ -10,15 +10,15 @@ Request and Response Objects .. note:: This chapter is adapted from a portion of the :term:`WebOb` documentation, originally written by Ian Bicking. -:app:`Pyramid` uses the :term:`WebOb` package to supply +:app:`Pyramid` uses the :term:`WebOb` package as a basis for its :term:`request` and :term:`response` object implementations. The -:term:`request` object that is passed to a :app:`Pyramid` -:term:`view` is an instance of the :class:`pyramid.request.Request` -class, which is a subclass of :class:`webob.Request`. The -:term:`response` returned from a :app:`Pyramid` :term:`view` -:term:`renderer` is an instance of the :mod:`webob.Response` class. -Users can also return an instance of :mod:`webob.Response` directly -from a view as necessary. +:term:`request` object that is passed to a :app:`Pyramid` :term:`view` is an +instance of the :class:`pyramid.request.Request` class, which is a subclass +of :class:`webob.Request`. The :term:`response` returned from a +:app:`Pyramid` :term:`view` :term:`renderer` is an instance of the +:mod:`pyramid.response.Response` class, which is a subclass of the +:class:`webob.Response` class. Users can also return an instance of +:class:`pyramid.response.Response` directly from a view as necessary. WebOb is a project separate from :app:`Pyramid` with a separate set of authors and a fully separate `set of documentation @@ -26,16 +26,15 @@ authors and a fully separate `set of documentation standard WebOb request, which is documented in the :ref:`request_module` API documentation. -WebOb provides objects for HTTP requests and responses. Specifically -it does this by wrapping the `WSGI `_ request -environment and response status/headers/app_iter (body). +WebOb provides objects for HTTP requests and responses. Specifically it does +this by wrapping the `WSGI `_ request environment and +response status, header list, and app_iter (body) values. -WebOb request and response objects provide many conveniences for -parsing WSGI requests and forming WSGI responses. WebOb is a nice way -to represent "raw" WSGI requests and responses; however, we won't -cover that use case in this document, as users of :app:`Pyramid` -don't typically need to use the WSGI-related features of WebOb -directly. The `reference documentation +WebOb request and response objects provide many conveniences for parsing WSGI +requests and forming WSGI responses. WebOb is a nice way to represent "raw" +WSGI requests and responses; however, we won't cover that use case in this +document, as users of :app:`Pyramid` don't typically need to use the +WSGI-related features of WebOb directly. The `reference documentation `_ shows many examples of creating requests and using response objects in this manner, however. @@ -170,9 +169,9 @@ of the request. I'll show various values for an example URL Methods +++++++ -There are `several methods -`_ but -only a few you'll use often: +There are methods of request objects documented in +:class:`pyramid.request.Request` but you'll find that you won't use very many +of them. Here are a couple that might be useful: ``Request.blank(base_url)``: Creates a new request with blank information, based at the given @@ -183,9 +182,9 @@ only a few you'll use often: subrequests). ``req.get_response(wsgi_application)``: - This method calls the given WSGI application with this request, - and returns a `Response`_ object. You can also use this for - subrequests, or testing. + This method calls the given WSGI application with this request, and + returns a :class:`pyramid.response.Response` object. You can also use + this for subrequests, or testing. .. index:: single: request (and unicode) @@ -259,8 +258,10 @@ Response ~~~~~~~~ The :app:`Pyramid` response object can be imported as -:class:`pyramid.response.Response`. This import location is merely a facade -for its original location: ``webob.Response``. +:class:`pyramid.response.Response`. This class is a subclass of the +``webob.Response`` class. The subclass does not add or change any +functionality, so the WebOb Response documentation will be completely +relevant for this class as well. A response object has three fundamental parts: @@ -283,8 +284,8 @@ A response object has three fundamental parts: ``response.body_file`` (a file-like object; writing to it appends to ``app_iter``). -Everything else in the object derives from this underlying state. -Here's the highlights: +Everything else in the object typically derives from this underlying state. +Here are some highlights: ``response.content_type`` The content type *not* including the ``charset`` parameter. @@ -359,11 +360,12 @@ Exception Responses +++++++++++++++++++ To facilitate error responses like ``404 Not Found``, the module -:mod:`webob.exc` contains classes for each kind of error response. These -include boring, but appropriate error bodies. The exceptions exposed by this -module, when used under :app:`Pyramid`, should be imported from the -:mod:`pyramid.httpexceptions` module. This import location contains -subclasses and replacements that mirror those in the original ``webob.exc``. +:mod:`pyramid.httpexceptions` contains classes for each kind of error +response. These include boring, but appropriate error bodies. The +exceptions exposed by this module, when used under :app:`Pyramid`, should be +imported from the :mod:`pyramid.httpexceptions` module. This import location +contains subclasses and replacements that mirror those in the ``webob.exc`` +module. Each class is named ``pyramid.httpexceptions.HTTP*``, where ``*`` is the reason for the error. For instance, -- cgit v1.2.3 From 1a6fc7062f803b9f15b7677db9a9257a4f00bfcb Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Tue, 14 Jun 2011 02:36:07 -0400 Subject: - Added new add_response_adapter method to Configurator. - Fix Configurator docstring wrt exception responses. - Speed up registry.queryAdapterOrSelf --- docs/narr/hooks.rst | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'docs/narr') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 0db8ce5e0..8e5b93ed4 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -532,7 +532,7 @@ Changing How Pyramid Treats View Responses It is possible to control how Pyramid treats the result of calling a view callable on a per-type basis by using a hook involving -:class:`pyramid.interfaces.IResponse`. +:method:`pyramid.config.Configurator.add_response_adapter`. .. note:: This feature is new as of Pyramid 1.1. @@ -559,7 +559,6 @@ Response: .. code-block:: python :linenos: - from pyramid.interfaces import IResponse from pyramid.response import Response def string_response_adapter(s): @@ -568,8 +567,7 @@ Response: # config is an instance of pyramid.config.Configurator - config.registry.registerAdapter(string_response_adapter, (str,), - IResponse) + config.add_response_adapter(string_response_adapter, str) Likewise, if you want to be able to return a simplified kind of response object from view callables, you can use the IResponse hook to register an @@ -578,7 +576,6 @@ adapter to the more complex IResponse interface: .. code-block:: python :linenos: - from pyramid.interfaces import IResponse from pyramid.response import Response class SimpleResponse(object): @@ -591,14 +588,12 @@ adapter to the more complex IResponse interface: # config is an instance of pyramid.config.Configurator - config.registry.registerAdapter(simple_response_adapter, - (SimpleResponse,), - IResponse) + config.add_response_adapter(simple_response_adapter, SimpleResponse) If you want to implement your own Response object instead of using the :class:`pyramid.response.Response` object in any capacity at all, you'll have to make sure the object implements every attribute and method outlined in -:class:`pyramid.interfaces.IResponse` *and* you'll have to ensure that it's +:class:`pyramid.interfaces.IResponse` and you'll have to ensure that it's marked up with ``zope.interface.implements(IResponse)``: from pyramid.interfaces import IResponse -- cgit v1.2.3