diff options
| author | Chris McDonough <chrism@agendaless.com> | 2009-10-30 18:56:58 +0000 |
|---|---|---|
| committer | Chris McDonough <chrism@agendaless.com> | 2009-10-30 18:56:58 +0000 |
| commit | 11644e705834ff65cb8963333855a1db6272ae1e (patch) | |
| tree | 6730225c3c81d52263f37ceac0876b11a57865ae /repoze | |
| parent | 1b2d8e7326cd1eaa95b3522d985e97642764c7c8 (diff) | |
| download | pyramid-11644e705834ff65cb8963333855a1db6272ae1e.tar.gz pyramid-11644e705834ff65cb8963333855a1db6272ae1e.tar.bz2 pyramid-11644e705834ff65cb8963333855a1db6272ae1e.zip | |
Features
--------
- In previous versions of BFG, the "root factory" (the ``get_root``
callable passed to ``make_app`` or a function pointed to by the
``factory`` attribute of a route) was called with a "bare" WSGI
environment. In this version, and going forward, it will be called
with a ``request`` object. The request object passed to the factory
implements dictionary-like methods in such a way that existing root
factory code which expects to be passed an environ will continue to
work.
Internal
--------
- The request implements dictionary-like methods that mutate and query
the WSGI environ. This is only for the purpose of backwards
compatibility with root factories which expect an ``environ`` rather
than a request.
- The ``repoze.bfg.request.create_route_request_factory`` function,
which returned a request factory was removed in favor of a
``repoze.bfg.request.route_request_interface`` function, which
returns an interface.
- The ``repoze.bfg.request.Request`` class, which is a subclass of
``webob.Request`` now defines its own ``__setattr__``,
``__getattr__`` and ``__delattr__`` methods, which override the
default WebOb behavior. The default WebOb behavior stores
attributes of the request in ``self.environ['webob.adhoc_attrs']``,
and retrieves them from that dictionary during a ``__getattr__``.
This behavior was undesirable for speed and "expectation" reasons.
Now attributes of the ``request`` are stored in ``request.__dict__``
(as you otherwise might expect from an object that did not override
these methods).
- Reverse the order in which the router calls the request factory and
the root factory. The request factory is now called first; the
resulting request is passed to the root factory.
- The ``repoze.bfg.request.request_factory`` function has been
removed. Its functionality is no longer required.
- The "routes root factory" that wraps the default root factory when
there are routes mentioned in the configuration now attaches an
interface to the request via ``zope.interface.directlyProvides``.
This replaces logic in the (now-gone)
``repoze.bfg.request.request_factory`` function.
- The ``route`` and ``view`` ZCML directives now register an interface
as a named utility (retrieved from
``repoze.bfg.request.route_request_interface``) rather than a
request factory (the previous return value of the now-missing
``repoze.bfg.request.create_route_request_factory``.
Diffstat (limited to 'repoze')
| -rw-r--r-- | repoze/bfg/request.py | 80 | ||||
| -rw-r--r-- | repoze/bfg/router.py | 9 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_request.py | 168 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_urldispatch.py | 78 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_zcml.py | 77 | ||||
| -rw-r--r-- | repoze/bfg/urldispatch.py | 32 | ||||
| -rw-r--r-- | repoze/bfg/zcml.py | 16 |
7 files changed, 286 insertions, 174 deletions
diff --git a/repoze/bfg/request.py b/repoze/bfg/request.py index e81710ae1..751d1fba1 100644 --- a/repoze/bfg/request.py +++ b/repoze/bfg/request.py @@ -24,29 +24,63 @@ class Request(WebobRequest): __setattr__ = object.__setattr__ __delattr__ = object.__delattr__ -def request_factory(environ): - if 'bfg.routes.route' in environ: - route = environ['bfg.routes.route'] - factory = queryUtility(IRouteRequest, name=route.name) - if factory is not None: - request = factory(environ) - request.matchdict = environ['bfg.routes.matchdict'] - return request - return Request(environ) - -def create_route_request_factory(name): - iface = InterfaceClass('%s_IRequest' % name, (IRouteRequest,)) - - class RouteRequest(WebobRequest): - implements(iface) - charset = 'utf-8' - - # override default WebOb "environ['adhoc_attr']" mutation behavior - __getattr__ = object.__getattribute__ - __setattr__ = object.__setattr__ - __delattr__ = object.__delattr__ - - return RouteRequest + # b/c dict interface for "root factory" code that expects a bare + # environ. Explicitly omitted dict methods: clear (unnecessary), + # copy (implemented by WebOb), fromkeys (unnecessary) + + def __contains__(self, k): + return self.environ.__contains__(k) + + def __delitem__(self, k): + return self.environ.__delitem__(k) + + def __getitem__(self, k): + return self.environ.__getitem__(k) + + def __iter__(self): + return iter(self.environ) + + def __setitem__(self, k, v): + self.environ[k] = v + + def get(self, k, default=None): + return self.environ.get(k, default) + + def has_key(self, k): + return self.environ.has_key(k) + + def items(self): + return self.environ.items() + + def iteritems(self): + return self.environ.iteritems() + + def iterkeys(self): + return self.environ.iterkeys() + + def itervalues(self): + return self.environ.itervalues() + + def keys(self): + return self.environ.keys() + + def pop(self, k): + return self.environ.pop(k) + + def popitem(self): + return self.environ.popitem() + + def setdefault(self, v, default): + return self.environ.setdefault(v, default) + + def update(self, v, **kw): + return self.environ.update(v, **kw) + + def values(self): + return self.environ.values() + +def route_request_iface(name): + return InterfaceClass('%s_IRequest' % name, (IRouteRequest,)) def add_global_response_headers(request, headerlist): attrs = request.__dict__ diff --git a/repoze/bfg/router.py b/repoze/bfg/router.py index 5f5214c10..3916d6627 100644 --- a/repoze/bfg/router.py +++ b/repoze/bfg/router.py @@ -19,7 +19,7 @@ from repoze.bfg.events import NewResponse from repoze.bfg.events import WSGIApplicationCreatedEvent from repoze.bfg.exceptions import Forbidden from repoze.bfg.exceptions import NotFound -from repoze.bfg.request import request_factory +from repoze.bfg.request import Request from repoze.bfg.threadlocal import manager from repoze.bfg.traversal import ModelGraphTraverser from repoze.bfg.view import default_forbidden_view @@ -60,14 +60,13 @@ class Router(object): manager.push(threadlocals) try: - root = self.root_factory(environ) - request = request_factory(environ) - + request = Request(environ) + threadlocals['request'] = request attrs = request.__dict__ attrs['registry'] = registry + root = self.root_factory(request) attrs['root'] = root - threadlocals['request'] = request registry.has_listeners and registry.notify(NewRequest(request)) traverser = registry.queryAdapter(root, ITraverser) if traverser is None: diff --git a/repoze/bfg/tests/test_request.py b/repoze/bfg/tests/test_request.py index 8c868fcf5..2ecb060cc 100644 --- a/repoze/bfg/tests/test_request.py +++ b/repoze/bfg/tests/test_request.py @@ -1,5 +1,4 @@ import unittest -from repoze.bfg.testing import cleanUp class TestMakeRequestASCII(unittest.TestCase): def _callFUT(self, event): @@ -12,10 +11,14 @@ class TestMakeRequestASCII(unittest.TestCase): self._callFUT(event) self.assertEqual(request.charset, None) -class RequestTestBase(object): +class TestRequest(unittest.TestCase): def _makeOne(self, environ): - request = self._getTargetClass()(environ) - return request + return self._getTargetClass()(environ) + + def _getTargetClass(self): + from repoze.bfg.request import Request + return Request + def test_params_decoded_from_utf_8_by_default(self): environ = { @@ -44,64 +47,114 @@ class RequestTestBase(object): inst = self._makeOne({}) self.assertTrue(IRequest.providedBy(inst)) -class TestRequest(unittest.TestCase, RequestTestBase): - def _getTargetClass(self): - from repoze.bfg.request import Request - return Request - -class TestRouteRequest(unittest.TestCase, RequestTestBase): - def _getTargetClass(self): - from repoze.bfg.request import create_route_request_factory - return create_route_request_factory('abc') - -class TestRequestFactory(unittest.TestCase): - def setUp(self): - cleanUp() - - def tearDown(self): - cleanUp() + def test___contains__(self): + environ ={'zooma':1} + inst = self._makeOne(environ) + self.failUnless('zooma' in inst) + + def test___delitem__(self): + environ = {'zooma':1} + inst = self._makeOne(environ) + del inst['zooma'] + self.failIf('zooma' in environ) + + def test___getitem__(self): + environ = {'zooma':1} + inst = self._makeOne(environ) + self.assertEqual(inst['zooma'], 1) + + def test___iter__(self): + environ = {'zooma':1} + inst = self._makeOne(environ) + iterator = iter(inst) + self.assertEqual(list(iterator), list(iter(environ))) + + def test___setitem__(self): + environ = {} + inst = self._makeOne(environ) + inst['zooma'] = 1 + self.assertEqual(environ, {'zooma':1}) + + def test_get(self): + environ = {'zooma':1} + inst = self._makeOne(environ) + self.assertEqual(inst.get('zooma'), 1) - def _callFUT(self, environ): - from repoze.bfg.request import request_factory - return request_factory(environ) - - def test_it_no_route(self): - from repoze.bfg.interfaces import IRequest - from repoze.bfg.request import Request - result = self._callFUT({}) - self.assertEqual(result.__class__, Request) - self.failUnless(IRequest.providedBy(result)) - - def test_it_with_route_found(self): - from zope.component import getSiteManager - from repoze.bfg.interfaces import IRouteRequest - sm = getSiteManager() - sm.registerUtility(DummyRequest, IRouteRequest, 'routename') - route = DummyRoute('routename') - result = self._callFUT({'bfg.routes.route':route, - 'bfg.routes.matchdict':{'match':'1'}}) - self.assertEqual(result.__class__, DummyRequest) - self.assertEqual(result.matchdict, {'match':'1'}) - - def test_it_with_route_notfound(self): - from repoze.bfg.request import Request - route = DummyRoute('routename') - result = self._callFUT({'bfg.routes.route':route, - 'bfg.routes.matchdict':{'match':'1'}}) - self.assertEqual(result.__class__, Request) - self.failIf(getattr(result, 'matchdict', None) is not None) - -class Test_create_route_request_factory(unittest.TestCase): + def test_has_key(self): + environ = {'zooma':1} + inst = self._makeOne(environ) + self.assertEqual(inst.has_key('zooma'), True) + + def test_items(self): + environ = {'zooma':1} + inst = self._makeOne(environ) + self.assertEqual(inst.items(), environ.items()) + + def test_iteritems(self): + environ = {'zooma':1} + inst = self._makeOne(environ) + self.assertEqual(list(inst.iteritems()), list(environ.iteritems())) + + def test_iterkeys(self): + environ = {'zooma':1} + inst = self._makeOne(environ) + self.assertEqual(list(inst.iterkeys()), list(environ.iterkeys())) + + def test_itervalues(self): + environ = {'zooma':1} + inst = self._makeOne(environ) + self.assertEqual(list(inst.itervalues()), list(environ.itervalues())) + + def test_keys(self): + environ = {'zooma':1} + inst = self._makeOne(environ) + self.assertEqual(inst.keys(), environ.keys()) + + def test_pop(self): + environ = {'zooma':1} + inst = self._makeOne(environ) + popped = inst.pop('zooma') + self.assertEqual(environ, {}) + self.assertEqual(popped, 1) + + def test_popitem(self): + environ = {'zooma':1} + inst = self._makeOne(environ) + popped = inst.popitem() + self.assertEqual(environ, {}) + self.assertEqual(popped, ('zooma', 1)) + + def test_setdefault(self): + environ = {} + inst = self._makeOne(environ) + marker = [] + result = inst.setdefault('a', marker) + self.assertEqual(environ, {'a':marker}) + self.assertEqual(result, marker) + + def test_update(self): + environ = {} + inst = self._makeOne(environ) + inst.update({'a':1}, b=2) + self.assertEqual(environ, {'a':1, 'b':2}) + + def test_values(self): + environ = {'zooma':1} + inst = self._makeOne(environ) + result = inst.values() + self.assertEqual(result, environ.values()) + +class Test_route_request_iface(unittest.TestCase): def _callFUT(self, name): - from repoze.bfg.request import create_route_request_factory - return create_route_request_factory(name) + from repoze.bfg.request import route_request_iface + return route_request_iface(name) def test_it(self): from repoze.bfg.interfaces import IRouteRequest from repoze.bfg.interfaces import IRequest - factory = self._callFUT('routename') - self.failUnless(IRouteRequest.implementedBy(factory)) - self.failUnless(IRequest.implementedBy(factory)) + iface = self._callFUT('routename') + self.failUnless(iface.extends(IRouteRequest)) + self.failUnless(iface.extends(IRequest)) class Test_add_global_response_headers(unittest.TestCase): def _callFUT(self, request, headerlist): @@ -115,9 +168,6 @@ class Test_add_global_response_headers(unittest.TestCase): self._callFUT(request, [('c', 1)]) self.assertEqual(request.global_response_headers, headers + [('c', 1)]) -class DummyRoute: - def __init__(self, name): - self.name = name class DummyRequest: def __init__(self, environ=None): if environ is None: diff --git a/repoze/bfg/tests/test_urldispatch.py b/repoze/bfg/tests/test_urldispatch.py index c7a6c7ff3..99d5d1a98 100644 --- a/repoze/bfg/tests/test_urldispatch.py +++ b/repoze/bfg/tests/test_urldispatch.py @@ -1,5 +1,5 @@ import unittest -from repoze.bfg.testing import cleanUp +from repoze.bfg import testing class TestRoute(unittest.TestCase): def _getTargetClass(self): @@ -37,16 +37,30 @@ class TestRoute(unittest.TestCase): class RoutesRootFactoryTests(unittest.TestCase): def setUp(self): - cleanUp() + testing.setUp() def tearDown(self): - cleanUp() + testing.tearDown() - def _getEnviron(self, **kw): + def _getRequest(self, **kw): + from zope.component import getSiteManager environ = {'SERVER_NAME':'localhost', 'wsgi.url_scheme':'http'} environ.update(kw) - return environ + request = DummyRequest(environ) + sm = getSiteManager() + request.registry = sm + return request + + def _registerRouteRequest(self, name): + from repoze.bfg.interfaces import IRouteRequest + from zope.interface import Interface + from zope.component import getSiteManager + class IRequest(Interface): + """ """ + sm = getSiteManager() + sm.registerUtility(IRequest, IRouteRequest, name=name) + return IRequest def _getTargetClass(self): from repoze.bfg.urldispatch import RoutesRootFactory @@ -61,61 +75,80 @@ class RoutesRootFactoryTests(unittest.TestCase): self.assertEqual(mapper.default_root_factory, None) def test_no_route_matches(self): - get_root = DummyRootFactory(123) - mapper = self._makeOne(get_root) - environ = self._getEnviron(PATH_INFO='/') - result = mapper(environ) + root_factory = DummyRootFactory(123) + mapper = self._makeOne(root_factory) + request = self._getRequest(PATH_INFO='/') + result = mapper(request) + self.assertEqual(result, 123) + + def test_passed_environ_returns_default(self): + root_factory = DummyRootFactory(123) + mapper = self._makeOne(root_factory) + request = self._getRequest(PATH_INFO='/') + result = mapper(request.environ) self.assertEqual(result, 123) def test_route_matches(self): - get_root = DummyRootFactory(123) - mapper = self._makeOne(get_root) + root_factory = DummyRootFactory(123) + req_iface = self._registerRouteRequest('foo') + mapper = self._makeOne(root_factory) mapper.connect('archives/:action/:article', 'foo') - environ = self._getEnviron(PATH_INFO='/archives/action1/article1') - result = mapper(environ) + 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_root_route_matches(self): root_factory = DummyRootFactory(123) + req_iface = self._registerRouteRequest('root') mapper = self._makeOne(root_factory) mapper.connect('', 'root') - environ = self._getEnviron(PATH_INFO='/') - result = mapper(environ) + request = self._getRequest(PATH_INFO='/') + result = mapper(request) + environ = request.environ self.assertEqual(result, 123) self.assertEqual(environ['bfg.routes.route'].name, 'root') self.assertEqual(environ['bfg.routes.matchdict'], {}) self.assertEqual(environ['wsgiorg.routing_args'], ((), {})) + self.assertEqual(request.matchdict, {}) + self.failUnless(req_iface.providedBy(request)) def test_root_route_matches2(self): root_factory = DummyRootFactory(123) + req_iface = self._registerRouteRequest('root') mapper = self._makeOne(root_factory) mapper.connect('/', 'root') - environ = self._getEnviron(PATH_INFO='/') - result = mapper(environ) + request = self._getRequest(PATH_INFO='/') + result = mapper(request) + environ = request.environ self.assertEqual(result, 123) self.assertEqual(environ['bfg.routes.route'].name, 'root') self.assertEqual(environ['bfg.routes.matchdict'], {}) self.assertEqual(environ['wsgiorg.routing_args'], ((), {})) + self.assertEqual(request.matchdict, {}) + self.failUnless(req_iface.providedBy(request)) def test_fallback_to_default_root_factory(self): root_factory = DummyRootFactory(123) mapper = self._makeOne(root_factory) mapper.connect('wont/:be/:found', 'wont') - environ = self._getEnviron(PATH_INFO='/archives/action1/article1') - result = mapper(environ) + request = self._getRequest(PATH_INFO='/archives/action1/article1') + result = mapper(request) self.assertEqual(result, 123) def test_no_path_info(self): root_factory = DummyRootFactory(123) mapper = self._makeOne(root_factory) mapper.connect('/', 'root') - environ = self._getEnviron() - result = mapper(environ) + request = self._getRequest() + result = mapper(request) self.assertEqual(result, 123) def test_has_routes(self): @@ -230,7 +263,8 @@ class DummyContext(object): """ """ class DummyRequest(object): - """ """ + def __init__(self, environ): + self.environ = environ class DummyRoute(object): def __init__(self, generator): diff --git a/repoze/bfg/tests/test_zcml.py b/repoze/bfg/tests/test_zcml.py index 352a53e53..8106baa03 100644 --- a/repoze/bfg/tests/test_zcml.py +++ b/repoze/bfg/tests/test_zcml.py @@ -517,7 +517,6 @@ class TestViewDirective(unittest.TestCase): def test_with_route_name(self): from zope.interface import Interface - from zope.interface import implementedBy from zope.component import getSiteManager from repoze.bfg.interfaces import IView from repoze.bfg.interfaces import IRouteRequest @@ -534,13 +533,12 @@ class TestViewDirective(unittest.TestCase): register = action['callable'] register() sm = getSiteManager() - factory = sm.getUtility(IRouteRequest, 'foo') - request_type = implementedBy(factory) + request_type = sm.getUtility(IRouteRequest, 'foo') discrim = ('view', IFoo, '', request_type, IView, None, None, None, 'foo', None, False, None, None, None) self.assertEqual(action['discriminator'], discrim) the_view = sm.adapters.lookup((IFoo, request_type), IView, name='') - request = factory({}) + request = DummyRequest({}) self.assertEqual(the_view(None, request), '123') def test_with_request_method_true(self): @@ -1591,7 +1589,6 @@ class TestRouteDirective(unittest.TestCase): def test_with_view(self): from zope.interface import Interface - from zope.interface import implementedBy from zope.component import getSiteManager from repoze.bfg.interfaces import IRouteRequest from repoze.bfg.zcml import connect_route @@ -1608,8 +1605,7 @@ class TestRouteDirective(unittest.TestCase): register = view_action['callable'] register() sm = getSiteManager() - request_factory = sm.getUtility(IRouteRequest, 'name') - request_type = implementedBy(request_factory) + 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, None) @@ -1633,7 +1629,6 @@ class TestRouteDirective(unittest.TestCase): def test_with_view_and_view_for(self): from zope.component import getSiteManager - from zope.interface import implementedBy from repoze.bfg.zcml import connect_route from repoze.bfg.interfaces import IView from repoze.bfg.interfaces import IRouteRequest @@ -1649,8 +1644,7 @@ class TestRouteDirective(unittest.TestCase): register = view_action['callable'] register() sm = getSiteManager() - request_factory = sm.getUtility(IRouteRequest, 'name') - request_type = implementedBy(request_factory) + request_type = sm.getUtility(IRouteRequest, 'name') view_discriminator = view_action['discriminator'] discrim = ('view', IDummy, '', request_type, IView, None, None, None, 'name', None, False, None, None, None) @@ -1688,7 +1682,6 @@ class TestRouteDirective(unittest.TestCase): def test_with_view_request_type(self): from zope.component import getSiteManager - from zope.interface import implementedBy from repoze.bfg.zcml import connect_route from repoze.bfg.interfaces import IView from repoze.bfg.interfaces import IRouteRequest @@ -1705,8 +1698,7 @@ class TestRouteDirective(unittest.TestCase): register = view_action['callable'] register() sm = getSiteManager() - request_factory = sm.getUtility(IRouteRequest, 'name') - request_type = implementedBy(request_factory) + 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) @@ -1726,7 +1718,6 @@ class TestRouteDirective(unittest.TestCase): def test_with_view_request_type_alias(self): from zope.component import getSiteManager - from zope.interface import implementedBy from repoze.bfg.zcml import connect_route from repoze.bfg.interfaces import IView from repoze.bfg.interfaces import IRouteRequest @@ -1742,8 +1733,7 @@ class TestRouteDirective(unittest.TestCase): register = view_action['callable'] register() sm = getSiteManager() - request_factory = sm.getUtility(IRouteRequest, 'name') - request_type = implementedBy(request_factory) + 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) @@ -1763,7 +1753,6 @@ class TestRouteDirective(unittest.TestCase): def test_with_view_request_method(self): from zope.component import getSiteManager - from zope.interface import implementedBy from repoze.bfg.zcml import connect_route from repoze.bfg.interfaces import IView from repoze.bfg.interfaces import IRouteRequest @@ -1780,8 +1769,7 @@ class TestRouteDirective(unittest.TestCase): register = view_action['callable'] register() sm = getSiteManager() - request_factory = sm.getUtility(IRouteRequest, 'name') - request_type = implementedBy(request_factory) + 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) @@ -1801,7 +1789,6 @@ class TestRouteDirective(unittest.TestCase): def test_with_view_request_method_alias(self): from zope.component import getSiteManager - from zope.interface import implementedBy from repoze.bfg.zcml import connect_route from repoze.bfg.interfaces import IView from repoze.bfg.interfaces import IRouteRequest @@ -1817,8 +1804,8 @@ class TestRouteDirective(unittest.TestCase): register = view_action['callable'] register() sm = getSiteManager() - request_factory = sm.getUtility(IRouteRequest, 'name') - request_type = implementedBy(request_factory) + 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) @@ -1838,7 +1825,6 @@ class TestRouteDirective(unittest.TestCase): def test_with_view_containment(self): from zope.component import getSiteManager - from zope.interface import implementedBy from repoze.bfg.zcml import connect_route from repoze.bfg.interfaces import IView from repoze.bfg.interfaces import IRouteRequest @@ -1854,8 +1840,7 @@ class TestRouteDirective(unittest.TestCase): register = view_action['callable'] register() sm = getSiteManager() - request_factory = sm.getUtility(IRouteRequest, 'name') - request_type = implementedBy(request_factory) + 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) @@ -1875,7 +1860,6 @@ class TestRouteDirective(unittest.TestCase): def test_with_view_containment_alias(self): from zope.component import getSiteManager - from zope.interface import implementedBy from repoze.bfg.zcml import connect_route from repoze.bfg.interfaces import IView from repoze.bfg.interfaces import IRouteRequest @@ -1891,8 +1875,7 @@ class TestRouteDirective(unittest.TestCase): register = view_action['callable'] register() sm = getSiteManager() - request_factory = sm.getUtility(IRouteRequest, 'name') - request_type = implementedBy(request_factory) + 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) @@ -1912,7 +1895,6 @@ class TestRouteDirective(unittest.TestCase): def test_with_view_header(self): from zope.component import getSiteManager - from zope.interface import implementedBy from repoze.bfg.zcml import connect_route from repoze.bfg.interfaces import IView from repoze.bfg.interfaces import IRouteRequest @@ -1928,8 +1910,7 @@ class TestRouteDirective(unittest.TestCase): register = view_action['callable'] register() sm = getSiteManager() - request_factory = sm.getUtility(IRouteRequest, 'name') - request_type = implementedBy(request_factory) + 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) @@ -1949,7 +1930,6 @@ class TestRouteDirective(unittest.TestCase): def test_with_view_header_alias(self): from zope.component import getSiteManager - from zope.interface import implementedBy from repoze.bfg.zcml import connect_route from repoze.bfg.interfaces import IView from repoze.bfg.interfaces import IRouteRequest @@ -1965,8 +1945,7 @@ class TestRouteDirective(unittest.TestCase): register = view_action['callable'] register() sm = getSiteManager() - request_factory = sm.getUtility(IRouteRequest, 'name') - request_type = implementedBy(request_factory) + 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) @@ -1986,7 +1965,6 @@ class TestRouteDirective(unittest.TestCase): def test_with_view_path_info(self): from zope.component import getSiteManager - from zope.interface import implementedBy from repoze.bfg.zcml import connect_route from repoze.bfg.interfaces import IView from repoze.bfg.interfaces import IRouteRequest @@ -2002,8 +1980,7 @@ class TestRouteDirective(unittest.TestCase): register = view_action['callable'] register() sm = getSiteManager() - request_factory = sm.getUtility(IRouteRequest, 'name') - request_type = implementedBy(request_factory) + 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') @@ -2023,7 +2000,6 @@ class TestRouteDirective(unittest.TestCase): def test_with_view_xhr(self): from zope.component import getSiteManager - from zope.interface import implementedBy from repoze.bfg.zcml import connect_route from repoze.bfg.interfaces import IView from repoze.bfg.interfaces import IRouteRequest @@ -2039,8 +2015,7 @@ class TestRouteDirective(unittest.TestCase): register = view_action['callable'] register() sm = getSiteManager() - request_factory = sm.getUtility(IRouteRequest, 'name') - request_type = implementedBy(request_factory) + 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) @@ -2060,7 +2035,6 @@ class TestRouteDirective(unittest.TestCase): def test_with_view_xhr_alias(self): from zope.component import getSiteManager - from zope.interface import implementedBy from repoze.bfg.zcml import connect_route from repoze.bfg.interfaces import IView from repoze.bfg.interfaces import IRouteRequest @@ -2076,8 +2050,7 @@ class TestRouteDirective(unittest.TestCase): register = view_action['callable'] register() sm = getSiteManager() - request_factory = sm.getUtility(IRouteRequest, 'name') - request_type = implementedBy(request_factory) + 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) @@ -2097,7 +2070,6 @@ class TestRouteDirective(unittest.TestCase): def test_with_view_accept(self): from zope.component import getSiteManager - from zope.interface import implementedBy from repoze.bfg.zcml import connect_route from repoze.bfg.interfaces import IView from repoze.bfg.interfaces import IRouteRequest @@ -2114,8 +2086,7 @@ class TestRouteDirective(unittest.TestCase): register = view_action['callable'] register() sm = getSiteManager() - request_factory = sm.getUtility(IRouteRequest, 'name') - request_type = implementedBy(request_factory) + 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) @@ -2135,7 +2106,6 @@ class TestRouteDirective(unittest.TestCase): def test_with_view_accept_alias(self): from zope.component import getSiteManager - from zope.interface import implementedBy from repoze.bfg.zcml import connect_route from repoze.bfg.interfaces import IView from repoze.bfg.interfaces import IRouteRequest @@ -2151,8 +2121,8 @@ class TestRouteDirective(unittest.TestCase): register = view_action['callable'] register() sm = getSiteManager() - request_factory = sm.getUtility(IRouteRequest, 'name') - request_type = implementedBy(request_factory) + 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) @@ -2206,8 +2176,7 @@ class TestStaticDirective(unittest.TestCase): register() sm = getSiteManager() iface = implementedBy(StaticRootFactory) - request_factory = sm.getUtility(IRouteRequest, 'name') - request_type = implementedBy(request_factory) + request_type = sm.getUtility(IRouteRequest, 'name') wrapped = sm.adapters.lookup((iface, request_type), IView, name='') request = DummyRequest() self.assertEqual(wrapped(None, request).__class__, StaticURLParser) @@ -2241,8 +2210,7 @@ class TestStaticDirective(unittest.TestCase): register() sm = getSiteManager() iface = implementedBy(StaticRootFactory) - request_factory = sm.getUtility(IRouteRequest, 'name') - request_type = implementedBy(request_factory) + request_type = sm.getUtility(IRouteRequest, 'name') view = sm.adapters.lookup((iface, request_type), IView, name='') request = DummyRequest() self.assertEqual(view(None, request).__class__, PackageURLParser) @@ -2277,8 +2245,7 @@ class TestStaticDirective(unittest.TestCase): register() sm = getSiteManager() iface = implementedBy(StaticRootFactory) - request_factory = sm.getUtility(IRouteRequest, 'name') - request_type = implementedBy(request_factory) + request_type = sm.getUtility(IRouteRequest, 'name') wrapped = sm.adapters.lookup((iface, request_type), IView, name='') request = DummyRequest() self.assertEqual(wrapped(None, request).__class__, PackageURLParser) diff --git a/repoze/bfg/urldispatch.py b/repoze/bfg/urldispatch.py index 14a81062c..4088cef12 100644 --- a/repoze/bfg/urldispatch.py +++ b/repoze/bfg/urldispatch.py @@ -1,6 +1,10 @@ import re from urllib import unquote +from zope.interface import directlyProvides + +from repoze.bfg.interfaces import IRouteRequest + from repoze.bfg.traversal import traversal_path from repoze.bfg.traversal import quote_path_segment from repoze.bfg.encode import url_quote @@ -35,7 +39,29 @@ class RoutesRootFactory(object): def generate(self, name, kw): return self.routes[name].generate(kw) - def __call__(self, environ): + def __call__(self, request): + try: + # As of BFG 1.1a9, a root factory is now typically called + # with a request object (instead of a WSGI environ, as in + # previous versions) by the router. Simultaneously, as of + # 1.1a9, the RoutesRootFactory *requires* that the object + # passed to it be a request, instead of an environ, as it + # uses both the ``registry`` attribute of the request, and + # if a route is found, it decorates the object with an + # interface using directlyProvides. However, existing app + # code "in the wild" calls the root factory explicitly + # with a dictionary argument (e.g. a subscriber to + # WSGIApplicationCreatedEvent does + # ``app.root_factory({})``). It makes no sense for such + # code to depend on the side effects of a + # RoutesRootFactory, for bw compat purposes we catch the + # exception that will be raised when passed a dictionary + # and just return the result of the default root factory. + environ = request.environ + registry = request.registry + except AttributeError: + return self.default_root_factory(request) + try: path = environ['PATH_INFO'] except KeyError: @@ -46,6 +72,10 @@ class RoutesRootFactory(object): environ['wsgiorg.routing_args'] = ((), match) environ['bfg.routes.route'] = route environ['bfg.routes.matchdict'] = match + request.matchdict = match + iface = registry.queryUtility(IRouteRequest, name=route.name) + if iface is not None: + directlyProvides(request, iface) factory = route.factory or self.default_root_factory return factory(environ) diff --git a/repoze/bfg/zcml.py b/repoze/bfg/zcml.py index c192fddfb..c39f06bb3 100644 --- a/repoze/bfg/zcml.py +++ b/repoze/bfg/zcml.py @@ -38,7 +38,7 @@ from repoze.bfg.authentication import AuthTktAuthenticationPolicy from repoze.bfg.authorization import ACLAuthorizationPolicy from repoze.bfg.configuration import zcml_configure from repoze.bfg.path import package_name -from repoze.bfg.request import create_route_request_factory +from repoze.bfg.request import route_request_iface from repoze.bfg.resource import PackageOverrides from repoze.bfg.resource import resource_spec from repoze.bfg.static import StaticRootFactory @@ -287,9 +287,8 @@ def view( else: request_type = queryUtility(IRouteRequest, name=route_name) if request_type is None: - factory = create_route_request_factory(route_name) - request_type = implementedBy(factory) - sm.registerUtility(factory, IRouteRequest, name=route_name) + request_type = route_request_iface(route_name) + sm.registerUtility(request_type, IRouteRequest, name=route_name) if isinstance(request_type, basestring): request_type = _context.resolve(request_type) @@ -634,11 +633,10 @@ def route(_context, name, path, view=None, view_for=None, request_type = None if request_type is None: - request_factory = queryUtility(IRouteRequest, name=name) - if request_factory is None: - request_factory = create_route_request_factory(name) - sm.registerUtility(request_factory, IRouteRequest, name=name) - request_type = implementedBy(request_factory) + request_type = queryUtility(IRouteRequest, name=name) + if request_type is None: + request_type = route_request_iface(name) + sm.registerUtility(request_type, IRouteRequest, name=name) if view: _view(_context, permission=permission, for_=for_, view=view, name='', |
