summaryrefslogtreecommitdiff
path: root/docs/narr/hooks.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/narr/hooks.rst')
-rw-r--r--docs/narr/hooks.rst230
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.
+
+
+