summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2010-06-30 18:44:09 +0000
committerChris McDonough <chrism@agendaless.com>2010-06-30 18:44:09 +0000
commitd61024a2a7f625dd61b5face58f4190c9e233718 (patch)
tree5d197693b8d9440c4b5c69f689064ee1219e1fc7
parent1a47ed8a6f2c552062b228c362edbea511e26dd6 (diff)
downloadpyramid-d61024a2a7f625dd61b5face58f4190c9e233718.tar.gz
pyramid-d61024a2a7f625dd61b5face58f4190c9e233718.tar.bz2
pyramid-d61024a2a7f625dd61b5face58f4190c9e233718.zip
- A section named ``Custom Predicates`` was added to the URL Dispatch
narrative chapter.
-rw-r--r--CHANGES.txt3
-rw-r--r--docs/narr/urldispatch.rst100
-rw-r--r--repoze/bfg/urldispatch.py3
3 files changed, 102 insertions, 4 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 1c631591a..0780e94d3 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -65,6 +65,9 @@ Documentation
http://docs.repoze.org/bfgwiki-1.3 and
http://docs.repoze.org/bfgwiki2-1.3/ respectively.
+- A section named ``Custom Predicates`` was added to the URL Dispatch
+ narrative chapter.
+
1.3a3 (2010-05-01)
==================
diff --git a/docs/narr/urldispatch.rst b/docs/narr/urldispatch.rst
index 571388929..68cbaeb29 100644
--- a/docs/narr/urldispatch.rst
+++ b/docs/narr/urldispatch.rst
@@ -571,6 +571,105 @@ represent neither predicates nor view configuration information.
try to fall back to using a view that otherwise matches the context,
request, and view name (but does not match the route name predicate).
+Custom Predicates
+~~~~~~~~~~~~~~~~~
+
+Each of the predicate callables fed to the ``custom_predicates``
+argument of :meth:`repoze.bfg.configuration.Configurator.add_route` or
+the ``custom_predicates`` ZCML attribute must be a callable accepting
+two arguments. The first argument passed to a custom predicate is a
+dictionary conventionally named ``info`. The second argument is the
+current :term:`request` object.
+
+The ``info`` dictionary has a number of contained values: ``match`` is
+a dictionary: it represents the arguments matched in the URL by the
+route. ``route`` is an object representing the route which was
+matched.
+
+``info['match']`` is useful when predicates need access to the route
+match. For example:
+
+.. code-block:: python
+
+ def any_of(segment_name, *allowed):
+ def predicate(info, request):
+ if info['match'][segment_name] in allowed:
+ return True
+ return predicate
+
+ num_one_two_or_three = any_of('num, 'one', 'two', 'three')
+
+ config.add_route('num', '/:num',
+ custom_predicates=(num_one_two_or_three,))
+
+The above ``any_of`` function generates a predicate which ensures that
+the match value named ``segment_name`` is in the set of allowable
+values represented by ``allowed``. We use this ``any_of`` function to
+generate a predicate function named ``num_one_two_or_three``, which
+ensures that the ``num`` segment is one of the values ``one``,
+``two``, or ``three`` , and use the result as a custom predicate by
+feeding it inside a tuple to the ``custom_predicates`` argument to
+:meth:`repoze.configuration.Configurator.add_route`.
+
+A custom route predicate may also *modify* the ``match`` dictionary.
+For instance, a predicate might do some type conversion of values:
+
+.. code-block:: python
+
+ def integers(*segment_names):
+ def predicate(info, request):
+ match = info['match']
+ for segment_name in segment_names:
+ try:
+ match[segment_name] = int(match[segment_name])
+ except (TypeError, ValueError):
+ pass
+ return predicate
+
+ ymd_to_int = integers('year', 'month', 'day')
+
+ config.add_route('num', '/:year/:month/:day',
+ custom_predicates=(ymd_to_int,))
+
+The ``match`` dictionary passed within ``info`` to each predicate
+attached to a route will be the same dictionary. Therefore, when
+registering a custom predicate which modifies the ``match`` dict, the
+code registering the predicate should usually arrange for the
+predicate to be the *last* custom predicate in the custom predicate
+list. Otherwise, custom predicates which fire subsequent to the
+predicate which performs the ``match`` modification will receive the
+*modified* match dictionary.
+
+.. warning::
+
+ It is a poor idea to rely on ordering of custom predicates to build
+ some conversion pipeline, where one predicate depends on the side
+ effect of another. For instance, it's a poor idea to register two
+ custom predicates, one which handles conversion of a value to an
+ int, the next which handles conversion of that integer to some
+ custom object. Just do all that in a single custom predicate.
+
+The ``route`` object in the ``info`` dict is an object that has two
+useful attributes: ``name`` and ``path``. The ``name`` attribute is
+the route name. The ``path`` attribute is the route pattern. An
+example of using the route in a set of route predicates:
+
+.. code-block:: python
+ :linenos:
+
+ def twenty_ten(info, request):
+ if info['route'].name in ('ymd', 'ym', 'y'):
+ return info['match']['year'] == '2010'
+
+ config.add_route('y', '/:year', custom_predicates=(twenty_ten,))
+ config.add_route('ym', '/:year/:month', custom_predicates=(twenty_ten,))
+ config.add_route('ymd', '/:year/:month:/day',
+ custom_predicates=(twenty_ten,))
+
+The above predicate, when added to a number of route configurations
+ensures that the year match argument is '2010' if and only if the
+route name is 'ymd', 'ym', or 'y'.
+
Route Matching
--------------
@@ -606,7 +705,6 @@ If no route matches after all route patterns are exhausted,
:mod:`repoze.bfg` falls back to :term:`traversal` to do :term:`context
finding` and :term:`view lookup`.
-
.. index::
single: matchdict
diff --git a/repoze/bfg/urldispatch.py b/repoze/bfg/urldispatch.py
index 51b6f9f84..7a77fec5b 100644
--- a/repoze/bfg/urldispatch.py
+++ b/repoze/bfg/urldispatch.py
@@ -51,9 +51,6 @@ class RoutesMapper(object):
match = route.match(path)
if match is not None:
preds = route.predicates
- # NB: it is the intent that only 'match' be relied on
- # by built-in predicates. 'route' and 'mapper' may be
- # used by custom predicates.
info = {'match':match, 'route':route}
if preds and not all((p(info, request) for p in preds)):
continue