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 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) (limited to 'docs/narr/hooks.rst') 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 -- 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/hooks.rst') 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 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) (limited to 'docs/narr/hooks.rst') 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 -- 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/hooks.rst | 134 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 98 insertions(+), 36 deletions(-) (limited to 'docs/narr/hooks.rst') 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 -- 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/hooks.rst') 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 From 4fd3e66d5ae48acf53534a21ebf900e74f714541 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 18 Jun 2011 23:09:53 -0400 Subject: fix rendering --- docs/narr/hooks.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 8426f11fd..e5b85dfbf 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 -:method:`pyramid.config.Configurator.add_response_adapter`. +:meth:`pyramid.config.Configurator.add_response_adapter`. .. note:: This feature is new as of Pyramid 1.1. -- cgit v1.2.3 From d69ae60b9a195c7cb72122b59335ba886bfffe50 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Mon, 20 Jun 2011 00:37:59 -0400 Subject: - Register the default exception view for context of webob.exc.WSGIHTTPException (convenience). - Use ``exc.message`` in docs rather than ``exc.args[0]`` now that we control this. --- docs/narr/hooks.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index e5b85dfbf..1c8a64fd7 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -59,7 +59,7 @@ Here's some sample code that implements a minimal NotFound view callable: :term:`request`. The ``exception`` attribute of the request will be an 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 + ``request.exception.message`` 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. @@ -125,8 +125,9 @@ Here's some sample code that implements a minimal forbidden view: :term:`request`. The ``exception`` attribute of the request will be an 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 + ``request.exception.message`` will be a value explaining why the forbidden + was raised and ``request.exception.result`` will be extended information + about the forbidden exception. These messages will be different when the ``debug_authorization`` environment setting is true than it is when it is false. -- cgit v1.2.3 From b7f33b5fdd062e007723d0eb60001442f35c0bf7 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Fri, 1 Jul 2011 01:24:39 -0400 Subject: - Deprecated the ``set_renderer_globals_factory`` method of the Configurator and the ``renderer_globals`` Configurator constructor parameter. --- docs/narr/hooks.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 1c8a64fd7..56c566a4c 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -183,6 +183,10 @@ already constructed a :term:`configurator` it can also be registered via the Adding Renderer Globals ----------------------- +.. warning:: this feature is deprecated as of Pyramid 1.1. A non-deprecated + mechanism which allows event subscribers to add renderer global values + is documented in :ref:`beforerender_event`. + Whenever :app:`Pyramid` handles a request to perform a rendering (after a view with a ``renderer=`` configuration attribute is invoked, or when any of the methods beginning with ``render`` within the :mod:`pyramid.renderers` @@ -227,9 +231,6 @@ already constructed a :term:`configurator` it can also be registered via the config = Configurator() config.set_renderer_globals_factory(renderer_globals_factory) -Another mechanism which allows event subscribers to add renderer global values -exists in :ref:`beforerender_event`. - .. index:: single: before render event -- cgit v1.2.3 From ac7a9aac93392ca035a983b138df4848b6a333b6 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 2 Jul 2011 17:00:09 -0400 Subject: reorder --- docs/narr/hooks.rst | 86 +++++++++++++++++++++++++++-------------------------- 1 file changed, 44 insertions(+), 42 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 56c566a4c..94701c9f9 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -175,13 +175,55 @@ already constructed a :term:`configurator` it can also be registered via the config = Configurator() config.set_request_factory(MyRequest) +.. index:: + single: before render event + single: adding renderer globals + +.. _beforerender_event: + +Using The Before Render Event +----------------------------- + +Subscribers to the :class:`pyramid.events.BeforeRender` event may introspect +and modify the set of :term:`renderer globals` before they are passed to a +:term:`renderer`. This event object iself has a dictionary-like interface +that can be used for this purpose. For example: + +.. code-block:: python + :linenos: + + from pyramid.events import subscriber + from pyramid.events import BeforeRender + + @subscriber(BeforeRender) + def add_global(event): + event['mykey'] = 'foo' + +An object of this type is sent as an event just before a :term:`renderer` is +invoked (but *after* the application-level renderer globals factory added via +:class:`~pyramid.config.Configurator.set_renderer_globals_factory`, if any, +has injected its own keys into the renderer globals dictionary). + +If a subscriber attempts to add a key that already exist in the renderer +globals dictionary, a :exc:`KeyError` is raised. This limitation is enforced +because event subscribers do not possess any relative ordering. The set of +keys added to the renderer globals dictionary by all +:class:`pyramid.events.BeforeRender` subscribers and renderer globals +factories must be unique. + +See the API documentation for the :class:`~pyramid.events.BeforeRender` event +interface at :class:`pyramid.interfaces.IBeforeRender`. + +Another (deprecated) mechanism which allows event subscribers more control +when adding renderer global values exists in :ref:`adding_renderer_globals`. + .. index:: single: renderer globals .. _adding_renderer_globals: -Adding Renderer Globals ------------------------ +Adding Renderer Globals (Deprecated) +------------------------------------ .. warning:: this feature is deprecated as of Pyramid 1.1. A non-deprecated mechanism which allows event subscribers to add renderer global values @@ -231,46 +273,6 @@ already constructed a :term:`configurator` it can also be registered via the config = Configurator() config.set_renderer_globals_factory(renderer_globals_factory) -.. index:: - single: before render event - -.. _beforerender_event: - -Using The Before Render Event ------------------------------ - -Subscribers to the :class:`pyramid.events.BeforeRender` event may introspect -and modify the set of :term:`renderer globals` before they are passed to a -:term:`renderer`. This event object iself has a dictionary-like interface -that can be used for this purpose. For example: - -.. code-block:: python - :linenos: - - from pyramid.events import subscriber - from pyramid.events import BeforeRender - - @subscriber(BeforeRender) - def add_global(event): - event['mykey'] = 'foo' - -An object of this type is sent as an event just before a :term:`renderer` is -invoked (but *after* the application-level renderer globals factory added via -:class:`~pyramid.config.Configurator.set_renderer_globals_factory`, if any, -has injected its own keys into the renderer globals dictionary). - -If a subscriber attempts to add a key that already exist in the renderer -globals dictionary, a :exc:`KeyError` is raised. This limitation is enforced -because event subscribers do not possess any relative ordering. The set of -keys added to the renderer globals dictionary by all -:class:`pyramid.events.BeforeRender` subscribers and renderer globals -factories must be unique. - -See the API documentation for the :class:`~pyramid.events.BeforeRender` event -interface at :class:`pyramid.interfaces.IBeforeRender`. - -Another mechanism which allows event subscribers more control when adding -renderer global values exists in :ref:`adding_renderer_globals`. .. index:: single: response callback -- cgit v1.2.3 From 0784123a4042353beedc84960bbbf51068eec295 Mon Sep 17 00:00:00 2001 From: Manuel Hermann Date: Mon, 11 Jul 2011 16:47:38 +0200 Subject: Decorator version of config.add_response_adapter. --- docs/narr/hooks.rst | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 94701c9f9..0dcbcd371 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -536,7 +536,8 @@ 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 -:meth:`pyramid.config.Configurator.add_response_adapter`. +:meth:`pyramid.config.Configurator.add_response_adapter` or the +:class:`~pyramid.response.response_adapter` decorator. .. note:: This feature is new as of Pyramid 1.1. @@ -573,6 +574,20 @@ Response: config.add_response_adapter(string_response_adapter, str) +The above example using the :class:`~pyramid.response.response_adapter` +decorator: + +.. code-block:: python + :linenos: + + from pyramid.response import Response + from pyramid.response import response_adapter + + @response_adapter(str) + def string_response_adapter(s): + response = Response(s) + return response + 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: -- cgit v1.2.3 From f9896b60700ea4334f3df0a83f9b291e167b322d Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Tue, 12 Jul 2011 03:31:08 -0400 Subject: reviewed --- docs/narr/hooks.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 94701c9f9..a156426ae 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -284,8 +284,8 @@ Using Response Callbacks Unlike many other web frameworks, :app:`Pyramid` does not eagerly create a global response object. Adding a :term:`response callback` allows an -application to register an action to be performed against a response object -once it is created, usually in order to mutate it. +application to register an action to be performed against whatever response +object is returned by a view, usually in order to mutate the response. The :meth:`pyramid.request.Request.add_response_callback` method is used to register a response callback. -- cgit v1.2.3 From 6ce1e0cf1a141767ee0aca70786c15dd993347c5 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Wed, 20 Jul 2011 06:10:38 -0400 Subject: add more index markers --- docs/narr/hooks.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index a156426ae..2a6414e1f 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -218,7 +218,7 @@ Another (deprecated) mechanism which allows event subscribers more control when adding renderer global values exists in :ref:`adding_renderer_globals`. .. index:: - single: renderer globals + single: adding renderer globals .. _adding_renderer_globals: @@ -528,6 +528,7 @@ The default context URL generator is available for perusal as the class .. index:: single: IResponse + single: special view responses .. _using_iresponse: -- cgit v1.2.3 From 15ac15d60e788c087facfce85b1ead9f7dd4c3ae Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Fri, 22 Jul 2011 11:55:19 -0500 Subject: Fixed formatting fail. --- docs/narr/hooks.rst | 3 +++ 1 file changed, 3 insertions(+) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 2a6414e1f..985934736 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -601,6 +601,9 @@ 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)``: +.. code-block:: python + :linenos: + from pyramid.interfaces import IResponse from zope.interface import implements -- cgit v1.2.3 From 1f901ab75c55bafc9c233c3c9588cc1bd92d9d66 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Thu, 28 Jul 2011 17:06:29 -0400 Subject: add some edits to the docs for response_adapter decorator; fix renderings --- docs/narr/hooks.rst | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index df081d35c..fc3f01271 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -575,20 +575,6 @@ Response: config.add_response_adapter(string_response_adapter, str) -The above example using the :class:`~pyramid.response.response_adapter` -decorator: - -.. code-block:: python - :linenos: - - from pyramid.response import Response - from pyramid.response import response_adapter - - @response_adapter(str) - def string_response_adapter(s): - response = Response(s) - return response - 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: @@ -639,6 +625,29 @@ 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. +Instead of using :meth:`pyramid.config.Configurator.add_response_adapter`, +you can use the :class:`pyramid.response.response_adapter` decorator: + +.. code-block:: python + :linenos: + + from pyramid.response import Response + from pyramid.response import response_adapter + + @response_adapter(str) + def string_response_adapter(s): + response = Response(s) + return response + +The above example, when scanned, has the same effect as: + +.. code-block:: python + + config.add_response_adapter(string_response_adapter, str) + +The :class:`~pyramid.response.response_adapter` decorator will have no effect +until activated by a :term:`scan`. + .. index:: single: view mapper -- cgit v1.2.3 From 875ded31e7fdd0c85d1c91458248581b9dd729d7 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Sat, 30 Jul 2011 01:50:24 -0600 Subject: Updated all of the docs to reflect the new pyramid.* settings prefix. --- docs/narr/hooks.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index fc3f01271..4f493c854 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -61,8 +61,8 @@ Here's some sample code that implements a minimal NotFound view callable: caused the not found view to be called. The value of ``request.exception.message`` 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. + ``pyramid.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`` @@ -128,8 +128,8 @@ Here's some sample code that implements a minimal forbidden view: ``request.exception.message`` will be a value explaining why the forbidden was raised and ``request.exception.result`` will be extended information about the forbidden exception. These messages will be different when the - ``debug_authorization`` environment setting is true than it is when it is - false. + ``pyramid.debug_authorization`` environment setting is true than it is when + it is false. .. index:: single: request factory -- cgit v1.2.3 From 1311321d454ded6226b09f929ebc9e4aa2c12771 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 6 Aug 2011 18:58:26 -0400 Subject: add tweens module, add docs for ptweens and tweens to hooks --- docs/narr/hooks.rst | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 4f493c854..7290876e6 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -828,3 +828,131 @@ performed, enabling you to set up the utility in advance: For full details, please read the `Venusian documentation `_. +.. _registering_tweens: + +Registering "Tweens" +-------------------- + +.. note:: Tweens are a feature which were added in Pyramid 1.1.1. They are + not available in any previous version. + +A :term:`tween` (think: "between") is a bit of code that sits between the +Pyramid router's main request handling function and the upstream WSGI +component that uses :app:`Pyramid` as its "app". This is a feature that may +be used by Pyramid framework extensions, to provide, for example, +Pyramid-specific view timing support bookkeeping code that examines +exceptions before they are returned to the upstream WSGI application. Tweens +behave a bit like :term:`WSGI` middleware but they have the benefit of +running in a context in which they have access to the Pyramid +:term:`application registry` as well as the Pyramid rendering machinery. + +To make use of tweens, you must construct a "tween factory". A tween factory +must be a callable (or a :term:`dotted Python name` to such a callable) which +accepts two arguments: ``handler`` and ``registry``. ``handler`` will be the +either the main Pyramid request handling function or another tween (if more +than one tween is configured into the request handling chain). ``registry`` +will be the Pyramid :term:`application registry` represented by this +Configurator. A tween factory must return a tween when it is called. + +A tween is a callable which accepts a :term:`request` object and returns a +two-tuple consisting of a :term:`request` object and a :term:`response` +object. + +Once you've created a tween factory, you can register it using the +:meth:`pyramid.config.Configurator.add_tween` method. + +Here's an example creating a tween factory and registering it: + +.. code-block:: python + :lineno: + + import time + from pyramid.settings import asbool + import logging + + log = logging.getLogger(__name__) + + def timing_tween_factory(handler, registry): + if asbool(registry.settings.get('do_timing')): + # if timing support is enabled, return a wrapper + def timing_tween(request): + start = time.time() + try: + request, response = handler(request) + finally: + end = time.time() + log.debug('The request took %s seconds' % + (end - start)) + return request, response + return timing_tween + # if timing support is not enabled, return the original + # handler + return handler + + from pyramid.config import Configurator + + config = Configurator() + config.add_tween(timing_tween_factory) + +The ``request`` argument to a tween will be the request created by Pyramid's +router when it receives a WSGI request. + +If more than one call to :meth:`pyramid.config.Configurator.add_tween` is +made within a single application configuration, the added tweens will be +chained together. The first tween factory added will be called with the +default Pyramid request handler as its ``handler`` argument, the second tween +factory added will be called with the result of the first tween factory as +its ``handler`` argument, and so on, ad infinitum. The Pyramid router will +use the outermost tween produced by this chain (the tween generated by the +very last tween factory added) as its request handler function. + +Pyramid will prevent the same tween factory from being added to the implicit +tween chain more than once using configuration conflict detection. If you +wish to add the same tween factory more than once in a configuration, you +should either: a) use a tween factory that is an instance rather than a +function or class, b) use a function or class as a tween factory with the +same logic as the other tween factory it conflicts with but with a different +``__name__`` attribute or c) call :meth:`pyramid.config.Configurator.commit` +between calls to :meth:`pyramid.config.Configurator.add_tween`. + +By default, the ordering of the chain is controlled entirely by the relative +ordering of calls to :meth:`pyramid.config.Configurator.add_tween`. However, +the deploying user can override tween inclusion and ordering entirely in his +Pyramid configuration using the ``pyramid.tweens`` settings value. When +used, this settings value will be a list of Python dotted names which imply +the ordering (and inclusion) of tween factories in the tween chain. For +example: + +.. code-block:: ini + :linenos: + + [app:main] + use = egg:MyApp + pyramid.reload_templates = true + pyramid.debug_authorization = false + pyramid.debug_notfound = false + pyramid.debug_routematch = false + pyramid.debug_templates = true + pyramid.tweens = pyramid.tweens.excview_tween_factory + myapp.my_cool_tween_factory + +In the above configuration, calls made during configuration to +:meth:`pyramid.config.Configurator.add_tween` are ignored, and the user is +telling the system to use the tween factories he has listed in the +``pyramid.tweens`` configuration setting (each is a:term:`Python dotted name` +which points to a tween factory). The *last* tween factory in the +``pyramid.tweens`` list will be used as the producer of the effective +:app:`Pyramid` request handling function; it will wrap the tween factory +declared directly "above" it, ad infinitum. + +.. note:: Pyramid's own :term:`exception view` handling logic is implemented + as a tween factory function: :func:`pyramid.tweens.excview_tween_factory`. + If Pyramid exception view handling is desired, and tween factories are + specified via the ``pyramid.tweens`` configuration setting, the + :func:`pyramid.tweens.excview_tween_factory` function must be added to the + ``pyramid.tweens`` configuration setting list explicitly. If it is not + present, Pyramid will not perform exception view handling. + +The ``paster ptweens`` command-line utility can be used to report the current +tween chain used by an application. See :ref:`displaying_tweens`. + -- cgit v1.2.3 From 8d1533d95ceebbef641a220236b77d9b3931cc31 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 6 Aug 2011 20:22:43 -0400 Subject: change return value of tween to just response --- docs/narr/hooks.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 7290876e6..c6438dfdf 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -855,8 +855,7 @@ will be the Pyramid :term:`application registry` represented by this Configurator. A tween factory must return a tween when it is called. A tween is a callable which accepts a :term:`request` object and returns a -two-tuple consisting of a :term:`request` object and a :term:`response` -object. +two-tuple a :term:`response` object. Once you've created a tween factory, you can register it using the :meth:`pyramid.config.Configurator.add_tween` method. @@ -878,12 +877,12 @@ Here's an example creating a tween factory and registering it: def timing_tween(request): start = time.time() try: - request, response = handler(request) + response = handler(request) finally: end = time.time() log.debug('The request took %s seconds' % (end - start)) - return request, response + return response return timing_tween # if timing support is not enabled, return the original # handler -- cgit v1.2.3 From 18a99ae15e7f36cd21da6e2d2e70d61d1733bf30 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 6 Aug 2011 20:35:34 -0400 Subject: docs rendering --- docs/narr/hooks.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index c6438dfdf..889e8d6d8 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -863,7 +863,7 @@ Once you've created a tween factory, you can register it using the Here's an example creating a tween factory and registering it: .. code-block:: python - :lineno: + :linenos: import time from pyramid.settings import asbool -- cgit v1.2.3 From 05f610e6ed66f8d5aca9d77ae0748feb0c8f8479 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Mon, 8 Aug 2011 23:26:59 -0400 Subject: document under and over params --- docs/narr/hooks.rst | 208 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 169 insertions(+), 39 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 889e8d6d8..f7ee82821 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -836,11 +836,11 @@ Registering "Tweens" .. note:: Tweens are a feature which were added in Pyramid 1.1.1. They are not available in any previous version. -A :term:`tween` (think: "between") is a bit of code that sits between the -Pyramid router's main request handling function and the upstream WSGI -component that uses :app:`Pyramid` as its "app". This is a feature that may -be used by Pyramid framework extensions, to provide, for example, -Pyramid-specific view timing support bookkeeping code that examines +A :term:`tween` (a contraction of the word "between") is a bit of code that +sits between the Pyramid router's main request handling function and the +upstream WSGI component that uses :app:`Pyramid` as its "app". This is a +feature that may be used by Pyramid framework extensions, to provide, for +example, Pyramid-specific view timing support bookkeeping code that examines exceptions before they are returned to the upstream WSGI application. Tweens behave a bit like :term:`WSGI` middleware but they have the benefit of running in a context in which they have access to the Pyramid @@ -857,8 +857,8 @@ Configurator. A tween factory must return a tween when it is called. A tween is a callable which accepts a :term:`request` object and returns a two-tuple a :term:`response` object. -Once you've created a tween factory, you can register it using the -:meth:`pyramid.config.Configurator.add_tween` method. +Once you've created a tween factory, you can register it into the implicit +tween chain using the :meth:`pyramid.config.Configurator.add_tween` method. Here's an example creating a tween factory and registering it: @@ -897,30 +897,145 @@ The ``request`` argument to a tween will be the request created by Pyramid's router when it receives a WSGI request. If more than one call to :meth:`pyramid.config.Configurator.add_tween` is -made within a single application configuration, the added tweens will be -chained together. The first tween factory added will be called with the -default Pyramid request handler as its ``handler`` argument, the second tween -factory added will be called with the result of the first tween factory as -its ``handler`` argument, and so on, ad infinitum. The Pyramid router will -use the outermost tween produced by this chain (the tween generated by the -very last tween factory added) as its request handler function. - -Pyramid will prevent the same tween factory from being added to the implicit -tween chain more than once using configuration conflict detection. If you -wish to add the same tween factory more than once in a configuration, you -should either: a) use a tween factory that is an instance rather than a -function or class, b) use a function or class as a tween factory with the -same logic as the other tween factory it conflicts with but with a different -``__name__`` attribute or c) call :meth:`pyramid.config.Configurator.commit` -between calls to :meth:`pyramid.config.Configurator.add_tween`. - -By default, the ordering of the chain is controlled entirely by the relative -ordering of calls to :meth:`pyramid.config.Configurator.add_tween`. However, -the deploying user can override tween inclusion and ordering entirely in his -Pyramid configuration using the ``pyramid.tweens`` settings value. When -used, this settings value will be a list of Python dotted names which imply -the ordering (and inclusion) of tween factories in the tween chain. For -example: +made within a single application configuration, the tweens will be chained +together at application startup time. The *first* tween factory added via +``add_tween`` will be called with the Pyramid exception view tween factory as +its ``handler`` argument, then the tween factory added directly after that +one will be called with the result of the first tween factory as its +``handler`` argument, and so on, ad infinitum until all tween factories have +been called. The Pyramid router will use the outermost tween produced by this +chain (the tween generated by the very last tween factory added) as its +request handler function. For example: + +.. code-block:: python + :linenos: + + from pyramid.config import Configurator + + config = Configurator() + config.add_tween('myapp.tween_factory1') + config.add_tween('myapp.tween_factory2') + +The above example will generate an implicit tween chain that looks like +this:: + + INGRESS (implicit) + myapp.tween_factory2 + myapp.tween_factory1 + pyramid.tweens.excview_tween_factory (implicit) + MAIN (implicit) + +By default, as described above, the ordering of the chain is controlled +entirely by the relative ordering of calls to +:meth:`pyramid.config.Configurator.add_tween`. However, the caller of +add_tween can provide an optional hint that can influence the implicit tween +chain ordering by supplying ``under`` or ``over`` (or both) arguments to +:meth:`~pyramid.config.Configurator.add_tween`. These hints are only used +used when an explicit tween chain is not used (when the ``pyramid.tweens`` +configuration value is not set). + +Allowable values for ``under`` or ``over`` (or both) are: + +- ``None`` (the default). + +- A :term:`dotted Python name` to a tween factory: a string representing the + predicted dotted name of a tween factory added in a call to ``add_tween`` + in the same configuration session. + +- A "tween alias": a string representing the predicted value of ``alias`` in + a separate call to ``add_tween`` in the same configuration session + +- One of the constants :attr:`pyramid.tweens.MAIN`, + :attr:`pyramid.tweens.INGRESS`, or :attr:`pyramid.tweens.EXCVIEW`. + +Effectively, ``under`` means "closer to the main Pyramid application than", +``over`` means "closer to the request ingress than". + +For example, the following call to +:meth:`~pyramid.config.Configurator.add_tween` will attempt to place the +tween factory represented by ``myapp.tween_factory`` directly 'above' (in +``paster ptweens`` order) the main Pyramid request handler. + +.. code-block:: python + :linenos: + + import pyramid.tweens + + config.add_tween('myapp.tween_factory', over=pyramid.tweens.MAIN) + +The above example will generate an implicit tween chain that looks like +this:: + + INGRESS (implicit) + pyramid.tweens.excview_tween_factory (implicit) + myapp.tween_factory + MAIN (implicit) + +Likewise, calling the following call to +:meth:`~pyramid.config.Configurator.add_tween` will attempt to place this +tween factory 'above' the main handler but 'below' a separately added tween +factory: + +.. code-block:: python + :linenos: + + import pyramid.tweens + + config.add_tween('myapp.tween_factory1', + over=pyramid.tweens.MAIN) + config.add_tween('myapp.tween_factory2', + over=pyramid.tweens.MAIN, + under='myapp.tween_factory1') + +The above example will generate an implicit tween chain that looks like +this:: + + INGRESS (implicit) + pyramid.tweens.excview_tween_factory (implicit) + myapp.tween_factory1 + myapp.tween_factory2 + MAIN (implicit) + +Specifying neither ``over`` nor ``under`` is equivalent to specifying +``under=INGRESS``. + +If an ``under`` or ``over`` value is provided that does not match a tween +factory dotted name or alias in the current configuration, that value will be +ignored. It is not an error to provide an ``under`` or ``over`` value that +matches an unused tween factory. + +:meth:`~pyramid.config.Configurator.add_tween` also accepts an ``alias`` +argument. If ``alias`` is not ``None``, should be a string. The string will +represent a value that other callers of ``add_tween`` may pass as an +``under`` and ``over`` argument instead of a dotted name to a tween factory. +For example: + +.. code-block:: python + :linenos: + + import pyramid.tweens + + config.add_tween('myapp.tween_factory1', + alias='one' + over=pyramid.tweens.MAIN) + config.add_tween('myapp.tween_factory2', + alias='two' + over=pyramid.tweens.MAIN, + under='one') + +Alias names are only useful in relation to ``under`` and ``over`` values. +They cannot be used in explicit tween chain configuration, or anywhere else. + +Implicit tween ordering is obviously only best-effort. Pyramid will attempt +to provide an implicit order of tweens as best it can using hints provided by +calls to :meth:`~pyramid.config.Configurator.add_tween`, but because it's +only best-effort, if very precise tween ordering is required, the only +surefire way to get it is to use an explicit tween order. The deploying user +can override the implicit tween inclusion and ordering implied by calls to +:meth:`~pyramid.config.Configurator.add_tween` entirely by using the +``pyramid.tweens`` settings value. When used, this settings value must be a +list of Python dotted names which will override the ordering (and inclusion) +of tween factories in the implicit tween chain. For example: .. code-block:: ini :linenos: @@ -932,17 +1047,19 @@ example: pyramid.debug_notfound = false pyramid.debug_routematch = false pyramid.debug_templates = true - pyramid.tweens = pyramid.tweens.excview_tween_factory - myapp.my_cool_tween_factory + pyramid.tweens = myapp.my_cool_tween_factory + pyramid.tweens.excview_tween_factory In the above configuration, calls made during configuration to :meth:`pyramid.config.Configurator.add_tween` are ignored, and the user is telling the system to use the tween factories he has listed in the -``pyramid.tweens`` configuration setting (each is a:term:`Python dotted name` -which points to a tween factory). The *last* tween factory in the -``pyramid.tweens`` list will be used as the producer of the effective +``pyramid.tweens`` configuration setting (each is a :term:`dotted Python +name` which points to a tween factory) instead of any tween factories added +via :meth:`pyramid.config.Configurator.add_tween`. The *first* tween factory +in the ``pyramid.tweens`` list will be used as the producer of the effective :app:`Pyramid` request handling function; it will wrap the tween factory -declared directly "above" it, ad infinitum. +declared directly "below" it, ad infinitum. The "main" Pyramid request +handler is implicit, and always "at the bottom". .. note:: Pyramid's own :term:`exception view` handling logic is implemented as a tween factory function: :func:`pyramid.tweens.excview_tween_factory`. @@ -952,6 +1069,19 @@ declared directly "above" it, ad infinitum. ``pyramid.tweens`` configuration setting list explicitly. If it is not present, Pyramid will not perform exception view handling. -The ``paster ptweens`` command-line utility can be used to report the current -tween chain used by an application. See :ref:`displaying_tweens`. +Pyramid will prevent the same tween factory from being added to the tween +chain more than once using configuration conflict detection. If you wish to +add the same tween factory more than once in a configuration, you should +either: a) use a tween factory that is an instance rather than a function or +class, b) use a function or class as a tween factory with the same logic as +the other tween factory it conflicts with but with a different ``__name__`` +attribute or c) call :meth:`pyramid.config.Configurator.commit` between calls +to :meth:`pyramid.config.Configurator.add_tween`. +If a cycle is detected in implicit tween ordering when ``over`` and ``under`` +are used in any call to "add_tween", an exception will be raised at startup +time. + +The ``paster ptweens`` command-line utility can be used to report the current +implict and explicit tween chains used by an application. See +:ref:`displaying_tweens`. -- cgit v1.2.3 From 57144ec3a2387abc46abea1e00d36c23b25cc1b7 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Wed, 10 Aug 2011 20:52:06 -0400 Subject: trunk is 1.2dev, who are we fooling --- docs/narr/hooks.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index f7ee82821..f81385c93 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -833,7 +833,7 @@ For full details, please read the `Venusian documentation Registering "Tweens" -------------------- -.. note:: Tweens are a feature which were added in Pyramid 1.1.1. They are +.. note:: Tweens are a feature which were added in Pyramid 1.2. They are not available in any previous version. A :term:`tween` (a contraction of the word "between") is a bit of code that -- cgit v1.2.3 From be46dacfd3b197ce3d8cb907532daa49c93fb8df Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Fri, 12 Aug 2011 00:08:16 -0400 Subject: add pyramid.tweens configuration value docs --- docs/narr/hooks.rst | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index f81385c93..e07dca9bd 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -932,7 +932,8 @@ add_tween can provide an optional hint that can influence the implicit tween chain ordering by supplying ``under`` or ``over`` (or both) arguments to :meth:`~pyramid.config.Configurator.add_tween`. These hints are only used used when an explicit tween chain is not used (when the ``pyramid.tweens`` -configuration value is not set). +configuration value is not set). See :ref:`explicit_tweens` for a +description of how to set an explicit tweens list. Allowable values for ``under`` or ``over`` (or both) are: @@ -1026,6 +1027,11 @@ For example: Alias names are only useful in relation to ``under`` and ``over`` values. They cannot be used in explicit tween chain configuration, or anywhere else. +.. _explicit_tween_ordering: + +Explicit Tween Ordering +~~~~~~~~~~~~~~~~~~~~~~~ + Implicit tween ordering is obviously only best-effort. Pyramid will attempt to provide an implicit order of tweens as best it can using hints provided by calls to :meth:`~pyramid.config.Configurator.add_tween`, but because it's @@ -1069,6 +1075,9 @@ handler is implicit, and always "at the bottom". ``pyramid.tweens`` configuration setting list explicitly. If it is not present, Pyramid will not perform exception view handling. +Tween Conflicts and Ordering Cycles +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Pyramid will prevent the same tween factory from being added to the tween chain more than once using configuration conflict detection. If you wish to add the same tween factory more than once in a configuration, you should @@ -1082,6 +1091,9 @@ If a cycle is detected in implicit tween ordering when ``over`` and ``under`` are used in any call to "add_tween", an exception will be raised at startup time. +Displaying Tween Ordering +~~~~~~~~~~~~~~~~~~~~~~~~~ + The ``paster ptweens`` command-line utility can be used to report the current implict and explicit tween chains used by an application. See :ref:`displaying_tweens`. -- cgit v1.2.3 From 47369747d8050faddd8b98f4cad9f5d0bb263130 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Fri, 12 Aug 2011 00:17:52 -0400 Subject: garden changes; fix docs rendering --- docs/narr/hooks.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index e07dca9bd..cd2109c5c 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -931,9 +931,9 @@ entirely by the relative ordering of calls to add_tween can provide an optional hint that can influence the implicit tween chain ordering by supplying ``under`` or ``over`` (or both) arguments to :meth:`~pyramid.config.Configurator.add_tween`. These hints are only used -used when an explicit tween chain is not used (when the ``pyramid.tweens`` -configuration value is not set). See :ref:`explicit_tweens` for a -description of how to set an explicit tweens list. +used when an explicit tween ordering is not used. See +:ref:`explicit_tween_ordering` for a description of how to set an explicit +tween ordering. Allowable values for ``under`` or ``over`` (or both) are: -- cgit v1.2.3 From 9ec766cf34014de1e357a449133830ff944efb19 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Fri, 12 Aug 2011 03:08:54 -0500 Subject: Updated the docs with the new over/under tuples. --- docs/narr/hooks.rst | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index f81385c93..fafb407d3 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -948,6 +948,10 @@ Allowable values for ``under`` or ``over`` (or both) are: - One of the constants :attr:`pyramid.tweens.MAIN`, :attr:`pyramid.tweens.INGRESS`, or :attr:`pyramid.tweens.EXCVIEW`. +- An iterable of any combination of the above. This allows the user to specify + fallbacks if the desired tween is not included, as well as compatibility + with multiple other tweens. + Effectively, ``under`` means "closer to the main Pyramid application than", ``over`` means "closer to the request ingress than". @@ -999,10 +1003,14 @@ this:: Specifying neither ``over`` nor ``under`` is equivalent to specifying ``under=INGRESS``. -If an ``under`` or ``over`` value is provided that does not match a tween -factory dotted name or alias in the current configuration, that value will be -ignored. It is not an error to provide an ``under`` or ``over`` value that -matches an unused tween factory. +If all options for ``under`` (or ``over``) cannot be found in the current +configuration, it is an error. If some options are specified purely for +compatibilty with other tweens, just add a fallback of MAIN or INGRESS. +For example, ``under=('someothertween', 'someothertween2', INGRESS)``. +This constraint will require the tween to be located under both the +'someothertween' tween, the 'someothertween2' tween, and INGRESS. If any of +these is not in the current configuration, this constraint will only organize +itself based on the tweens that are present. :meth:`~pyramid.config.Configurator.add_tween` also accepts an ``alias`` argument. If ``alias`` is not ``None``, should be a string. The string will -- cgit v1.2.3 From 157c29002377b65834a960fd2d59c40bdd43f417 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 13 Aug 2011 06:11:26 -0400 Subject: disallow adding a tween factory which is an instance without passing its globally importable name --- docs/narr/hooks.rst | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index c8efc057c..97bee479b 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -847,12 +847,12 @@ running in a context in which they have access to the Pyramid :term:`application registry` as well as the Pyramid rendering machinery. To make use of tweens, you must construct a "tween factory". A tween factory -must be a callable (or a :term:`dotted Python name` to such a callable) which -accepts two arguments: ``handler`` and ``registry``. ``handler`` will be the -either the main Pyramid request handling function or another tween (if more -than one tween is configured into the request handling chain). ``registry`` -will be the Pyramid :term:`application registry` represented by this -Configurator. A tween factory must return a tween when it is called. +must be a globally importable callable (or a :term:`dotted Python name` to +such a callable) which accepts two arguments: ``handler`` and ``registry``. +``handler`` will be the either the main Pyramid request handling function or +another tween. ``registry`` will be the Pyramid :term:`application registry` +represented by this Configurator. A tween factory must return a tween when +it is called. A tween is a callable which accepts a :term:`request` object and returns a two-tuple a :term:`response` object. @@ -1089,11 +1089,12 @@ Tween Conflicts and Ordering Cycles Pyramid will prevent the same tween factory from being added to the tween chain more than once using configuration conflict detection. If you wish to add the same tween factory more than once in a configuration, you should -either: a) use a tween factory that is an instance rather than a function or -class, b) use a function or class as a tween factory with the same logic as -the other tween factory it conflicts with but with a different ``__name__`` -attribute or c) call :meth:`pyramid.config.Configurator.commit` between calls -to :meth:`pyramid.config.Configurator.add_tween`. +either: a) use a tween factory that is a separate globally importable +instance object from the factory that it conflicts with b) use a function or +class as a tween factory with the same logic as the other tween factory it +conflicts with but with a different ``__name__`` attribute or c) call +:meth:`pyramid.config.Configurator.commit` between calls to +:meth:`pyramid.config.Configurator.add_tween`. If a cycle is detected in implicit tween ordering when ``over`` and ``under`` are used in any call to "add_tween", an exception will be raised at startup -- cgit v1.2.3 From 5396466b819692ae0d1ea2b78e6df6093545963a Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 13 Aug 2011 23:30:46 -0400 Subject: Require that tween_factory argument to add_tween be a dotted name. --- docs/narr/hooks.rst | 79 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 64 insertions(+), 15 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 97bee479b..50758f327 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -846,25 +846,26 @@ behave a bit like :term:`WSGI` middleware but they have the benefit of running in a context in which they have access to the Pyramid :term:`application registry` as well as the Pyramid rendering machinery. +Creating a Tween Factory +~~~~~~~~~~~~~~~~~~~~~~~~ + To make use of tweens, you must construct a "tween factory". A tween factory -must be a globally importable callable (or a :term:`dotted Python name` to -such a callable) which accepts two arguments: ``handler`` and ``registry``. -``handler`` will be the either the main Pyramid request handling function or -another tween. ``registry`` will be the Pyramid :term:`application registry` -represented by this Configurator. A tween factory must return a tween when -it is called. +must be a globally importable callable which accepts two arguments: +``handler`` and ``registry``. ``handler`` will be the either the main +Pyramid request handling function or another tween. ``registry`` will be the +Pyramid :term:`application registry` represented by this Configurator. A +tween factory must return a tween when it is called. A tween is a callable which accepts a :term:`request` object and returns a two-tuple a :term:`response` object. -Once you've created a tween factory, you can register it into the implicit -tween chain using the :meth:`pyramid.config.Configurator.add_tween` method. - -Here's an example creating a tween factory and registering it: +Here's an example of a tween factory: .. code-block:: python :linenos: + # in a module named myapp.tweens + import time from pyramid.settings import asbool import logging @@ -888,13 +889,58 @@ Here's an example creating a tween factory and registering it: # handler return handler - from pyramid.config import Configurator +If you remember, a tween is an object which accepts a :term:`request` object +and which returns a :term:`response` argument. The ``request`` argument to a +tween will be the request created by Pyramid's router when it receives a WSGI +request. The response object will be generated by the downstream Pyramid +application and it should be returned by the tween. + +In the above example, the tween factory defines a ``timing_tween`` tween and +returns it if ``asbool(registry.settings.get('do_timing'))`` is true. It +otherwise simply returns the handler it was given. The ``registry.settings`` +attribute is a handle to the deployment settings provided by the user +(usually in an ``.ini`` file). In this case, if the user has defined a +``do_timing`` setting, and that setting is ``True``, the user has said she +wants to do timing, so the tween factory returns the timing tween; it +otherwise just returns the handler it has been provided, preventing any +timing. + +The example timing tween simply records the start time, calls the downstream +handler, logs the number of seconds consumed by the downstream handler, and +returns the response. + +Registering an Implicit Tween Factory +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - config = Configurator() - config.add_tween(timing_tween_factory) +Once you've created a tween factory, you can register it into the implicit +tween chain using the :meth:`pyramid.config.Configurator.add_tween` method +using its :term:`dotted Python name`. -The ``request`` argument to a tween will be the request created by Pyramid's -router when it receives a WSGI request. +Here's an example of registering the a tween factory as an "implicit" +tween in a Pyramid application: + +.. code-block:: python + :linenos: + + from pyramid.config import Configurator + config = Configurator() + config.add_tween('myapp.tweens.timing_tween_factory') + +Note that you must use a :term:`dotted Python name` as the first argument to +:meth:`pyramid.config.Configurator.add_tween`; this must point at a tween +factory. You cannot pass the tween factory object itself to the method: it +must be a globally importable object. In the above example, we assume that a +``timing_tween_factory`` tween factory was defined in a module named +``myapp.tweens``, so the tween factory is importable as +``myapp.tweens.timing_tween_factory``. + +When you use :meth:`pyramid.config.Configurator.add_tween`, you're +instructing the system to use your tween factory at startup time unless the +user has provided an explicit tween list in his configuration. This is +what's meant by an "implicit" tween. A user can always elect to supply an +explicit tween list, reordering or disincluding implicitly added tweens. See +:ref:`explicit_tween_ordering` for more information about explicit tween +ordering. If more than one call to :meth:`pyramid.config.Configurator.add_tween` is made within a single application configuration, the tweens will be chained @@ -925,6 +971,9 @@ this:: pyramid.tweens.excview_tween_factory (implicit) MAIN (implicit) +Suggesting Implicit Tween Ordering +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + By default, as described above, the ordering of the chain is controlled entirely by the relative ordering of calls to :meth:`pyramid.config.Configurator.add_tween`. However, the caller of -- cgit v1.2.3 From fb90f0166728af40142ed9a31039d26ca3f97c73 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 14 Aug 2011 04:58:34 -0400 Subject: - The ``route_url``, ``route_path``, ``resource_url``, ``static_url``, and ``current_route_url`` functions in the ``pyramid.url`` package now delegate to a method on the request they've been passed, instead of the other way around. The pyramid.request.Request object now inherits from a mixin named pyramid.url.URLMethodsMixin to make this possible, and all url/path generation logic is embedded in this mixin. - Narrative and API documentation which used the ``route_url``, ``route_path``, ``resource_url``, ``static_url``, and ``current_route_url`` functions in the ``pyramid.url`` package have now been changed to use eponymous methods of the request instead. --- docs/narr/hooks.rst | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 50758f327..df5339c8a 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -468,17 +468,18 @@ when the application :term:`root factory` returned an instance of the .. _changing_resource_url: -Changing How :mod:`pyramid.url.resource_url` Generates a URL ------------------------------------------------------------- +Changing How :meth:`pyramid.request.Request.resource_url` Generates a URL +------------------------------------------------------------------------- When you add a traverser as described in :ref:`changing_the_traverser`, it's -often convenient to continue to use the :func:`pyramid.url.resource_url` API. -However, since the way traversal is done will have been modified, the URLs it -generates by default may be incorrect. +often convenient to continue to use the +:meth:`pyramid.request.Request.resource_url` API. However, since the way +traversal is done will have been modified, the URLs it generates by default +may be incorrect. If you've added a traverser, you can change how -:func:`~pyramid.url.resource_url` generates a URL for a specific type of -resource by adding a registerAdapter call for +:meth:`~pyramid.request.Request.resource_url` generates a URL for a specific +type of resource by adding a registerAdapter call for :class:`pyramid.interfaces.IContextURL` to your application: .. code-block:: python @@ -493,8 +494,8 @@ resource by adding a registerAdapter call for IContextURL) In the above example, the ``myapp.traversal.URLGenerator`` class will be used -to provide services to :func:`~pyramid.url.resource_url` any time the -:term:`context` passed to ``resource_url`` is of class +to provide services to :meth:`~pyramid.request.Request.resource_url` any time +the :term:`context` passed to ``resource_url`` is of class ``myapp.resources.MyRoot``. The second argument in the ``(MyRoot, Interface)`` tuple represents the type of interface that must be possessed by the :term:`request` (in this case, any interface, represented by -- cgit v1.2.3 From 4f070b0887e43c6582a06e0e2c318a5c09962340 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 20 Aug 2011 22:10:23 -0400 Subject: remove tween aliases as a concept --- docs/narr/hooks.rst | 33 ++++----------------------------- 1 file changed, 4 insertions(+), 29 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index df5339c8a..4afc0506b 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -930,10 +930,10 @@ tween in a Pyramid application: Note that you must use a :term:`dotted Python name` as the first argument to :meth:`pyramid.config.Configurator.add_tween`; this must point at a tween factory. You cannot pass the tween factory object itself to the method: it -must be a globally importable object. In the above example, we assume that a -``timing_tween_factory`` tween factory was defined in a module named -``myapp.tweens``, so the tween factory is importable as -``myapp.tweens.timing_tween_factory``. +must be :term:`dotted Python name` that points to a globally importable +object. In the above example, we assume that a ``timing_tween_factory`` +tween factory was defined in a module named ``myapp.tweens``, so the tween +factory is importable as ``myapp.tweens.timing_tween_factory``. When you use :meth:`pyramid.config.Configurator.add_tween`, you're instructing the system to use your tween factory at startup time unless the @@ -993,9 +993,6 @@ Allowable values for ``under`` or ``over`` (or both) are: predicted dotted name of a tween factory added in a call to ``add_tween`` in the same configuration session. -- A "tween alias": a string representing the predicted value of ``alias`` in - a separate call to ``add_tween`` in the same configuration session - - One of the constants :attr:`pyramid.tweens.MAIN`, :attr:`pyramid.tweens.INGRESS`, or :attr:`pyramid.tweens.EXCVIEW`. @@ -1063,28 +1060,6 @@ This constraint will require the tween to be located under both the these is not in the current configuration, this constraint will only organize itself based on the tweens that are present. -:meth:`~pyramid.config.Configurator.add_tween` also accepts an ``alias`` -argument. If ``alias`` is not ``None``, should be a string. The string will -represent a value that other callers of ``add_tween`` may pass as an -``under`` and ``over`` argument instead of a dotted name to a tween factory. -For example: - -.. code-block:: python - :linenos: - - import pyramid.tweens - - config.add_tween('myapp.tween_factory1', - alias='one' - over=pyramid.tweens.MAIN) - config.add_tween('myapp.tween_factory2', - alias='two' - over=pyramid.tweens.MAIN, - under='one') - -Alias names are only useful in relation to ``under`` and ``over`` values. -They cannot be used in explicit tween chain configuration, or anywhere else. - .. _explicit_tween_ordering: Explicit Tween Ordering -- cgit v1.2.3 From 012b9762cd0b114b6afbf2d6356554b51706804a Mon Sep 17 00:00:00 2001 From: michr Date: Fri, 23 Sep 2011 18:48:28 -0700 Subject: fixed up all the warning dealing ..note and ..warn added a hide toc for glossary to prevent warnings --- docs/narr/hooks.rst | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 4afc0506b..3ab82ecf7 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -55,7 +55,9 @@ Here's some sample code that implements a minimal NotFound view callable: def notfound_view(request): return HTTPNotFound() -.. note:: When a NotFound view callable is invoked, it is passed a +.. 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.httpexceptions.HTTPNotFound` exception that caused the not found view to be called. The value of @@ -64,7 +66,9 @@ Here's some sample code that implements a minimal NotFound view callable: ``pyramid.debug_notfound`` environment setting is true than it is when it is false. -.. warning:: When a NotFound view callable accepts an argument list as +.. 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.httpexceptions.HTTPNotFound` exception instance. If @@ -121,7 +125,9 @@ Here's some sample code that implements a minimal forbidden view: def forbidden_view(request): return Response('forbidden') -.. note:: When a forbidden view callable is invoked, it is passed a +.. 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.httpexceptions.HTTPForbidden` exception that caused the forbidden view to be called. The value of @@ -1100,7 +1106,9 @@ in the ``pyramid.tweens`` list will be used as the producer of the effective declared directly "below" it, ad infinitum. The "main" Pyramid request handler is implicit, and always "at the bottom". -.. note:: Pyramid's own :term:`exception view` handling logic is implemented +.. note:: + + Pyramid's own :term:`exception view` handling logic is implemented as a tween factory function: :func:`pyramid.tweens.excview_tween_factory`. If Pyramid exception view handling is desired, and tween factories are specified via the ``pyramid.tweens`` configuration setting, the -- cgit v1.2.3 From 7a66b778592422e32d121cf96313204c2ba23b44 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Tue, 27 Sep 2011 00:11:58 -0400 Subject: typo --- docs/narr/hooks.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 3ab82ecf7..7db1eca73 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -863,8 +863,8 @@ Pyramid request handling function or another tween. ``registry`` will be the Pyramid :term:`application registry` represented by this Configurator. A tween factory must return a tween when it is called. -A tween is a callable which accepts a :term:`request` object and returns a -two-tuple a :term:`response` object. +A tween is a callable which accepts a :term:`request` object and returns +a :term:`response` object. Here's an example of a tween factory: -- cgit v1.2.3 From cfb2b5596b8ef366aeef3bce5b61eafc7a2f175d Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Thu, 6 Oct 2011 03:05:29 -0400 Subject: remove all reference to the paster command-line utility --- docs/narr/hooks.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 7db1eca73..3c6799afb 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -727,7 +727,7 @@ A user might make use of these framework components like so: from pyramid.response import Response from pyramid.config import Configurator import pyramid_handlers - from paste.httpserver import serve + from wsgiref.simple_server import make_server class MyController(BaseController): def index(self, id): @@ -738,7 +738,8 @@ A user might make use of these framework components like so: config.include(pyramid_handlers) config.add_handler('one', '/{id}', MyController, action='index') config.add_handler('two', '/{action}/{id}', MyController) - serve(config.make_wsgi_app()) + server.make_server('0.0.0.0', 8080, config.make_wsgi_app()) + server.serve_forever() The :meth:`pyramid.config.Configurator.set_view_mapper` method can be used to set a *default* view mapper (overriding the superdefault view mapper used by @@ -1012,7 +1013,7 @@ Effectively, ``under`` means "closer to the main Pyramid application than", For example, the following call to :meth:`~pyramid.config.Configurator.add_tween` will attempt to place the tween factory represented by ``myapp.tween_factory`` directly 'above' (in -``paster ptweens`` order) the main Pyramid request handler. +``ptweens`` order) the main Pyramid request handler. .. code-block:: python :linenos: @@ -1136,6 +1137,6 @@ time. Displaying Tween Ordering ~~~~~~~~~~~~~~~~~~~~~~~~~ -The ``paster ptweens`` command-line utility can be used to report the current +The ``ptweens`` command-line utility can be used to report the current implict and explicit tween chains used by an application. See :ref:`displaying_tweens`. -- cgit v1.2.3 From 02d7451d4e6a3fafdda8ebbb65e19d4333bb9c33 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Thu, 15 Dec 2011 21:25:43 -0500 Subject: fix import --- docs/narr/hooks.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 3c6799afb..a1ed6c7ff 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -119,7 +119,7 @@ Here's some sample code that implements a minimal forbidden view: .. code-block:: python :linenos: - from pyramid.views import view_config + from pyramid.view import view_config from pyramid.response import Response def forbidden_view(request): -- cgit v1.2.3 From 10f1b5c35072c5499f3504dc261fb3c67a90c70d Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Fri, 16 Dec 2011 04:54:09 -0500 Subject: stamp out paste.httpserver usage --- docs/narr/hooks.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index a1ed6c7ff..fd6544416 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -812,7 +812,7 @@ performed, enabling you to set up the utility in advance: .. code-block:: python :linenos: - from paste.httpserver import serve + from wsgiref.simple_server import make_server from pyramid.config import Configurator from mypackage.interfaces import IMyUtility @@ -831,7 +831,8 @@ performed, enabling you to set up the utility in advance: config.registry.registerUtility(UtilityImplementation()) config.scan() app = config.make_wsgi_app() - serve(app, host='0.0.0.0') + server = make_server('0.0.0.0', 8080, app) + server.serve_forever() For full details, please read the `Venusian documentation `_. -- cgit v1.2.3 From 1ca5b34f17ea889f705c1120a5b8878bff16ec63 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Wed, 15 Feb 2012 16:23:59 -0500 Subject: - Replace all mentions of zope.interface.implements with zope.interface.implementer. --- docs/narr/hooks.rst | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index fd6544416..350b5734d 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -606,24 +606,24 @@ adapter to the more complex IResponse interface: 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)``: +:class:`pyramid.interfaces.IResponse` and you'll have to ensure that it uses +``zope.interface.implementer(IResponse)`` as a class decoratoror. .. code-block:: python :linenos: from pyramid.interfaces import IResponse - from zope.interface import implements + from zope.interface import implementer + @implementer(IResponse) 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 +``zope.interface.implementer(IResponse)``) , an adapter needn't be registered for the object; Pyramid will use it directly. An IResponse adapter for ``webob.Response`` (as opposed to @@ -812,14 +812,15 @@ performed, enabling you to set up the utility in advance: .. code-block:: python :linenos: + from zope.interface import implementer + from wsgiref.simple_server import make_server from pyramid.config import Configurator from mypackage.interfaces import IMyUtility + @implementer(IMyUtility) class UtilityImplementation: - implements(IMyUtility) - def __init__(self): self.registrations = {} -- cgit v1.2.3 From 748aad47f90136b151be13f477ed6af1caed0493 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Wed, 15 Feb 2012 19:09:08 -0500 Subject: - Add ``pyramid.config.Configurator.set_traverser`` API method. See the Hooks narrative documentation section entitled "Changing the Traverser" for more information. This is not a new feature, it just provides an API for adding a traverser without needing to use the ZCA API. --- docs/narr/hooks.rst | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 350b5734d..076f9fa5c 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -406,11 +406,10 @@ via configuration. .. code-block:: python :linenos: - from pyramid.interfaces import ITraverser - from zope.interface import Interface + from pyramid.config import Configurator from myapp.traversal import Traverser - - config.registry.registerAdapter(Traverser, (Interface,), ITraverser) + config = Configurator() + config.set_traverser(Traverser) In the example above, ``myapp.traversal.Traverser`` is assumed to be a class that implements the following interface: @@ -456,12 +455,11 @@ used. Otherwise, the default traverser would be used. For example: .. code-block:: python :linenos: - from pyramid.interfaces import ITraverser - from zope.interface import Interface from myapp.traversal import Traverser from myapp.resources import MyRoot - - config.registry.registerAdapter(Traverser, (MyRoot,), ITraverser) + from pyramid.config import Configurator + config = Configurator() + config.set_traverser(Traverser, MyRoot) If the above stanza was added to a Pyramid ``__init__.py`` file's ``main`` function, :app:`Pyramid` would use the ``myapp.traversal.Traverser`` only -- cgit v1.2.3 From c51896756eeffc7e8c50ad71300ec355ae47465a Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Fri, 17 Feb 2012 01:08:42 -0500 Subject: Features -------- - Add ``pyramid.config.Configurator.add_resource_url_adapter`` API method. See the Hooks narrative documentation section entitled "Changing How pyramid.request.Request.resource_url Generates a URL" for more information. This is not a new feature, it just provides an API for adding a resource url adapter without needing to use the ZCA API. - A new interface was added: ``pyramid.interfaces.IResourceURL``. An adapter implementing its interface can be used to override resource URL generation when ``request.resource_url`` is called. This interface replaces the now-deprecated ``pyramid.interfaces.IContextURL`` interface. - The dictionary passed to a resource's ``__resource_url__`` method (see "Overriding Resource URL Generation" in the "Resources" chapter) now contains an ``app_url`` key, representing the application URL generated during ``request.resource_url``. It represents a potentially customized URL prefix, containing potentially custom scheme, host and port information passed by the user to ``request.resource_url``. It should be used instead of ``request.application_url`` where necessary. - The ``request.resource_url`` API now accepts these arguments: ``app_url``, ``scheme``, ``host``, and ``port``. The app_url argument can be used to replace the URL prefix wholesale during url generation. The ``scheme``, ``host``, and ``port`` arguments can be used to replace the respective default values of ``request.application_url`` partially. - A new API named ``request.resource_path`` now exists. It works like ``request.resource_url`` but produces a relative URL rather than an absolute one. - The ``request.route_url`` API now accepts these arguments: ``_app_url``, ``_scheme``, ``_host``, and ``_port``. The ``_app_url`` argument can be used to replace the URL prefix wholesale during url generation. The ``_scheme``, ``_host``, and ``_port`` arguments can be used to replace the respective default values of ``request.application_url`` partially. Backwards Incompatibilities --------------------------- - The ``pyramid.interfaces.IContextURL`` interface has been deprecated. People have been instructed to use this to register a resource url adapter in the "Hooks" chapter to use to influence ``request.resource_url`` URL generation for resources found via custom traversers since Pyramid 1.0. The interface still exists and registering such an adapter still works, but this interface will be removed from the software after a few major Pyramid releases. You should replace it with an equivalent ``pyramid.interfaces.IResourceURL`` adapter, registered using the new ``pyramid.config.Configurator.add_resource_url_adapter`` API. A deprecation warning is now emitted when a ``pyramid.interfaces.IContextURL`` adapter is found when ``request.resource_url`` is called. Misc ---- - Change ``set_traverser`` API name to ``add_traverser``. Ref #438. --- docs/narr/hooks.rst | 59 +++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 31 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 076f9fa5c..2c4310080 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -479,58 +479,55 @@ When you add a traverser as described in :ref:`changing_the_traverser`, it's often convenient to continue to use the :meth:`pyramid.request.Request.resource_url` API. However, since the way traversal is done will have been modified, the URLs it generates by default -may be incorrect. +may be incorrect when used against resources derived from your custom +traverser. If you've added a traverser, you can change how :meth:`~pyramid.request.Request.resource_url` generates a URL for a specific -type of resource by adding a registerAdapter call for -:class:`pyramid.interfaces.IContextURL` to your application: +type of resource by adding a call to +:meth:`pyramid.config.add_resource_url_adapter`. + +For example: .. code-block:: python :linenos: - from pyramid.interfaces import ITraverser - from zope.interface import Interface - from myapp.traversal import URLGenerator + from myapp.traversal import ResourceURLAdapter from myapp.resources import MyRoot - config.registry.registerAdapter(URLGenerator, (MyRoot, Interface), - IContextURL) + config.add_resource_url_adapter(ResourceURLAdapter, resource_iface=MyRoot) -In the above example, the ``myapp.traversal.URLGenerator`` class will be used -to provide services to :meth:`~pyramid.request.Request.resource_url` any time -the :term:`context` passed to ``resource_url`` is of class -``myapp.resources.MyRoot``. The second argument in the ``(MyRoot, -Interface)`` tuple represents the type of interface that must be possessed by -the :term:`request` (in this case, any interface, represented by -``zope.interface.Interface``). +In the above example, the ``myapp.traversal.ResourceURLAdapter`` class will +be used to provide services to :meth:`~pyramid.request.Request.resource_url` +any time the :term:`resource` passed to ``resource_url`` is of the class +``myapp.resources.MyRoot``. The ``resource_iface`` argument ``MyRoot`` +represents the type of interface that must be possessed by the resource for +this resource url factory to be found. If the ``resource_iface`` argument is +omitted, this resource url adapter will be used for *all* resources. -The API that must be implemented by a class that provides -:class:`~pyramid.interfaces.IContextURL` is as follows: +The API that must be implemented by your a class that provides +:class:`~pyramid.interfaces.IResourceURL` is as follows: .. code-block:: python :linenos: - from zope.interface import Interface - - class IContextURL(Interface): - """ An adapter which deals with URLs related to a context. + class MyResourceURL(object): + """ An adapter which provides the virtual and physical paths of a + resource """ - def __init__(self, context, request): - """ Accept the context and request """ - - def virtual_root(self): - """ Return the virtual root object related to a request and the - current context""" - - def __call__(self): - """ Return a URL that points to the context """ + def __init__(self, resource, request): + """ Accept the resource and request and set self.physical_path and + self.virtual_path""" + self.virtual_path = some_function_of(resource, request) + self.physical_path = some_other_function_of(resource, request) The default context URL generator is available for perusal as the class -:class:`pyramid.traversal.TraversalContextURL` in the `traversal module +:class:`pyramid.traversal.ResourceURL` in the `traversal module `_ of the :term:`Pylons` GitHub Pyramid repository. +See :meth:`pyramid.config.add_resource_url_adapter` for more information. + .. index:: single: IResponse single: special view responses -- cgit v1.2.3 From ee9769d5a23bc346911c00b482865360babf9f36 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 18 Feb 2012 08:17:32 -0500 Subject: minor wording fixes --- docs/narr/hooks.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 2c4310080..a782b9ec6 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -145,10 +145,10 @@ Here's some sample code that implements a minimal forbidden view: Changing the Request Factory ---------------------------- -Whenever :app:`Pyramid` handles a :term:`WSGI` request, it creates a -:term:`request` object based on the WSGI environment it has been passed. By -default, an instance of the :class:`pyramid.request.Request` class is created -to represent the request object. +Whenever :app:`Pyramid` handles a request from a :term:`WSGI` server, it +creates a :term:`request` object based on the WSGI environment it has been +passed. By default, an instance of the :class:`pyramid.request.Request` +class is created to represent the request object. The class (aka "factory") that :app:`Pyramid` uses to create a request object instance can be changed by passing a ``request_factory`` argument to the @@ -236,11 +236,11 @@ Adding Renderer Globals (Deprecated) is documented in :ref:`beforerender_event`. Whenever :app:`Pyramid` handles a request to perform a rendering (after a -view with a ``renderer=`` configuration attribute is invoked, or when any -of the methods beginning with ``render`` within the :mod:`pyramid.renderers` +view with a ``renderer=`` configuration attribute is invoked, or when any of +the methods beginning with ``render`` within the :mod:`pyramid.renderers` module are called), *renderer globals* can be injected into the *system* values sent to the renderer. By default, no renderer globals are injected, -and the "bare" system values (such as ``request``, ``context``, and +and the "bare" system values (such as ``request``, ``context``, ``view``, and ``renderer_name``) are the only values present in the system dictionary passed to every renderer. @@ -447,7 +447,7 @@ that implements the following interface: More than one traversal algorithm can be active at the same time. For instance, if your :term:`root factory` returns more than one type of object -conditionally, you could claim that an alternate traverser adapter is ``for`` +conditionally, you could claim that an alternate traverser adapter is "for" only one particular class or interface. When the root factory returned an object that implemented that class or interface, a custom traverser would be used. Otherwise, the default traverser would be used. For example: -- cgit v1.2.3 From 95129f178f674a9f8def9aa853bacbc2b8e8f0d3 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 18 Feb 2012 19:00:45 -0500 Subject: dont mention arg by name --- docs/narr/hooks.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index a782b9ec6..eaccc14a3 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -495,7 +495,7 @@ For example: from myapp.traversal import ResourceURLAdapter from myapp.resources import MyRoot - config.add_resource_url_adapter(ResourceURLAdapter, resource_iface=MyRoot) + config.add_resource_url_adapter(ResourceURLAdapter, MyRoot) In the above example, the ``myapp.traversal.ResourceURLAdapter`` class will be used to provide services to :meth:`~pyramid.request.Request.resource_url` -- cgit v1.2.3 From 0db4a157083d51251b4d3f574a1699fc76359c9d Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Wed, 22 Feb 2012 15:37:50 -0500 Subject: - New API: ``pyramid.config.Configurator.add_notfound_view``. This is a wrapper for ``pyramid.Config.configurator.add_view`` which provides easy append_slash support. It should be preferred over calling ``add_view`` directly with ``context=HTTPNotFound`` as was previously recommended. - New API: ``pyramid.view.notfound_view_config``. This is a decorator constructor like ``pyramid.view.view_config`` that calls ``pyramid.config.Configurator.add_notfound_view`` when scanned. It should be preferred over using ``pyramid.view.view_config`` with ``context=HTTPNotFound`` as was previously recommended. - The older deprecated ``set_notfound_view`` Configurator method is now an alias for the new ``add_notfound_view`` Configurator method. This has the following impact: the ``context`` sent to views with a ``(context, request)`` call signature registered via the deprecated ``add_notfound_view``/``set_notfound_view`` will now be the HTTPNotFound exception object instead of the actual resource context found. Use ``request.context`` to get the actual resource context. It's also recommended to disuse ``set_notfound_view`` in favor of ``add_notfound_view``, despite the aliasing. - The API documentation for ``pyramid.view.append_slash_notfound_view`` and ``pyramid.view.AppendSlashNotFoundViewFactory`` was removed. These names still exist and are still importable, but they are no longer APIs. Use ``pyramid.config.Configurator.add_notfound_view(append_slash=True)`` or ``pyramid.view.notfound_view_config(append_slash=True)`` to get the same behavior. - The ``set_forbidden_view`` method of the Configurator was removed from the documentation. It has been deprecated since Pyramid 1.1. - The AppendSlashNotFoundViewFactory used request.path to match routes. This was wrong because request.path contains the script name, and this would cause it to fail in circumstances where the script name was not empty. It should have used request.path_info, and now does. - Updated the "Registering a Not Found View" section of the "Hooks" chapter, replacing explanations of registering a view using ``add_view`` or ``view_config`` with ones using ``add_notfound_view`` or ``notfound_view_config``. - Updated the "Redirecting to Slash-Appended Routes" section of the "URL Dispatch" chapter, replacing explanations of registering a view using ``add_view`` or ``view_config`` with ones using ``add_notfound_view`` or ``notfound_view_config`` --- docs/narr/hooks.rst | 81 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 68 insertions(+), 13 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index eaccc14a3..cbc40ceee 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -19,24 +19,66 @@ found view`, which is a :term:`view callable`. A default notfound view exists. The default not found view can be overridden through application 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.httpexceptions.HTTPNotFound` class as the -``context`` of the view configuration. - If your application uses :term:`imperative configuration`, you can replace -the Not Found view by using the :meth:`pyramid.config.Configurator.add_view` -method to register an "exception view": +the Not Found view by using the +:meth:`pyramid.config.Configurator.add_notfound_view` method: .. code-block:: python :linenos: - from pyramid.httpexceptions import HTTPNotFound - from helloworld.views import notfound_view - config.add_view(notfound_view, context=HTTPNotFound) + from helloworld.views import notfound + config.add_notfound_view(notfound) + +Replace ``helloworld.views.notfound`` with a reference to the :term:`view +callable` you want to use to represent the Not Found view. The :term:`not +found view` callable is a view callable like any other. + +If your application instead uses :class:`pyramid.view.view_config` decorators +and a :term:`scan`, you can replace the Not Found view by using the +:class:`pyramid.view.notfound_view_config` decorator: + +.. code-block:: python + :linenos: + + from pyramid.view import notfound_view_config + + notfound_view_config() + def notfound(request): + return Response('Not Found, dude', status='404 Not Found') + + def main(globals, **settings): + config = Configurator() + config.scan() + +This does exactly what the imperative example above showed. -Replace ``helloworld.views.notfound_view`` with a reference to the -:term:`view callable` you want to use to represent the Not Found view. +Your application can define *multiple* not found views if necessary. Both +:meth:`pyramid.config.Configurator.add_notfound_view` and +:class:`pyramid.view.notfound_view_config` take most of the same arguments as +:class:`pyramid.config.Configurator.add_view` and +:class:`pyramid.view.view_config`, respectively. This means that not found +views can carry predicates limiting their applicability. For example: + +.. code-block:: python + :linenos: + + from pyramid.view import notfound_view_config + + notfound_view_config(request_method='GET') + def notfound_get(request): + return Response('Not Found during GET, dude', status='404 Not Found') + + notfound_view_config(request_method='POST') + def notfound_post(request): + return Response('Not Found during POST, dude', status='404 Not Found') + + def main(globals, **settings): + config = Configurator() + config.scan() + +The ``notfound_get`` view will be called when a view could not be found and +the request method was ``GET``. The ``notfound_post`` view will be called +when a view could not be found and the request method was ``POST``. Like any other view, the notfound view must accept at least a ``request`` parameter, or both ``context`` and ``request``. The ``request`` is the @@ -45,6 +87,11 @@ used in the call signature) will be the instance of the :exc:`~pyramid.httpexceptions.HTTPNotFound` exception that caused the view to be called. +Both :meth:`pyramid.config.Configurator.add_notfound_view` and +:class:`pyramid.view.notfound_view_config` can be used to automatically +redirect requests to slash-appended routes. See +:ref:`redirecting_to_slash_appended_routes` for examples. + Here's some sample code that implements a minimal NotFound view callable: .. code-block:: python @@ -52,7 +99,7 @@ Here's some sample code that implements a minimal NotFound view callable: from pyramid.httpexceptions import HTTPNotFound - def notfound_view(request): + def notfound(request): return HTTPNotFound() .. note:: @@ -66,6 +113,14 @@ Here's some sample code that implements a minimal NotFound view callable: ``pyramid.debug_notfound`` environment setting is true than it is when it is false. +.. note:: + + Both :meth:`pyramid.config.Configurator.add_notfound_view` and + :class:`pyramid.view.notfound_view_config` are new as of Pyramid 1.3. + Older Pyramid documentation instructed users to use ``add_view`` instead, + with a ``context`` of ``HTTPNotFound``. This still works; the convenience + method and decorator are just wrappers around this functionality. + .. warning:: When a NotFound view callable accepts an argument list as -- cgit v1.2.3 From a7fe30f0eabd6c6fd3bcc910faa41720a75056de Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Wed, 22 Feb 2012 19:24:09 -0500 Subject: - New API: ``pyramid.config.Configurator.add_forbidden_view``. This is a wrapper for ``pyramid.Config.configurator.add_view`` which does the right thing about permissions. It should be preferred over calling ``add_view`` directly with ``context=HTTPForbidden`` as was previously recommended. - New API: ``pyramid.view.forbidden_view_config``. This is a decorator constructor like ``pyramid.view.view_config`` that calls ``pyramid.config.Configurator.add_forbidden_view`` when scanned. It should be preferred over using ``pyramid.view.view_config`` with ``context=HTTPForbidden`` as was previously recommended. - Updated the "Creating a Not Forbidden View" section of the "Hooks" chapter, replacing explanations of registering a view using ``add_view`` or ``view_config`` with ones using ``add_forbidden_view`` or ``forbidden_view_config``. - Updated all tutorials to use ``pyramid.view.forbidden_view_config`` rather than ``pyramid.view.view_config`` with an HTTPForbidden context. --- docs/narr/hooks.rst | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index cbc40ceee..b7f052b00 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -145,23 +145,40 @@ 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 "forbidden" view consists -only of naming the :exc:`pyramid.httpexceptions.HTTPForbidden` class as the -``context`` of the view configuration. +of using the meth:`pyramid.config.Configurator.add_forbidden_view` API or the +:class:`pyramid.view.forbidden_view_config` decorator. -You can replace the forbidden view by using the -:meth:`pyramid.config.Configurator.add_view` method to register an "exception -view": +For example, you can add a forbidden view by using the +:meth:`pyramid.config.Configurator.add_forbidden_view` method to register a +forbidden view: .. code-block:: python :linenos: from helloworld.views import forbidden_view from pyramid.httpexceptions import HTTPForbidden - config.add_view(forbidden_view, context=HTTPForbidden) + config.add_forbidden_view(forbidden_view) Replace ``helloworld.views.forbidden_view`` with a reference to the Python :term:`view callable` you want to use to represent the Forbidden view. +If instead you prefer to use decorators and a :term:`scan`, you can use the +:class:`pyramid.view.forbidden_view_config` decorator to mark a view callable +as a forbidden view: + +.. code-block:: python + :linenos: + + from pyramid.view import forbidden_view_config + + forbidden_view_config() + def forbidden(request): + return Response('forbidden') + + def main(globals, **settings): + config = Configurator() + config.scan() + Like any other view, the forbidden view must accept at least a ``request`` parameter, or both ``context`` and ``request``. The ``context`` (available as ``request.context`` if you're using the request-only view argument -- cgit v1.2.3 From 46eccc677d8a4995ac08023b1b7c41b79c171fed Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 26 Feb 2012 14:58:14 -0500 Subject: fix instance creation --- docs/narr/hooks.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index b7f052b00..c44323201 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -776,7 +776,7 @@ as keyword arguments. def wrapper(context, request): matchdict = request.matchdict.copy() matchdict.pop('action', None) - inst = view() + inst = view(request) meth = getattr(inst, attr) return meth(**matchdict) return wrapper -- cgit v1.2.3 From 25d7c28c6830d7f55b206b0467cd987e77f07515 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Wed, 29 Feb 2012 08:59:48 -0500 Subject: fix decorators --- docs/narr/hooks.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index c44323201..f1a122c6c 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -42,7 +42,7 @@ and a :term:`scan`, you can replace the Not Found view by using the from pyramid.view import notfound_view_config - notfound_view_config() + @notfound_view_config() def notfound(request): return Response('Not Found, dude', status='404 Not Found') @@ -64,11 +64,11 @@ views can carry predicates limiting their applicability. For example: from pyramid.view import notfound_view_config - notfound_view_config(request_method='GET') + @notfound_view_config(request_method='GET') def notfound_get(request): return Response('Not Found during GET, dude', status='404 Not Found') - notfound_view_config(request_method='POST') + @notfound_view_config(request_method='POST') def notfound_post(request): return Response('Not Found during POST, dude', status='404 Not Found') -- cgit v1.2.3 From ae6d08b96d3a366f979719c05926dc5292d904d3 Mon Sep 17 00:00:00 2001 From: Ruslan Spivak Date: Fri, 2 Mar 2012 03:45:54 -0500 Subject: Remove some confusion about finished callbacks. Rework an example code and remove an incorrect statement about request.exception being set when an exception occurs in a view. The reason for the change is issue #454: https://github.com/Pylons/pyramid/issues/454 --- docs/narr/hooks.rst | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index f1a122c6c..24ea5de21 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -421,15 +421,14 @@ parameter: ``request``. For example: .. code-block:: python :linenos: - import transaction + import logging - def commit_callback(request): - '''commit or abort the transaction associated with request''' - if request.exception is not None: - transaction.abort() - else: - transaction.commit() - request.add_finished_callback(commit_callback) + log = logging.getLogger(__name__) + + def log_callback(request): + """Log information at the end of request""" + log.debug('Request is finished.') + request.add_finished_callback(log_callback) Finished callbacks are called in the order they're added (first-to-most-recently-added). Finished callbacks (unlike a @@ -447,12 +446,6 @@ meaningful effect, because response processing will have already occurred, and the request's scope will expire almost immediately after all finished callbacks have been processed. -It is often necessary to tell whether an exception occurred within -:term:`view callable` code from within a finished callback: in such a case, -the :attr:`request.exception` attribute of the request when it enters a -response callback will be an exception object instead of its default value of -``None``. - Errors raised by finished callbacks are not handled specially. They will be propagated to the caller of the :app:`Pyramid` router application. -- cgit v1.2.3 From 13305e14b74c4ef6bbd44817ed0eac5c36499c2b Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Mon, 5 Mar 2012 03:26:27 -0500 Subject: add_traverser --- docs/narr/hooks.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 24ea5de21..b6e3dd163 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -474,7 +474,7 @@ via configuration. from pyramid.config import Configurator from myapp.traversal import Traverser config = Configurator() - config.set_traverser(Traverser) + config.add_traverser(Traverser) In the example above, ``myapp.traversal.Traverser`` is assumed to be a class that implements the following interface: @@ -524,7 +524,7 @@ used. Otherwise, the default traverser would be used. For example: from myapp.resources import MyRoot from pyramid.config import Configurator config = Configurator() - config.set_traverser(Traverser, MyRoot) + config.add_traverser(Traverser, MyRoot) If the above stanza was added to a Pyramid ``__init__.py`` file's ``main`` function, :app:`Pyramid` would use the ``myapp.traversal.Traverser`` only -- cgit v1.2.3 From bce621a99ee495d8d82f744eaa209ae0f1ac504e Mon Sep 17 00:00:00 2001 From: Patricio Paez Date: Fri, 6 Apr 2012 18:22:13 -0500 Subject: Typos --- docs/narr/hooks.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index b6e3dd163..a2143b3c5 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -145,7 +145,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 "forbidden" view consists -of using the meth:`pyramid.config.Configurator.add_forbidden_view` API or the +of using the :meth:`pyramid.config.Configurator.add_forbidden_view` API or the :class:`pyramid.view.forbidden_view_config` decorator. For example, you can add a forbidden view by using the @@ -171,7 +171,7 @@ as a forbidden view: from pyramid.view import forbidden_view_config - forbidden_view_config() + @forbidden_view_config() def forbidden(request): return Response('forbidden') @@ -625,7 +625,7 @@ 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 +objects (without requiring a :term:`renderer` to convert a string to a response object), you can register an adapter which converts the string to a Response: -- cgit v1.2.3 From a319249fdb6e0539e65e0b297829ed8c7f799b98 Mon Sep 17 00:00:00 2001 From: Jeff Cook Date: Thu, 7 Jun 2012 14:00:07 -0600 Subject: Update documentation to clarify purpose of BeforeRender.rendering_val. --- docs/narr/hooks.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index a2143b3c5..30eec04f0 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -289,6 +289,21 @@ keys added to the renderer globals dictionary by all :class:`pyramid.events.BeforeRender` subscribers and renderer globals factories must be unique. +The dictionary returned from the view is accessible through the +:attr:`rendering_val` attribute of a :class:`~pyramid.events.BeforeRender` +event, like so: + +.. code-block:: python + :linenos: + + from pyramid.events import subscriber + from pyramid.events import BeforeRender + + @subscriber(BeforeRender) + def read_return(event): + # 'mykey' is returned from the view + print(event.rendering_val['mykey']) + See the API documentation for the :class:`~pyramid.events.BeforeRender` event interface at :class:`pyramid.interfaces.IBeforeRender`. -- cgit v1.2.3 From 2516df30d73afdf6606ad3d89b7c24ab496f356d Mon Sep 17 00:00:00 2001 From: Jeff Cook Date: Sun, 17 Jun 2012 01:20:37 -0600 Subject: docs: Add view callable example to section on rendering_val. --- docs/narr/hooks.rst | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 30eec04f0..332805152 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -291,18 +291,33 @@ factories must be unique. The dictionary returned from the view is accessible through the :attr:`rendering_val` attribute of a :class:`~pyramid.events.BeforeRender` -event, like so: +event. + +Suppose you return ``{'mykey': 'somevalue', 'mykey2': 'somevalue2'}`` from +your view callable, like so: .. code-block:: python - :linenos: + :linenos: - from pyramid.events import subscriber - from pyramid.events import BeforeRender + from pyramid.view import view_config - @subscriber(BeforeRender) - def read_return(event): - # 'mykey' is returned from the view - print(event.rendering_val['mykey']) + @view_config(renderer='some_renderer') + def myview(request): + return {'mykey': 'somevalue', 'mykey2': 'somevalue2'} + +:attr:`rendering_val` can be used to access these values from the +:class:`~pyramid.events.BeforeRender` object: + +.. code-block:: python + :linenos: + + from pyramid.events import subscriber + from pyramid.events import BeforeRender + + @subscriber(BeforeRender) + def read_return(event): + # {'mykey': 'somevalue'} is returned from the view + print(event.rendering_val['mykey']) See the API documentation for the :class:`~pyramid.events.BeforeRender` event interface at :class:`pyramid.interfaces.IBeforeRender`. -- cgit v1.2.3 From 0196b2a06ef66d2e8b33a03cc84373ab84ba44be Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Mon, 6 Aug 2012 00:48:29 -0400 Subject: add docs for third-party view predicates --- docs/narr/hooks.rst | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 332805152..bdd968362 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -1232,3 +1232,97 @@ Displaying Tween Ordering The ``ptweens`` command-line utility can be used to report the current implict and explicit tween chains used by an application. See :ref:`displaying_tweens`. + +.. _registering_thirdparty_predicates: + +Adding A Third Party View or Route Predicate +-------------------------------------------- + +View and route predicates used during view configuration allow you to narrow +the set of circumstances under which a view or route will match. For +example, the ``request_method`` view predicate can be used to ensure a view +callable is only invoked when the request's method is ``POST``: + +.. code-block:: python + + @view_config(request_method='POST') + def someview(request): + ... + +Likewise, a similar predicate can be used as a *route* predicate: + +.. code-block:: python + + config.add_route('name', '/foo', request_method='POST') + +Many other built-in predicates exists (``request_param``, and others). You +can add third-party predicates to the list of available predicates by using +one of :meth:`pyramid.config.Configurator.add_view_predicate` or +:meth:`pyramid.config.Configurator.add_route_predicate`. The former adds a +view predicate, the latter a route predicate. + +When using one of those APIs, you pass a *name* and a *factory* to add a +predicate during Pyramid's configuration stage. For example: + +.. code-block:: python + + config.add_view_predicate('content_type', ContentTypePredicate) + +The above example adds a new predicate named ``content_type`` to the list of +available predicates for views. This will allow the following view +configuration statement to work: + +.. code-block:: python + :linenos: + + @view_config(content_type='File') + def aview(request): ... + +The first argument to :meth:`pyramid.config.Configurator.add_view_predicate`, +the name, is a string representing the name that is expected to be passed to +``view_config`` (or its imperative analogue ``add_view``). + +The second argument is a predicate factory. A predicate factory is most +often a class with a constructor (``__init__``), a ``text`` method, a +``phash`` method and a ``__call__`` method. For example: + +.. code-block:: python + :linenos: + + class ContentTypePredicate(object): + def __init__(self, val, config): + self.val + + def text(self): + return 'content_type = %s' % (self.val,) + + phash = text + + def __call__(self, context, request): + return getattr(context, 'content_type', None) == self.val + +The constructor of a predicate factory takes two arguments: ``val`` and +``config``. The ``val`` argument will be the argument passed to +``view_config`` (or ``add_view``). In the example above, it will be the +string ``File``. The second arg, ``config`` will be the Configurator +instance at the time of configuration. + +The ``text`` method must return a string. It should be useful to describe +the behavior of the predicate in error messages. + +The ``phash`` method must return a string or a sequence of strings. It's +most often the same as ``text``, as long as ``text`` uniquely describes the +predicate's name and the value passed to the constructor. If ``text`` is +more general, or doesn't describe things that way, ``phash`` should return a +string with the name and the value serialized. The result of ``phash`` is +not seen in output anywhere, it just informs the uniqueness constraints for +view configuration. + +The ``__call__`` method of a predicate factory must accept a resource +(``context``) and a request, and must return ``True`` or ``False``. It is +the "meat" of the predicate. + +You can use the same predicate factory as both a view predicate and as a +route predicate, but you'll need to call ``add_view_predicate`` and +``add_route_predicate`` separately with the same factory. + -- cgit v1.2.3 From cff71c316eb8b77b936bfc14a29d7ff9727edf70 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Mon, 6 Aug 2012 00:05:12 -0500 Subject: garden --- docs/narr/hooks.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index bdd968362..9482bfcf8 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -1291,7 +1291,7 @@ often a class with a constructor (``__init__``), a ``text`` method, a class ContentTypePredicate(object): def __init__(self, val, config): - self.val + self.val = val def text(self): return 'content_type = %s' % (self.val,) -- cgit v1.2.3 From 5664c428e22d73f8b4315b678588150d9bb2f0f5 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Mon, 6 Aug 2012 11:10:15 -0400 Subject: add as-of-version notes --- docs/narr/hooks.rst | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index bdd968362..73ee655ea 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -1238,6 +1238,10 @@ implict and explicit tween chains used by an application. See Adding A Third Party View or Route Predicate -------------------------------------------- +.. note:: + + Third-party predicates are a feature new as of Pyramid 1.4. + View and route predicates used during view configuration allow you to narrow the set of circumstances under which a view or route will match. For example, the ``request_method`` view predicate can be used to ensure a view -- cgit v1.2.3 From 95f766bc7c380797c569da464f1f41d12b05bdbe Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 25 Aug 2012 00:10:46 -0400 Subject: Subscriber predicates: - Add ``add_subscriber_predicate`` method to Configurator. - Allow ``add_subscriber`` and ``subscriber`` venusian decorator to accept ``**predicates`` arguments. - Document subscriber predicate feature. - Share more code between view, route, and subscriber related method wrt predicates. --- docs/narr/hooks.rst | 122 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 112 insertions(+), 10 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 2c15cd690..96fa77a07 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -1235,17 +1235,23 @@ implict and explicit tween chains used by an application. See .. _registering_thirdparty_predicates: -Adding A Third Party View or Route Predicate --------------------------------------------- +Adding A Third Party View, Route, or Subscriber Predicate +--------------------------------------------------------- .. note:: - Third-party predicates are a feature new as of Pyramid 1.4. + Third-party view, route, and subscriber predicates are a feature new as of + Pyramid 1.4. -View and route predicates used during view configuration allow you to narrow -the set of circumstances under which a view or route will match. For -example, the ``request_method`` view predicate can be used to ensure a view -callable is only invoked when the request's method is ``POST``: +.. _view_and_route_predicates: + +View and Route Predicates +~~~~~~~~~~~~~~~~~~~~~~~~~ + +View and route predicates used during configuration allow you to narrow the +set of circumstances under which a view or route will match. For example, +the ``request_method`` view predicate can be used to ensure a view callable +is only invoked when the request's method is ``POST``: .. code-block:: python @@ -1286,9 +1292,9 @@ The first argument to :meth:`pyramid.config.Configurator.add_view_predicate`, the name, is a string representing the name that is expected to be passed to ``view_config`` (or its imperative analogue ``add_view``). -The second argument is a predicate factory. A predicate factory is most -often a class with a constructor (``__init__``), a ``text`` method, a -``phash`` method and a ``__call__`` method. For example: +The second argument is a view or route predicate factory. A view or route +predicate factory is most often a class with a constructor (``__init__``), a +``text`` method, a ``phash`` method and a ``__call__`` method. For example: .. code-block:: python :linenos: @@ -1330,3 +1336,99 @@ You can use the same predicate factory as both a view predicate and as a route predicate, but you'll need to call ``add_view_predicate`` and ``add_route_predicate`` separately with the same factory. +.. _subscriber_predicates: + +Subscriber Predicates +~~~~~~~~~~~~~~~~~~~~~ + +Subscriber predicates work almost exactly like view and route predicates. +They narrow the set of circumstances in which a subscriber will be called. +There are several minor differences between a subscriber predicate and a +view/route predicate: + +- There are no default subscriber predicates. You must register one to use + one. + +- The ``__call__`` method of a subscriber predicate accepts a single + ``event`` object instead of a ``context`` and a ``request``. + +- Not every subscriber predicate can be used with every event type. Some + subscriber predicates will assume a certain event type. + +Here's an example of a subscriber predicate that can be used in conjunction +with a subscriber that subscribes to the :class:`pyramid.events.NewReqest` +event type. + +.. code-block:: python + :linenos: + + class RequestPathStartsWith(object): + def __init__(self, val, config): + self.val = val + + def text(self): + return 'path_startswith = %s' % (self.val,) + + phash = text + + def __call__(self, event): + return event.request.path.startswith(self.val) + +Once you've created a subscriber predicate, it may registered via +:meth:`pyramid.config.Configurator.add_subscriber_predicate`. For example: + +.. code-block:: python + + config.add_subscriber_predicate( + 'request_path_startswith', RequestPathStartsWith) + +Once a subscriber predicate is registered, you can use it in a call to +:meth:`pyramid.config.Configurator.add_subscriber` or to +:class:`pyramid.events.subscriber`. Here's an example of using the +previously registered ``request_path_startswith`` predicate in a call to +:meth:`~pyramid.config.Configurator.add_subscriber`: + +.. code-block:: python + :linenos: + + # define a subscriber in your code + + def yosubscriber(event): + event.request.yo = 'YO!' + + # and at configuration time + + config.add_subscriber(yosubscriber, NewRequest, + request_path_startswith='/add_yo') + +Here's the same subscriber/predicate/event-type combination used via +:class:`~pyramid.events.subscriber`. + +.. code-block:: python + :linenos: + + from pyramid.events import subscriber + + @subscriber(NewRequest, request_path_startswith='/add_yo') + def yosubscriber(event): + event.request.yo = 'YO!' + +In either of the above configurations, the ``yosubscriber`` callable will +only be called if the request path starts with ``/add_yo``. Otherwise the +event subscriber will not be called. + +Note that the ``request_path_startswith`` subscriber you defined can be used +with events that have a ``request`` attribute, but not ones that do not. So, +for example, the predicate can be used with subscribers registered for +:class:`pyramid.events.NewRequest` and :class:`pyramid.events.ContextFound` +events, but it cannot be used with subscribers registered for +:class:`pyramid.events.ApplicationCreated` because the latter type of event +has no ``request`` attribute. The point being: unlike route and view +predicates, not every type of subscriber predicate will necessarily be +applicable for use in every subscriber registration. It is not the +responsibility of the predicate author to make every predicate make sense for +every event type; it is the responsibility of the predicate consumer to use +predicates that make sense for a particular event type registration. + + + -- cgit v1.2.3 From 8818ea59e253b855e1b0f09b856560cb71c9e8de Mon Sep 17 00:00:00 2001 From: Robert Jackiewicz Date: Mon, 12 Nov 2012 12:27:23 -0500 Subject: Modified the hooks documentation to currently describe how to access the context in a forbidden view. --- docs/narr/hooks.rst | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 96fa77a07..ea75e5fe4 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -180,11 +180,14 @@ as a forbidden view: config.scan() Like any other view, the forbidden view must accept at least a ``request`` -parameter, or both ``context`` and ``request``. The ``context`` (available -as ``request.context`` if you're using the request-only view argument -pattern) is the context found by the router when the view invocation was -denied. The ``request`` is the current :term:`request` representing the -denied action. +parameter, or both ``context`` and ``request``. If a forbidden view +callable accepts both ``context`` and ``request``, the HTTP Exception is passed +as context. The ``context`` as found by the router when view was +denied (that you normally would expect) is available as +``request.context``. The ``request`` is the current :term:`request` +representing the denied action. + + Here's some sample code that implements a minimal forbidden view: -- cgit v1.2.3 From 043ccddb909327106264d10ed5d413760a51770d Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Wed, 2 Jan 2013 02:22:52 +0200 Subject: eliminate other repeated words --- docs/narr/hooks.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index ea75e5fe4..b5efc0df1 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -1082,7 +1082,7 @@ entirely by the relative ordering of calls to :meth:`pyramid.config.Configurator.add_tween`. However, the caller of add_tween can provide an optional hint that can influence the implicit tween chain ordering by supplying ``under`` or ``over`` (or both) arguments to -:meth:`~pyramid.config.Configurator.add_tween`. These hints are only used +:meth:`~pyramid.config.Configurator.add_tween`. These hints are only used when an explicit tween ordering is not used. See :ref:`explicit_tween_ordering` for a description of how to set an explicit tween ordering. -- cgit v1.2.3 From 9db1a14cd16f6e92fdb72650d2a3e3ef6e55ef9a Mon Sep 17 00:00:00 2001 From: kusut Date: Mon, 28 Jan 2013 23:42:27 +0700 Subject: narrative docs for add_request_method --- docs/narr/hooks.rst | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index b5efc0df1..957426ec2 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -256,6 +256,97 @@ already constructed a :term:`configurator` it can also be registered via the config = Configurator() config.set_request_factory(MyRequest) +.. index:: + single: request method + +.. _adding_request_method: + +Adding Methods or Properties to Request Object +---------------------------------------------- + +Since each pyramid application can only have one :term:`request` factory, +:ref:`changing the request factory ` +is not that extensible especially if you want to build composable features +(e.g., pyramid add-ons and plugins). + +A lazy property can be registered to the request object via the +:meth:`pyramid.config.Configurator.add_request_method` API. This allows you +to specify a callable that will be available on the request object, but will not +actually execute the function until accessed. + +.. note:: This feature is new as of Pyramid 1.4. + +.. warning:: This will silently override methods and properties from + :term:`request factory` that have the same name. + +.. code-block:: python + :linenos: + + from pyramid.config import Configurator + + def total(request, *args): + return sum(args) + + def prop(request): + print "getting the property" + return "the property" + + config = Configurator() + config.add_request_method(total) + config.add_request_method(prop, reify=True) + +In the above example, ``total`` is added as a method. However, ``prop`` is added +as a property and its result is cached per-request by setting ``reify=True``. +This way, we eliminate the overhead of running the function multiple times. + + >>> request.total(1, 2, 3) + 6 + >>> request.prop + getting the property + the property + >>> request.prop + the property + +To not cache the result of ``request.prop``, set ``property=True`` instead of +``reify=True``. + +Here is an example of passing a class to ``Configurator.add_request_method``: + +.. code-block:: python + :linenos: + + from pyramid.config import Configurator + from pyramid.decorator import reify + + + class ExtraStuff(object): + + def __init__(self, request): + self.request = request + + def total(self, *args): + return sum(args) + + # use @property if you don't want to cache the result + @reify + def prop(self): + print "getting the property" + return "the property" + + config = Configurator() + config.add_request_method(ExtraStuff, 'extra', reify=True) + +We attach and cache an object named ``extra`` to the ``request`` object. + + >>> request.extra.total(1, 2, 3) + 6 + >>> request.extra.prop + getting the property + the property + >>> request.extra.prop + the property + + .. index:: single: before render event single: adding renderer globals -- cgit v1.2.3 From 5b9c21ebe7d295bb9ac4356033899181ac69396e Mon Sep 17 00:00:00 2001 From: kusut Date: Tue, 29 Jan 2013 22:16:00 +0700 Subject: enhance! --- docs/narr/hooks.rst | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 957426ec2..d693149e4 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -264,18 +264,18 @@ already constructed a :term:`configurator` it can also be registered via the Adding Methods or Properties to Request Object ---------------------------------------------- -Since each pyramid application can only have one :term:`request` factory, +.. versionadded:: 1.4. + +Since each Pyramid application can only have one :term:`request` factory, :ref:`changing the request factory ` -is not that extensible especially if you want to build composable features -(e.g., pyramid add-ons and plugins). +is not that extensible, especially if you want to build composable features +(e.g., Pyramid add-ons and plugins). A lazy property can be registered to the request object via the :meth:`pyramid.config.Configurator.add_request_method` API. This allows you to specify a callable that will be available on the request object, but will not actually execute the function until accessed. -.. note:: This feature is new as of Pyramid 1.4. - .. warning:: This will silently override methods and properties from :term:`request factory` that have the same name. @@ -318,7 +318,6 @@ Here is an example of passing a class to ``Configurator.add_request_method``: from pyramid.config import Configurator from pyramid.decorator import reify - class ExtraStuff(object): def __init__(self, request): @@ -346,7 +345,6 @@ We attach and cache an object named ``extra`` to the ``request`` object. >>> request.extra.prop the property - .. index:: single: before render event single: adding renderer globals -- cgit v1.2.3 From 40dbf42a2df1783c3d803adf950380c21512bb91 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Wed, 30 Jan 2013 00:41:23 +0200 Subject: use the more appropriate directives --- docs/narr/hooks.rst | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index b5efc0df1..fc5c0ff23 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -336,9 +336,9 @@ when adding renderer global values exists in :ref:`adding_renderer_globals`. Adding Renderer Globals (Deprecated) ------------------------------------ -.. warning:: this feature is deprecated as of Pyramid 1.1. A non-deprecated - mechanism which allows event subscribers to add renderer global values - is documented in :ref:`beforerender_event`. +.. deprecated:: 1.1 + An alternative mechanism which allows event subscribers to add renderer + global values is documented in :ref:`beforerender_event`. Whenever :app:`Pyramid` handles a request to perform a rendering (after a view with a ``renderer=`` configuration attribute is invoked, or when any of @@ -635,13 +635,13 @@ See :meth:`pyramid.config.add_resource_url_adapter` for more information. Changing How Pyramid Treats View Responses ------------------------------------------ +.. versionadded:: 1.1 + 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 :meth:`pyramid.config.Configurator.add_response_adapter` or the :class:`~pyramid.response.response_adapter` decorator. -.. 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 @@ -936,8 +936,8 @@ For full details, please read the `Venusian documentation Registering "Tweens" -------------------- -.. note:: Tweens are a feature which were added in Pyramid 1.2. They are - not available in any previous version. +.. versionadded:: 1.2 + Tweens A :term:`tween` (a contraction of the word "between") is a bit of code that sits between the Pyramid router's main request handling function and the @@ -1241,10 +1241,7 @@ implict and explicit tween chains used by an application. See Adding A Third Party View, Route, or Subscriber Predicate --------------------------------------------------------- -.. note:: - - Third-party view, route, and subscriber predicates are a feature new as of - Pyramid 1.4. +.. versionadded:: 1.4 .. _view_and_route_predicates: -- cgit v1.2.3 From c7a06f41d56d076dc979d800388c8befc1b8e5e5 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 9 Feb 2013 19:54:32 -0500 Subject: fix warning block for newer docutils versions --- docs/narr/hooks.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 43bf48289..7d4d03b89 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -276,8 +276,10 @@ A lazy property can be registered to the request object via the to specify a callable that will be available on the request object, but will not actually execute the function until accessed. -.. warning:: This will silently override methods and properties from - :term:`request factory` that have the same name. +.. warning:: + + This will silently override methods and properties from :term:`request + factory` that have the same name. .. code-block:: python :linenos: -- cgit v1.2.3 From 580d74db2a032fa6c84662d1d89362f83d068d48 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Sat, 23 Feb 2013 12:42:52 +0200 Subject: replace awkward explanation --- docs/narr/hooks.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 7d4d03b89..f38d57e73 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -15,9 +15,8 @@ Changing the Not Found View --------------------------- When :app:`Pyramid` can't map a URL to view code, it invokes a :term:`not -found view`, which is a :term:`view callable`. A default notfound view -exists. The default not found view can be overridden through application -configuration. +found view`, which is a :term:`view callable`. The default Not Found View +can be overridden through application configuration. If your application uses :term:`imperative configuration`, you can replace the Not Found view by using the -- cgit v1.2.3 From cd8ac801ac1ccefb81c2e015124be910cb8c93de Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Fri, 15 Feb 2013 00:48:08 +0200 Subject: update some links and fix others --- docs/narr/hooks.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index f38d57e73..20cadc996 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -711,7 +711,7 @@ The API that must be implemented by your a class that provides The default context URL generator is available for perusal as the class :class:`pyramid.traversal.ResourceURL` in the `traversal module -`_ of the +`_ of the :term:`Pylons` GitHub Pyramid repository. See :meth:`pyramid.config.add_resource_url_adapter` for more information. -- cgit v1.2.3 From 2f4bdefd18073c418ae95fe9e5a8c7b2a9d1130e Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Sat, 9 Mar 2013 03:06:17 +0200 Subject: capitalize; add term role --- docs/narr/hooks.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index f38d57e73..d7af5ab98 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -19,7 +19,7 @@ found view`, which is a :term:`view callable`. The default Not Found View can be overridden through application configuration. If your application uses :term:`imperative configuration`, you can replace -the Not Found view by using the +the Not Found View by using the :meth:`pyramid.config.Configurator.add_notfound_view` method: .. code-block:: python @@ -29,7 +29,7 @@ the Not Found view by using the config.add_notfound_view(notfound) Replace ``helloworld.views.notfound`` with a reference to the :term:`view -callable` you want to use to represent the Not Found view. The :term:`not +callable` you want to use to represent the Not Found View. The :term:`not found view` callable is a view callable like any other. If your application instead uses :class:`pyramid.view.view_config` decorators @@ -51,12 +51,12 @@ and a :term:`scan`, you can replace the Not Found view by using the This does exactly what the imperative example above showed. -Your application can define *multiple* not found views if necessary. Both +Your application can define *multiple* Not Found Views if necessary. Both :meth:`pyramid.config.Configurator.add_notfound_view` and :class:`pyramid.view.notfound_view_config` take most of the same arguments as :class:`pyramid.config.Configurator.add_view` and -:class:`pyramid.view.view_config`, respectively. This means that not found -views can carry predicates limiting their applicability. For example: +:class:`pyramid.view.view_config`, respectively. This means that Not Found +Views can carry predicates limiting their applicability. For example: .. code-block:: python :linenos: @@ -106,8 +106,8 @@ Here's some sample code that implements a minimal NotFound view callable: 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.httpexceptions.HTTPNotFound` exception that - caused the not found view to be called. The value of - ``request.exception.message`` will be a value explaining why the not found + caused the Not Found View to be called. The value of + ``request.exception.message`` will be a value explaining why the Not Found error was raised. This message will be different when the ``pyramid.debug_notfound`` environment setting is true than it is when it is false. -- cgit v1.2.3 From cec2b05e74b3296ab8b54b9644223e08f269808b Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Sat, 9 Mar 2013 03:15:15 +0200 Subject: consistency --- docs/narr/hooks.rst | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index d7af5ab98..d103ca1cd 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -79,7 +79,7 @@ The ``notfound_get`` view will be called when a view could not be found and the request method was ``GET``. The ``notfound_post`` view will be called when a view could not be found and the request method was ``POST``. -Like any other view, the notfound view must accept at least a ``request`` +Like any other view, the Not Found 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 @@ -91,7 +91,8 @@ Both :meth:`pyramid.config.Configurator.add_notfound_view` and redirect requests to slash-appended routes. See :ref:`redirecting_to_slash_appended_routes` for examples. -Here's some sample code that implements a minimal NotFound view callable: +Here's some sample code that implements a minimal :term:`Not Found View` +callable: .. code-block:: python :linenos: @@ -103,7 +104,7 @@ Here's some sample code that implements a minimal NotFound view callable: .. note:: - When a NotFound view callable is invoked, it is passed a + When a Not Found View callable is invoked, it is passed a :term:`request`. The ``exception`` attribute of the request will be an instance of the :exc:`~pyramid.httpexceptions.HTTPNotFound` exception that caused the Not Found View to be called. The value of @@ -122,7 +123,7 @@ Here's some sample code that implements a minimal NotFound view callable: .. warning:: - When a NotFound view callable accepts an argument list as + When a Not Found 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.httpexceptions.HTTPNotFound` exception instance. If -- cgit v1.2.3 From e2b67957fddb01f8f17ee55ba726122977cdef1b Mon Sep 17 00:00:00 2001 From: Catalin Iacob Date: Sun, 24 Feb 2013 18:01:17 +0100 Subject: Remove extra word --- docs/narr/hooks.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 330eb0cd3..07983808c 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -694,7 +694,7 @@ represents the type of interface that must be possessed by the resource for this resource url factory to be found. If the ``resource_iface`` argument is omitted, this resource url adapter will be used for *all* resources. -The API that must be implemented by your a class that provides +The API that must be implemented by a class that provides :class:`~pyramid.interfaces.IResourceURL` is as follows: .. code-block:: python -- cgit v1.2.3 From 46d5058a99dee32bc02c1ef93ec5fddf35867505 Mon Sep 17 00:00:00 2001 From: Catalin Iacob Date: Sun, 24 Feb 2013 18:34:08 +0100 Subject: Fix typo that broke the reference to pyramid.events.NewRequest --- docs/narr/hooks.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 07983808c..c2c7417a7 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -1447,7 +1447,7 @@ view/route predicate: subscriber predicates will assume a certain event type. Here's an example of a subscriber predicate that can be used in conjunction -with a subscriber that subscribes to the :class:`pyramid.events.NewReqest` +with a subscriber that subscribes to the :class:`pyramid.events.NewRequest` event type. .. code-block:: python -- cgit v1.2.3 From 37607c3a9382de7c3757799791a91b80e2d9888d Mon Sep 17 00:00:00 2001 From: Catalin Iacob Date: Sun, 31 Mar 2013 14:33:24 +0200 Subject: Consistently link middleware term to the glossary --- docs/narr/hooks.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index c2c7417a7..e984dc24f 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -1036,7 +1036,7 @@ upstream WSGI component that uses :app:`Pyramid` as its "app". This is a feature that may be used by Pyramid framework extensions, to provide, for example, Pyramid-specific view timing support bookkeeping code that examines exceptions before they are returned to the upstream WSGI application. Tweens -behave a bit like :term:`WSGI` middleware but they have the benefit of +behave a bit like :term:`WSGI` :term:`middleware` but they have the benefit of running in a context in which they have access to the Pyramid :term:`application registry` as well as the Pyramid rendering machinery. -- cgit v1.2.3 From 991a1abd3ddf682240a540fcb7fd309dc1d50f34 Mon Sep 17 00:00:00 2001 From: Catalin Iacob Date: Mon, 1 Apr 2013 17:58:09 +0200 Subject: Remove extra word --- docs/narr/hooks.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index e984dc24f..f16ab93d8 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -1110,8 +1110,8 @@ Once you've created a tween factory, you can register it into the implicit tween chain using the :meth:`pyramid.config.Configurator.add_tween` method using its :term:`dotted Python name`. -Here's an example of registering the a tween factory as an "implicit" -tween in a Pyramid application: +Here's an example of registering a tween factory as an "implicit" tween in a +Pyramid application: .. code-block:: python :linenos: -- cgit v1.2.3 From c69f357e79c9b1b619fa5a68137d9e11de39bc9e Mon Sep 17 00:00:00 2001 From: Catalin Iacob Date: Mon, 1 Apr 2013 18:12:46 +0200 Subject: Improve phrasing --- docs/narr/hooks.rst | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index f16ab93d8..a3de23baa 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -109,9 +109,8 @@ callable: instance of the :exc:`~pyramid.httpexceptions.HTTPNotFound` exception that caused the Not Found View to be called. The value of ``request.exception.message`` will be a value explaining why the Not Found - error was raised. This message will be different when the - ``pyramid.debug_notfound`` environment setting is true than it is when it - is false. + error was raised. This message has different values depending whether the + ``pyramid.debug_notfound`` environment setting is true or false. .. note:: @@ -208,9 +207,9 @@ Here's some sample code that implements a minimal forbidden view: that caused the forbidden view to be called. The value of ``request.exception.message`` will be a value explaining why the forbidden was raised and ``request.exception.result`` will be extended information - about the forbidden exception. These messages will be different when the - ``pyramid.debug_authorization`` environment setting is true than it is when - it is false. + about the forbidden exception. These messages have different values + depending whether the ``pyramid.debug_authorization`` environment setting + is true or false. .. index:: single: request factory -- cgit v1.2.3 From f5eb753eebbda6fa55ccc5108fcc325931a17f85 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Fri, 5 Apr 2013 22:56:48 +0200 Subject: fix some cross-references --- docs/narr/hooks.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index a3de23baa..77c66b0d2 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -929,7 +929,7 @@ set a *default* view mapper (overriding the superdefault view mapper used by Pyramid itself). A *single* view registration can use a view mapper by passing the mapper as -the ``mapper`` argument to :meth:`~pyramid.config.Configuration.add_view`. +the ``mapper`` argument to :meth:`~pyramid.config.Configurator.add_view`. .. index:: single: configuration decorator -- cgit v1.2.3 From 125ea45ae864a5513e6d83fdded6ceea9516b578 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Sat, 6 Apr 2013 07:07:37 +0200 Subject: fix some cross-references Also, pyramid_zcml is cross-referenced, so add it to intersphinx_mapping dict. --- docs/narr/hooks.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 77c66b0d2..1bd294bd1 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -673,7 +673,7 @@ traverser. If you've added a traverser, you can change how :meth:`~pyramid.request.Request.resource_url` generates a URL for a specific type of resource by adding a call to -:meth:`pyramid.config.add_resource_url_adapter`. +:meth:`pyramid.config.Configurator.add_resource_url_adapter`. For example: -- cgit v1.2.3 From 439a02a420d9014a56d01f7e08db89ec65d943c5 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Sun, 21 Apr 2013 15:27:24 +0200 Subject: docs/narr/hooks.rst: some improvements * consistency fixes: "not found view" --> "Not Found View" * use comparable code for Imperative and Declarative configuration * remove unused import, HTTPForbidden --- docs/narr/hooks.rst | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 1bd294bd1..37a74b53a 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -14,8 +14,8 @@ in various ways. Changing the Not Found View --------------------------- -When :app:`Pyramid` can't map a URL to view code, it invokes a :term:`not -found view`, which is a :term:`view callable`. The default Not Found View +When :app:`Pyramid` can't map a URL to view code, it invokes a :term:`Not +Found View`, which is a :term:`view callable`. The default Not Found View can be overridden through application configuration. If your application uses :term:`imperative configuration`, you can replace @@ -25,15 +25,17 @@ the Not Found View by using the .. code-block:: python :linenos: - from helloworld.views import notfound - config.add_notfound_view(notfound) + def notfound(request): + return Response('Not Found, dude', status='404 Not Found') -Replace ``helloworld.views.notfound`` with a reference to the :term:`view -callable` you want to use to represent the Not Found View. The :term:`not -found view` callable is a view callable like any other. + def main(globals, **settings): + config = Configurator() + config.add_notfound_view(notfound) + +The :term:`Not Found View` callable is a view callable like any other. If your application instead uses :class:`pyramid.view.view_config` decorators -and a :term:`scan`, you can replace the Not Found view by using the +and a :term:`scan`, you can replace the Not Found View by using the :class:`pyramid.view.notfound_view_config` decorator: .. code-block:: python @@ -46,8 +48,8 @@ and a :term:`scan`, you can replace the Not Found view by using the return Response('Not Found, dude', status='404 Not Found') def main(globals, **settings): - config = Configurator() - config.scan() + config = Configurator() + config.scan() This does exactly what the imperative example above showed. @@ -154,12 +156,12 @@ forbidden view: .. code-block:: python :linenos: - from helloworld.views import forbidden_view - from pyramid.httpexceptions import HTTPForbidden - config.add_forbidden_view(forbidden_view) + def forbidden(request): + return Response('forbidden') -Replace ``helloworld.views.forbidden_view`` with a reference to the Python -:term:`view callable` you want to use to represent the Forbidden view. + def main(globals, **settings): + config = Configurator() + config.add_forbidden_view(forbidden_view) If instead you prefer to use decorators and a :term:`scan`, you can use the :class:`pyramid.view.forbidden_view_config` decorator to mark a view callable -- cgit v1.2.3 From edfc4f80a1240f6f5f0c41e53078a8f5d305075f Mon Sep 17 00:00:00 2001 From: Philip Jenvey Date: Thu, 15 Aug 2013 15:57:14 -0700 Subject: prefer the functionish print --- docs/narr/hooks.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 37a74b53a..3a2568775 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -291,7 +291,7 @@ actually execute the function until accessed. return sum(args) def prop(request): - print "getting the property" + print("getting the property") return "the property" config = Configurator() @@ -332,7 +332,7 @@ Here is an example of passing a class to ``Configurator.add_request_method``: # use @property if you don't want to cache the result @reify def prop(self): - print "getting the property" + print("getting the property") return "the property" config = Configurator() -- cgit v1.2.3 From fc477b2e4b20ae2788e468e45b2831e774be8ced Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 7 Sep 2013 21:59:41 -0400 Subject: - The ``pyramid.events.NewResponse`` event is now sent **after** response callbacks are executed. It previously executed before response callbacks were executed. Rationale: it's more useful to be able to inspect the response after response callbacks have done their jobs instead of before. Closes #1116. --- docs/narr/hooks.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 3a2568775..8ffda1a5f 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -514,7 +514,7 @@ callback will be an exception object instead of its default value of ``None``. Response callbacks are called in the order they're added -(first-to-most-recently-added). All response callbacks are called *after* +(first-to-most-recently-added). All response callbacks are called *before* the :class:`~pyramid.events.NewResponse` event is sent. Errors raised by response callbacks are not handled specially. They will be propagated to the caller of the :app:`Pyramid` router application. -- cgit v1.2.3 From d71acabebb804ebbd37703e78ac9886fcdded827 Mon Sep 17 00:00:00 2001 From: Bert JW Regeer Date: Sun, 8 Sep 2013 15:15:58 -0600 Subject: Update documentation to reflect the dotted python name --- docs/narr/hooks.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 8ffda1a5f..a7dc3e78b 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -1384,9 +1384,11 @@ The first argument to :meth:`pyramid.config.Configurator.add_view_predicate`, the name, is a string representing the name that is expected to be passed to ``view_config`` (or its imperative analogue ``add_view``). -The second argument is a view or route predicate factory. A view or route -predicate factory is most often a class with a constructor (``__init__``), a -``text`` method, a ``phash`` method and a ``__call__`` method. For example: +The second argument is a view or route predicate factory, or a :term:`dotted +Python name` which refers to a view or route predicate factory. A view or +route predicate factory is most often a class with a constructor +(``__init__``), a ``text`` method, a ``phash`` method and a ``__call__`` +method. For example: .. code-block:: python :linenos: -- cgit v1.2.3 From c6601f77f91dc933ca429d1448f4c6b27857b608 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 8 Sep 2013 22:52:54 -0400 Subject: - The ``renderer_globals_factory`` argument to the ``pyramid.config.Configurator` constructor and its ``setup_registry`` method has been removed. The ``set_renderer_globals_factory`` method of ``pyramid.config.Configurator`` has also been removed. The (internal) ``pyramid.interfaces.IRendererGlobals`` interface was also removed. These arguments, methods and interfaces had been deprecated since 1.1. Use a ``BeforeRender`` event subscriber as documented in the "Hooks" chapter of the Pyramid narrative documentation instead of providing renderer globals values to the configurator. --- docs/narr/hooks.rst | 66 ++--------------------------------------------------- 1 file changed, 2 insertions(+), 64 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index a7dc3e78b..0c450fad7 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -372,10 +372,8 @@ that can be used for this purpose. For example: def add_global(event): event['mykey'] = 'foo' -An object of this type is sent as an event just before a :term:`renderer` is -invoked (but *after* the application-level renderer globals factory added via -:class:`~pyramid.config.Configurator.set_renderer_globals_factory`, if any, -has injected its own keys into the renderer globals dictionary). +An object of this type is sent as an event just before a :term:`renderer` +is invoked. If a subscriber attempts to add a key that already exist in the renderer globals dictionary, a :exc:`KeyError` is raised. This limitation is enforced @@ -417,66 +415,6 @@ your view callable, like so: See the API documentation for the :class:`~pyramid.events.BeforeRender` event interface at :class:`pyramid.interfaces.IBeforeRender`. -Another (deprecated) mechanism which allows event subscribers more control -when adding renderer global values exists in :ref:`adding_renderer_globals`. - -.. index:: - single: adding renderer globals - -.. _adding_renderer_globals: - -Adding Renderer Globals (Deprecated) ------------------------------------- - -.. deprecated:: 1.1 - An alternative mechanism which allows event subscribers to add renderer - global values is documented in :ref:`beforerender_event`. - -Whenever :app:`Pyramid` handles a request to perform a rendering (after a -view with a ``renderer=`` configuration attribute is invoked, or when any of -the methods beginning with ``render`` within the :mod:`pyramid.renderers` -module are called), *renderer globals* can be injected into the *system* -values sent to the renderer. By default, no renderer globals are injected, -and the "bare" system values (such as ``request``, ``context``, ``view``, and -``renderer_name``) are the only values present in the system dictionary -passed to every renderer. - -A callback that :app:`Pyramid` will call every time a renderer is invoked can -be added by passing a ``renderer_globals_factory`` argument to the -constructor of the :term:`configurator`. This callback can either be a -callable object or a :term:`dotted Python name` representing such a callable. - -.. code-block:: python - :linenos: - - def renderer_globals_factory(system): - return {'a': 1} - - config = Configurator( - renderer_globals_factory=renderer_globals_factory) - -Such a callback must accept a single positional argument (notionally named -``system``) which will contain the original system values. It must return a -dictionary of values that will be merged into the system dictionary. See -:ref:`renderer_system_values` for description of the values present in the -system dictionary. - -If you're doing imperative configuration, and you'd rather do it after you've -already constructed a :term:`configurator` it can also be registered via the -:meth:`pyramid.config.Configurator.set_renderer_globals_factory` method: - -.. code-block:: python - :linenos: - - from pyramid.config import Configurator - - def renderer_globals_factory(system): - return {'a': 1} - - config = Configurator() - config.set_renderer_globals_factory(renderer_globals_factory) - - .. index:: single: response callback -- cgit v1.2.3 From 04e6bf670e3968864fd858e3d3fa310d601a2420 Mon Sep 17 00:00:00 2001 From: Antti Haapala Date: Sat, 16 Nov 2013 00:31:48 +0200 Subject: Enhanced the narrative documentation for tweens. --- docs/narr/hooks.rst | 87 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 68 insertions(+), 19 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 0c450fad7..b26a46272 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -963,8 +963,8 @@ For full details, please read the `Venusian documentation .. _registering_tweens: -Registering "Tweens" --------------------- +Registering Tweens +------------------ .. versionadded:: 1.2 Tweens @@ -976,23 +976,76 @@ feature that may be used by Pyramid framework extensions, to provide, for example, Pyramid-specific view timing support bookkeeping code that examines exceptions before they are returned to the upstream WSGI application. Tweens behave a bit like :term:`WSGI` :term:`middleware` but they have the benefit of -running in a context in which they have access to the Pyramid -:term:`application registry` as well as the Pyramid rendering machinery. +running in a context in which they have access to the Pyramid :term:`request`, +:term:`response` and :term:`application registry` as well as the Pyramid +rendering machinery. -Creating a Tween Factory -~~~~~~~~~~~~~~~~~~~~~~~~ +Creating a Tween +~~~~~~~~~~~~~~~~ -To make use of tweens, you must construct a "tween factory". A tween factory +To create a tween, you must write a "tween factory". A tween factory must be a globally importable callable which accepts two arguments: ``handler`` and ``registry``. ``handler`` will be the either the main Pyramid request handling function or another tween. ``registry`` will be the Pyramid :term:`application registry` represented by this Configurator. A -tween factory must return a tween when it is called. +tween factory must return the tween (a callable object) when it is called. -A tween is a callable which accepts a :term:`request` object and returns -a :term:`response` object. +A tween is called with a single argument, ``request``, which is the +:term:`request` created by Pyramid's router when it receives a WSGI request. +A tween should return a :term:`response`, usually the one generated by the +downstream Pyramid application. -Here's an example of a tween factory: +You can write the tween factory as a simple closure-returning function: + +.. code-block:: python + :linenos: + + def simple_tween_factory(handler, registry): + # one-time configuration code goes here + + def simple_tween(request): + # code to be executed for each request before + # the actual application code goes here + + response = handler(request) + + # code to be executed for each request after + # the actual application code goes here + + return response + + return handler + +Alternatively, the tween factory can be a class with the ``__call__`` magic method: + +.. code-block:: python + :linenos: + + class simple_tween_factory(object): + def __init__(handler, registry): + self.handler = handler + self.registry = registry + + # one-time configuration code goes here + + def __call__(self, request): + # code to be executed for each request before + # the actual application code goes here + + response = self.handler(request) + + # code to be executed for each request after + # the actual application code goes here + + return response + +The closure style performs slightly better and enables you to conditionally +omit the tween from the request processing pipeline (see the following timing +tween example), whereas the class style makes it easier to have shared mutable +state, and it allows subclassing. + +Here's a complete example of a tween that logs the time spent processing each +request: .. code-block:: python :linenos: @@ -1022,12 +1075,6 @@ Here's an example of a tween factory: # handler return handler -If you remember, a tween is an object which accepts a :term:`request` object -and which returns a :term:`response` argument. The ``request`` argument to a -tween will be the request created by Pyramid's router when it receives a WSGI -request. The response object will be generated by the downstream Pyramid -application and it should be returned by the tween. - In the above example, the tween factory defines a ``timing_tween`` tween and returns it if ``asbool(registry.settings.get('do_timing'))`` is true. It otherwise simply returns the handler it was given. The ``registry.settings`` @@ -1132,8 +1179,10 @@ Allowable values for ``under`` or ``over`` (or both) are: fallbacks if the desired tween is not included, as well as compatibility with multiple other tweens. -Effectively, ``under`` means "closer to the main Pyramid application than", -``over`` means "closer to the request ingress than". +Effectively, ``over`` means "closer to the request ingress than" and +``under`` means "closer to the main Pyramid application than". +You can think of an onion with outer layers over the inner layers, +the application being under all the layers at the center. For example, the following call to :meth:`~pyramid.config.Configurator.add_tween` will attempt to place the -- cgit v1.2.3 From a0ef135f2ad6e4425eec7ffcc0839b605347c346 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sat, 16 Nov 2013 05:06:38 -0500 Subject: 80 chars --- docs/narr/hooks.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index b26a46272..84dd2143c 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -1016,7 +1016,8 @@ You can write the tween factory as a simple closure-returning function: return handler -Alternatively, the tween factory can be a class with the ``__call__`` magic method: +Alternatively, the tween factory can be a class with the ``__call__`` magic +method: .. code-block:: python :linenos: -- cgit v1.2.3 From 392a6c7df93b67d6889680133fda0f744970d61f Mon Sep 17 00:00:00 2001 From: Antti Haapala Date: Sun, 17 Nov 2013 00:11:37 +0200 Subject: Removed extra indentation from some examples (:linenos: should be indented with the same indentation as the rest of the code block) --- docs/narr/hooks.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 84dd2143c..14009a094 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -363,7 +363,7 @@ and modify the set of :term:`renderer globals` before they are passed to a that can be used for this purpose. For example: .. code-block:: python - :linenos: + :linenos: from pyramid.events import subscriber from pyramid.events import BeforeRender @@ -998,7 +998,7 @@ downstream Pyramid application. You can write the tween factory as a simple closure-returning function: .. code-block:: python - :linenos: + :linenos: def simple_tween_factory(handler, registry): # one-time configuration code goes here @@ -1020,7 +1020,7 @@ Alternatively, the tween factory can be a class with the ``__call__`` magic method: .. code-block:: python - :linenos: + :linenos: class simple_tween_factory(object): def __init__(handler, registry): @@ -1049,7 +1049,7 @@ Here's a complete example of a tween that logs the time spent processing each request: .. code-block:: python - :linenos: + :linenos: # in a module named myapp.tweens @@ -1101,7 +1101,7 @@ Here's an example of registering a tween factory as an "implicit" tween in a Pyramid application: .. code-block:: python - :linenos: + :linenos: from pyramid.config import Configurator config = Configurator() @@ -1135,7 +1135,7 @@ chain (the tween generated by the very last tween factory added) as its request handler function. For example: .. code-block:: python - :linenos: + :linenos: from pyramid.config import Configurator @@ -1379,7 +1379,7 @@ route predicate factory is most often a class with a constructor method. For example: .. code-block:: python - :linenos: + :linenos: class ContentTypePredicate(object): def __init__(self, val, config): @@ -1442,7 +1442,7 @@ with a subscriber that subscribes to the :class:`pyramid.events.NewRequest` event type. .. code-block:: python - :linenos: + :linenos: class RequestPathStartsWith(object): def __init__(self, val, config): @@ -1471,7 +1471,7 @@ previously registered ``request_path_startswith`` predicate in a call to :meth:`~pyramid.config.Configurator.add_subscriber`: .. code-block:: python - :linenos: + :linenos: # define a subscriber in your code @@ -1487,7 +1487,7 @@ Here's the same subscriber/predicate/event-type combination used via :class:`~pyramid.events.subscriber`. .. code-block:: python - :linenos: + :linenos: from pyramid.events import subscriber -- cgit v1.2.3 From fab44e1e402efbf37fc58875974e9ae42827446e Mon Sep 17 00:00:00 2001 From: Antti Haapala Date: Sun, 17 Nov 2013 19:08:18 +0200 Subject: Should return the simple_tween here, not the handler. --- docs/narr/hooks.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 14009a094..f2542f1d7 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -1014,7 +1014,7 @@ You can write the tween factory as a simple closure-returning function: return response - return handler + return simple_tween Alternatively, the tween factory can be a class with the ``__call__`` magic method: -- cgit v1.2.3 From fbcce774fb33b57673c99f9e82058c507e212611 Mon Sep 17 00:00:00 2001 From: synthomat Date: Tue, 13 May 2014 13:29:56 +0200 Subject: Update hooks.rst 'self' param was omitted in the constructor of simple_tween_factory class --- docs/narr/hooks.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index f2542f1d7..94be31bbc 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -1023,7 +1023,7 @@ method: :linenos: class simple_tween_factory(object): - def __init__(handler, registry): + def __init__(self, handler, registry): self.handler = handler self.registry = registry -- cgit v1.2.3 From d194f3df5b5941251a36e0e7d535eaf0d633dd1b Mon Sep 17 00:00:00 2001 From: flibustenet Date: Sun, 18 May 2014 11:26:48 +0200 Subject: Draw attention that tweens instances are unique and shared between threads Forgetting that tween instance are not instantiated for each request leads to threads issues difficult to detect --- docs/narr/hooks.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 94be31bbc..91392ce7a 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -1017,7 +1017,8 @@ You can write the tween factory as a simple closure-returning function: return simple_tween Alternatively, the tween factory can be a class with the ``__call__`` magic -method: +method (the instance will be unique, be aware that it will be shared +between threads): .. code-block:: python :linenos: -- cgit v1.2.3 From bf669af7f10ec81280fd8dbee43e414fa75457c5 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Wed, 21 May 2014 11:03:13 -0500 Subject: clarify tween thread-safety --- docs/narr/hooks.rst | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 91392ce7a..fe7749cac 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -985,7 +985,7 @@ Creating a Tween To create a tween, you must write a "tween factory". A tween factory must be a globally importable callable which accepts two arguments: -``handler`` and ``registry``. ``handler`` will be the either the main +``handler`` and ``registry``. ``handler`` will be either the main Pyramid request handling function or another tween. ``registry`` will be the Pyramid :term:`application registry` represented by this Configurator. A tween factory must return the tween (a callable object) when it is called. @@ -995,6 +995,11 @@ A tween is called with a single argument, ``request``, which is the A tween should return a :term:`response`, usually the one generated by the downstream Pyramid application. +The tween factory will be shared between requests and is used to create one +tween per-request. Shared mutable state on the factory itself needs to be +carefully handled, and should be avoided unless you are willing to handle +the race conditions that may arise. + You can write the tween factory as a simple closure-returning function: .. code-block:: python @@ -1017,8 +1022,7 @@ You can write the tween factory as a simple closure-returning function: return simple_tween Alternatively, the tween factory can be a class with the ``__call__`` magic -method (the instance will be unique, be aware that it will be shared -between threads): +method: .. code-block:: python :linenos: -- cgit v1.2.3 From 2c096b0a8b7a83f5ded54a3fd6c048cd5f01b9a4 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Wed, 21 May 2014 12:20:56 -0500 Subject: oops, re-clarify that tweens should not have mutable state --- docs/narr/hooks.rst | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index fe7749cac..4da36e730 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -995,11 +995,6 @@ A tween is called with a single argument, ``request``, which is the A tween should return a :term:`response`, usually the one generated by the downstream Pyramid application. -The tween factory will be shared between requests and is used to create one -tween per-request. Shared mutable state on the factory itself needs to be -carefully handled, and should be avoided unless you are willing to handle -the race conditions that may arise. - You can write the tween factory as a simple closure-returning function: .. code-block:: python @@ -1045,6 +1040,10 @@ method: return response +You should avoid mutating any state on the tween instance. The tween is +invoked once per request and any shared mutable state needs to be carefully +handled to avoid any race conditions. + The closure style performs slightly better and enables you to conditionally omit the tween from the request processing pipeline (see the following timing tween example), whereas the class style makes it easier to have shared mutable -- cgit v1.2.3 From 1236dec0dcfd916bca4e233587f86baa8d2418a8 Mon Sep 17 00:00:00 2001 From: John Anderson Date: Sat, 27 Dec 2014 00:18:23 -0800 Subject: Add the `set_response_factory` API --- docs/narr/hooks.rst | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 4da36e730..f557527bb 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -354,6 +354,68 @@ We attach and cache an object named ``extra`` to the ``request`` object. .. _beforerender_event: +.. index:: + single: response factory + +.. _changing_the_response_factory: + +Changing the Response Factory +---------------------------- + +Whenever :app:`Pyramid` returns a response from a view it creates a +:term:`response` object. By default, an instance of the +:class:`pyramid.response.Response` class is created to represent the response +object. + +The class (aka "factory") that :app:`Pyramid` uses to create a response object +instance can be changed by passing a ``response_factory`` argument to the +constructor of the :term:`configurator`. This argument can be either a +callable or a :term:`dotted Python name` representing a callable. + +.. code-block:: python + :linenos: + + from pyramid.response import Response + + class MyResponse(Response): + pass + + config = Configurator(response_factory=MyResponse) + +If you're doing imperative configuration, and you'd rather do it after you've +already constructed a :term:`configurator` it can also be registered via the +:meth:`pyramid.config.Configurator.set_response_factory` method: + +.. code-block:: python + :linenos: + + from pyramid.config import Configurator + from pyramid.response import Response + + class MyResponse(Response): + pass + + config = Configurator() + config.set_response_factory(MyRequest) + +If you are already using a custom ```request_factory`` you can also set the +``ResponseClass`` on your :class:`pyramid.request.Request`: + +.. code-block:: python + :linenos: + + from pyramid.config import Configurator + from pyramid.response import Response + from pyramid.request import Request + + class MyResponse(Response): + pass + + class MyRequest(Request): + ResponseClass = MyResponse + + config = Configurator() + Using The Before Render Event ----------------------------- -- cgit v1.2.3 From e8a666655b5365a0adde32f2bd387b0d42690384 Mon Sep 17 00:00:00 2001 From: John Anderson Date: Sat, 27 Dec 2014 00:23:18 -0800 Subject: basic docs cleanup --- docs/narr/hooks.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index f557527bb..4702c09b0 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -360,7 +360,7 @@ We attach and cache an object named ``extra`` to the ``request`` object. .. _changing_the_response_factory: Changing the Response Factory ----------------------------- +------------------------------- Whenever :app:`Pyramid` returns a response from a view it creates a :term:`response` object. By default, an instance of the -- cgit v1.2.3 From 807e941787e157db882fcd95e13f5cafb7ebde7f Mon Sep 17 00:00:00 2001 From: John Anderson Date: Sat, 27 Dec 2014 13:33:39 -0800 Subject: Added a version added flag --- docs/narr/hooks.rst | 2 ++ 1 file changed, 2 insertions(+) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 4702c09b0..689ce9dc2 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -362,6 +362,8 @@ We attach and cache an object named ``extra`` to the ``request`` object. Changing the Response Factory ------------------------------- +.. versionadded:: 1.6 + Whenever :app:`Pyramid` returns a response from a view it creates a :term:`response` object. By default, an instance of the :class:`pyramid.response.Response` class is created to represent the response -- cgit v1.2.3 From 32cb805132e8149a276a8c65fdfa961384e8254e Mon Sep 17 00:00:00 2001 From: John Anderson Date: Thu, 1 Jan 2015 15:03:56 -0800 Subject: Mkae the response factory a factory that takes a request --- docs/narr/hooks.rst | 29 ++++++----------------------- 1 file changed, 6 insertions(+), 23 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 689ce9dc2..e250c2d7e 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -369,10 +369,10 @@ Whenever :app:`Pyramid` returns a response from a view it creates a :class:`pyramid.response.Response` class is created to represent the response object. -The class (aka "factory") that :app:`Pyramid` uses to create a response object -instance can be changed by passing a ``response_factory`` argument to the -constructor of the :term:`configurator`. This argument can be either a -callable or a :term:`dotted Python name` representing a callable. +The factory that :app:`Pyramid` uses to create a response object instance can be +changed by passing a ``response_factory`` argument to the constructor of the +:term:`configurator`. This argument can be either a callable or a +:term:`dotted Python name` representing a callable. .. code-block:: python :linenos: @@ -382,7 +382,7 @@ callable or a :term:`dotted Python name` representing a callable. class MyResponse(Response): pass - config = Configurator(response_factory=MyResponse) + config = Configurator(response_factory=lambda r: MyResponse()) If you're doing imperative configuration, and you'd rather do it after you've already constructed a :term:`configurator` it can also be registered via the @@ -398,25 +398,8 @@ already constructed a :term:`configurator` it can also be registered via the pass config = Configurator() - config.set_response_factory(MyRequest) - -If you are already using a custom ```request_factory`` you can also set the -``ResponseClass`` on your :class:`pyramid.request.Request`: - -.. code-block:: python - :linenos: - - from pyramid.config import Configurator - from pyramid.response import Response - from pyramid.request import Request - - class MyResponse(Response): - pass - - class MyRequest(Request): - ResponseClass = MyResponse + config.set_response_factory(lambda r: MyResponse()) - config = Configurator() Using The Before Render Event ----------------------------- -- cgit v1.2.3 From 3702ab07e835a06f30abf5ceb626f81114115062 Mon Sep 17 00:00:00 2001 From: Pavlo Kapyshin Date: Wed, 7 Jan 2015 15:09:26 +0200 Subject: Fix typo --- docs/narr/hooks.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index e250c2d7e..5bba0d143 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -777,7 +777,7 @@ 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 uses -``zope.interface.implementer(IResponse)`` as a class decoratoror. +``zope.interface.implementer(IResponse)`` as a class decorator. .. code-block:: python :linenos: -- cgit v1.2.3 From 8b5000f44cddd24df111c8a1d2ff65ee6d37afbb Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Thu, 22 Jan 2015 02:46:09 -0800 Subject: move index and reference down to proper section so that docs will build on master again --- docs/narr/hooks.rst | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 5bba0d143..17cae2c67 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -348,12 +348,6 @@ We attach and cache an object named ``extra`` to the ``request`` object. >>> request.extra.prop the property -.. index:: - single: before render event - single: adding renderer globals - -.. _beforerender_event: - .. index:: single: response factory @@ -400,6 +394,11 @@ already constructed a :term:`configurator` it can also be registered via the config = Configurator() config.set_response_factory(lambda r: MyResponse()) +.. index:: + single: before render event + single: adding renderer globals + +.. _beforerender_event: Using The Before Render Event ----------------------------- -- cgit v1.2.3 From 5de795938f4ec23c53cd4678021e36a72d3188cb Mon Sep 17 00:00:00 2001 From: Bert JW Regeer Date: Sat, 7 Feb 2015 01:06:29 -0700 Subject: Document the factory requires a positional argument --- docs/narr/hooks.rst | 3 +++ 1 file changed, 3 insertions(+) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 17cae2c67..8e6cf8343 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -368,6 +368,9 @@ changed by passing a ``response_factory`` argument to the constructor of the :term:`configurator`. This argument can be either a callable or a :term:`dotted Python name` representing a callable. +The factory takes a single positional argument, which is a :term:`Request` +object. The argument may be the value ``None``. + .. code-block:: python :linenos: -- cgit v1.2.3 From da5f5f9ea02c2c9830c7ae016547d2bedd0e0171 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Sat, 7 Feb 2015 02:38:54 -0600 Subject: move the IResponseFactory into the public api --- docs/narr/hooks.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 8e6cf8343..4fd7670b9 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -364,12 +364,12 @@ Whenever :app:`Pyramid` returns a response from a view it creates a object. The factory that :app:`Pyramid` uses to create a response object instance can be -changed by passing a ``response_factory`` argument to the constructor of the -:term:`configurator`. This argument can be either a callable or a -:term:`dotted Python name` representing a callable. +changed by passing a :class:`pyramid.interfaces.IResponseFactory` argument to +the constructor of the :term:`configurator`. This argument can be either a +callable or a :term:`dotted Python name` representing a callable. The factory takes a single positional argument, which is a :term:`Request` -object. The argument may be the value ``None``. +object. The argument may be ``None``. .. code-block:: python :linenos: -- cgit v1.2.3 From 8aa1c2a8bfed910a69aba974b611e21d9421e0e5 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Tue, 3 Nov 2015 00:41:58 -0800 Subject: minor grammar, fix .rst markup, rewrap to 79 columns --- docs/narr/hooks.rst | 644 +++++++++++++++++++++++++--------------------------- 1 file changed, 312 insertions(+), 332 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 4fd7670b9..6aa1a99c2 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -14,12 +14,12 @@ in various ways. Changing the Not Found View --------------------------- -When :app:`Pyramid` can't map a URL to view code, it invokes a :term:`Not -Found View`, which is a :term:`view callable`. The default Not Found View -can be overridden through application configuration. +When :app:`Pyramid` can't map a URL to view code, it invokes a :term:`Not Found +View`, which is a :term:`view callable`. The default Not Found View can be +overridden through application configuration. -If your application uses :term:`imperative configuration`, you can replace -the Not Found View by using the +If your application uses :term:`imperative configuration`, you can replace the +Not Found View by using the :meth:`pyramid.config.Configurator.add_notfound_view` method: .. code-block:: python @@ -77,14 +77,14 @@ Views can carry predicates limiting their applicability. For example: config = Configurator() config.scan() -The ``notfound_get`` view will be called when a view could not be found and -the request method was ``GET``. The ``notfound_post`` view will be called -when a view could not be found and the request method was ``POST``. +The ``notfound_get`` view will be called when a view could not be found and the +request method was ``GET``. The ``notfound_post`` view will be called when a +view could not be found and the request method was ``POST``. Like any other view, the Not Found 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 +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.httpexceptions.HTTPNotFound` exception that caused the view to be called. @@ -106,13 +106,13 @@ callable: .. note:: - When a Not Found View callable is invoked, it is passed a - :term:`request`. The ``exception`` attribute of the request will be an - instance of the :exc:`~pyramid.httpexceptions.HTTPNotFound` exception that - caused the Not Found View to be called. The value of - ``request.exception.message`` will be a value explaining why the Not Found - error was raised. This message has different values depending whether the - ``pyramid.debug_notfound`` environment setting is true or false. + When a Not Found View callable is invoked, it is passed a :term:`request`. + The ``exception`` attribute of the request will be an instance of the + :exc:`~pyramid.httpexceptions.HTTPNotFound` exception that caused the Not + Found View to be called. The value of ``request.exception.message`` will be + a value explaining why the Not Found exception was raised. This message has + different values depending on whether the ``pyramid.debug_notfound`` + environment setting is true or false. .. note:: @@ -124,9 +124,9 @@ callable: .. warning:: - When a Not Found 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 + When a Not Found 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.httpexceptions.HTTPNotFound` exception instance. If available, the resource context will still be available as ``request.context``. @@ -140,13 +140,13 @@ Changing the Forbidden View --------------------------- When :app:`Pyramid` can't authorize execution of a view based on the -:term:`authorization policy` in use, it invokes a :term:`forbidden view`. -The default forbidden response has a 403 status code and is very plain, but -the view which generates it can be overridden as necessary. +:term:`authorization policy` in use, it invokes a :term:`forbidden view`. The +default forbidden response has a 403 status code and is very plain, but 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 "forbidden" view consists -of using the :meth:`pyramid.config.Configurator.add_forbidden_view` API or the +:term:`view configuration` which causes it to be a "forbidden" view consists of +using the :meth:`pyramid.config.Configurator.add_forbidden_view` API or the :class:`pyramid.view.forbidden_view_config` decorator. For example, you can add a forbidden view by using the @@ -181,14 +181,11 @@ as a forbidden view: config.scan() Like any other view, the forbidden view must accept at least a ``request`` -parameter, or both ``context`` and ``request``. If a forbidden view -callable accepts both ``context`` and ``request``, the HTTP Exception is passed -as context. The ``context`` as found by the router when view was -denied (that you normally would expect) is available as -``request.context``. The ``request`` is the current :term:`request` -representing the denied action. - - +parameter, or both ``context`` and ``request``. If a forbidden view callable +accepts both ``context`` and ``request``, the HTTP Exception is passed as +context. The ``context`` as found by the router when the view was denied (which +you normally would expect) is available as ``request.context``. The +``request`` is the current :term:`request` representing the denied action. Here's some sample code that implements a minimal forbidden view: @@ -203,15 +200,15 @@ 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.httpexceptions.HTTPForbidden` exception - that caused the forbidden view to be called. The value of - ``request.exception.message`` will be a value explaining why the forbidden - was raised and ``request.exception.result`` will be extended information - about the forbidden exception. These messages have different values - depending whether the ``pyramid.debug_authorization`` environment setting - is true or false. + 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.httpexceptions.HTTPForbidden` exception that caused the + forbidden view to be called. The value of ``request.exception.message`` + will be a value explaining why the forbidden exception was raised, and + ``request.exception.result`` will be extended information about the + forbidden exception. These messages have different values depending on + whether the ``pyramid.debug_authorization`` environment setting is true or + false. .. index:: single: request factory @@ -223,11 +220,11 @@ Changing the Request Factory Whenever :app:`Pyramid` handles a request from a :term:`WSGI` server, it creates a :term:`request` object based on the WSGI environment it has been -passed. By default, an instance of the :class:`pyramid.request.Request` -class is created to represent the request object. +passed. By default, an instance of the :class:`pyramid.request.Request` class +is created to represent the request object. -The class (aka "factory") that :app:`Pyramid` uses to create a request object -instance can be changed by passing a ``request_factory`` argument to the +The class (a.k.a., "factory") that :app:`Pyramid` uses to create a request +object instance can be changed by passing a ``request_factory`` argument to the constructor of the :term:`configurator`. This argument can be either a callable or a :term:`dotted Python name` representing a callable. @@ -242,7 +239,7 @@ callable or a :term:`dotted Python name` representing a callable. config = Configurator(request_factory=MyRequest) If you're doing imperative configuration, and you'd rather do it after you've -already constructed a :term:`configurator` it can also be registered via the +already constructed a :term:`configurator`, it can also be registered via the :meth:`pyramid.config.Configurator.set_request_factory` method: .. code-block:: python @@ -262,19 +259,19 @@ already constructed a :term:`configurator` it can also be registered via the .. _adding_request_method: -Adding Methods or Properties to Request Object ----------------------------------------------- +Adding Methods or Properties to a Request Object +------------------------------------------------ .. versionadded:: 1.4. Since each Pyramid application can only have one :term:`request` factory, -:ref:`changing the request factory ` -is not that extensible, especially if you want to build composable features -(e.g., Pyramid add-ons and plugins). +:ref:`changing the request factory ` is not that +extensible, especially if you want to build composable features (e.g., Pyramid +add-ons and plugins). A lazy property can be registered to the request object via the -:meth:`pyramid.config.Configurator.add_request_method` API. This allows you -to specify a callable that will be available on the request object, but will not +:meth:`pyramid.config.Configurator.add_request_method` API. This allows you to +specify a callable that will be available on the request object, but will not actually execute the function until accessed. .. warning:: @@ -298,9 +295,10 @@ actually execute the function until accessed. config.add_request_method(total) config.add_request_method(prop, reify=True) -In the above example, ``total`` is added as a method. However, ``prop`` is added -as a property and its result is cached per-request by setting ``reify=True``. -This way, we eliminate the overhead of running the function multiple times. +In the above example, ``total`` is added as a method. However, ``prop`` is +added as a property and its result is cached per-request by setting +``reify=True``. This way, we eliminate the overhead of running the function +multiple times. >>> request.total(1, 2, 3) 6 @@ -354,18 +352,18 @@ We attach and cache an object named ``extra`` to the ``request`` object. .. _changing_the_response_factory: Changing the Response Factory -------------------------------- +----------------------------- .. versionadded:: 1.6 -Whenever :app:`Pyramid` returns a response from a view it creates a +Whenever :app:`Pyramid` returns a response from a view, it creates a :term:`response` object. By default, an instance of the :class:`pyramid.response.Response` class is created to represent the response object. -The factory that :app:`Pyramid` uses to create a response object instance can be -changed by passing a :class:`pyramid.interfaces.IResponseFactory` argument to -the constructor of the :term:`configurator`. This argument can be either a +The factory that :app:`Pyramid` uses to create a response object instance can +be changed by passing a :class:`pyramid.interfaces.IResponseFactory` argument +to the constructor of the :term:`configurator`. This argument can be either a callable or a :term:`dotted Python name` representing a callable. The factory takes a single positional argument, which is a :term:`Request` @@ -381,8 +379,8 @@ object. The argument may be ``None``. config = Configurator(response_factory=lambda r: MyResponse()) -If you're doing imperative configuration, and you'd rather do it after you've -already constructed a :term:`configurator` it can also be registered via the +If you're doing imperative configuration and you'd rather do it after you've +already constructed a :term:`configurator`, it can also be registered via the :meth:`pyramid.config.Configurator.set_response_factory` method: .. code-block:: python @@ -403,13 +401,13 @@ already constructed a :term:`configurator` it can also be registered via the .. _beforerender_event: -Using The Before Render Event +Using the Before Render Event ----------------------------- Subscribers to the :class:`pyramid.events.BeforeRender` event may introspect and modify the set of :term:`renderer globals` before they are passed to a -:term:`renderer`. This event object iself has a dictionary-like interface -that can be used for this purpose. For example: +:term:`renderer`. This event object iself has a dictionary-like interface that +can be used for this purpose. For example: .. code-block:: python :linenos: @@ -421,22 +419,22 @@ that can be used for this purpose. For example: def add_global(event): event['mykey'] = 'foo' -An object of this type is sent as an event just before a :term:`renderer` -is invoked. +An object of this type is sent as an event just before a :term:`renderer` is +invoked. -If a subscriber attempts to add a key that already exist in the renderer +If a subscriber attempts to add a key that already exists in the renderer globals dictionary, a :exc:`KeyError` is raised. This limitation is enforced because event subscribers do not possess any relative ordering. The set of keys added to the renderer globals dictionary by all -:class:`pyramid.events.BeforeRender` subscribers and renderer globals -factories must be unique. +:class:`pyramid.events.BeforeRender` subscribers and renderer globals factories +must be unique. The dictionary returned from the view is accessible through the :attr:`rendering_val` attribute of a :class:`~pyramid.events.BeforeRender` event. -Suppose you return ``{'mykey': 'somevalue', 'mykey2': 'somevalue2'}`` from -your view callable, like so: +Suppose you return ``{'mykey': 'somevalue', 'mykey2': 'somevalue2'}`` from your +view callable, like so: .. code-block:: python :linenos: @@ -492,24 +490,23 @@ A response callback is a callable which accepts two positional parameters: response.cache_control.max_age = 360 request.add_response_callback(cache_callback) -No response callback is called if an unhandled exception happens in -application code, or if the response object returned by a :term:`view -callable` is invalid. Response callbacks *are*, however, invoked when a -:term:`exception view` is rendered successfully: in such a case, the -:attr:`request.exception` attribute of the request when it enters a response -callback will be an exception object instead of its default value of -``None``. +No response callback is called if an unhandled exception happens in application +code, or if the response object returned by a :term:`view callable` is invalid. +Response callbacks *are*, however, invoked when a :term:`exception view` is +rendered successfully. In such a case, the :attr:`request.exception` attribute +of the request when it enters a response callback will be an exception object +instead of its default value of ``None``. Response callbacks are called in the order they're added -(first-to-most-recently-added). All response callbacks are called *before* -the :class:`~pyramid.events.NewResponse` event is sent. Errors raised by -response callbacks are not handled specially. They will be propagated to the -caller of the :app:`Pyramid` router application. +(first-to-most-recently-added). All response callbacks are called *before* the +:class:`~pyramid.events.NewResponse` event is sent. Errors raised by response +callbacks are not handled specially. They will be propagated to the caller of +the :app:`Pyramid` router application. A response callback has a lifetime of a *single* request. If you want a response callback to happen as the result of *every* request, you must -re-register the callback into every new request (perhaps within a subscriber -of a :class:`~pyramid.events.NewRequest` event). +re-register the callback into every new request (perhaps within a subscriber of +a :class:`~pyramid.events.NewRequest` event). .. index:: single: finished callback @@ -520,15 +517,15 @@ Using Finished Callbacks ------------------------ A :term:`finished callback` is a function that will be called unconditionally -by the :app:`Pyramid` :term:`router` at the very end of request processing. -A finished callback can be used to perform an action at the end of a request +by the :app:`Pyramid` :term:`router` at the very end of request processing. A +finished callback can be used to perform an action at the end of a request unconditionally. The :meth:`pyramid.request.Request.add_finished_callback` method is used to register a finished callback. -A finished callback is a callable which accepts a single positional -parameter: ``request``. For example: +A finished callback is a callable which accepts a single positional parameter: +``request``. For example: .. code-block:: python :linenos: @@ -543,29 +540,27 @@ parameter: ``request``. For example: request.add_finished_callback(log_callback) Finished callbacks are called in the order they're added -(first-to-most-recently-added). Finished callbacks (unlike a -:term:`response callback`) are *always* called, even if an exception -happens in application code that prevents a response from being -generated. - -The set of finished callbacks associated with a request are called *very -late* in the processing of that request; they are essentially the very last -thing called by the :term:`router` before a request "ends". They are called -after response processing has already occurred in a top-level ``finally:`` -block within the router request processing code. As a result, mutations -performed to the ``request`` provided to a finished callback will have no -meaningful effect, because response processing will have already occurred, -and the request's scope will expire almost immediately after all finished -callbacks have been processed. - -Errors raised by finished callbacks are not handled specially. They -will be propagated to the caller of the :app:`Pyramid` router -application. +(first-to-most-recently-added). Finished callbacks (unlike a :term:`response +callback`) are *always* called, even if an exception happens in application +code that prevents a response from being generated. + +The set of finished callbacks associated with a request are called *very late* +in the processing of that request; they are essentially the very last thing +called by the :term:`router` before a request "ends". They are called after +response processing has already occurred in a top-level ``finally:`` block +within the router request processing code. As a result, mutations performed to +the ``request`` provided to a finished callback will have no meaningful effect, +because response processing will have already occurred, and the request's scope +will expire almost immediately after all finished callbacks have been +processed. + +Errors raised by finished callbacks are not handled specially. They will be +propagated to the caller of the :app:`Pyramid` router application. A finished callback has a lifetime of a *single* request. If you want a finished callback to happen as the result of *every* request, you must -re-register the callback into every new request (perhaps within a subscriber -of a :class:`~pyramid.events.NewRequest` event). +re-register the callback into every new request (perhaps within a subscriber of +a :class:`~pyramid.events.NewRequest` event). .. index:: single: traverser @@ -577,8 +572,8 @@ Changing the Traverser The default :term:`traversal` algorithm that :app:`Pyramid` uses is explained in :ref:`traversal_algorithm`. Though it is rarely necessary, this default -algorithm can be swapped out selectively for a different traversal pattern -via configuration. +algorithm can be swapped out selectively for a different traversal pattern via +configuration. .. code-block:: python :linenos: @@ -624,10 +619,10 @@ that implements the following interface: More than one traversal algorithm can be active at the same time. For instance, if your :term:`root factory` returns more than one type of object -conditionally, you could claim that an alternate traverser adapter is "for" +conditionally, you could claim that an alternative traverser adapter is "for" only one particular class or interface. When the root factory returned an object that implemented that class or interface, a custom traverser would be -used. Otherwise, the default traverser would be used. For example: +used. Otherwise the default traverser would be used. For example: .. code-block:: python :linenos: @@ -639,13 +634,13 @@ used. Otherwise, the default traverser would be used. For example: config.add_traverser(Traverser, MyRoot) If the above stanza was added to a Pyramid ``__init__.py`` file's ``main`` -function, :app:`Pyramid` would use the ``myapp.traversal.Traverser`` only -when the application :term:`root factory` returned an instance of the +function, :app:`Pyramid` would use the ``myapp.traversal.Traverser`` only when +the application :term:`root factory` returned an instance of the ``myapp.resources.MyRoot`` object. Otherwise it would use the default :app:`Pyramid` traverser to do traversal. .. index:: - single: url generator + single: URL generator .. _changing_resource_url: @@ -655,9 +650,8 @@ Changing How :meth:`pyramid.request.Request.resource_url` Generates a URL When you add a traverser as described in :ref:`changing_the_traverser`, it's often convenient to continue to use the :meth:`pyramid.request.Request.resource_url` API. However, since the way -traversal is done will have been modified, the URLs it generates by default -may be incorrect when used against resources derived from your custom -traverser. +traversal is done will have been modified, the URLs it generates by default may +be incorrect when used against resources derived from your custom traverser. If you've added a traverser, you can change how :meth:`~pyramid.request.Request.resource_url` generates a URL for a specific @@ -674,13 +668,13 @@ For example: config.add_resource_url_adapter(ResourceURLAdapter, MyRoot) -In the above example, the ``myapp.traversal.ResourceURLAdapter`` class will -be used to provide services to :meth:`~pyramid.request.Request.resource_url` -any time the :term:`resource` passed to ``resource_url`` is of the class +In the above example, the ``myapp.traversal.ResourceURLAdapter`` class will be +used to provide services to :meth:`~pyramid.request.Request.resource_url` any +time the :term:`resource` passed to ``resource_url`` is of the class ``myapp.resources.MyRoot``. The ``resource_iface`` argument ``MyRoot`` represents the type of interface that must be possessed by the resource for this resource url factory to be found. If the ``resource_iface`` argument is -omitted, this resource url adapter will be used for *all* resources. +omitted, this resource URL adapter will be used for *all* resources. The API that must be implemented by a class that provides :class:`~pyramid.interfaces.IResourceURL` is as follows: @@ -693,8 +687,8 @@ The API that must be implemented by a class that provides resource """ def __init__(self, resource, request): - """ Accept the resource and request and set self.physical_path and - self.virtual_path""" + """ Accept the resource and request and set self.physical_path and + self.virtual_path """ self.virtual_path = some_function_of(resource, request) self.physical_path = some_other_function_of(resource, request) @@ -703,7 +697,8 @@ The default context URL generator is available for perusal as the class `_ of the :term:`Pylons` GitHub Pyramid repository. -See :meth:`pyramid.config.add_resource_url_adapter` for more information. +See :meth:`pyramid.config.Configurator.add_resource_url_adapter` for more +information. .. index:: single: IResponse @@ -721,25 +716,24 @@ callable on a per-type basis by using a hook involving :meth:`pyramid.config.Configurator.add_response_adapter` or the :class:`~pyramid.response.response_adapter` decorator. -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 +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`, they 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 :term:`renderer` to convert a string to a -response object), you can register an adapter which converts the string to a -Response: +objects (without requiring 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: @@ -754,9 +748,9 @@ Response: 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 -adapter to the more complex IResponse interface: +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: @@ -777,7 +771,7 @@ adapter to the more complex IResponse interface: 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 +to make sure that the object implements every attribute and method outlined in :class:`pyramid.interfaces.IResponse` and you'll have to ensure that it uses ``zope.interface.implementer(IResponse)`` as a class decorator. @@ -789,7 +783,7 @@ to make sure the object implements every attribute and method outlined in @implementer(IResponse) class MyResponse(object): - # ... an implementation of every method and attribute + # ... an implementation of every method and attribute # documented in IResponse should follow ... When an alternate response object implementation is returned by a view @@ -804,8 +798,8 @@ 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. -Instead of using :meth:`pyramid.config.Configurator.add_response_adapter`, -you can use the :class:`pyramid.response.response_adapter` decorator: +Instead of using :meth:`pyramid.config.Configurator.add_response_adapter`, you +can use the :class:`pyramid.response.response_adapter` decorator: .. code-block:: python :linenos: @@ -841,31 +835,29 @@ callables by employing a :term:`view mapper`. A view mapper is an object that accepts a set of keyword arguments and which returns a callable. The returned callable is called with the :term:`view -callable` object. The returned callable should itself return another -callable which can be called with the "internal calling protocol" ``(context, +callable` object. The returned callable should itself return another callable +which can be called with the "internal calling protocol" ``(context, request)``. You can use a view mapper in a number of ways: -- by setting a ``__view_mapper__`` attribute (which is the view mapper - object) on the view callable itself +- by setting a ``__view_mapper__`` attribute (which is the view mapper object) + on the view callable itself -- by passing the mapper object to - :meth:`pyramid.config.Configurator.add_view` (or its declarative/decorator - equivalents) as the ``mapper`` argument. +- by passing the mapper object to :meth:`pyramid.config.Configurator.add_view` + (or its declarative and decorator equivalents) as the ``mapper`` argument -- by registering a *default* view mapper. +- by registering a *default* view mapper Here's an example of a view mapper that emulates (somewhat) a Pylons "controller". The mapper is initialized with some keyword arguments. Its ``__call__`` method accepts the view object (which will be a class). It uses -the ``attr`` keyword argument it is passed to determine which attribute -should be used as an action method. The wrapper method it returns accepts -``(context, request)`` and returns the result of calling the action method -with keyword arguments implied by the :term:`matchdict` after popping the -``action`` out of it. This somewhat emulates the Pylons style of calling -action methods with routing parameters pulled out of the route matching dict -as keyword arguments. +the ``attr`` keyword argument it is passed to determine which attribute should +be used as an action method. The wrapper method it returns accepts ``(context, +request)`` and returns the result of calling the action method with keyword +arguments implied by the :term:`matchdict` after popping the ``action`` out of +it. This somewhat emulates the Pylons style of calling action methods with +routing parameters pulled out of the route matching dict as keyword arguments. .. code-block:: python :linenos: @@ -917,8 +909,8 @@ The :meth:`pyramid.config.Configurator.set_view_mapper` method can be used to set a *default* view mapper (overriding the superdefault view mapper used by Pyramid itself). -A *single* view registration can use a view mapper by passing the mapper as -the ``mapper`` argument to :meth:`~pyramid.config.Configurator.add_view`. +A *single* view registration can use a view mapper by passing the mapper as the +``mapper`` argument to :meth:`~pyramid.config.Configurator.add_view`. .. index:: single: configuration decorator @@ -928,14 +920,14 @@ the ``mapper`` argument to :meth:`~pyramid.config.Configurator.add_view`. Registering Configuration Decorators ------------------------------------ -Decorators such as :class:`~pyramid.view.view_config` don't change the -behavior of the functions or classes they're decorating. Instead, when a -:term:`scan` is performed, a modified version of the function or class is -registered with :app:`Pyramid`. +Decorators such as :class:`~pyramid.view.view_config` don't change the behavior +of the functions or classes they're decorating. Instead when a :term:`scan` is +performed, a modified version of the function or class is registered with +:app:`Pyramid`. You may wish to have your own decorators that offer such behaviour. This is -possible by using the :term:`Venusian` package in the same way that it is -used by :app:`Pyramid`. +possible by using the :term:`Venusian` package in the same way that it is used +by :app:`Pyramid`. By way of example, let's suppose you want to write a decorator that registers the function it wraps with a :term:`Zope Component Architecture` "utility" @@ -945,8 +937,7 @@ available once your application's configuration is at least partially completed. A normal decorator would fail as it would be executed before the configuration had even begun. -However, using :term:`Venusian`, the decorator could be written as -follows: +However, using :term:`Venusian`, the decorator could be written as follows: .. code-block:: python :linenos: @@ -968,18 +959,17 @@ follows: venusian.attach(wrapped, self.register) return wrapped -This decorator could then be used to register functions throughout -your code: +This decorator could then be used to register functions throughout your code: .. code-block:: python :linenos: @registerFunction('/some/path') def my_function(): - do_stuff() + do_stuff() -However, the utility would only be looked up when a :term:`scan` was -performed, enabling you to set up the utility in advance: +However, the utility would only be looked up when a :term:`scan` was performed, +enabling you to set up the utility in advance: .. code-block:: python :linenos: @@ -994,10 +984,10 @@ performed, enabling you to set up the utility in advance: class UtilityImplementation: def __init__(self): - self.registrations = {} + self.registrations = {} def register(self, path, callable_): - self.registrations[path] = callable_ + self.registrations[path] = callable_ if __name__ == '__main__': config = Configurator() @@ -1021,27 +1011,27 @@ Registering Tweens A :term:`tween` (a contraction of the word "between") is a bit of code that sits between the Pyramid router's main request handling function and the upstream WSGI component that uses :app:`Pyramid` as its "app". This is a -feature that may be used by Pyramid framework extensions, to provide, for +feature that may be used by Pyramid framework extensions to provide, for example, Pyramid-specific view timing support bookkeeping code that examines exceptions before they are returned to the upstream WSGI application. Tweens -behave a bit like :term:`WSGI` :term:`middleware` but they have the benefit of +behave a bit like :term:`WSGI` :term:`middleware`, but they have the benefit of running in a context in which they have access to the Pyramid :term:`request`, -:term:`response` and :term:`application registry` as well as the Pyramid +:term:`response`, and :term:`application registry`, as well as the Pyramid rendering machinery. Creating a Tween ~~~~~~~~~~~~~~~~ -To create a tween, you must write a "tween factory". A tween factory -must be a globally importable callable which accepts two arguments: -``handler`` and ``registry``. ``handler`` will be either the main -Pyramid request handling function or another tween. ``registry`` will be the -Pyramid :term:`application registry` represented by this Configurator. A -tween factory must return the tween (a callable object) when it is called. +To create a tween, you must write a "tween factory". A tween factory must be a +globally importable callable which accepts two arguments: ``handler`` and +``registry``. ``handler`` will be either the main Pyramid request handling +function or another tween. ``registry`` will be the Pyramid :term:`application +registry` represented by this Configurator. A tween factory must return the +tween (a callable object) when it is called. A tween is called with a single argument, ``request``, which is the -:term:`request` created by Pyramid's router when it receives a WSGI request. -A tween should return a :term:`response`, usually the one generated by the +:term:`request` created by Pyramid's router when it receives a WSGI request. A +tween should return a :term:`response`, usually the one generated by the downstream Pyramid application. You can write the tween factory as a simple closure-returning function: @@ -1089,14 +1079,14 @@ method: return response -You should avoid mutating any state on the tween instance. The tween is -invoked once per request and any shared mutable state needs to be carefully -handled to avoid any race conditions. +You should avoid mutating any state on the tween instance. The tween is invoked +once per request and any shared mutable state needs to be carefully handled to +avoid any race conditions. The closure style performs slightly better and enables you to conditionally omit the tween from the request processing pipeline (see the following timing tween example), whereas the class style makes it easier to have shared mutable -state, and it allows subclassing. +state and allows subclassing. Here's a complete example of a tween that logs the time spent processing each request: @@ -1131,13 +1121,12 @@ request: In the above example, the tween factory defines a ``timing_tween`` tween and returns it if ``asbool(registry.settings.get('do_timing'))`` is true. It -otherwise simply returns the handler it was given. The ``registry.settings`` -attribute is a handle to the deployment settings provided by the user -(usually in an ``.ini`` file). In this case, if the user has defined a -``do_timing`` setting, and that setting is ``True``, the user has said she -wants to do timing, so the tween factory returns the timing tween; it -otherwise just returns the handler it has been provided, preventing any -timing. +otherwise simply returns the handler which it was given. The +``registry.settings`` attribute is a handle to the deployment settings provided +by the user (usually in an ``.ini`` file). In this case, if the user has +defined a ``do_timing`` setting and that setting is ``True``, the user has said +they want to do timing, so the tween factory returns the timing tween; it +otherwise just returns the handler it has been provided, preventing any timing. The example timing tween simply records the start time, calls the downstream handler, logs the number of seconds consumed by the downstream handler, and @@ -1163,29 +1152,28 @@ Pyramid application: Note that you must use a :term:`dotted Python name` as the first argument to :meth:`pyramid.config.Configurator.add_tween`; this must point at a tween factory. You cannot pass the tween factory object itself to the method: it -must be :term:`dotted Python name` that points to a globally importable -object. In the above example, we assume that a ``timing_tween_factory`` -tween factory was defined in a module named ``myapp.tweens``, so the tween -factory is importable as ``myapp.tweens.timing_tween_factory``. - -When you use :meth:`pyramid.config.Configurator.add_tween`, you're -instructing the system to use your tween factory at startup time unless the -user has provided an explicit tween list in his configuration. This is -what's meant by an "implicit" tween. A user can always elect to supply an -explicit tween list, reordering or disincluding implicitly added tweens. See +must be :term:`dotted Python name` that points to a globally importable object. +In the above example, we assume that a ``timing_tween_factory`` tween factory +was defined in a module named ``myapp.tweens``, so the tween factory is +importable as ``myapp.tweens.timing_tween_factory``. + +When you use :meth:`pyramid.config.Configurator.add_tween`, you're instructing +the system to use your tween factory at startup time unless the user has +provided an explicit tween list in their configuration. This is what's meant +by an "implicit" tween. A user can always elect to supply an explicit tween +list, reordering or disincluding implicitly added tweens. See :ref:`explicit_tween_ordering` for more information about explicit tween ordering. -If more than one call to :meth:`pyramid.config.Configurator.add_tween` is -made within a single application configuration, the tweens will be chained -together at application startup time. The *first* tween factory added via -``add_tween`` will be called with the Pyramid exception view tween factory as -its ``handler`` argument, then the tween factory added directly after that -one will be called with the result of the first tween factory as its -``handler`` argument, and so on, ad infinitum until all tween factories have -been called. The Pyramid router will use the outermost tween produced by this -chain (the tween generated by the very last tween factory added) as its -request handler function. For example: +If more than one call to :meth:`pyramid.config.Configurator.add_tween` is made +within a single application configuration, the tweens will be chained together +at application startup time. The *first* tween factory added via ``add_tween`` +will be called with the Pyramid exception view tween factory as its ``handler`` +argument, then the tween factory added directly after that one will be called +with the result of the first tween factory as its ``handler`` argument, and so +on, ad infinitum until all tween factories have been called. The Pyramid router +will use the outermost tween produced by this chain (the tween generated by the +very last tween factory added) as its request handler function. For example: .. code-block:: python :linenos: @@ -1196,8 +1184,7 @@ request handler function. For example: config.add_tween('myapp.tween_factory1') config.add_tween('myapp.tween_factory2') -The above example will generate an implicit tween chain that looks like -this:: +The above example will generate an implicit tween chain that looks like this:: INGRESS (implicit) myapp.tween_factory2 @@ -1211,37 +1198,36 @@ Suggesting Implicit Tween Ordering By default, as described above, the ordering of the chain is controlled entirely by the relative ordering of calls to :meth:`pyramid.config.Configurator.add_tween`. However, the caller of -add_tween can provide an optional hint that can influence the implicit tween -chain ordering by supplying ``under`` or ``over`` (or both) arguments to -:meth:`~pyramid.config.Configurator.add_tween`. These hints are only -used when an explicit tween ordering is not used. See -:ref:`explicit_tween_ordering` for a description of how to set an explicit -tween ordering. +``add_tween`` can provide an optional hint that can influence the implicit +tween chain ordering by supplying ``under`` or ``over`` (or both) arguments to +:meth:`~pyramid.config.Configurator.add_tween`. These hints are only used when +an explicit tween ordering is not used. See :ref:`explicit_tween_ordering` for +a description of how to set an explicit tween ordering. Allowable values for ``under`` or ``over`` (or both) are: -- ``None`` (the default). +- ``None`` (the default), -- A :term:`dotted Python name` to a tween factory: a string representing the - predicted dotted name of a tween factory added in a call to ``add_tween`` - in the same configuration session. +- a :term:`dotted Python name` to a tween factory: a string representing the + predicted dotted name of a tween factory added in a call to ``add_tween`` in + the same configuration session, -- One of the constants :attr:`pyramid.tweens.MAIN`, - :attr:`pyramid.tweens.INGRESS`, or :attr:`pyramid.tweens.EXCVIEW`. +- one of the constants :attr:`pyramid.tweens.MAIN`, + :attr:`pyramid.tweens.INGRESS`, or :attr:`pyramid.tweens.EXCVIEW`, or -- An iterable of any combination of the above. This allows the user to specify +- an iterable of any combination of the above. This allows the user to specify fallbacks if the desired tween is not included, as well as compatibility with multiple other tweens. -Effectively, ``over`` means "closer to the request ingress than" and -``under`` means "closer to the main Pyramid application than". -You can think of an onion with outer layers over the inner layers, -the application being under all the layers at the center. +Effectively, ``over`` means "closer to the request ingress than" and ``under`` +means "closer to the main Pyramid application than". You can think of an onion +with outer layers over the inner layers, the application being under all the +layers at the center. For example, the following call to -:meth:`~pyramid.config.Configurator.add_tween` will attempt to place the -tween factory represented by ``myapp.tween_factory`` directly 'above' (in -``ptweens`` order) the main Pyramid request handler. +:meth:`~pyramid.config.Configurator.add_tween` will attempt to place the tween +factory represented by ``myapp.tween_factory`` directly "above" (in ``ptweens`` +order) the main Pyramid request handler. .. code-block:: python :linenos: @@ -1250,8 +1236,7 @@ tween factory represented by ``myapp.tween_factory`` directly 'above' (in config.add_tween('myapp.tween_factory', over=pyramid.tweens.MAIN) -The above example will generate an implicit tween chain that looks like -this:: +The above example will generate an implicit tween chain that looks like this:: INGRESS (implicit) pyramid.tweens.excview_tween_factory (implicit) @@ -1259,9 +1244,8 @@ this:: MAIN (implicit) Likewise, calling the following call to -:meth:`~pyramid.config.Configurator.add_tween` will attempt to place this -tween factory 'above' the main handler but 'below' a separately added tween -factory: +:meth:`~pyramid.config.Configurator.add_tween` will attempt to place this tween +factory "above" the main handler but "below" a separately added tween factory: .. code-block:: python :linenos: @@ -1274,8 +1258,7 @@ factory: over=pyramid.tweens.MAIN, under='myapp.tween_factory1') -The above example will generate an implicit tween chain that looks like -this:: +The above example will generate an implicit tween chain that looks like this:: INGRESS (implicit) pyramid.tweens.excview_tween_factory (implicit) @@ -1288,28 +1271,28 @@ Specifying neither ``over`` nor ``under`` is equivalent to specifying If all options for ``under`` (or ``over``) cannot be found in the current configuration, it is an error. If some options are specified purely for -compatibilty with other tweens, just add a fallback of MAIN or INGRESS. -For example, ``under=('someothertween', 'someothertween2', INGRESS)``. -This constraint will require the tween to be located under both the -'someothertween' tween, the 'someothertween2' tween, and INGRESS. If any of -these is not in the current configuration, this constraint will only organize -itself based on the tweens that are present. +compatibilty with other tweens, just add a fallback of ``MAIN`` or ``INGRESS``. +For example, ``under=('someothertween', 'someothertween2', INGRESS)``. This +constraint will require the tween to be located under the ``someothertween`` +tween, the ``someothertween2`` tween, and ``INGRESS``. If any of these is not +in the current configuration, this constraint will only organize itself based +on the tweens that are present. .. _explicit_tween_ordering: Explicit Tween Ordering ~~~~~~~~~~~~~~~~~~~~~~~ -Implicit tween ordering is obviously only best-effort. Pyramid will attempt -to provide an implicit order of tweens as best it can using hints provided by -calls to :meth:`~pyramid.config.Configurator.add_tween`, but because it's -only best-effort, if very precise tween ordering is required, the only -surefire way to get it is to use an explicit tween order. The deploying user -can override the implicit tween inclusion and ordering implied by calls to +Implicit tween ordering is obviously only best-effort. Pyramid will attempt to +provide an implicit order of tweens as best it can using hints provided by +calls to :meth:`~pyramid.config.Configurator.add_tween`. But because it's only +best-effort, if very precise tween ordering is required, the only surefire way +to get it is to use an explicit tween order. The deploying user can override +the implicit tween inclusion and ordering implied by calls to :meth:`~pyramid.config.Configurator.add_tween` entirely by using the ``pyramid.tweens`` settings value. When used, this settings value must be a -list of Python dotted names which will override the ordering (and inclusion) -of tween factories in the implicit tween chain. For example: +list of Python dotted names which will override the ordering (and inclusion) of +tween factories in the implicit tween chain. For example: .. code-block:: ini :linenos: @@ -1327,19 +1310,19 @@ of tween factories in the implicit tween chain. For example: In the above configuration, calls made during configuration to :meth:`pyramid.config.Configurator.add_tween` are ignored, and the user is telling the system to use the tween factories he has listed in the -``pyramid.tweens`` configuration setting (each is a :term:`dotted Python -name` which points to a tween factory) instead of any tween factories added -via :meth:`pyramid.config.Configurator.add_tween`. The *first* tween factory -in the ``pyramid.tweens`` list will be used as the producer of the effective +``pyramid.tweens`` configuration setting (each is a :term:`dotted Python name` +which points to a tween factory) instead of any tween factories added via +:meth:`pyramid.config.Configurator.add_tween`. The *first* tween factory in +the ``pyramid.tweens`` list will be used as the producer of the effective :app:`Pyramid` request handling function; it will wrap the tween factory -declared directly "below" it, ad infinitum. The "main" Pyramid request -handler is implicit, and always "at the bottom". +declared directly "below" it, ad infinitum. The "main" Pyramid request handler +is implicit, and always "at the bottom". .. note:: - Pyramid's own :term:`exception view` handling logic is implemented - as a tween factory function: :func:`pyramid.tweens.excview_tween_factory`. - If Pyramid exception view handling is desired, and tween factories are + Pyramid's own :term:`exception view` handling logic is implemented as a + tween factory function: :func:`pyramid.tweens.excview_tween_factory`. If + Pyramid exception view handling is desired, and tween factories are specified via the ``pyramid.tweens`` configuration setting, the :func:`pyramid.tweens.excview_tween_factory` function must be added to the ``pyramid.tweens`` configuration setting list explicitly. If it is not @@ -1348,30 +1331,30 @@ handler is implicit, and always "at the bottom". Tween Conflicts and Ordering Cycles ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Pyramid will prevent the same tween factory from being added to the tween -chain more than once using configuration conflict detection. If you wish to -add the same tween factory more than once in a configuration, you should -either: a) use a tween factory that is a separate globally importable -instance object from the factory that it conflicts with b) use a function or -class as a tween factory with the same logic as the other tween factory it -conflicts with but with a different ``__name__`` attribute or c) call +Pyramid will prevent the same tween factory from being added to the tween chain +more than once using configuration conflict detection. If you wish to add the +same tween factory more than once in a configuration, you should either: (a) +use a tween factory that is a separate globally importable instance object from +the factory that it conflicts with; (b) use a function or class as a tween +factory with the same logic as the other tween factory it conflicts with, but +with a different ``__name__`` attribute; or (c) call :meth:`pyramid.config.Configurator.commit` between calls to :meth:`pyramid.config.Configurator.add_tween`. If a cycle is detected in implicit tween ordering when ``over`` and ``under`` -are used in any call to "add_tween", an exception will be raised at startup +are used in any call to ``add_tween``, an exception will be raised at startup time. Displaying Tween Ordering ~~~~~~~~~~~~~~~~~~~~~~~~~ -The ``ptweens`` command-line utility can be used to report the current -implict and explicit tween chains used by an application. See +The ``ptweens`` command-line utility can be used to report the current implict +and explicit tween chains used by an application. See :ref:`displaying_tweens`. .. _registering_thirdparty_predicates: -Adding A Third Party View, Route, or Subscriber Predicate +Adding a Third Party View, Route, or Subscriber Predicate --------------------------------------------------------- .. versionadded:: 1.4 @@ -1381,10 +1364,10 @@ Adding A Third Party View, Route, or Subscriber Predicate View and Route Predicates ~~~~~~~~~~~~~~~~~~~~~~~~~ -View and route predicates used during configuration allow you to narrow the -set of circumstances under which a view or route will match. For example, -the ``request_method`` view predicate can be used to ensure a view callable -is only invoked when the request's method is ``POST``: +View and route predicates used during configuration allow you to narrow the set +of circumstances under which a view or route will match. For example, the +``request_method`` view predicate can be used to ensure a view callable is only +invoked when the request's method is ``POST``: .. code-block:: python @@ -1398,9 +1381,9 @@ Likewise, a similar predicate can be used as a *route* predicate: config.add_route('name', '/foo', request_method='POST') -Many other built-in predicates exists (``request_param``, and others). You -can add third-party predicates to the list of available predicates by using -one of :meth:`pyramid.config.Configurator.add_view_predicate` or +Many other built-in predicates exists (``request_param``, and others). You can +add third-party predicates to the list of available predicates by using one of +:meth:`pyramid.config.Configurator.add_view_predicate` or :meth:`pyramid.config.Configurator.add_route_predicate`. The former adds a view predicate, the latter a route predicate. @@ -1428,7 +1411,7 @@ the name, is a string representing the name that is expected to be passed to The second argument is a view or route predicate factory, or a :term:`dotted Python name` which refers to a view or route predicate factory. A view or route predicate factory is most often a class with a constructor -(``__init__``), a ``text`` method, a ``phash`` method and a ``__call__`` +(``__init__``), a ``text`` method, a ``phash`` method, and a ``__call__`` method. For example: .. code-block:: python @@ -1448,27 +1431,27 @@ method. For example: The constructor of a predicate factory takes two arguments: ``val`` and ``config``. The ``val`` argument will be the argument passed to -``view_config`` (or ``add_view``). In the example above, it will be the -string ``File``. The second arg, ``config`` will be the Configurator -instance at the time of configuration. +``view_config`` (or ``add_view``). In the example above, it will be the string +``File``. The second argument, ``config``, will be the Configurator instance +at the time of configuration. -The ``text`` method must return a string. It should be useful to describe -the behavior of the predicate in error messages. +The ``text`` method must return a string. It should be useful to describe the +behavior of the predicate in error messages. -The ``phash`` method must return a string or a sequence of strings. It's -most often the same as ``text``, as long as ``text`` uniquely describes the -predicate's name and the value passed to the constructor. If ``text`` is -more general, or doesn't describe things that way, ``phash`` should return a -string with the name and the value serialized. The result of ``phash`` is -not seen in output anywhere, it just informs the uniqueness constraints for -view configuration. +The ``phash`` method must return a string or a sequence of strings. It's most +often the same as ``text``, as long as ``text`` uniquely describes the +predicate's name and the value passed to the constructor. If ``text`` is more +general, or doesn't describe things that way, ``phash`` should return a string +with the name and the value serialized. The result of ``phash`` is not seen in +output anywhere, it just informs the uniqueness constraints for view +configuration. The ``__call__`` method of a predicate factory must accept a resource -(``context``) and a request, and must return ``True`` or ``False``. It is -the "meat" of the predicate. +(``context``) and a request, and must return ``True`` or ``False``. It is the +"meat" of the predicate. -You can use the same predicate factory as both a view predicate and as a -route predicate, but you'll need to call ``add_view_predicate`` and +You can use the same predicate factory as both a view predicate and as a route +predicate, but you'll need to call ``add_view_predicate`` and ``add_route_predicate`` separately with the same factory. .. _subscriber_predicates: @@ -1476,16 +1459,16 @@ route predicate, but you'll need to call ``add_view_predicate`` and Subscriber Predicates ~~~~~~~~~~~~~~~~~~~~~ -Subscriber predicates work almost exactly like view and route predicates. -They narrow the set of circumstances in which a subscriber will be called. -There are several minor differences between a subscriber predicate and a -view/route predicate: +Subscriber predicates work almost exactly like view and route predicates. They +narrow the set of circumstances in which a subscriber will be called. There are +several minor differences between a subscriber predicate and a view or route +predicate: - There are no default subscriber predicates. You must register one to use one. -- The ``__call__`` method of a subscriber predicate accepts a single - ``event`` object instead of a ``context`` and a ``request``. +- The ``__call__`` method of a subscriber predicate accepts a single ``event`` + object instead of a ``context`` and a ``request``. - Not every subscriber predicate can be used with every event type. Some subscriber predicates will assume a certain event type. @@ -1519,8 +1502,8 @@ Once you've created a subscriber predicate, it may registered via Once a subscriber predicate is registered, you can use it in a call to :meth:`pyramid.config.Configurator.add_subscriber` or to -:class:`pyramid.events.subscriber`. Here's an example of using the -previously registered ``request_path_startswith`` predicate in a call to +:class:`pyramid.events.subscriber`. Here's an example of using the previously +registered ``request_path_startswith`` predicate in a call to :meth:`~pyramid.config.Configurator.add_subscriber`: .. code-block:: python @@ -1533,7 +1516,7 @@ previously registered ``request_path_startswith`` predicate in a call to # and at configuration time - config.add_subscriber(yosubscriber, NewRequest, + config.add_subscriber(yosubscriber, NewRequest, request_path_startswith='/add_yo') Here's the same subscriber/predicate/event-type combination used via @@ -1548,22 +1531,19 @@ Here's the same subscriber/predicate/event-type combination used via def yosubscriber(event): event.request.yo = 'YO!' -In either of the above configurations, the ``yosubscriber`` callable will -only be called if the request path starts with ``/add_yo``. Otherwise the -event subscriber will not be called. +In either of the above configurations, the ``yosubscriber`` callable will only +be called if the request path starts with ``/add_yo``. Otherwise the event +subscriber will not be called. Note that the ``request_path_startswith`` subscriber you defined can be used with events that have a ``request`` attribute, but not ones that do not. So, for example, the predicate can be used with subscribers registered for :class:`pyramid.events.NewRequest` and :class:`pyramid.events.ContextFound` events, but it cannot be used with subscribers registered for -:class:`pyramid.events.ApplicationCreated` because the latter type of event -has no ``request`` attribute. The point being: unlike route and view -predicates, not every type of subscriber predicate will necessarily be -applicable for use in every subscriber registration. It is not the -responsibility of the predicate author to make every predicate make sense for -every event type; it is the responsibility of the predicate consumer to use -predicates that make sense for a particular event type registration. - - - +:class:`pyramid.events.ApplicationCreated` because the latter type of event has +no ``request`` attribute. The point being, unlike route and view predicates, +not every type of subscriber predicate will necessarily be applicable for use +in every subscriber registration. It is not the responsibility of the +predicate author to make every predicate make sense for every event type; it is +the responsibility of the predicate consumer to use predicates that make sense +for a particular event type registration. -- cgit v1.2.3 From d49c69250b406597a4796d158cf6540469ade414 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Wed, 20 Jan 2016 00:18:41 -0800 Subject: Do not use trailing . on versionadded rst directive. It automatically adds a . --- docs/narr/hooks.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 6aa1a99c2..7ff119b53 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -262,7 +262,7 @@ already constructed a :term:`configurator`, it can also be registered via the Adding Methods or Properties to a Request Object ------------------------------------------------ -.. versionadded:: 1.4. +.. versionadded:: 1.4 Since each Pyramid application can only have one :term:`request` factory, :ref:`changing the request factory ` is not that -- cgit v1.2.3 From fdd1f8352fc341bc60e0b7d32dadd2b4109a2b41 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Mon, 14 Mar 2016 22:08:04 -0500 Subject: first cut at documenting view derivers --- docs/narr/hooks.rst | 140 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 7ff119b53..13daed1fc 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -1547,3 +1547,143 @@ in every subscriber registration. It is not the responsibility of the predicate author to make every predicate make sense for every event type; it is the responsibility of the predicate consumer to use predicates that make sense for a particular event type registration. + +.. index:: + single: view derivers + +.. _view_derivers: + +View Derivers +------------- + +Every URL processed by :app:`Pyramid` is matched against a custom view +pipeline. See :ref:`router_chapter` for how this works. The view pipeline +itself is built from the user-supplied :term:`view callable` which is then +composed with :term:`view derivers `. A view deriver is a +composable element of the view pipeline which is used to wrap a view with +added functionality. View derivers are very similar to the ``decorator`` +argument to :meth:`pyramid.config.Configurator.add_view` except that they have +the option to execute for every view in the application. + +Built-in View Derivers +~~~~~~~~~~~~~~~~~~~~~~ + +There are several builtin view derivers that :app:`Pyramid` will automatically +apply to any view. They are defined in order from closest to furthest from +the user-defined :term:`view callable`: + +``mapped_view`` + + Applies the :term:`view mapper` defined by the ``mapper`` option or the + application's default view mapper to the :term:`view callable`. This + is always the closest deriver to the user-defined view and standardizes the + view pipeline interface to accept ``(context, request)`` from all previous + view derivers. + +``decorated_view`` + + Wraps the view with the decorators from the ``decorator`` option. + +``http_cached_view`` + + Applies cache control headers to the response defined by the ``http_cache`` + option. This element is a noop if the ``pyramid.prevent_http_cache`` setting + is enabled or the ``http_cache`` option is ``None``. + +``owrapped_view`` + + Invokes the wrapped view defined by the ``wrapper`` option. + +``secured_view`` + + Enforce the ``permission`` defined on the view. This element is a noop if + no permission is defined. Note there will always be a permission defined + if a default permission was assigned via + :meth:`pyramid.config.Configurator.set_default_permission`. + +``authdebug_view`` + + Used to output useful debugging information when + ``pyramid.debug_authorization`` is enabled. This element is a noop otherwise. + +Custom View Derivers +~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 1.7 + +It is possible to define custom view derivers which will affect all views in +an application. There are many uses for this but most will likely be centered +around monitoring and security. In order to register a custom +:term:`view deriver` you should create a callable that conforms to the +:class:`pyramid.interfaces.IViewDeriver` interface. For example, below +is a callable that can provide timing information for the view pipeline: + +.. code-block:: python + :linenos: + + import time + + def timing_view(view, info): + def wrapper_view(context, request): + start = time.time() + response = view(context, request) + end = time.time() + response.headers['X-View-Performance'] = '%.3f' % (end - start,) + return wrapper_view + + config.add_view_deriver('timing_view', timing_view) + +View derivers are unique in that they have access to most of the options +passed to :meth:`pyramid.config.Configurator.add_view` in order to decide what +to do and they have a chance to affect every view in the application. + +Let's look at one more example which will protect views by requiring a CSRF +token unless ``disable_csrf=True`` is passed to the view: + +.. code-block:: python + :linenos: + + from pyramid.session import check_csrf_token + + def require_csrf_view(view, info): + wrapper_view = view + if not info.options.get('disable_csrf', False): + def wrapper_view(context, request): + if request.method == 'POST': + check_csrf_token(request) + return view(context, request) + return wrapper_view + + require_csrf_view.options = ('disable_csrf',) + + config.add_view_deriver('require_csrf_view', require_csrf_view) + + def myview(request): + return 'protected' + + def my_unprotected_view(request): + return 'unprotected' + + config.add_view(myview, name='safe', renderer='string') + config.add_view(my_unprotected_, name='unsafe', disable_csrf=True, renderer='string') + +Navigating to ``/safe`` with a POST request will then fail when the call to +:func:`pyramid.session.check_csrf_token` raises a +:class:`pyramid.exceptions.BadCSRFToken` exception. However, ``/unsafe`` will +not error. + +Ordering View Derivers +~~~~~~~~~~~~~~~~~~~~~~ + +By default, every new view deriver is added between the ``decorated_view`` +and ``mapped_view`` built-in derivers. It is possible to customize this +ordering using the ``over`` and ``under`` options. Each option can use the +names of other view derivers in order to specify an ordering. There should +rarely be a reason to worry about the ordering of the derivers. + +It is not possible to add a deriver OVER the ``mapped_view`` as the +:term:`view mapper` is intimately tied to the signature of the user-defined +:term:`view callable`. If you simply need to know what the original view +callable was, it can be found as ``info.original_view`` on the provided +:class:`pyramid.interfaces.IViewDeriverInfo` object passed to every view +deriver. -- cgit v1.2.3 From 64bf7eec9b868fbc113341c7f5675c063aea002b Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Mon, 14 Mar 2016 22:35:19 -0500 Subject: use the implicit name in the doc examples --- docs/narr/hooks.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 13daed1fc..3f66f4988 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -1631,7 +1631,7 @@ is a callable that can provide timing information for the view pipeline: response.headers['X-View-Performance'] = '%.3f' % (end - start,) return wrapper_view - config.add_view_deriver('timing_view', timing_view) + config.add_view_deriver(timing_view) View derivers are unique in that they have access to most of the options passed to :meth:`pyramid.config.Configurator.add_view` in order to decide what @@ -1656,7 +1656,7 @@ token unless ``disable_csrf=True`` is passed to the view: require_csrf_view.options = ('disable_csrf',) - config.add_view_deriver('require_csrf_view', require_csrf_view) + config.add_view_deriver(require_csrf_view) def myview(request): return 'protected' -- cgit v1.2.3 From a0945399b24fb38607107a55b12b7997723de2a0 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Mon, 14 Mar 2016 23:25:10 -0500 Subject: do not guess at the name of the view deriver without further discussion --- docs/narr/hooks.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 3f66f4988..e3843cfbd 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -1631,7 +1631,7 @@ is a callable that can provide timing information for the view pipeline: response.headers['X-View-Performance'] = '%.3f' % (end - start,) return wrapper_view - config.add_view_deriver(timing_view) + config.add_view_deriver(timing_view, 'timing view') View derivers are unique in that they have access to most of the options passed to :meth:`pyramid.config.Configurator.add_view` in order to decide what @@ -1656,7 +1656,7 @@ token unless ``disable_csrf=True`` is passed to the view: require_csrf_view.options = ('disable_csrf',) - config.add_view_deriver(require_csrf_view) + config.add_view_deriver(require_csrf_view, 'require_csrf_view') def myview(request): return 'protected' -- cgit v1.2.3 From 35e632635b1b4e0a767024689d69d9469ae98c0f Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Mon, 14 Mar 2016 23:28:15 -0500 Subject: add a docstring for add_view_deriver and expose the method to the api docs --- docs/narr/hooks.rst | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index e3843cfbd..a5a03ef95 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -1580,6 +1580,10 @@ the user-defined :term:`view callable`: view pipeline interface to accept ``(context, request)`` from all previous view derivers. +``rendered_view`` + + Adapts the result of :term:`view callable` into a :term:`response` object. + ``decorated_view`` Wraps the view with the decorators from the ``decorator`` option. @@ -1615,8 +1619,10 @@ It is possible to define custom view derivers which will affect all views in an application. There are many uses for this but most will likely be centered around monitoring and security. In order to register a custom :term:`view deriver` you should create a callable that conforms to the -:class:`pyramid.interfaces.IViewDeriver` interface. For example, below -is a callable that can provide timing information for the view pipeline: +:class:`pyramid.interfaces.IViewDeriver` interface and then register it with +your application using :meth:`pyramid.config.Configurator.add_view_deriver`. +For example, below is a callable that can provide timing information for the +view pipeline: .. code-block:: python :linenos: @@ -1676,7 +1682,7 @@ Ordering View Derivers ~~~~~~~~~~~~~~~~~~~~~~ By default, every new view deriver is added between the ``decorated_view`` -and ``mapped_view`` built-in derivers. It is possible to customize this +and ``rendered_view`` built-in derivers. It is possible to customize this ordering using the ``over`` and ``under`` options. Each option can use the names of other view derivers in order to specify an ordering. There should rarely be a reason to worry about the ordering of the derivers. -- cgit v1.2.3 From a116948ffe14449ac6ef29145b62eb2976130d83 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Thu, 17 Mar 2016 01:24:21 -0500 Subject: fix deriver docs to explain ordering issues --- docs/narr/hooks.rst | 81 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 31 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index a5a03ef95..4a1233244 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -1556,6 +1556,8 @@ for a particular event type registration. View Derivers ------------- +.. versionadded:: 1.7 + Every URL processed by :app:`Pyramid` is matched against a custom view pipeline. See :ref:`router_chapter` for how this works. The view pipeline itself is built from the user-supplied :term:`view callable` which is then @@ -1565,28 +1567,33 @@ added functionality. View derivers are very similar to the ``decorator`` argument to :meth:`pyramid.config.Configurator.add_view` except that they have the option to execute for every view in the application. +It is helpful to think of a :term:`view deriver` as middleware for views. +Unlike tweens or WSGI middleware which are scoped to the application itself, +a view deriver is invoked once per view in the application and can use +configuration options from the view to customize its behavior. + Built-in View Derivers ~~~~~~~~~~~~~~~~~~~~~~ There are several builtin view derivers that :app:`Pyramid` will automatically -apply to any view. They are defined in order from closest to furthest from +apply to any view. Below they are defined in order from furthest to closest to the user-defined :term:`view callable`: -``mapped_view`` +``authdebug_view`` - Applies the :term:`view mapper` defined by the ``mapper`` option or the - application's default view mapper to the :term:`view callable`. This - is always the closest deriver to the user-defined view and standardizes the - view pipeline interface to accept ``(context, request)`` from all previous - view derivers. + Used to output useful debugging information when + ``pyramid.debug_authorization`` is enabled. This element is a noop otherwise. -``rendered_view`` +``secured_view`` - Adapts the result of :term:`view callable` into a :term:`response` object. + Enforce the ``permission`` defined on the view. This element is a noop if + no permission is defined. Note there will always be a permission defined + if a default permission was assigned via + :meth:`pyramid.config.Configurator.set_default_permission`. -``decorated_view`` +``owrapped_view`` - Wraps the view with the decorators from the ``decorator`` option. + Invokes the wrapped view defined by the ``wrapper`` option. ``http_cached_view`` @@ -1594,27 +1601,26 @@ the user-defined :term:`view callable`: option. This element is a noop if the ``pyramid.prevent_http_cache`` setting is enabled or the ``http_cache`` option is ``None``. -``owrapped_view`` +``decorated_view`` - Invokes the wrapped view defined by the ``wrapper`` option. + Wraps the view with the decorators from the ``decorator`` option. -``secured_view`` +``rendered_view`` - Enforce the ``permission`` defined on the view. This element is a noop if - no permission is defined. Note there will always be a permission defined - if a default permission was assigned via - :meth:`pyramid.config.Configurator.set_default_permission`. + Adapts the result of the :term:`view callable` into a :term:`response` + object. Below this point the result may be any Python object. -``authdebug_view`` +``mapped_view`` - Used to output useful debugging information when - ``pyramid.debug_authorization`` is enabled. This element is a noop otherwise. + Applies the :term:`view mapper` defined by the ``mapper`` option or the + application's default view mapper to the :term:`view callable`. This + is always the closest deriver to the user-defined view and standardizes the + view pipeline interface to accept ``(context, request)`` from all previous + view derivers. Custom View Derivers ~~~~~~~~~~~~~~~~~~~~ -.. versionadded:: 1.7 - It is possible to define custom view derivers which will affect all views in an application. There are many uses for this but most will likely be centered around monitoring and security. In order to register a custom @@ -1649,6 +1655,7 @@ token unless ``disable_csrf=True`` is passed to the view: .. code-block:: python :linenos: + from pyramid.response import Response from pyramid.session import check_csrf_token def require_csrf_view(view, info): @@ -1664,14 +1671,14 @@ token unless ``disable_csrf=True`` is passed to the view: config.add_view_deriver(require_csrf_view, 'require_csrf_view') - def myview(request): - return 'protected' + def protected_view(request): + return Response('protected') - def my_unprotected_view(request): - return 'unprotected' + def unprotected_view(request): + return Response('unprotected') - config.add_view(myview, name='safe', renderer='string') - config.add_view(my_unprotected_, name='unsafe', disable_csrf=True, renderer='string') + config.add_view(protected_view, name='safe') + config.add_view(unprotected_view, name='unsafe', disable_csrf=True) Navigating to ``/safe`` with a POST request will then fail when the call to :func:`pyramid.session.check_csrf_token` raises a @@ -1685,11 +1692,23 @@ By default, every new view deriver is added between the ``decorated_view`` and ``rendered_view`` built-in derivers. It is possible to customize this ordering using the ``over`` and ``under`` options. Each option can use the names of other view derivers in order to specify an ordering. There should -rarely be a reason to worry about the ordering of the derivers. +rarely be a reason to worry about the ordering of the derivers. Both ``over`` +and ``under`` may also be iterables of constraints. For either option, if one +or more constraints was defined, at least one must be satisfied or a +:class:`pyramid.exceptions.ConfigurationError` will be raised. This may be +used to define fallback constraints if another deriver is missing. -It is not possible to add a deriver OVER the ``mapped_view`` as the +It is not possible to add a view deriver under the ``mapped_view`` as the :term:`view mapper` is intimately tied to the signature of the user-defined :term:`view callable`. If you simply need to know what the original view callable was, it can be found as ``info.original_view`` on the provided :class:`pyramid.interfaces.IViewDeriverInfo` object passed to every view deriver. + +.. warning:: + + Any view derivers defined ``under`` the ``rendered_view`` are not + guaranteed to receive a valid response object. Rather they will receive the + result from the :term:`view mapper` which is likely the original response + returned from the view. This is possibly a dictionary for a renderer but it + may be any Python object that may be adapted into a response. -- cgit v1.2.3 From 6fb44f451abb657716ae0066ed70af66060ef3b8 Mon Sep 17 00:00:00 2001 From: Steve Piercy Date: Mon, 21 Mar 2016 04:32:21 -0700 Subject: polish view derivers docs, minor grammar --- docs/narr/hooks.rst | 51 +++++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 24 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 4a1233244..a32e94d1a 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -1548,6 +1548,7 @@ predicate author to make every predicate make sense for every event type; it is the responsibility of the predicate consumer to use predicates that make sense for a particular event type registration. + .. index:: single: view derivers @@ -1560,35 +1561,36 @@ View Derivers Every URL processed by :app:`Pyramid` is matched against a custom view pipeline. See :ref:`router_chapter` for how this works. The view pipeline -itself is built from the user-supplied :term:`view callable` which is then +itself is built from the user-supplied :term:`view callable`, which is then composed with :term:`view derivers `. A view deriver is a composable element of the view pipeline which is used to wrap a view with added functionality. View derivers are very similar to the ``decorator`` -argument to :meth:`pyramid.config.Configurator.add_view` except that they have +argument to :meth:`pyramid.config.Configurator.add_view`, except that they have the option to execute for every view in the application. It is helpful to think of a :term:`view deriver` as middleware for views. Unlike tweens or WSGI middleware which are scoped to the application itself, -a view deriver is invoked once per view in the application and can use +a view deriver is invoked once per view in the application, and can use configuration options from the view to customize its behavior. Built-in View Derivers ~~~~~~~~~~~~~~~~~~~~~~ -There are several builtin view derivers that :app:`Pyramid` will automatically +There are several built-in view derivers that :app:`Pyramid` will automatically apply to any view. Below they are defined in order from furthest to closest to the user-defined :term:`view callable`: ``authdebug_view`` Used to output useful debugging information when - ``pyramid.debug_authorization`` is enabled. This element is a noop otherwise. + ``pyramid.debug_authorization`` is enabled. This element is a no-op + otherwise. ``secured_view`` - Enforce the ``permission`` defined on the view. This element is a noop if - no permission is defined. Note there will always be a permission defined - if a default permission was assigned via + Enforce the ``permission`` defined on the view. This element is a no-op if no + permission is defined. Note there will always be a permission defined if a + default permission was assigned via :meth:`pyramid.config.Configurator.set_default_permission`. ``owrapped_view`` @@ -1598,7 +1600,7 @@ the user-defined :term:`view callable`: ``http_cached_view`` Applies cache control headers to the response defined by the ``http_cache`` - option. This element is a noop if the ``pyramid.prevent_http_cache`` setting + option. This element is a no-op if the ``pyramid.prevent_http_cache`` setting is enabled or the ``http_cache`` option is ``None``. ``decorated_view`` @@ -1621,11 +1623,11 @@ the user-defined :term:`view callable`: Custom View Derivers ~~~~~~~~~~~~~~~~~~~~ -It is possible to define custom view derivers which will affect all views in -an application. There are many uses for this but most will likely be centered -around monitoring and security. In order to register a custom -:term:`view deriver` you should create a callable that conforms to the -:class:`pyramid.interfaces.IViewDeriver` interface and then register it with +It is possible to define custom view derivers which will affect all views in an +application. There are many uses for this, but most will likely be centered +around monitoring and security. In order to register a custom :term:`view +deriver`, you should create a callable that conforms to the +:class:`pyramid.interfaces.IViewDeriver` interface, and then register it with your application using :meth:`pyramid.config.Configurator.add_view_deriver`. For example, below is a callable that can provide timing information for the view pipeline: @@ -1647,7 +1649,7 @@ view pipeline: View derivers are unique in that they have access to most of the options passed to :meth:`pyramid.config.Configurator.add_view` in order to decide what -to do and they have a chance to affect every view in the application. +to do, and they have a chance to affect every view in the application. Let's look at one more example which will protect views by requiring a CSRF token unless ``disable_csrf=True`` is passed to the view: @@ -1688,15 +1690,16 @@ not error. Ordering View Derivers ~~~~~~~~~~~~~~~~~~~~~~ -By default, every new view deriver is added between the ``decorated_view`` -and ``rendered_view`` built-in derivers. It is possible to customize this -ordering using the ``over`` and ``under`` options. Each option can use the -names of other view derivers in order to specify an ordering. There should -rarely be a reason to worry about the ordering of the derivers. Both ``over`` -and ``under`` may also be iterables of constraints. For either option, if one -or more constraints was defined, at least one must be satisfied or a -:class:`pyramid.exceptions.ConfigurationError` will be raised. This may be -used to define fallback constraints if another deriver is missing. +By default, every new view deriver is added between the ``decorated_view`` and +``rendered_view`` built-in derivers. It is possible to customize this ordering +using the ``over`` and ``under`` options. Each option can use the names of +other view derivers in order to specify an ordering. There should rarely be a +reason to worry about the ordering of the derivers. + +Both ``over`` and ``under`` may also be iterables of constraints. For either +option, if one or more constraints was defined, at least one must be satisfied, +else a :class:`pyramid.exceptions.ConfigurationError` will be raised. This may +be used to define fallback constraints if another deriver is missing. It is not possible to add a view deriver under the ``mapped_view`` as the :term:`view mapper` is intimately tied to the signature of the user-defined -- cgit v1.2.3 From a3db3cab713fecc0c83c742cfe3f0736b1d94a92 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Thu, 7 Apr 2016 01:16:45 -0500 Subject: separate the viewderiver module and allow overriding the mapper --- docs/narr/hooks.rst | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index a32e94d1a..3a1ad8363 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -1580,12 +1580,6 @@ There are several built-in view derivers that :app:`Pyramid` will automatically apply to any view. Below they are defined in order from furthest to closest to the user-defined :term:`view callable`: -``authdebug_view`` - - Used to output useful debugging information when - ``pyramid.debug_authorization`` is enabled. This element is a no-op - otherwise. - ``secured_view`` Enforce the ``permission`` defined on the view. This element is a no-op if no @@ -1593,6 +1587,9 @@ the user-defined :term:`view callable`: default permission was assigned via :meth:`pyramid.config.Configurator.set_default_permission`. + This element will also output useful debugging information when + ``pyramid.debug_authorization`` is enabled. + ``owrapped_view`` Invokes the wrapped view defined by the ``wrapper`` option. -- cgit v1.2.3 From c231d8174e811eec5a3faeafa5aee60757c6d31f Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Fri, 8 Apr 2016 00:47:01 -0500 Subject: update constraints for derivers as well as docs --- docs/narr/hooks.rst | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 3a1ad8363..2c3782387 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -1617,6 +1617,14 @@ the user-defined :term:`view callable`: view pipeline interface to accept ``(context, request)`` from all previous view derivers. +.. warning:: + + Any view derivers defined ``under`` the ``rendered_view`` are not + guaranteed to receive a valid response object. Rather they will receive the + result from the :term:`view mapper` which is likely the original response + returned from the view. This is possibly a dictionary for a renderer but it + may be any Python object that may be adapted into a response. + Custom View Derivers ~~~~~~~~~~~~~~~~~~~~ @@ -1642,7 +1650,7 @@ view pipeline: response.headers['X-View-Performance'] = '%.3f' % (end - start,) return wrapper_view - config.add_view_deriver(timing_view, 'timing view') + config.add_view_deriver(timing_view) View derivers are unique in that they have access to most of the options passed to :meth:`pyramid.config.Configurator.add_view` in order to decide what @@ -1668,7 +1676,7 @@ token unless ``disable_csrf=True`` is passed to the view: require_csrf_view.options = ('disable_csrf',) - config.add_view_deriver(require_csrf_view, 'require_csrf_view') + config.add_view_deriver(require_csrf_view) def protected_view(request): return Response('protected') @@ -1691,13 +1699,19 @@ By default, every new view deriver is added between the ``decorated_view`` and ``rendered_view`` built-in derivers. It is possible to customize this ordering using the ``over`` and ``under`` options. Each option can use the names of other view derivers in order to specify an ordering. There should rarely be a -reason to worry about the ordering of the derivers. +reason to worry about the ordering of the derivers except when the deriver +depends on other operations in the view pipeline. Both ``over`` and ``under`` may also be iterables of constraints. For either option, if one or more constraints was defined, at least one must be satisfied, else a :class:`pyramid.exceptions.ConfigurationError` will be raised. This may be used to define fallback constraints if another deriver is missing. +Two sentinel values exist, :attr:`pyramid.viewderivers.INGRESS` and +:attr:`pyramid.viewderivers.VIEW`, which may be used when specifying +constraints at the edges of the view pipeline. For example, to add a deriver +at the start of the pipeline you may use ``under=INGRESS``. + It is not possible to add a view deriver under the ``mapped_view`` as the :term:`view mapper` is intimately tied to the signature of the user-defined :term:`view callable`. If you simply need to know what the original view @@ -1707,8 +1721,12 @@ deriver. .. warning:: - Any view derivers defined ``under`` the ``rendered_view`` are not - guaranteed to receive a valid response object. Rather they will receive the - result from the :term:`view mapper` which is likely the original response - returned from the view. This is possibly a dictionary for a renderer but it - may be any Python object that may be adapted into a response. + The default constraints for any view deriver are ``over='rendered_view'`` + and ``under='decorated_view'``. When escaping these constraints you must + take care to avoid cyclic dependencies between derivers. For example, if + you want to add a new view deriver before ``secured_view`` then + simply specifying ``over='secured_view'`` is not enough, because the + default is also under ``decorated view`` there will be an unsatisfiable + cycle. You must specify a valid ``under`` constraint as well, such as + ``under=INGRESS`` to fall between INGRESS and ``secured_view`` at the + beginning of the view pipeline. -- cgit v1.2.3 From 9e9fa9ac40bdd79fbce69f94a13d705e40f3d458 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Tue, 22 Mar 2016 01:02:05 -0500 Subject: add a csrf_view to the view pipeline supporting a require_csrf option --- docs/narr/hooks.rst | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 2c3782387..e7db97565 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -1580,6 +1580,11 @@ There are several built-in view derivers that :app:`Pyramid` will automatically apply to any view. Below they are defined in order from furthest to closest to the user-defined :term:`view callable`: +``csrf_view`` + + Used to check the CSRF token provided in the request. This element is a + no-op if ``require_csrf`` is not defined. + ``secured_view`` Enforce the ``permission`` defined on the view. This element is a no-op if no @@ -1656,27 +1661,32 @@ View derivers are unique in that they have access to most of the options passed to :meth:`pyramid.config.Configurator.add_view` in order to decide what to do, and they have a chance to affect every view in the application. -Let's look at one more example which will protect views by requiring a CSRF -token unless ``disable_csrf=True`` is passed to the view: +Let's override the default CSRF checker to default to on instead of off and +only check ``POST`` requests: .. code-block:: python :linenos: from pyramid.response import Response from pyramid.session import check_csrf_token + from pyramid.viewderivers import INGRESS - def require_csrf_view(view, info): + def csrf_view(view, info): + val = info.options.get('require_csrf', True) wrapper_view = view - if not info.options.get('disable_csrf', False): - def wrapper_view(context, request): + if val: + if val is True: + val = 'csrf_token' + def csrf_view(context, request): if request.method == 'POST': - check_csrf_token(request) + check_csrf_token(request, val, raises=True) return view(context, request) + wrapper_view = csrf_view return wrapper_view - require_csrf_view.options = ('disable_csrf',) + csrf_view.options = ('require_csrf',) - config.add_view_deriver(require_csrf_view) + config.add_view_deriver(csrf_view, 'csrf_view', over='secured_view', under=INGRESS) def protected_view(request): return Response('protected') @@ -1685,7 +1695,7 @@ token unless ``disable_csrf=True`` is passed to the view: return Response('unprotected') config.add_view(protected_view, name='safe') - config.add_view(unprotected_view, name='unsafe', disable_csrf=True) + config.add_view(unprotected_view, name='unsafe', require_csrf=False) Navigating to ``/safe`` with a POST request will then fail when the call to :func:`pyramid.session.check_csrf_token` raises a -- cgit v1.2.3 From 6b35eb6ca3b271e2943d37307c925c5733e082d9 Mon Sep 17 00:00:00 2001 From: Michael Merickel Date: Sun, 10 Apr 2016 20:50:10 -0500 Subject: rewrite csrf checks to support a global setting to turn it on - only check csrf on POST - support "pyramid.require_default_csrf" setting - support "require_csrf=True" to fallback to the global setting to determine the token name --- docs/narr/hooks.rst | 52 ++++++---------------------------------------------- 1 file changed, 6 insertions(+), 46 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index e7db97565..28d1e09d5 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -1580,11 +1580,6 @@ There are several built-in view derivers that :app:`Pyramid` will automatically apply to any view. Below they are defined in order from furthest to closest to the user-defined :term:`view callable`: -``csrf_view`` - - Used to check the CSRF token provided in the request. This element is a - no-op if ``require_csrf`` is not defined. - ``secured_view`` Enforce the ``permission`` defined on the view. This element is a no-op if no @@ -1595,6 +1590,12 @@ the user-defined :term:`view callable`: This element will also output useful debugging information when ``pyramid.debug_authorization`` is enabled. +``csrf_view`` + + Used to check the CSRF token provided in the request. This element is a + no-op if both the ``require_csrf`` view option and the + ``pyramid.require_default_csrf`` setting are disabled. + ``owrapped_view`` Invokes the wrapped view defined by the ``wrapper`` option. @@ -1661,47 +1662,6 @@ View derivers are unique in that they have access to most of the options passed to :meth:`pyramid.config.Configurator.add_view` in order to decide what to do, and they have a chance to affect every view in the application. -Let's override the default CSRF checker to default to on instead of off and -only check ``POST`` requests: - -.. code-block:: python - :linenos: - - from pyramid.response import Response - from pyramid.session import check_csrf_token - from pyramid.viewderivers import INGRESS - - def csrf_view(view, info): - val = info.options.get('require_csrf', True) - wrapper_view = view - if val: - if val is True: - val = 'csrf_token' - def csrf_view(context, request): - if request.method == 'POST': - check_csrf_token(request, val, raises=True) - return view(context, request) - wrapper_view = csrf_view - return wrapper_view - - csrf_view.options = ('require_csrf',) - - config.add_view_deriver(csrf_view, 'csrf_view', over='secured_view', under=INGRESS) - - def protected_view(request): - return Response('protected') - - def unprotected_view(request): - return Response('unprotected') - - config.add_view(protected_view, name='safe') - config.add_view(unprotected_view, name='unsafe', require_csrf=False) - -Navigating to ``/safe`` with a POST request will then fail when the call to -:func:`pyramid.session.check_csrf_token` raises a -:class:`pyramid.exceptions.BadCSRFToken` exception. However, ``/unsafe`` will -not error. - Ordering View Derivers ~~~~~~~~~~~~~~~~~~~~~~ -- cgit v1.2.3 From 16f98991ba067313c018bf8b127dc4ca1a74f5d0 Mon Sep 17 00:00:00 2001 From: Chris McDonough Date: Sun, 17 Apr 2016 16:09:47 -0400 Subject: better explain view deriver options --- docs/narr/hooks.rst | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) (limited to 'docs/narr/hooks.rst') diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index 28d1e09d5..b776f99e8 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -1649,15 +1649,43 @@ view pipeline: import time def timing_view(view, info): - def wrapper_view(context, request): - start = time.time() - response = view(context, request) - end = time.time() - response.headers['X-View-Performance'] = '%.3f' % (end - start,) - return wrapper_view + if info.options.get('timed'): + def wrapper_view(context, request): + start = time.time() + response = view(context, request) + end = time.time() + response.headers['X-View-Performance'] = '%.3f' % (end - start,) + return response + return wrapper_view + return view + + timing_view.options = ('timed',) config.add_view_deriver(timing_view) +The setting of ``timed`` on the timing_view signifies to Pyramid that ``timed`` +is a valid ``view_config`` keyword argument now. The ``timing_view`` custom +view deriver as registered above will only be active for any view defined with +a ``timed=True`` value passed as one of its ``view_config`` keywords. + +For example, this view configuration will *not* be a timed view: + +.. code-block:: python + :linenos: + + @view_config(route_name='home') + def home(request): + return Response('Home') + +But this view *will* have timing information added to the response headers: + +.. code-block:: python + :linenos: + + @view_config(route_name='home', timed=True) + def home(request): + return Response('Home') + View derivers are unique in that they have access to most of the options passed to :meth:`pyramid.config.Configurator.add_view` in order to decide what to do, and they have a chance to affect every view in the application. -- cgit v1.2.3