Chris McDonough
2010-06-30 44bc118a61e2e9d93a65b8edd5be9118fb478741
- 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,))


3 files modified
42 ■■■■■ changed files
CHANGES.txt 27 ●●●●● patch | view | raw | blame | history
repoze/bfg/tests/test_urldispatch.py 10 ●●●●● patch | view | raw | blame | history
repoze/bfg/urldispatch.py 5 ●●●●● patch | view | raw | blame | history
CHANGES.txt
@@ -8,6 +8,33 @@
  ``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
-------------
repoze/bfg/tests/test_urldispatch.py
@@ -108,6 +108,16 @@
        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/
repoze/bfg/urldispatch.py
@@ -51,9 +51,10 @@
            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}