diff options
Diffstat (limited to 'docs/narr/hooks.rst')
| -rw-r--r-- | docs/narr/hooks.rst | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst index a2143b3c5..96fa77a07 100644 --- a/docs/narr/hooks.rst +++ b/docs/narr/hooks.rst @@ -289,6 +289,36 @@ 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. + +Suppose you return ``{'mykey': 'somevalue', 'mykey2': 'somevalue2'}`` from +your view callable, like so: + +.. code-block:: python + :linenos: + + from pyramid.view import view_config + + @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`. @@ -1202,3 +1232,203 @@ 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, Route, or Subscriber Predicate +--------------------------------------------------------- + +.. note:: + + Third-party view, route, and subscriber predicates are a feature new as of + Pyramid 1.4. + +.. _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 + + @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 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: + + class ContentTypePredicate(object): + def __init__(self, val, config): + self.val = 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. + +.. _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. + + + |
