summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.txt27
-rw-r--r--repoze/bfg/tests/test_urldispatch.py10
-rw-r--r--repoze/bfg/urldispatch.py5
3 files changed, 40 insertions, 2 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 65690e73e..8eb1b57c7 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -8,6 +8,33 @@ Features
``repoze.bfg.paster.BFGShellCommand`` hookable in cases where
endware may interfere with the default versions.
+- In earlier versions, a custom route predicate associated with a url
+ dispatch route (each of the predicate functions fed to the
+ ``custom_predicates`` argument of
+ ``repoze.bfg.configuration.Configurator.add_route``) has always
+ required a 2-positional argument signature, e.g. ``(context,
+ request)``. Before this release, the ``context`` argument was
+ always ``None``.
+
+ As of this release, the first argument passed to a predicate is now
+ a dictionary conventionally named ``info`` consisting of ``match``,
+ ``route``, and ``mapper``. ``match`` is a dictionary: it represents
+ the arguments matched in the URL by the route. ``route`` is an
+ object representing the route that matched. ``mapper`` is the url
+ dispatch route mapper object.
+
+ This is useful when predicates need access to the route match. For
+ example::
+
+ def any_of(segment_name, *args):
+ def predicate(info, request):
+ if info['match'][segment_name] in args:
+ return True
+
+ num_one_two_or_three = any_of('num, 'one', 'two', 'three')
+
+ add_route('/:num', custom_predicates=(num_one_two_or_three,))
+
Documentation
-------------
diff --git a/repoze/bfg/tests/test_urldispatch.py b/repoze/bfg/tests/test_urldispatch.py
index c1fa66aa7..69bd3d971 100644
--- a/repoze/bfg/tests/test_urldispatch.py
+++ b/repoze/bfg/tests/test_urldispatch.py
@@ -108,6 +108,16 @@ class RoutesMapperTests(unittest.TestCase):
self.assertEqual(result['match']['action'], 'action1')
self.assertEqual(result['match']['article'], 'article1')
+ def test_custom_predicate_gets_info(self):
+ mapper = self._makeOne()
+ def pred(info, request):
+ self.assertEqual(info['match'], {'action':u'action1'})
+ self.assertEqual(info['route'], mapper.routes['foo'])
+ return True
+ mapper.connect('archives/:action/article1', 'foo', predicates=[pred])
+ request = self._getRequest(PATH_INFO='/archives/action1/article1')
+ mapper(request)
+
def test_cc_bug(self):
# "unordered" as reported in IRC by author of
# http://labs.creativecommons.org/2010/01/13/cc-engine-and-web-non-frameworks/
diff --git a/repoze/bfg/urldispatch.py b/repoze/bfg/urldispatch.py
index becde3ea2..458f1a7a5 100644
--- a/repoze/bfg/urldispatch.py
+++ b/repoze/bfg/urldispatch.py
@@ -51,9 +51,10 @@ class RoutesMapper(object):
match = route.match(path)
if match is not None:
preds = route.predicates
- if preds and not all((p(None, request) for p in preds)):
+ info = {'route':route, 'match':match}
+ if preds and not all((p(info, request) for p in preds)):
continue
- return {'route':route, 'match':match}
+ return info
return {'route':None, 'match':None}