summaryrefslogtreecommitdiff
path: root/repoze
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2009-11-01 00:48:04 +0000
committerChris McDonough <chrism@agendaless.com>2009-11-01 00:48:04 +0000
commit65476e8d2cef6b3ce105c4786645a88151a09a6c (patch)
tree40d0c77df2fa1ba54c6bdb9df7effcc7a70049a9 /repoze
parent3052d0b41bd06314b0b1f1c78e9977b8174f637a (diff)
downloadpyramid-65476e8d2cef6b3ce105c4786645a88151a09a6c.tar.gz
pyramid-65476e8d2cef6b3ce105c4786645a88151a09a6c.tar.bz2
pyramid-65476e8d2cef6b3ce105c4786645a88151a09a6c.zip
- The ZCML ``route`` directive's attributes ``xhr``,
``request_method``, ``path_info``, ``request_param``, ``header`` and ``accept`` are now *route* predicates rather than *view* predicates. If one or more of these predicates is specified in the route configuration, all of the predicates must return true for the route to match a request. If one or more of the route predicates associated with a route returns ``False`` when checked during a request, the route match fails, and the next match in the routelist is tried. This differs from the previous behavior, where no route predicates existed and all predicates were considered view predicates, because in that scenario, the next route was not tried.
Diffstat (limited to 'repoze')
-rw-r--r--repoze/bfg/tests/test_urldispatch.py39
-rw-r--r--repoze/bfg/tests/test_zcml.py317
-rw-r--r--repoze/bfg/urldispatch.py13
-rw-r--r--repoze/bfg/zcml.py110
4 files changed, 303 insertions, 176 deletions
diff --git a/repoze/bfg/tests/test_urldispatch.py b/repoze/bfg/tests/test_urldispatch.py
index 99d5d1a98..c7dfdf196 100644
--- a/repoze/bfg/tests/test_urldispatch.py
+++ b/repoze/bfg/tests/test_urldispatch.py
@@ -105,6 +105,45 @@ class RoutesRootFactoryTests(unittest.TestCase):
self.assertEqual(request.matchdict, routing_args)
self.failUnless(req_iface.providedBy(request))
+ def test_route_matches_with_predicates(self):
+ root_factory = DummyRootFactory(123)
+ req_iface = self._registerRouteRequest('foo')
+ mapper = self._makeOne(root_factory)
+ mapper.connect('archives/:action/:article', 'foo',
+ predicates=[lambda *arg: True])
+ request = self._getRequest(PATH_INFO='/archives/action1/article1')
+ result = mapper(request)
+ self.assertEqual(result, 123)
+ environ = request.environ
+ routing_args = environ['wsgiorg.routing_args'][1]
+ self.assertEqual(routing_args['action'], 'action1')
+ self.assertEqual(routing_args['article'], 'article1')
+ self.assertEqual(environ['bfg.routes.matchdict'], routing_args)
+ self.assertEqual(environ['bfg.routes.route'].name, 'foo')
+ self.assertEqual(request.matchdict, routing_args)
+ self.failUnless(req_iface.providedBy(request))
+
+ def test_route_fails_to_match_with_predicates(self):
+ root_factory = DummyRootFactory(123)
+ foo_iface = self._registerRouteRequest('foo')
+ bar_iface = self._registerRouteRequest('bar')
+ mapper = self._makeOne(root_factory)
+ mapper.connect('archives/:action/article1', 'foo',
+ predicates=[lambda *arg: True, lambda *arg: False])
+ mapper.connect('archives/:action/:article', 'bar')
+ request = self._getRequest(PATH_INFO='/archives/action1/article1')
+ result = mapper(request)
+ self.assertEqual(result, 123)
+ environ = request.environ
+ routing_args = environ['wsgiorg.routing_args'][1]
+ self.assertEqual(routing_args['action'], 'action1')
+ self.assertEqual(routing_args['article'], 'article1')
+ self.assertEqual(environ['bfg.routes.matchdict'], routing_args)
+ self.assertEqual(environ['bfg.routes.route'].name, 'bar')
+ self.assertEqual(request.matchdict, routing_args)
+ self.failUnless(bar_iface.providedBy(request))
+ self.failIf(foo_iface.providedBy(request))
+
def test_root_route_matches(self):
root_factory = DummyRootFactory(123)
req_iface = self._registerRouteRequest('root')
diff --git a/repoze/bfg/tests/test_zcml.py b/repoze/bfg/tests/test_zcml.py
index 8106baa03..d534559f6 100644
--- a/repoze/bfg/tests/test_zcml.py
+++ b/repoze/bfg/tests/test_zcml.py
@@ -1542,9 +1542,9 @@ class TestConnectRouteFunction(unittest.TestCase):
def tearDown(self):
cleanUp()
- def _callFUT(self, path, name, factory):
+ def _callFUT(self, path, name, factory, predicates):
from repoze.bfg.zcml import connect_route
- return connect_route(path, name, factory)
+ return connect_route(path, name, factory, predicates)
def _registerRoutesMapper(self):
from zope.component import getSiteManager
@@ -1556,8 +1556,9 @@ class TestConnectRouteFunction(unittest.TestCase):
def test_defaults(self):
mapper = self._registerRoutesMapper()
- self._callFUT('path', 'name', 'factory')
- self.assertEqual(mapper.connections, [('path', 'name', 'factory')])
+ self._callFUT('path', 'name', 'factory', 'predicates')
+ self.assertEqual(mapper.connections, [('path', 'name', 'factory',
+ 'predicates')])
class TestRouteDirective(unittest.TestCase):
def setUp(self):
@@ -1582,10 +1583,12 @@ class TestRouteDirective(unittest.TestCase):
route_discriminator = route_action['discriminator']
route_args = route_action['args']
self.assertEqual(route_callable, connect_route)
- self.assertEqual(len(route_discriminator), 2)
- self.assertEqual(route_discriminator[0], 'route')
- self.assertEqual(route_discriminator[1], 'name')
- self.assertEqual(route_args, ('path', 'name', None))
+ self.assertEqual(
+ route_discriminator,
+ ('route', 'name', False, None, None, None, None, None))
+ self.assertEqual(route_args[:3], ('path', 'name', None))
+ predicates = route_args[3]
+ self.assertEqual(len(predicates), 0)
def test_with_view(self):
from zope.interface import Interface
@@ -1622,10 +1625,12 @@ class TestRouteDirective(unittest.TestCase):
route_discriminator = route_action['discriminator']
route_args = route_action['args']
self.assertEqual(route_callable, connect_route)
- self.assertEqual(len(route_discriminator), 2)
- self.assertEqual(route_discriminator[0], 'route')
- self.assertEqual(route_discriminator[1], 'name')
- self.assertEqual(route_args, ('path', 'name', None))
+ self.assertEqual(
+ route_discriminator,
+ ('route', 'name', False, None, None, None, None, None))
+ self.assertEqual(route_args[:3], ('path', 'name', None))
+ predicates = route_args[3]
+ self.assertEqual(len(predicates), 0)
def test_with_view_and_view_for(self):
from zope.component import getSiteManager
@@ -1658,10 +1663,11 @@ class TestRouteDirective(unittest.TestCase):
route_discriminator = route_action['discriminator']
route_args = route_action['args']
self.assertEqual(route_callable, connect_route)
- self.assertEqual(len(route_discriminator), 2)
- self.assertEqual(route_discriminator[0], 'route')
- self.assertEqual(route_discriminator[1], 'name')
- self.assertEqual(route_args, ('path', 'name', None,))
+ self.assertEqual(route_discriminator,
+ ('route', 'name', False, None, None, None, None,None))
+ self.assertEqual(route_args[:3], ('path', 'name', None))
+ predicates = route_args[3]
+ self.assertEqual(len(predicates), 0)
def test_without_view(self):
from repoze.bfg.zcml import connect_route
@@ -1675,10 +1681,9 @@ class TestRouteDirective(unittest.TestCase):
route_discriminator = route_action['discriminator']
route_args = route_action['args']
self.assertEqual(route_callable, connect_route)
- self.assertEqual(len(route_discriminator), 2)
- self.assertEqual(route_discriminator[0], 'route')
- self.assertEqual(route_discriminator[1], 'name')
- self.assertEqual(route_args, ('path', 'name', None))
+ self.assertEqual(route_discriminator,
+ ('route', 'name', False, None, None, None, None, None))
+ self.assertEqual(route_args, ('path', 'name', None, []))
def test_with_view_request_type(self):
from zope.component import getSiteManager
@@ -1711,12 +1716,13 @@ class TestRouteDirective(unittest.TestCase):
route_discriminator = route_action['discriminator']
route_args = route_action['args']
self.assertEqual(route_callable, connect_route)
- self.assertEqual(len(route_discriminator), 2)
- self.assertEqual(route_discriminator[0], 'route')
- self.assertEqual(route_discriminator[1], 'name')
- self.assertEqual(route_args, ('path', 'name', None))
+ self.assertEqual(route_discriminator,
+ ('route', 'name', False, None, None, None, None,None))
+ self.assertEqual(route_args[:3], ('path', 'name', None))
+ predicates = route_args[3]
+ self.assertEqual(len(predicates), 0)
- def test_with_view_request_type_alias(self):
+ def test_with_view_request_method(self):
from zope.component import getSiteManager
from repoze.bfg.zcml import connect_route
from repoze.bfg.interfaces import IView
@@ -1725,7 +1731,8 @@ class TestRouteDirective(unittest.TestCase):
context = DummyContext()
def view(context, request):
""" """
- self._callFUT(context, 'name', 'path', view=view, request_type="GET")
+ self._callFUT(context, 'name', 'path', view=view,
+ view_request_method="GET")
actions = context.actions
self.assertEqual(len(actions), 2)
@@ -1746,12 +1753,13 @@ class TestRouteDirective(unittest.TestCase):
route_discriminator = route_action['discriminator']
route_args = route_action['args']
self.assertEqual(route_callable, connect_route)
- self.assertEqual(len(route_discriminator), 2)
- self.assertEqual(route_discriminator[0], 'route')
- self.assertEqual(route_discriminator[1], 'name')
- self.assertEqual(route_args, ('path', 'name', None))
+ self.assertEqual(route_discriminator,
+ ('route', 'name', False, None, None, None, None, None))
+ self.assertEqual(route_args[:3], ('path', 'name', None))
+ predicates = route_args[3]
+ self.assertEqual(len(predicates), 0)
- def test_with_view_request_method(self):
+ def test_with_view_containment(self):
from zope.component import getSiteManager
from repoze.bfg.zcml import connect_route
from repoze.bfg.interfaces import IView
@@ -1760,8 +1768,7 @@ class TestRouteDirective(unittest.TestCase):
context = DummyContext()
def view(context, request):
""" """
- self._callFUT(context, 'name', 'path', view=view,
- view_request_method="GET")
+ self._callFUT(context, 'name', 'path', view=view, view_containment=True)
actions = context.actions
self.assertEqual(len(actions), 2)
@@ -1771,7 +1778,7 @@ class TestRouteDirective(unittest.TestCase):
sm = getSiteManager()
request_type = sm.getUtility(IRouteRequest, 'name')
view_discriminator = view_action['discriminator']
- discrim = ('view', None, '', request_type, IView, None, None, 'GET',
+ discrim = ('view', None, '', request_type, IView, True, None, None,
'name', None, False, None, None, None)
self.assertEqual(view_discriminator, discrim)
wrapped = sm.adapters.lookup((IDummy, request_type), IView, name='')
@@ -1782,12 +1789,13 @@ class TestRouteDirective(unittest.TestCase):
route_discriminator = route_action['discriminator']
route_args = route_action['args']
self.assertEqual(route_callable, connect_route)
- self.assertEqual(len(route_discriminator), 2)
- self.assertEqual(route_discriminator[0], 'route')
- self.assertEqual(route_discriminator[1], 'name')
- self.assertEqual(route_args, ('path', 'name', None))
+ self.assertEqual(route_discriminator,
+ ('route', 'name', False, None, None,None, None, None))
+ self.assertEqual(route_args[:3], ('path', 'name', None))
+ predicates = route_args[3]
+ self.assertEqual(len(predicates), 0)
- def test_with_view_request_method_alias(self):
+ def test_with_view_header(self):
from zope.component import getSiteManager
from repoze.bfg.zcml import connect_route
from repoze.bfg.interfaces import IView
@@ -1796,7 +1804,7 @@ class TestRouteDirective(unittest.TestCase):
context = DummyContext()
def view(context, request):
""" """
- self._callFUT(context, 'name', 'path', view=view, request_method="GET")
+ self._callFUT(context, 'name', 'path', view=view, view_header='Host')
actions = context.actions
self.assertEqual(len(actions), 2)
@@ -1805,10 +1813,45 @@ class TestRouteDirective(unittest.TestCase):
register()
sm = getSiteManager()
request_type = sm.getUtility(IRouteRequest, 'name')
+ view_discriminator = view_action['discriminator']
+ discrim = ('view', None, '', request_type, IView, None, None, None,
+ 'name', None, False, None, 'Host', None)
+ self.assertEqual(view_discriminator, discrim)
+ wrapped = sm.adapters.lookup((IDummy, request_type), IView, name='')
+ self.failUnless(wrapped)
+
+ route_action = actions[1]
+ route_callable = route_action['callable']
+ route_discriminator = route_action['discriminator']
+ route_args = route_action['args']
+ self.assertEqual(route_callable, connect_route)
+ self.assertEqual(route_discriminator,
+ ('route', 'name', False, None, None,None, None, None))
+ self.assertEqual(route_args[:3], ('path', 'name', None))
+ predicates = route_args[3]
+ self.assertEqual(len(predicates), 0)
+ def test_with_view_path_info(self):
+ from zope.component import getSiteManager
+ from repoze.bfg.zcml import connect_route
+ from repoze.bfg.interfaces import IView
+ from repoze.bfg.interfaces import IRouteRequest
+
+ context = DummyContext()
+ def view(context, request):
+ """ """
+ self._callFUT(context, 'name', 'path', view=view, view_path_info='/foo')
+ actions = context.actions
+ self.assertEqual(len(actions), 2)
+
+ view_action = actions[0]
+ register = view_action['callable']
+ register()
+ sm = getSiteManager()
+ request_type = sm.getUtility(IRouteRequest, 'name')
view_discriminator = view_action['discriminator']
- discrim = ('view', None, '', request_type, IView, None, None, 'GET',
- 'name', None, False, None, None, None)
+ discrim = ('view', None, '', request_type, IView, None, None, None,
+ 'name', None, False, None, None, '/foo')
self.assertEqual(view_discriminator, discrim)
wrapped = sm.adapters.lookup((IDummy, request_type), IView, name='')
self.failUnless(wrapped)
@@ -1818,12 +1861,13 @@ class TestRouteDirective(unittest.TestCase):
route_discriminator = route_action['discriminator']
route_args = route_action['args']
self.assertEqual(route_callable, connect_route)
- self.assertEqual(len(route_discriminator), 2)
- self.assertEqual(route_discriminator[0], 'route')
- self.assertEqual(route_discriminator[1], 'name')
- self.assertEqual(route_args, ('path', 'name', None))
+ self.assertEqual(route_discriminator,
+ ('route', 'name', False, None, None, None, None, None))
+ self.assertEqual(route_args[:3], ('path', 'name', None))
+ predicates = route_args[3]
+ self.assertEqual(len(predicates), 0)
- def test_with_view_containment(self):
+ def test_with_view_xhr(self):
from zope.component import getSiteManager
from repoze.bfg.zcml import connect_route
from repoze.bfg.interfaces import IView
@@ -1832,7 +1876,7 @@ class TestRouteDirective(unittest.TestCase):
context = DummyContext()
def view(context, request):
""" """
- self._callFUT(context, 'name', 'path', view=view, view_containment=True)
+ self._callFUT(context, 'name', 'path', view=view, view_xhr=True)
actions = context.actions
self.assertEqual(len(actions), 2)
@@ -1842,8 +1886,8 @@ class TestRouteDirective(unittest.TestCase):
sm = getSiteManager()
request_type = sm.getUtility(IRouteRequest, 'name')
view_discriminator = view_action['discriminator']
- discrim = ('view', None, '', request_type, IView, True, None, None,
- 'name', None, False, None, None, None)
+ discrim = ('view', None, '', request_type, IView, None, None, None,
+ 'name', None, True, None, None, None)
self.assertEqual(view_discriminator, discrim)
wrapped = sm.adapters.lookup((IDummy, request_type), IView, name='')
self.failUnless(wrapped)
@@ -1853,12 +1897,13 @@ class TestRouteDirective(unittest.TestCase):
route_discriminator = route_action['discriminator']
route_args = route_action['args']
self.assertEqual(route_callable, connect_route)
- self.assertEqual(len(route_discriminator), 2)
- self.assertEqual(route_discriminator[0], 'route')
- self.assertEqual(route_discriminator[1], 'name')
- self.assertEqual(route_args, ('path', 'name', None))
+ self.assertEqual(route_discriminator,
+ ('route', 'name', False, None, None, None, None, None))
+ self.assertEqual(route_args[:3], ('path', 'name', None))
+ predicates = route_args[3]
+ self.assertEqual(len(predicates), 0)
- def test_with_view_containment_alias(self):
+ def test_with_view_accept(self):
from zope.component import getSiteManager
from repoze.bfg.zcml import connect_route
from repoze.bfg.interfaces import IView
@@ -1867,7 +1912,8 @@ class TestRouteDirective(unittest.TestCase):
context = DummyContext()
def view(context, request):
""" """
- self._callFUT(context, 'name', 'path', view=view, containment=True)
+ self._callFUT(context, 'name', 'path', view=view,
+ view_accept='text/xml')
actions = context.actions
self.assertEqual(len(actions), 2)
@@ -1877,8 +1923,8 @@ class TestRouteDirective(unittest.TestCase):
sm = getSiteManager()
request_type = sm.getUtility(IRouteRequest, 'name')
view_discriminator = view_action['discriminator']
- discrim = ('view', None, '', request_type, IView, True, None, None,
- 'name', None, False, None, None, None)
+ discrim = ('view', None, '', request_type, IView, None, None, None,
+ 'name', None, False, 'text/xml', None, None)
self.assertEqual(view_discriminator, discrim)
wrapped = sm.adapters.lookup((IDummy, request_type), IView, name='')
self.failUnless(wrapped)
@@ -1888,12 +1934,14 @@ class TestRouteDirective(unittest.TestCase):
route_discriminator = route_action['discriminator']
route_args = route_action['args']
self.assertEqual(route_callable, connect_route)
- self.assertEqual(len(route_discriminator), 2)
- self.assertEqual(route_discriminator[0], 'route')
- self.assertEqual(route_discriminator[1], 'name')
- self.assertEqual(route_args, ('path', 'name', None))
+ self.assertEqual(
+ route_discriminator,
+ ('route', 'name', False, None, None, None, None, None))
+ self.assertEqual(route_args[:3], ('path', 'name', None))
+ predicates = route_args[3]
+ self.assertEqual(len(predicates), 0)
- def test_with_view_header(self):
+ def test_with_request_type_GET(self):
from zope.component import getSiteManager
from repoze.bfg.zcml import connect_route
from repoze.bfg.interfaces import IView
@@ -1902,7 +1950,7 @@ class TestRouteDirective(unittest.TestCase):
context = DummyContext()
def view(context, request):
""" """
- self._callFUT(context, 'name', 'path', view=view, view_header='Host')
+ self._callFUT(context, 'name', 'path', view=view, request_type="GET")
actions = context.actions
self.assertEqual(len(actions), 2)
@@ -1912,8 +1960,8 @@ class TestRouteDirective(unittest.TestCase):
sm = getSiteManager()
request_type = sm.getUtility(IRouteRequest, 'name')
view_discriminator = view_action['discriminator']
- discrim = ('view', None, '', request_type, IView, None, None, None,
- 'name', None, False, None, 'Host', None)
+ discrim = ('view', None, '', request_type, IView, None, None, 'GET',
+ 'name', None, False, None, None, None)
self.assertEqual(view_discriminator, discrim)
wrapped = sm.adapters.lookup((IDummy, request_type), IView, name='')
self.failUnless(wrapped)
@@ -1923,12 +1971,15 @@ class TestRouteDirective(unittest.TestCase):
route_discriminator = route_action['discriminator']
route_args = route_action['args']
self.assertEqual(route_callable, connect_route)
- self.assertEqual(len(route_discriminator), 2)
- self.assertEqual(route_discriminator[0], 'route')
- self.assertEqual(route_discriminator[1], 'name')
- self.assertEqual(route_args, ('path', 'name', None))
+ self.assertEqual(route_discriminator,
+ ('route', 'name', False, None, None, None, None,None))
+ self.assertEqual(route_args[:3], ('path', 'name', None))
+ predicates = route_args[3]
+ self.assertEqual(len(predicates), 0)
+
+ # route predicates
- def test_with_view_header_alias(self):
+ def test_with_xhr(self):
from zope.component import getSiteManager
from repoze.bfg.zcml import connect_route
from repoze.bfg.interfaces import IView
@@ -1937,7 +1988,7 @@ class TestRouteDirective(unittest.TestCase):
context = DummyContext()
def view(context, request):
""" """
- self._callFUT(context, 'name', 'path', view=view, header='Host')
+ self._callFUT(context, 'name', 'path', view=view, xhr=True)
actions = context.actions
self.assertEqual(len(actions), 2)
@@ -1948,7 +1999,7 @@ class TestRouteDirective(unittest.TestCase):
request_type = sm.getUtility(IRouteRequest, 'name')
view_discriminator = view_action['discriminator']
discrim = ('view', None, '', request_type, IView, None, None, None,
- 'name', None, False, None, 'Host', None)
+ 'name', None, False, None, None, None)
self.assertEqual(view_discriminator, discrim)
wrapped = sm.adapters.lookup((IDummy, request_type), IView, name='')
self.failUnless(wrapped)
@@ -1958,21 +2009,25 @@ class TestRouteDirective(unittest.TestCase):
route_discriminator = route_action['discriminator']
route_args = route_action['args']
self.assertEqual(route_callable, connect_route)
- self.assertEqual(len(route_discriminator), 2)
- self.assertEqual(route_discriminator[0], 'route')
- self.assertEqual(route_discriminator[1], 'name')
- self.assertEqual(route_args, ('path', 'name', None))
+ self.assertEqual(route_discriminator,
+ ('route', 'name', True, None, None, None, None, None))
+ self.assertEqual(route_args[:3], ('path', 'name', None))
+ predicates = route_args[3]
+ self.assertEqual(len(predicates), 1)
+ request = DummyRequest()
+ request.is_xhr = True
+ self.assertEqual(predicates[0](None, request), True)
- def test_with_view_path_info(self):
+ def test_with_request_method(self):
from zope.component import getSiteManager
from repoze.bfg.zcml import connect_route
from repoze.bfg.interfaces import IView
from repoze.bfg.interfaces import IRouteRequest
-
+
context = DummyContext()
def view(context, request):
""" """
- self._callFUT(context, 'name', 'path', view=view, view_path_info='/foo')
+ self._callFUT(context, 'name', 'path', view=view, request_method="GET")
actions = context.actions
self.assertEqual(len(actions), 2)
@@ -1981,9 +2036,10 @@ class TestRouteDirective(unittest.TestCase):
register()
sm = getSiteManager()
request_type = sm.getUtility(IRouteRequest, 'name')
+
view_discriminator = view_action['discriminator']
discrim = ('view', None, '', request_type, IView, None, None, None,
- 'name', None, False, None, None, '/foo')
+ 'name', None, False, None, None, None)
self.assertEqual(view_discriminator, discrim)
wrapped = sm.adapters.lookup((IDummy, request_type), IView, name='')
self.failUnless(wrapped)
@@ -1993,21 +2049,25 @@ class TestRouteDirective(unittest.TestCase):
route_discriminator = route_action['discriminator']
route_args = route_action['args']
self.assertEqual(route_callable, connect_route)
- self.assertEqual(len(route_discriminator), 2)
- self.assertEqual(route_discriminator[0], 'route')
- self.assertEqual(route_discriminator[1], 'name')
- self.assertEqual(route_args, ('path', 'name', None))
+ self.assertEqual(route_discriminator,
+ ('route', 'name', False, 'GET',None, None, None, None))
+ self.assertEqual(route_args[:3], ('path', 'name', None))
+ predicates = route_args[3]
+ self.assertEqual(len(predicates), 1)
+ request = DummyRequest()
+ request.method = 'GET'
+ self.assertEqual(predicates[0](None, request), True)
- def test_with_view_xhr(self):
+ def test_with_path_info(self):
from zope.component import getSiteManager
from repoze.bfg.zcml import connect_route
from repoze.bfg.interfaces import IView
from repoze.bfg.interfaces import IRouteRequest
-
+
context = DummyContext()
def view(context, request):
""" """
- self._callFUT(context, 'name', 'path', view=view, view_xhr=True)
+ self._callFUT(context, 'name', 'path', view=view, path_info='/foo')
actions = context.actions
self.assertEqual(len(actions), 2)
@@ -2018,7 +2078,7 @@ class TestRouteDirective(unittest.TestCase):
request_type = sm.getUtility(IRouteRequest, 'name')
view_discriminator = view_action['discriminator']
discrim = ('view', None, '', request_type, IView, None, None, None,
- 'name', None, True, None, None, None)
+ 'name', None, False, None, None, None)
self.assertEqual(view_discriminator, discrim)
wrapped = sm.adapters.lookup((IDummy, request_type), IView, name='')
self.failUnless(wrapped)
@@ -2028,12 +2088,16 @@ class TestRouteDirective(unittest.TestCase):
route_discriminator = route_action['discriminator']
route_args = route_action['args']
self.assertEqual(route_callable, connect_route)
- self.assertEqual(len(route_discriminator), 2)
- self.assertEqual(route_discriminator[0], 'route')
- self.assertEqual(route_discriminator[1], 'name')
- self.assertEqual(route_args, ('path', 'name', None))
+ self.assertEqual(route_discriminator,
+ ('route', 'name', False, None, '/foo',None,None, None))
+ self.assertEqual(route_args[:3], ('path', 'name', None))
+ predicates = route_args[3]
+ self.assertEqual(len(predicates), 1)
+ request = DummyRequest()
+ request.path_info = '/foo'
+ self.assertEqual(predicates[0](None, request), True)
- def test_with_view_xhr_alias(self):
+ def test_with_request_param(self):
from zope.component import getSiteManager
from repoze.bfg.zcml import connect_route
from repoze.bfg.interfaces import IView
@@ -2042,7 +2106,7 @@ class TestRouteDirective(unittest.TestCase):
context = DummyContext()
def view(context, request):
""" """
- self._callFUT(context, 'name', 'path', view=view, xhr=True)
+ self._callFUT(context, 'name', 'path', view=view, request_param='abc')
actions = context.actions
self.assertEqual(len(actions), 2)
@@ -2053,7 +2117,7 @@ class TestRouteDirective(unittest.TestCase):
request_type = sm.getUtility(IRouteRequest, 'name')
view_discriminator = view_action['discriminator']
discrim = ('view', None, '', request_type, IView, None, None, None,
- 'name', None, True, None, None, None)
+ 'name', None, False, None, None, None)
self.assertEqual(view_discriminator, discrim)
wrapped = sm.adapters.lookup((IDummy, request_type), IView, name='')
self.failUnless(wrapped)
@@ -2063,12 +2127,16 @@ class TestRouteDirective(unittest.TestCase):
route_discriminator = route_action['discriminator']
route_args = route_action['args']
self.assertEqual(route_callable, connect_route)
- self.assertEqual(len(route_discriminator), 2)
- self.assertEqual(route_discriminator[0], 'route')
- self.assertEqual(route_discriminator[1], 'name')
- self.assertEqual(route_args, ('path', 'name', None))
+ self.assertEqual(route_discriminator,
+ ('route', 'name', False, None, None,'abc', None, None))
+ self.assertEqual(route_args[:3], ('path', 'name', None))
+ predicates = route_args[3]
+ self.assertEqual(len(predicates), 1)
+ request = DummyRequest()
+ request.params = {'abc':'123'}
+ self.assertEqual(predicates[0](None, request), True)
- def test_with_view_accept(self):
+ def test_with_header(self):
from zope.component import getSiteManager
from repoze.bfg.zcml import connect_route
from repoze.bfg.interfaces import IView
@@ -2077,8 +2145,7 @@ class TestRouteDirective(unittest.TestCase):
context = DummyContext()
def view(context, request):
""" """
- self._callFUT(context, 'name', 'path', view=view,
- view_accept='text/xml')
+ self._callFUT(context, 'name', 'path', view=view, header='Host')
actions = context.actions
self.assertEqual(len(actions), 2)
@@ -2089,7 +2156,7 @@ class TestRouteDirective(unittest.TestCase):
request_type = sm.getUtility(IRouteRequest, 'name')
view_discriminator = view_action['discriminator']
discrim = ('view', None, '', request_type, IView, None, None, None,
- 'name', None, False, 'text/xml', None, None)
+ 'name', None, False, None, None, None)
self.assertEqual(view_discriminator, discrim)
wrapped = sm.adapters.lookup((IDummy, request_type), IView, name='')
self.failUnless(wrapped)
@@ -2099,12 +2166,16 @@ class TestRouteDirective(unittest.TestCase):
route_discriminator = route_action['discriminator']
route_args = route_action['args']
self.assertEqual(route_callable, connect_route)
- self.assertEqual(len(route_discriminator), 2)
- self.assertEqual(route_discriminator[0], 'route')
- self.assertEqual(route_discriminator[1], 'name')
- self.assertEqual(route_args, ('path', 'name', None))
+ self.assertEqual(route_discriminator,
+ ('route', 'name', False, None, None,None,'Host', None))
+ self.assertEqual(route_args[:3], ('path', 'name', None))
+ predicates = route_args[3]
+ self.assertEqual(len(predicates), 1)
+ request = DummyRequest()
+ request.headers = {'Host':'example.com'}
+ self.assertEqual(predicates[0](None, request), True)
- def test_with_view_accept_alias(self):
+ def test_with_accept(self):
from zope.component import getSiteManager
from repoze.bfg.zcml import connect_route
from repoze.bfg.interfaces import IView
@@ -2125,7 +2196,7 @@ class TestRouteDirective(unittest.TestCase):
view_discriminator = view_action['discriminator']
discrim = ('view', None, '', request_type, IView, None, None, None,
- 'name', None, False, 'text/xml', None, None)
+ 'name', None, False, None, None, None)
self.assertEqual(view_discriminator, discrim)
wrapped = sm.adapters.lookup((IDummy, request_type), IView, name='')
self.failUnless(wrapped)
@@ -2135,10 +2206,15 @@ class TestRouteDirective(unittest.TestCase):
route_discriminator = route_action['discriminator']
route_args = route_action['args']
self.assertEqual(route_callable, connect_route)
- self.assertEqual(len(route_discriminator), 2)
- self.assertEqual(route_discriminator[0], 'route')
- self.assertEqual(route_discriminator[1], 'name')
- self.assertEqual(route_args, ('path', 'name', None))
+ self.assertEqual(
+ route_discriminator,
+ ('route', 'name', False, None, None, None, None, 'text/xml'))
+ self.assertEqual(route_args[:3], ('path', 'name', None))
+ predicates = route_args[3]
+ self.assertEqual(len(predicates), 1)
+ request = DummyRequest()
+ request.accept = ['text/xml']
+ self.assertEqual(predicates[0](None, request), True)
class TestStaticDirective(unittest.TestCase):
def setUp(self):
@@ -2186,7 +2262,8 @@ class TestStaticDirective(unittest.TestCase):
discriminator = action['discriminator']
args = action['args']
self.assertEqual(callable, connect_route)
- self.assertEqual(discriminator, ('route', 'name'))
+ self.assertEqual(discriminator,
+ ('route', 'name', False, None, None, None, None, None))
self.assertEqual(args[0], 'name*subpath')
def test_package_relative(self):
@@ -2220,7 +2297,8 @@ class TestStaticDirective(unittest.TestCase):
discriminator = action['discriminator']
args = action['args']
self.assertEqual(callable, connect_route)
- self.assertEqual(discriminator, ('route', 'name'))
+ self.assertEqual(discriminator,
+ ('route', 'name', False, None, None, None, None, None))
self.assertEqual(args[0], 'name*subpath')
def test_here_relative(self):
@@ -2255,7 +2333,8 @@ class TestStaticDirective(unittest.TestCase):
discriminator = action['discriminator']
args = action['args']
self.assertEqual(callable, connect_route)
- self.assertEqual(discriminator, ('route', 'name'))
+ self.assertEqual(discriminator,
+ ('route', 'name', False, None, None, None, None, None))
self.assertEqual(args[0], 'name*subpath')
class TestResourceDirective(unittest.TestCase):
@@ -2564,8 +2643,8 @@ class DummyMapper:
def __init__(self):
self.connections = []
- def connect(self, *args):
- self.connections.append(args)
+ def connect(self, path, name, factory, predicates=()):
+ self.connections.append((path, name, factory, predicates))
class DummyRoute:
pass
diff --git a/repoze/bfg/urldispatch.py b/repoze/bfg/urldispatch.py
index 4088cef12..185baa1a1 100644
--- a/repoze/bfg/urldispatch.py
+++ b/repoze/bfg/urldispatch.py
@@ -5,18 +5,20 @@ from zope.interface import directlyProvides
from repoze.bfg.interfaces import IRouteRequest
+from repoze.bfg.compat import all
+from repoze.bfg.encode import url_quote
from repoze.bfg.traversal import traversal_path
from repoze.bfg.traversal import quote_path_segment
-from repoze.bfg.encode import url_quote
_marker = object()
class Route(object):
- def __init__(self, path, name=None, factory=None):
+ def __init__(self, path, name=None, factory=None, predicates=()):
self.path = path
self.match, self.generate = _compile_route(path)
self.name = name
self.factory = factory
+ self.predicates = predicates
class RoutesRootFactory(object):
def __init__(self, default_root_factory):
@@ -30,8 +32,8 @@ class RoutesRootFactory(object):
def get_routes(self):
return self.routelist
- def connect(self, path, name, factory=None):
- route = Route(path, name, factory)
+ def connect(self, path, name, factory=None, predicates=()):
+ route = Route(path, name, factory, predicates)
self.routelist.append(route)
self.routes[name] = route
return route
@@ -69,6 +71,9 @@ class RoutesRootFactory(object):
for route in self.routelist:
match = route.match(path)
if match is not None:
+ preds = route.predicates
+ if preds and not all((p(None, request) for p in preds)):
+ continue
environ['wsgiorg.routing_args'] = ((), match)
environ['bfg.routes.route'] = route
environ['bfg.routes.matchdict'] = match
diff --git a/repoze/bfg/zcml.py b/repoze/bfg/zcml.py
index c39f06bb3..97af9112a 100644
--- a/repoze/bfg/zcml.py
+++ b/repoze/bfg/zcml.py
@@ -197,7 +197,7 @@ def _make_predicates(xhr=None, request_method=None, path_info=None,
except re.error, why:
raise ConfigurationError(why[0])
def path_info_predicate(context, request):
- return path_info_val.match(request.path_info)
+ return path_info_val.match(request.path_info) is not None
weight = weight - 30
predicates.append(path_info_predicate)
@@ -553,9 +553,19 @@ class IRouteDirective(Interface):
path = TextLine(title=u'path', required=True)
factory = GlobalObject(title=u'context factory', required=False)
view = GlobalObject(title=u'view', required=False)
+
view_for = GlobalObject(title=u'view_for', required=False)
+ # alias for view_for
+ for_ = GlobalObject(title=u'for', required=False)
+
view_permission = TextLine(title=u'view_permission', required=False)
+ # alias for view_permission
+ permission = TextLine(title=u'permission', required=False)
+
view_request_type = TextLine(title=u'view_request_type', required=False)
+ # alias for view_request_type
+ request_type = TextLine(title=u'request_type', required=False)
+
view_request_method = TextLine(title=u'view_request_method', required=False)
view_containment = GlobalObject(
title = u'Dotted name of a containment class or interface',
@@ -566,31 +576,12 @@ class IRouteDirective(Interface):
view_accept = TextLine(title=u'view_accept', required=False)
view_xhr = Bool(title=u'view_xhr', required=False)
view_path_info = TextLine(title=u'view_path_info', required=False)
- # alias for "view_for"
- for_ = GlobalObject(title=u'for', required=False)
- # alias for "view_permission"
- permission = TextLine(title=u'permission', required=False)
- # alias for "view_request_type"
- request_type = TextLine(title=u'request_type', required=False)
- # alias for "view_request_method"
+
request_method = TextLine(title=u'request_method', required=False)
- # alias for "view_request_param"
request_param = TextLine(title=u'request_param', required=False)
- # alias for "view_containment"
- containment = GlobalObject(
- title = u'Dotted name of a containment class or interface',
- required=False)
- # alias for "view_attr"
- attr = TextLine(title=u'attr', required=False)
- # alias for "view_renderer"
- renderer = TextLine(title=u'renderer', required=False)
- # alias for "view_header"
header = TextLine(title=u'header', required=False)
- # alias for "view_accept"
accept = TextLine(title=u'accept', required=False)
- # alias for "view_xhr"
xhr = Bool(title=u'xhr', required=False)
- # alias for "view_path_info"
path_info = TextLine(title=u'path_info', required=False)
class IRouteRequirementDirective(Interface):
@@ -601,59 +592,72 @@ class IRouteRequirementDirective(Interface):
def route(_context, name, path, view=None, view_for=None,
permission=None, factory=None, request_type=None, for_=None,
+ header=None, xhr=False, accept=None, path_info=None,
view_permission=None, view_request_type=None,
request_method=None, view_request_method=None,
- request_param=None, view_request_param=None, containment=None,
- view_containment=None, attr=None, view_attr=None, renderer=None,
- view_renderer=None, header=None, view_header=None, accept=None,
- view_accept=None, xhr=False, view_xhr=False,
- path_info=None, view_path_info=None):
+ request_param=None, view_request_param=None,
+ view_containment=None, view_attr=None,
+ view_renderer=None, view_header=None,
+ view_accept=None, view_xhr=False,
+ view_path_info=None):
""" Handle ``route`` ZCML directives
"""
# the strange ordering of the request kw args above is for b/w
# compatibility purposes.
- for_ = view_for or for_
- request_type = view_request_type or request_type
- permission = view_permission or permission
- request_method = view_request_method or request_method
- request_param = view_request_param or request_param
- containment = view_containment or containment
- attr = view_attr or attr
- renderer = view_renderer or renderer
- header = view_header or header
- accept = view_accept or accept
- xhr = view_xhr or xhr
- path_info = view_path_info or path_info
+ # these are route predicates; if they do not match, the next route
+ # in the routelist will be tried
+ _, predicates = _make_predicates(xhr=xhr,
+ request_method=request_method,
+ path_info=path_info,
+ request_param=request_param,
+ header=header,
+ accept=accept)
sm = getSiteManager()
if request_type in ('GET', 'HEAD', 'PUT', 'POST', 'DELETE'):
# b/w compat for 1.0
- request_method = request_type
+ view_request_method = request_type
request_type = None
- if request_type is None:
- request_type = queryUtility(IRouteRequest, name=name)
- if request_type is None:
- request_type = route_request_iface(name)
- sm.registerUtility(request_type, IRouteRequest, name=name)
+ request_iface = queryUtility(IRouteRequest, name=name)
+ if request_iface is None:
+ request_iface = route_request_iface(name)
+ sm.registerUtility(request_iface, IRouteRequest, name=name)
if view:
- _view(_context, permission=permission, for_=for_, view=view, name='',
- request_type=request_type, route_name=name,
- request_method=request_method, request_param=request_param,
- containment=containment, attr=attr, renderer=renderer,
- header=header, accept=accept, xhr=xhr, path_info=path_info)
+ view_for = view_for or for_
+ view_request_type = view_request_type or request_type
+ view_permission = view_permission or permission
+ _view(
+ _context,
+ permission=view_permission,
+ for_=view_for,
+ view=view,
+ name='',
+ request_type=view_request_type,
+ route_name=name,
+ request_method=view_request_method,
+ request_param=view_request_param,
+ containment=view_containment,
+ attr=view_attr,
+ renderer=view_renderer,
+ header=view_header,
+ accept=view_accept,
+ xhr=view_xhr,
+ path_info=view_path_info,
+ )
_context.action(
- discriminator = ('route', name),
+ discriminator = ('route', name, xhr, request_method, path_info,
+ request_param, header, accept),
callable = connect_route,
- args = (path, name, factory),
+ args = (path, name, factory, predicates),
)
-def connect_route(path, name, factory):
+def connect_route(path, name, factory, predicates):
mapper = getUtility(IRoutesMapper)
- mapper.connect(path, name, factory)
+ mapper.connect(path, name, factory, predicates=predicates)
class IRendererDirective(Interface):
factory = GlobalObject(