summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2009-06-24 19:23:43 +0000
committerChris McDonough <chrism@agendaless.com>2009-06-24 19:23:43 +0000
commit05c02322f5a09c14f49c529d6fd885153e52c66f (patch)
treec09c43dc7b82d6cc475648c33313d1c1e495311e
parentaedb399ccb4da1d055163708894f690bb96685c0 (diff)
downloadpyramid-05c02322f5a09c14f49c529d6fd885153e52c66f.tar.gz
pyramid-05c02322f5a09c14f49c529d6fd885153e52c66f.tar.bz2
pyramid-05c02322f5a09c14f49c529d6fd885153e52c66f.zip
Merge noroutes branch to trunk.
-rw-r--r--repoze/bfg/includes/meta.zcml15
-rw-r--r--repoze/bfg/interfaces.py3
-rw-r--r--repoze/bfg/request.py4
-rw-r--r--repoze/bfg/tests/test_request.py34
-rw-r--r--repoze/bfg/tests/test_traversal.py21
-rw-r--r--repoze/bfg/tests/test_url.py61
-rw-r--r--repoze/bfg/tests/test_urldispatch.py128
-rw-r--r--repoze/bfg/tests/test_zcml.py309
-rw-r--r--repoze/bfg/traversal.py20
-rw-r--r--repoze/bfg/url.py97
-rw-r--r--repoze/bfg/urldispatch.py129
-rw-r--r--repoze/bfg/zcml.py165
-rw-r--r--setup.py1
13 files changed, 414 insertions, 573 deletions
diff --git a/repoze/bfg/includes/meta.zcml b/repoze/bfg/includes/meta.zcml
index 36129c5e3..4acdfe937 100644
--- a/repoze/bfg/includes/meta.zcml
+++ b/repoze/bfg/includes/meta.zcml
@@ -28,21 +28,12 @@
handler="repoze.bfg.zcml.forbidden"
/>
- </meta:directives>
-
- <meta:groupingDirective
- namespace="http://namespaces.repoze.org/bfg"
+ <meta:directive
name="route"
schema="repoze.bfg.zcml.IRouteDirective"
- handler="repoze.bfg.zcml.Route"
+ handler="repoze.bfg.zcml.route"
/>
- <meta:directive
- name="requirement"
- namespace="http://namespaces.repoze.org/bfg"
- usedIn="repoze.bfg.zcml.IRouteDirective"
- schema="repoze.bfg.zcml.IRouteRequirementDirective"
- handler="repoze.bfg.zcml.route_requirement"
- />
+ </meta:directives>
</configure>
diff --git a/repoze/bfg/interfaces.py b/repoze/bfg/interfaces.py
index b8f62c05f..2dcddd483 100644
--- a/repoze/bfg/interfaces.py
+++ b/repoze/bfg/interfaces.py
@@ -230,6 +230,9 @@ class IAuthorizationPolicy(Interface):
def principals_allowed_by_permission(context, permission):
""" Return a set of principal identifiers allowed by the permission """
+class IRequestFactories(Interface):
+ """ Marker interface for utilities representing request factories """
+
# VH_ROOT_KEY is an interface; its imported from other packages (e.g.
# traversalwrapper)
VH_ROOT_KEY = 'HTTP_X_VHM_ROOT'
diff --git a/repoze/bfg/request.py b/repoze/bfg/request.py
index 20e8070fc..932789e0a 100644
--- a/repoze/bfg/request.py
+++ b/repoze/bfg/request.py
@@ -1,3 +1,4 @@
+from zope.component import getUtility
from zope.interface import implements
from webob import Request as WebobRequest
@@ -10,6 +11,7 @@ from repoze.bfg.interfaces import IPOSTRequest
from repoze.bfg.interfaces import IPUTRequest
from repoze.bfg.interfaces import IDELETERequest
from repoze.bfg.interfaces import IHEADRequest
+from repoze.bfg.interfaces import IRequestFactories
def request_factory(environ):
try:
@@ -19,7 +21,7 @@ def request_factory(environ):
if 'bfg.routes.route' in environ:
route = environ['bfg.routes.route']
- request_factories = route.request_factories
+ request_factories = getUtility(IRequestFactories, name=route.name or '')
else:
request_factories = DEFAULT_REQUEST_FACTORIES
diff --git a/repoze/bfg/tests/test_request.py b/repoze/bfg/tests/test_request.py
index d5823e7d7..5f61f4efc 100644
--- a/repoze/bfg/tests/test_request.py
+++ b/repoze/bfg/tests/test_request.py
@@ -1,4 +1,5 @@
import unittest
+from repoze.bfg.testing import cleanUp
class TestMakeRequestASCII(unittest.TestCase):
def _callFUT(self, event):
@@ -103,22 +104,35 @@ class Test_HEADRequest(TestRequestSubclass, unittest.TestCase):
return DEFAULT_REQUEST_FACTORIES['HEAD']['interface']
class TestRequestFactory(unittest.TestCase):
+ def setUp(self):
+ cleanUp()
+
+ def tearDown(self):
+ cleanUp()
+
def _callFUT(self, environ):
from repoze.bfg.request import request_factory
return request_factory(environ)
- def _getRequestFactory(self, name_or_iface=None):
- from repoze.bfg.request import DEFAULT_REQUEST_FACTORIES
- return DEFAULT_REQUEST_FACTORIES[name_or_iface]['factory']
-
- def _makeRoute(self):
- route = DummyRoute()
+ def _registerRequestFactories(self, name=''):
+ from zope.component import getSiteManager
+ from repoze.bfg.interfaces import IRequestFactories
factories = {}
def factory(environ):
return environ
for name in (None, 'GET', 'POST', 'PUT', 'DELETE', 'HEAD'):
factories[name] = {'factory':factory}
- route.request_factories = factories
+ sm = getSiteManager()
+ sm.registerUtility(factories, IRequestFactories, name=name)
+ if name:
+ sm.registerUtility(factories, IRequestFactories, name='')
+
+ def _getRequestFactory(self, name_or_iface=None):
+ from repoze.bfg.request import DEFAULT_REQUEST_FACTORIES
+ return DEFAULT_REQUEST_FACTORIES[name_or_iface]['factory']
+
+ def _makeRoute(self, name=None):
+ route = DummyRoute(name)
return route
def test_no_route_no_request_method(self):
@@ -164,18 +178,21 @@ class TestRequestFactory(unittest.TestCase):
self.failUnless(IHEADRequest.providedBy(result))
def test_route_no_request_method(self):
+ self._registerRequestFactories()
route = self._makeRoute()
environ = {'bfg.routes.route':route}
result = self._callFUT(environ)
self.assertEqual(result, environ)
def test_route_unknown(self):
+ self._registerRequestFactories()
route = self._makeRoute()
environ = {'bfg.routes.route':route, 'REQUEST_METHOD':'UNKNOWN'}
result = self._callFUT(environ)
self.assertEqual(result, environ)
def test_route_known(self):
+ self._registerRequestFactories()
route = self._makeRoute()
environ = {'bfg.routes.route':route, 'REQUEST_METHOD':'GET'}
result = self._callFUT(environ)
@@ -273,7 +290,8 @@ class TestDefaultRequestFactories(unittest.TestCase):
class DummyRoute:
- pass
+ def __init__(self, name):
+ self.name=name
class DummyRequest:
pass
diff --git a/repoze/bfg/tests/test_traversal.py b/repoze/bfg/tests/test_traversal.py
index 081105f88..68b920fa4 100644
--- a/repoze/bfg/tests/test_traversal.py
+++ b/repoze/bfg/tests/test_traversal.py
@@ -785,11 +785,11 @@ class TraversalContextURLTests(unittest.TestCase):
one.__name__ = 'one'
one.__parent__ = root
route = DummyRoute()
- route.non_minimized_result = False
+ route.raise_exc = KeyError
request = DummyRequest({'bfg.routes.route':route,
'bfg.routes.matchdict':{'a':1}})
context_url = self._makeOne(one, request)
- self.assertRaises(ValueError, context_url)
+ self.assertRaises(KeyError, context_url)
class TestVirtualRoot(unittest.TestCase):
def setUp(self):
@@ -1005,15 +1005,10 @@ class DummyContextURL:
return '123'
class DummyRoute:
- minimization = False
-
- minimized_result = 'example/'
- non_minimized_result = '/example/'
-
- def generate_minimized(self, kw):
- self.generate_kw = kw
- return self.minimized_result
-
- def generate_non_minimized(self, kw):
+ result = '/example/'
+ raise_exc = None
+ def generate(self, kw):
self.generate_kw = kw
- return self.non_minimized_result
+ if self.raise_exc:
+ raise self.raise_exc
+ return self.result
diff --git a/repoze/bfg/tests/test_url.py b/repoze/bfg/tests/test_url.py
index 3c5bd7559..5f0fde872 100644
--- a/repoze/bfg/tests/test_url.py
+++ b/repoze/bfg/tests/test_url.py
@@ -168,31 +168,40 @@ class TestRouteUrl(unittest.TestCase):
from repoze.bfg.url import route_url
return route_url(*arg, **kw)
- def test_it(self):
+ def test_with_elements(self):
from repoze.bfg.interfaces import IRoutesMapper
- mapper = DummyRoutesMapper({'flub':DummyRoute({})})
+ mapper = DummyRoutesMapper(result='/1/2/3')
from zope.component import getSiteManager
sm = getSiteManager()
sm.registerUtility(mapper, IRoutesMapper)
- args = {'a':'1', 'b':'2', 'c':'3'}
- environ = {'SERVER_NAME':'example.com', 'wsgi.url_scheme':'http',
- 'SERVER_PORT':'80', 'wsgiorg.routing_args':((), args)}
- request = DummyRequest(environ)
- result = self._callFUT(request, 'flub', a=1, b=2, c=3)
- self.assertEqual(result, 'http://example.com/1/2/3')
+ request = DummyRequest()
+ result = self._callFUT('flub', request, 'extra1', 'extra2',
+ a=1, b=2, c=3, _query={'a':1},
+ _anchor=u"foo")
+ self.assertEqual(result,
+ 'http://example.com:5432/1/2/3/extra1/extra2?a=1#foo')
+
+ def test_no_elements(self):
+ from repoze.bfg.interfaces import IRoutesMapper
+ mapper = DummyRoutesMapper(result='/1/2/3')
+ from zope.component import getSiteManager
+ sm = getSiteManager()
+ sm.registerUtility(mapper, IRoutesMapper)
+ request = DummyRequest()
+ result = self._callFUT('flub', request, a=1, b=2, c=3, _query={'a':1},
+ _anchor=u"foo")
+ self.assertEqual(result,
+ 'http://example.com:5432/1/2/3?a=1#foo')
def test_it_generation_error(self):
from repoze.bfg.interfaces import IRoutesMapper
- mapper = DummyRoutesMapper({'flub':DummyRoute({})})
+ mapper = DummyRoutesMapper(raise_exc=KeyError)
from zope.component import getSiteManager
sm = getSiteManager()
sm.registerUtility(mapper, IRoutesMapper)
- args = {'a':'1', 'b':'2', 'c':'3'}
- mapper.raise_exc = True
- environ = {'SERVER_NAME':'example.com', 'wsgi.url_scheme':'http',
- 'SERVER_PORT':'80', 'wsgiorg.routing_args':((), args)}
- request = DummyRequest(environ)
- self.assertRaises(ValueError, self._callFUT, request, 'flub', a=1)
+ mapper.raise_exc = KeyError
+ request = DummyRequest()
+ self.assertRaises(KeyError, self._callFUT, 'flub', request, a=1)
class DummyContext(object):
def __init__(self, next=None):
@@ -206,24 +215,12 @@ class DummyRequest:
self.environ = environ
class DummyRoutesMapper:
- encoding = 'utf-8'
- hardcode_names = False
- sub_domains = []
- raise_exc = False
- def __init__(self, routes, generate_result='/1/2/3', raise_exc=False):
- self._routenames = routes
- self.generate_result = generate_result
+ raise_exc = None
+ def __init__(self, result='/1/2/3', raise_exc=False):
+ self.result = result
def generate(self, *route_args, **newargs):
if self.raise_exc:
- from routes.util import GenerationException
- raise GenerationException
- return self.generate_result
+ raise self.raise_exc
+ return self.result
-class DummyRoute:
- filter = None
- static = False
- def __init__(self, defaults):
- self.defaults = defaults
-
-
diff --git a/repoze/bfg/tests/test_urldispatch.py b/repoze/bfg/tests/test_urldispatch.py
index 68fda032d..cdb99b7f4 100644
--- a/repoze/bfg/tests/test_urldispatch.py
+++ b/repoze/bfg/tests/test_urldispatch.py
@@ -1,6 +1,33 @@
import unittest
from repoze.bfg.testing import cleanUp
+class TestRoute(unittest.TestCase):
+ def _getTargetClass(self):
+ from repoze.bfg.urldispatch import Route
+ return Route
+
+ def _makeOne(self, *arg):
+ return self._getTargetClass()(*arg)
+
+ def test_ctor(self):
+ route = self._makeOne('name', 'matcher', 'generator', 'factory')
+ self.assertEqual(route.name, 'name')
+ self.assertEqual(route.matcher, 'matcher')
+ self.assertEqual(route.generator, 'generator')
+ self.assertEqual(route.factory, 'factory')
+
+ def test_match(self):
+ def matcher(path):
+ return 123
+ route = self._makeOne('name', matcher, 'generator', 'factory')
+ self.assertEqual(route.match('whatever'), 123)
+
+ def test_generate(self):
+ def generator(path):
+ return 123
+ route = self._makeOne('name', 'matcher', generator, 'factory')
+ self.assertEqual(route.generate({}), 123)
+
class RoutesRootFactoryTests(unittest.TestCase):
def setUp(self):
cleanUp()
@@ -27,42 +54,40 @@ class RoutesRootFactoryTests(unittest.TestCase):
self.assertEqual(mapper.default_root_factory, None)
def test_no_route_matches(self):
- get_root = make_get_root(123)
+ get_root = DummyRootFactory(123)
mapper = self._makeOne(get_root)
environ = self._getEnviron(PATH_INFO='/')
result = mapper(environ)
self.assertEqual(result, 123)
- self.assertEqual(mapper.environ, environ)
def test_route_matches(self):
- get_root = make_get_root(123)
+ get_root = DummyRootFactory(123)
mapper = self._makeOne(get_root)
- mapper.connect('foo', 'archives/:action/:article', foo='foo')
+ mapper.connect('foo', 'archives/:action/:article')
environ = self._getEnviron(PATH_INFO='/archives/action1/article1')
result = mapper(environ)
self.assertEqual(result, 123)
routing_args = environ['wsgiorg.routing_args'][1]
- self.assertEqual(routing_args['foo'], 'foo')
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')
- def test_unnamed_root_route_matches(self):
- root_factory = make_get_root(123)
+ def test_root_route_matches(self):
+ root_factory = DummyRootFactory(123)
mapper = self._makeOne(root_factory)
- mapper.connect('')
+ mapper.connect('root', '')
environ = self._getEnviron(PATH_INFO='/')
result = mapper(environ)
self.assertEqual(result, 123)
- self.assertEqual(environ['bfg.routes.route'].name, None)
+ self.assertEqual(environ['bfg.routes.route'].name, 'root')
self.assertEqual(environ['bfg.routes.matchdict'], {})
self.assertEqual(environ['wsgiorg.routing_args'], ((), {}))
- def test_named_root_route_matches(self):
- root_factory = make_get_root(123)
+ def test_root_route_matches2(self):
+ root_factory = DummyRootFactory(123)
mapper = self._makeOne(root_factory)
- mapper.connect('root', '')
+ mapper.connect('root', '/')
environ = self._getEnviron(PATH_INFO='/')
result = mapper(environ)
self.assertEqual(result, 123)
@@ -70,25 +95,8 @@ class RoutesRootFactoryTests(unittest.TestCase):
self.assertEqual(environ['bfg.routes.matchdict'], {})
self.assertEqual(environ['wsgiorg.routing_args'], ((), {}))
- def test_unicode_in_route_default(self):
- root_factory = make_get_root(123)
- mapper = self._makeOne(root_factory)
- class DummyRoute:
- routepath = ':id'
- _factory = None
- la = unicode('\xc3\xb1a', 'utf-8')
- mapper.routematch = lambda *arg: ({la:'id'}, DummyRoute)
- mapper.connect('whatever', ':la')
- environ = self._getEnviron(PATH_INFO='/foo')
- result = mapper(environ)
- self.assertEqual(result, 123)
- self.assertEqual(environ['bfg.routes.route'], DummyRoute)
- self.assertEqual(environ['bfg.routes.matchdict'], {u'\xf1a': 'id'})
- routing_args = environ['wsgiorg.routing_args'][1]
- self.assertEqual(routing_args[la], 'id')
-
def test_fallback_to_default_root_factory(self):
- root_factory = make_get_root(123)
+ root_factory = DummyRootFactory(123)
mapper = self._makeOne(root_factory)
mapper.connect('wont', 'wont/:be/:found')
environ = self._getEnviron(PATH_INFO='/archives/action1/article1')
@@ -101,20 +109,50 @@ class RoutesRootFactoryTests(unittest.TestCase):
mapper.connect('whatever', 'archives/:action/:article')
self.assertEqual(mapper.has_routes(), True)
- def test_url_for(self):
- root_factory = make_get_root(None)
- mapper = self._makeOne(root_factory)
- mapper.connect('whatever', 'archives/:action/:article')
- environ = self._getEnviron(PATH_INFO='/archives/action1/article1')
- result = mapper(environ)
- from routes import url_for
- result = url_for(action='action2', article='article2')
- self.assertEqual(result, '/archives/action2/article2')
+ def test_generate(self):
+ mapper = self._makeOne(None)
+ def generator(kw):
+ return 123
+ route = DummyRoute(generator)
+ mapper.routes['abc'] = route
+ self.assertEqual(mapper.generate('abc', {}), 123)
-def make_get_root(result):
- def dummy_get_root(environ):
- return result
- return dummy_get_root
+class TestCompileRoute(unittest.TestCase):
+ def _callFUT(self, path):
+ from repoze.bfg.urldispatch import _compile_route
+ return _compile_route(path)
+
+ def test_no_star(self):
+ matcher, generator = self._callFUT('/foo/:baz/biz/:buz/bar')
+ self.assertEqual(matcher('/foo/baz/biz/buz/bar'),
+ {'baz':'baz', 'buz':'buz'})
+ self.assertEqual(matcher('foo/baz/biz/buz/bar'), None)
+ self.assertEqual(generator({'baz':1, 'buz':2}), '/foo/1/biz/2/bar')
+
+ def test_with_star(self):
+ matcher, generator = self._callFUT('/foo/:baz/biz/:buz/bar*traverse')
+ self.assertEqual(matcher('/foo/baz/biz/buz/bar'),
+ {'baz':'baz', 'buz':'buz', 'traverse':''})
+ self.assertEqual(matcher('/foo/baz/biz/buz/bar/everything/else/here'),
+ {'baz':'baz', 'buz':'buz',
+ 'traverse':'/everything/else/here'})
+ self.assertEqual(matcher('foo/baz/biz/buz/bar'), None)
+ self.assertEqual(generator(
+ {'baz':1, 'buz':2, 'traverse':u'/a/b'}), '/foo/1/biz/2/bar/a/b')
+
+ def test_no_beginning_slash(self):
+ matcher, generator = self._callFUT('foo/:baz/biz/:buz/bar')
+ self.assertEqual(matcher('/foo/baz/biz/buz/bar'),
+ {'baz':'baz', 'buz':'buz'})
+ self.assertEqual(matcher('foo/baz/biz/buz/bar'), None)
+ self.assertEqual(generator({'baz':1, 'buz':2}), '/foo/1/biz/2/bar')
+
+
+class DummyRootFactory(object):
+ def __init__(self, result):
+ self.result = result
+ def __call__(self, environ):
+ return self.result
class DummyContext(object):
""" """
@@ -122,3 +160,7 @@ class DummyContext(object):
class DummyRequest(object):
""" """
+class DummyRoute(object):
+ def __init__(self, generator):
+ self.generate = generator
+
diff --git a/repoze/bfg/tests/test_zcml.py b/repoze/bfg/tests/test_zcml.py
index 84c794e89..1a0ee3c3f 100644
--- a/repoze/bfg/tests/test_zcml.py
+++ b/repoze/bfg/tests/test_zcml.py
@@ -472,12 +472,16 @@ class TestViewDirective(unittest.TestCase):
self.assertEqual(regadapt['args'][2], (IFoo, IDummy))
def test_with_route_name(self):
+ from zope.component import getSiteManager
+ from repoze.bfg.interfaces import IRequestFactories
class IFoo:
pass
class IDummyRequest:
pass
context = DummyContext()
- context.request_factories = {'foo':{None:{'interface':IDummyRequest}}}
+ factories = {None:{'interface':IDummyRequest}}
+ sm = getSiteManager()
+ sm.registerUtility(factories, IRequestFactories, name='foo')
view = lambda *arg: None
self._callFUT(context, 'repoze.view', IFoo, view=view, route_name='foo')
actions = context.actions
@@ -671,19 +675,6 @@ class TestDeriveView(unittest.TestCase):
self.failUnless('instance' in result.__name__)
self.assertEqual(result(None, None), 'OK')
-class TestRouteRequirementFunction(unittest.TestCase):
- def _callFUT(self, context, attr, expr):
- from repoze.bfg.zcml import route_requirement
- return route_requirement(context, attr, expr)
-
- def test_it(self):
- context = DummyContext()
- context.context = DummyContext()
- context.context.requirements = {}
- self._callFUT(context, 'a', 'b')
- self.assertEqual(context.context.requirements['a'], 'b')
- self.assertRaises(ValueError, self._callFUT, context, 'a', 'b')
-
class TestConnectRouteFunction(unittest.TestCase):
def setUp(self):
cleanUp()
@@ -691,9 +682,9 @@ class TestConnectRouteFunction(unittest.TestCase):
def tearDown(self):
cleanUp()
- def _callFUT(self, directive):
+ def _callFUT(self, name, path, factory):
from repoze.bfg.zcml import connect_route
- return connect_route(directive)
+ return connect_route(name, path, factory)
def _registerRoutesMapper(self):
from zope.component import getGlobalSiteManager
@@ -703,145 +694,10 @@ class TestConnectRouteFunction(unittest.TestCase):
gsm.registerUtility(mapper, IRoutesMapper)
return mapper
- def test_no_mapper(self):
- directive = DummyRouteDirective()
- self._callFUT(directive) # doesn't blow up when no routes mapper reg'd
-
def test_defaults(self):
mapper = self._registerRoutesMapper()
- directive = DummyRouteDirective()
- self._callFUT(directive)
- self.assertEqual(len(mapper.connections), 1)
- self.assertEqual(mapper.connections[0][0], ('name', 'path'))
- self.assertEqual(mapper.connections[0][1], {'requirements': {}})
-
- def test_name_and_path(self):
- mapper = self._registerRoutesMapper()
- directive = DummyRouteDirective(name='abc', path='thepath')
- self._callFUT(directive)
- self.assertEqual(len(mapper.connections), 1)
- self.assertEqual(mapper.connections[0][0], ('abc', 'thepath',))
- self.assertEqual(mapper.connections[0][1], {'requirements': {}})
-
- def test_all_directives(self):
- mapper = self._registerRoutesMapper()
- def foo():
- """ """
- directive = DummyRouteDirective(
- minimize=False, explicit=True, encoding='utf-8', static=True,
- filter=foo, absolute=True, member_name='m', collection_name='c',
- parent_member_name='p', parent_collection_name='c',
- condition_method='GET', condition_subdomain=True,
- condition_function=foo, subdomains=['a'],
- name='thename', path='thepath',
- factory=foo, view='view', permission='permission')
- self._callFUT(directive)
- self.assertEqual(len(mapper.connections), 1)
- self.assertEqual(mapper.connections[0][0], ('thename', 'thepath'))
- pr = {'member_name':'p', 'collection_name':'c'}
- c = {'method':'GET', 'sub_domain':['a'], 'function':foo}
- D = mapper.connections[0][1]
-
- self.assertEqual(D['requirements'], {})
- self.assertEqual(D['_minimize'],False)
- self.assertEqual(D['_explicit'],True)
- self.assertEqual(D['_encoding'],'utf-8')
- self.assertEqual(D['_static'],True)
- self.assertEqual(D['_filter'],foo)
- self.assertEqual(D['_absolute'],True)
- self.assertEqual(D['_member_name'], 'm')
- self.assertEqual(D['_collection_name'], 'c')
- self.assertEqual(D['_parent_resource'], pr)
- self.assertEqual(D['conditions'], c)
- route = mapper.matchlist[-1]
- self.assertEqual(route._factory, foo)
- self.assertEqual(route.request_factories,
- directive.context.request_factories['thename'])
-
-
- def test_condition_subdomain_true(self):
- mapper = self._registerRoutesMapper()
- directive = DummyRouteDirective(static=True, explicit=True,
- condition_subdomain=True)
- self._callFUT(directive)
- self.assertEqual(len(mapper.connections), 1)
- self.assertEqual(mapper.connections[0][1],
- {'requirements': {},
- '_static':True,
- '_explicit':True,
- 'conditions':{'sub_domain':True}
- })
-
- def test_condition_function(self):
- mapper = self._registerRoutesMapper()
- def foo(e, r):
- """ """
- directive = DummyRouteDirective(static=True, explicit=True,
- condition_function=foo)
- self._callFUT(directive)
- self.assertEqual(len(mapper.connections), 1)
- self.assertEqual(mapper.connections[0][1],
- {'requirements': {},
- '_static':True,
- '_explicit':True,
- 'conditions':{'function':foo}
- })
-
- def test_condition_method(self):
- mapper = self._registerRoutesMapper()
- directive = DummyRouteDirective(static=True, explicit=True,
- condition_method='GET')
- self._callFUT(directive)
- self.assertEqual(len(mapper.connections), 1)
- self.assertEqual(mapper.connections[0][1],
- {'requirements': {},
- '_static':True,
- '_explicit':True,
- 'conditions':{'method':'GET'}
- })
-
- def test_request_type(self):
- mapper = self._registerRoutesMapper()
- directive = DummyRouteDirective(static=True, explicit=True,
- request_type='GET')
- self._callFUT(directive)
- self.assertEqual(len(mapper.connections), 1)
- self.assertEqual(mapper.connections[0][1],
- {'requirements': {},
- '_static':True,
- '_explicit':True,
- 'conditions':{'method':'GET'}
- })
-
- def test_condition_method_and_request_type(self):
- mapper = self._registerRoutesMapper()
- directive = DummyRouteDirective(static=True, explicit=True,
- request_type='GET',
- condition_method='POST')
- self._callFUT(directive)
- self.assertEqual(len(mapper.connections), 1)
- self.assertEqual(mapper.connections[0][1],
- {'requirements': {},
- '_static':True,
- '_explicit':True,
- 'conditions':{'method':'POST'}
- })
-
-
- def test_subdomains(self):
- mapper = self._registerRoutesMapper()
- directive = DummyRouteDirective(name='name',
- static=True, explicit=True,
- subdomains=['a', 'b'])
- self._callFUT(directive)
- self.assertEqual(len(mapper.connections), 1)
- self.assertEqual(mapper.connections[0][0], ('name', 'path'))
- self.assertEqual(mapper.connections[0][1],
- {'requirements': {},
- '_static':True,
- '_explicit':True,
- 'conditions':{'sub_domain':['a', 'b']}
- })
+ self._callFUT('name', 'path', 'factory')
+ self.assertEqual(mapper.connections, [('name', 'path', 'factory')])
class TestRouteDirective(unittest.TestCase):
def setUp(self):
@@ -850,48 +706,32 @@ class TestRouteDirective(unittest.TestCase):
def tearDown(self):
cleanUp()
- def _getTargetClass(self):
- from repoze.bfg.zcml import Route
- return Route
-
- def _makeOne(self, context, path, name, **kw):
- return self._getTargetClass()(context, path, name, **kw)
+ def _callFUT(self, *arg, **kw):
+ from repoze.bfg.zcml import route
+ return route(*arg, **kw)
def test_defaults(self):
+ from zope.component import getUtility
+ from repoze.bfg.interfaces import IRequestFactories
context = DummyContext()
- route = self._makeOne(context, 'path', 'name')
- self.assertEqual(route.path, 'path')
- self.assertEqual(route.name, 'name')
- self.assertEqual(route.requirements, {})
-
- def test_parent_collection_name_missing(self):
- context = DummyContext()
- from zope.configuration.exceptions import ConfigurationError
- self.assertRaises(ConfigurationError, self._makeOne, context,
- 'path', 'name', parent_member_name='a')
-
- def test_parent_collection_name_present(self):
- context = DummyContext()
- route = self._makeOne(context, 'path', 'name',
- parent_member_name='a',
- parent_collection_name='p')
- self.assertEqual(route.parent_member_name, 'a')
- self.assertEqual(route.parent_collection_name, 'p')
+ self._callFUT(context, 'name', 'path')
+ self.failUnless(getUtility(IRequestFactories, name='name'))
- def test_after_with_view(self):
+ def test_with_view(self):
+ from zope.component import getUtility
+ from repoze.bfg.interfaces import IRequestFactories
from repoze.bfg.zcml import handler
from repoze.bfg.zcml import connect_route
from repoze.bfg.interfaces import IView
context = DummyContext()
view = Dummy()
- route = self._makeOne(context, 'path', 'name', view=view)
- route.after()
+ self._callFUT(context, 'name', 'path', view=view)
actions = context.actions
self.assertEqual(len(actions), 2)
- factories = context.request_factories
- request_iface = factories['name'][None]['interface']
+ factories = getUtility(IRequestFactories, name='name')
+ request_iface = factories[None]['interface']
view_action = actions[0]
view_callable = view_action['callable']
@@ -913,31 +753,28 @@ 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), 7)
+ self.assertEqual(len(route_discriminator), 4)
self.assertEqual(route_discriminator[0], 'route')
self.assertEqual(route_discriminator[1], 'name')
- self.assertEqual(route_discriminator[2],'{}')
+ self.assertEqual(route_discriminator[2], None)
self.assertEqual(route_discriminator[3], None)
- self.assertEqual(route_discriminator[4], None)
- self.assertEqual(route_discriminator[5], None)
- self.assertEqual(route_discriminator[6], None)
- self.assertEqual(route_args, (route,))
+ self.assertEqual(route_args, ('name', 'path', None))
- def test_after_with_view_and_view_for(self):
+ def test_with_view_and_view_for(self):
+ from zope.component import getUtility
+ from repoze.bfg.interfaces import IRequestFactories
from repoze.bfg.zcml import handler
from repoze.bfg.zcml import connect_route
from repoze.bfg.interfaces import IView
context = DummyContext()
view = Dummy()
- route = self._makeOne(context, 'path', 'name', view=view,
- view_for=IDummy)
- route.after()
+ self._callFUT(context, 'name', 'path', view=view, view_for=IDummy)
actions = context.actions
self.assertEqual(len(actions), 2)
- factories = context.request_factories
- request_iface = factories['name'][None]['interface']
+ factories = getUtility(IRequestFactories, 'name')
+ request_iface = factories[None]['interface']
view_action = actions[0]
view_callable = view_action['callable']
@@ -959,23 +796,21 @@ 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), 7)
+ self.assertEqual(len(route_discriminator), 4)
self.assertEqual(route_discriminator[0], 'route')
self.assertEqual(route_discriminator[1], 'name')
- self.assertEqual(route_discriminator[2],'{}')
+ self.assertEqual(route_discriminator[2], IDummy)
self.assertEqual(route_discriminator[3], None)
- self.assertEqual(route_discriminator[4], None)
- self.assertEqual(route_discriminator[5], None)
- self.assertEqual(route_discriminator[6], None)
- self.assertEqual(route_args, (route,))
+ self.assertEqual(route_args, ('name', 'path', None,))
- def test_after_without_view(self):
+ def test_without_view(self):
+ from zope.component import getUtility
+ from repoze.bfg.interfaces import IRequestFactories
from repoze.bfg.zcml import connect_route
context = DummyContext()
view = Dummy()
- route = self._makeOne(context, 'path', 'name')
- route.after()
+ self._callFUT(context, 'name', 'path')
actions = context.actions
self.assertEqual(len(actions), 1)
@@ -984,15 +819,35 @@ 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), 7)
+ self.assertEqual(len(route_discriminator), 4)
self.assertEqual(route_discriminator[0], 'route')
self.assertEqual(route_discriminator[1], 'name')
- self.assertEqual(route_discriminator[2],'{}')
+ self.assertEqual(route_discriminator[2], None)
self.assertEqual(route_discriminator[3], None)
- self.assertEqual(route_discriminator[4], None)
- self.assertEqual(route_discriminator[5], None)
- self.assertEqual(route_discriminator[6], None)
- self.assertEqual(route_args, (route,))
+ self.assertEqual(route_args, ('name','path', None))
+
+ def test_with_request_type(self):
+ from zope.component import getUtility
+ from repoze.bfg.interfaces import IRequestFactories
+ from repoze.bfg.zcml import connect_route
+
+ context = DummyContext()
+ view = Dummy()
+ self._callFUT(context, 'name', 'path', request_type="GET")
+ actions = context.actions
+ self.assertEqual(len(actions), 1)
+
+ route_action = actions[0]
+ route_callable = route_action['callable']
+ route_discriminator = route_action['discriminator']
+ route_args = route_action['args']
+ self.assertEqual(route_callable, connect_route)
+ self.assertEqual(len(route_discriminator), 4)
+ self.assertEqual(route_discriminator[0], 'route')
+ self.assertEqual(route_discriminator[1], 'name')
+ self.assertEqual(route_discriminator[2], None)
+ self.assertEqual(route_discriminator[3], 'GET')
+ self.assertEqual(route_args, ('name','path', None))
class TestZCMLConfigure(unittest.TestCase):
i = 0
@@ -1360,44 +1215,12 @@ class DummyContext:
class Dummy:
pass
-class DummyRouteDirective:
- path = 'path'
- name = 'name'
- view = None
- view_for = None
- permission = None
- factory = None
- minimize = True
- encoding = None
- static = False
- filter = None
- absolute = False
- member_name = None
- collection_name = None
- condition_method = None
- request_type = None
- condition_subdomain = None
- condition_function = None
- parent_member_name = None
- parent_collection_name = None
- subdomains = None
- explicit = False
-
- def __init__(self, **kw):
- if not 'requirements' in kw:
- kw['requirements'] = {}
- self.__dict__.update(kw)
- self.context = DummyContext()
- self.context.request_factories = {self.name:{}}
-
class DummyMapper:
def __init__(self):
self.connections = []
- self.matchlist = []
- def connect(self, *arg, **kw):
- self.connections.append((arg, kw))
- self.matchlist.append(DummyRoute())
+ def connect(self, *args):
+ self.connections.append(args)
class DummyRoute:
pass
diff --git a/repoze/bfg/traversal.py b/repoze/bfg/traversal.py
index e15bb8f20..b79f87d4c 100644
--- a/repoze/bfg/traversal.py
+++ b/repoze/bfg/traversal.py
@@ -614,20 +614,14 @@ class TraversalContextURL(object):
route = environ['bfg.routes.route']
matchdict = environ['bfg.routes.matchdict'].copy()
matchdict['traverse'] = path
- # we can't use route.generate here because our matchdict
- # keys are Unicode
- if route.minimization:
- segments = route.generate_minimized(matchdict)
- else:
- segments = route.generate_non_minimized(matchdict)
- if segments is False:
- raise ValueError(
- "Couldn't generate URL for matchdict %r" % matchdict)
+ try:
+ segments = route.generate(matchdict)
+ except KeyError, why:
+ raise KeyError(
+ "Couldn't generate URL for matchdict %r: %s" %
+ (matchdict, str(why)))
app_url = request.application_url
- if segments.startswith('/'):
- return app_url + segments
- else:
- return app_url + '/' + segments
+ return app_url + segments
else:
app_url = request.application_url # never ends in a slash
return app_url + path
diff --git a/repoze/bfg/url.py b/repoze/bfg/url.py
index f9927c431..7f505e659 100644
--- a/repoze/bfg/url.py
+++ b/repoze/bfg/url.py
@@ -10,43 +10,88 @@ from repoze.bfg.interfaces import IRoutesMapper
from repoze.bfg.traversal import TraversalContextURL
from repoze.bfg.traversal import quote_path_segment
-from routes import URLGenerator
-from routes.util import GenerationException
-
-def route_url(request, route_name, **kw):
+def route_url(route_name, request, *elements, **kw):
"""Generates a fully qualified URL for a named BFG route.
Use the request object as the first positional argument. Use the
- route's ``name`` as the second positional argument. Use keyword
- arguments to supply values which match any dynamic path elements
- in the route definition. Raises a ValueError exception if the URL
- cannot be generated when the
+ route's ``name`` as the second positional argument. Additional
+ keyword elements are appended to the URL as path segments after it
+ is generated.
+
+ Use keyword arguments to supply values which match any dynamic
+ path elements in the route definition. Raises a KeyError
+ exception if the URL cannot be generated for any reason (not
+ enough arguments, for example).
For example, if you've defined a route named "foobar" with the path
``:foo/:bar/*traverse``::
- route_url(request, 'foobar', foo='1') => <ValueError exception>
- route_url(request, 'foobar', foo='1', bar='2') => <ValueError exception>
- route_url('foobar', foo='1', bar='2',
+ route_url('foobar', request, foo='1') => <KeyError exception>
+ route_url('foobar', request, foo='1', bar='2') => <KeyError exception>
+ route_url('foobar', request, foo='1', bar='2',
'traverse='a/b) => http://e.com/1/2/a/b
- All keys given to ``route_url`` are sent to the BFG Routes "mapper"
- instance for generation except for::
-
- anchor specifies the anchor name to be appened to the path
- host overrides the default host if provided
- protocol overrides the default (current) protocol if provided
- qualified return a fully qualified URL (default True)
+ If a keyword argument ``_query`` is present, it will used to
+ compose a query string that will be tacked on to the end of the
+ URL. The value of ``query`` must be a sequence of two-tuples *or*
+ a data structure with an ``.items()`` method that returns a
+ sequence of two-tuples (presumably a dictionary). This data
+ structure will be turned into a query string per the documentation
+ of ``repoze.url.urlencode`` function. After the query data is
+ turned into a query string, a leading ``?`` is prepended, and the
+ the resulting string is appended to the generated URL.
+ .. note:: Python data structures that are passed as ``_query``
+ which are sequences or dictionaries are turned into a
+ string under the same rules as when run through
+ urllib.urlencode with the ``doseq`` argument equal to
+ ``True``. This means that sequences can be passed as
+ values, and a k=v pair will be placed into the query
+ string for each value.
+
+ If a keyword argument ``_anchor`` is present, its string
+ representation will be used as a named anchor in the generated URL
+ (e.g. if ``anchor`` is passed as ``foo`` and the model URL is
+ ``http://example.com/model/url``, the resulting generated URL will
+ be ``http://example.com/model/url#foo``).
+
+ .. note:: If ``_anchor`` is passed as a string, it should be UTF-8
+ encoded. If ``anchor`` is passed as a Unicode object, it
+ will be converted to UTF-8 before being appended to the
+ URL. The anchor value is not quoted in any way before
+ being appended to the generated URL.
+
+ If both ``anchor`` and ``query`` are specified, the anchor element
+ will always follow the query element,
+ e.g. ``http://example.com?foo=1#bar``.
+
+ This function raises a ``KeyError`` if the route cannot be
+ generated due to missing replacement names. Extra replacement
+ names are ignored.
"""
- if not 'qualified' in kw:
- kw['qualified'] = True
- try:
- mapper = getUtility(IRoutesMapper)
- generator = URLGenerator(mapper, request.environ)
- return generator(route_name, **kw)
- except GenerationException, why:
- raise ValueError(str(why))
+ mapper = getUtility(IRoutesMapper)
+ path = mapper.generate(route_name, kw) # raises KeyError if generate fails
+
+ anchor = ''
+ qs = ''
+
+ if '_query' in kw:
+ qs = '?' + urlencode(kw['_query'], doseq=True)
+
+ if '_anchor' in kw:
+ anchor = kw['_anchor']
+ if isinstance(anchor, unicode):
+ anchor = anchor.encode('utf-8')
+ anchor = '#' + anchor
+
+ if elements:
+ suffix = '/'.join([quote_path_segment(s) for s in elements])
+ if not path.endswith('/'):
+ suffix = '/' + suffix
+ else:
+ suffix = ''
+
+ return request.application_url + path + suffix + qs + anchor
def model_url(model, request, *elements, **kw):
"""
diff --git a/repoze/bfg/urldispatch.py b/repoze/bfg/urldispatch.py
index 0281b52b3..497d3980e 100644
--- a/repoze/bfg/urldispatch.py
+++ b/repoze/bfg/urldispatch.py
@@ -1,53 +1,102 @@
-from routes import Mapper
-from routes import request_config
+import re
_marker = object()
-class RoutesRootFactory(Mapper):
- def __init__(self, default_root_factory, **kw):
+class Route(object):
+ def __init__(self, name, matcher, generator, factory):
+ self.name = name
+ self.matcher = matcher
+ self.generator = generator
+ self.factory = factory
+
+ def match(self, path):
+ return self.matcher(path)
+
+ def generate(self, kw):
+ return self.generator(kw)
+
+class RoutesRootFactory(object):
+ def __init__(self, default_root_factory):
self.default_root_factory = default_root_factory
- kw['controller_scan'] = None
- kw['always_scan'] = False
- kw['directory'] = None
- kw['explicit'] = True
- Mapper.__init__(self, **kw)
- self._regs_created = False
+ self.routelist = []
+ self.routes = {}
def has_routes(self):
- return bool(self.matchlist)
+ return bool(self.routelist)
- def connect(self, *arg, **kw):
- result = Mapper.connect(self, *arg, **kw)
- route = self.matchlist[-1]
- route._factory = None # overridden by ZCML
- return result
+ def connect(self, name, path, factory=None):
+ matcher, generator = _compile_route(path)
+ route = Route(name, matcher, generator, factory)
+ self.routelist.append(route)
+ self.routes[name] = route
+ return route
+
+ def generate(self, name, kw):
+ return self.routes[name].generate(kw)
def __call__(self, environ):
- if not self._regs_created:
- self.create_regs([])
- self._regs_created = True
path = environ.get('PATH_INFO', '/')
- self.environ = environ # sets the thread local
- match = self.routematch(path)
- if match:
- args, route = match
- else:
- args = None
- if isinstance(args, dict): # might be an empty dict
- args = args.copy()
- config = request_config()
- config.mapper = self
- config.mapper_dict = args
- config.host = environ.get('HTTP_HOST', environ['SERVER_NAME'])
- config.protocol = environ['wsgi.url_scheme']
- config.redirect = None
- environ['wsgiorg.routing_args'] = ((), args)
- environ['bfg.routes.route'] = route
- environ['bfg.routes.matchdict'] = args
- adhoc_attrs = environ.setdefault('webob.adhoc_attrs', {})
- adhoc_attrs['matchdict'] = args
- factory = route._factory or self.default_root_factory
- return factory(environ)
+ for route in self.routelist:
+ match = route.match(path)
+ if match is not None:
+ environ['wsgiorg.routing_args'] = ((), match)
+ environ['bfg.routes.route'] = route
+ environ['bfg.routes.matchdict'] = match
+ adhoc_attrs = environ.setdefault('webob.adhoc_attrs', {})
+ adhoc_attrs['matchdict'] = match
+ factory = route.factory or self.default_root_factory
+ return factory(environ)
return self.default_root_factory(environ)
+# stolen from bobo and modified
+route_re = re.compile(r'(/:[a-zA-Z]\w*)')
+def _compile_route(route):
+ if not route.startswith('/'):
+ route = '/' + route
+ star = None
+ if '*' in route:
+ route, star = route.rsplit('*', 1)
+ pat = route_re.split(route)
+ pat.reverse()
+ rpat = []
+ gen = []
+ prefix = pat.pop()
+ if prefix:
+ rpat.append(re.escape(prefix))
+ gen.append(prefix)
+ while pat:
+ name = pat.pop()
+ name = name[2:]
+ gen.append('/%%(%s)s' % name)
+ name = '/(?P<%s>[^/]*)' % name
+ rpat.append(name)
+ s = pat.pop()
+ if s:
+ rpat.append(re.escape(s))
+ gen.append(s)
+
+ if star:
+ rpat.append('(?P<%s>.*?)' % star)
+ gen.append('%%(%s)s' % star)
+
+ pattern = ''.join(rpat) + '$'
+
+ match = re.compile(pattern).match
+ def matcher(path):
+ m = match(path)
+ if m is None:
+ return m
+ return dict(item for item in m.groupdict().iteritems()
+ if item[1] is not None)
+
+ gen = ''.join(gen)
+ def generator(dict):
+ newdict = {}
+ for k, v in dict.items():
+ if isinstance(v, unicode):
+ v = v.encode('utf-8')
+ newdict[k] = v
+ return gen % newdict
+
+ return matcher, generator
diff --git a/repoze/bfg/zcml.py b/repoze/bfg/zcml.py
index 8d842fbfa..786301c45 100644
--- a/repoze/bfg/zcml.py
+++ b/repoze/bfg/zcml.py
@@ -4,18 +4,16 @@ import types
from zope.configuration import xmlconfig
from zope.component import getSiteManager
+from zope.component import getUtility
from zope.component import queryUtility
import zope.configuration.config
from zope.configuration.exceptions import ConfigurationError
from zope.configuration.fields import GlobalObject
-from zope.configuration.fields import Tokens
from zope.interface import Interface
-from zope.interface import implements
-from zope.schema import Bool
from zope.schema import TextLine
from repoze.bfg.interfaces import IRoutesMapper
@@ -28,6 +26,7 @@ from repoze.bfg.interfaces import ISecurityPolicy
from repoze.bfg.interfaces import IView
from repoze.bfg.interfaces import IUnauthorizedAppFactory
from repoze.bfg.interfaces import ILogger
+from repoze.bfg.interfaces import IRequestFactories
from repoze.bfg.request import DEFAULT_REQUEST_FACTORIES
from repoze.bfg.request import named_request_factories
@@ -60,9 +59,8 @@ def view(
if route_name is None:
request_factories = DEFAULT_REQUEST_FACTORIES
else:
- try:
- request_factories = _context.request_factories[route_name]
- except (KeyError, AttributeError):
+ request_factories = queryUtility(IRequestFactories, name=route_name)
+ if request_factories is None:
raise ConfigurationError(
'Unknown route_name "%s". <route> definitions must be ordered '
'before the view definition which mentions the route\'s name '
@@ -94,6 +92,8 @@ def view(
derived_view, (for_, request_type), IView, name, _context.info),
)
+_view = view # for directives that take a view arg
+
def view_utility(_context, view, iface):
derived_view = derive_view(view)
_context.action(
@@ -164,145 +164,28 @@ class IRouteDirective(Interface):
view_for = GlobalObject(title=u'view_for', required=False)
permission = TextLine(title=u'permission', required=False)
factory = GlobalObject(title=u'context factory', required=False)
- minimize = Bool(title=u'minimize', required=False)
- encoding = TextLine(title=u'encoding', required=False)
- static = Bool(title=u'static', required=False)
- filter = GlobalObject(title=u'filter', required=False)
- absolute = Bool(title=u'absolute', required=False)
- member_name = TextLine(title=u'member_name', required=False)
- collection_name = TextLine(title=u'collection_name', required=False)
request_type = TextLine(title=u'request_type', required=False)
- condition_method = TextLine(title=u'condition_method', required=False)
- condition_subdomain = TextLine(title=u'condition_subdomain', required=False)
- condition_function = GlobalObject(title=u'condition_function',
- required=False)
- parent_member_name = TextLine(title=u'parent member_name', required=False)
- parent_collection_name = TextLine(title=u'parent collection_name',
- required=False)
- explicit = Bool(title=u'explicit', required=False)
- subdomains = Tokens(title=u'subdomains', required=False,
- value_type=TextLine())
-
-class Route(zope.configuration.config.GroupingContextDecorator):
+
+def route(_context, name, path, view=None, view_for=None, permission=None,
+ factory=None, request_type=None):
""" Handle ``route`` ZCML directives
"""
- view = None
- view_for = None
- permission = None
- factory = None
- minimize = True
- encoding = None
- static = False
- filter = None
- absolute = False
- member_name = None
- collection_name = None
- condition_method = None
- request_type = None
- condition_subdomain = None
- condition_function = None
- parent_member_name = None
- parent_collection_name = None
- subdomains = None
- explicit = False
-
- implements(zope.configuration.config.IConfigurationContext,
- IRouteDirective)
-
- def __init__(self, context, path, name, **kw):
- self.validate(**kw)
- self.requirements = {} # mutated by subdirectives
- self.context = context
- self.path = path
- self.name = name
- self.__dict__.update(**kw)
-
- def validate(self, **kw):
- parent_member_name = kw.get('parent_member_name')
- parent_collection_name = kw.get('parent_collection_name')
- if parent_member_name or parent_collection_name:
- if not (parent_member_name and parent_collection_name):
- raise ConfigurationError(
- 'parent_member_name and parent_collection_name must be '
- 'specified together')
-
- def after(self):
- context = self.context
- name = self.name
- if not hasattr(context, 'request_factories'):
- context.request_factories = {}
- context.request_factories[name] = named_request_factories(name)
-
- if self.view:
- view(context, self.permission, self.view_for, self.view, '',
- self.request_type, name)
-
- method = self.condition_method or self.request_type
-
- self.context.action(
- discriminator = ('route', self.name, repr(self.requirements),
- method, self.condition_subdomain,
- self.condition_function, self.subdomains),
- callable = connect_route,
- args = (self,),
- )
+ sm = getSiteManager()
+ request_factories = named_request_factories(name)
+ sm.registerUtility(request_factories, IRequestFactories, name=name)
+
+ if view:
+ _view(_context, permission, view_for, view, '', request_type, name)
+
+ _context.action(
+ discriminator = ('route', name, view_for, request_type),
+ callable = connect_route,
+ args = (name, path, factory),
+ )
-def route_requirement(context, attr, expr):
- route = context.context
- if attr in route.requirements:
- raise ValueError('Duplicate requirement', attr)
- route.requirements[attr] = expr
-
-def connect_route(directive):
- mapper = queryUtility(IRoutesMapper)
- if mapper is None:
- return
- args = [directive.name, directive.path]
- kw = dict(requirements=directive.requirements)
- if not directive.minimize:
- kw['_minimize'] = False
- if directive.explicit:
- kw['_explicit'] = True
- if directive.encoding:
- kw['_encoding'] = directive.encoding
- if directive.static:
- kw['_static'] = True
- if directive.filter:
- kw['_filter'] = directive.filter
- if directive.absolute:
- kw['_absolute'] = True
- if directive.member_name:
- kw['_member_name'] = directive.member_name
- if directive.collection_name:
- kw['_collection_name'] = directive.collection_name
- if directive.parent_member_name and directive.parent_collection_name:
- kw['_parent_resource'] = {
- 'member_name':directive.parent_member_name,
- 'collection_name':directive.parent_collection_name,
- }
- conditions = {}
-
- # request_type and condition_method are aliases; condition_method
- # "wins"
- if directive.request_type:
- conditions['method'] = directive.request_type
- if directive.condition_method:
- conditions['method'] = directive.condition_method
- if directive.condition_subdomain:
- conditions['sub_domain'] = directive.condition_subdomain
- if directive.condition_function:
- conditions['function'] = directive.condition_function
- if directive.subdomains:
- conditions['sub_domain'] = directive.subdomains
- if conditions:
- kw['conditions'] = conditions
-
- result = mapper.connect(*args, **kw)
- route = mapper.matchlist[-1]
- route._factory = directive.factory
- context = directive.context
- route.request_factories = context.request_factories[directive.name]
- return result
+def connect_route(name, path, factory):
+ mapper = getUtility(IRoutesMapper)
+ mapper.connect(name, path, factory)
class IViewDirective(Interface):
for_ = GlobalObject(
diff --git a/setup.py b/setup.py
index 766015d42..e10ed2ae2 100644
--- a/setup.py
+++ b/setup.py
@@ -33,7 +33,6 @@ install_requires=[
'chameleon.core >= 1.0b32', # non-lxml version
'chameleon.zpt >= 1.0b16', # newest version as of non-xml core release
'PasteScript',
- 'Routes',
'WebOb',
'zope.interface >= 3.5.1', # 3.5.0 comment: "allow to bootstrap on jython"
'zope.component >= 3.6.0', # independent of zope.hookable