summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2009-05-16 20:59:41 +0000
committerChris McDonough <chrism@agendaless.com>2009-05-16 20:59:41 +0000
commitdef444c2c310c8cb117e0c5181bf74f5beed064c (patch)
tree7415757b8463512dd62923c6c7b400cee0eb8be8
parent090f6b77dcc8cd738caba4dbb3885ccb6ddb3d41 (diff)
downloadpyramid-def444c2c310c8cb117e0c5181bf74f5beed064c.tar.gz
pyramid-def444c2c310c8cb117e0c5181bf74f5beed064c.tar.bz2
pyramid-def444c2c310c8cb117e0c5181bf74f5beed064c.zip
Speed up common case (use default factory).
-rw-r--r--CHANGES.txt4
-rw-r--r--docs/narr/hooks.rst26
-rw-r--r--repoze/bfg/interfaces.py4
-rw-r--r--repoze/bfg/tests/test_urldispatch.py61
-rw-r--r--repoze/bfg/urldispatch.py19
5 files changed, 108 insertions, 6 deletions
diff --git a/CHANGES.txt b/CHANGES.txt
index 0a7610a7c..72c4a0fb6 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -90,6 +90,10 @@ Features
- The Routes ``Route`` object used to resolve the match is now put
into the environment as ``bfg.route`` when URL dispatch is used.
+- You can now change the default Routes "context factory" globally.
+ See the "ZCML Hooks" chapter of the documentation (in the "Changing
+ the Default Routes Context Factory" section).
+
0.8a6 (2009-05-11)
==================
diff --git a/docs/narr/hooks.rst b/docs/narr/hooks.rst
index 585e3e655..21906e466 100644
--- a/docs/narr/hooks.rst
+++ b/docs/narr/hooks.rst
@@ -167,3 +167,29 @@ factory:
Forbidden`` status code, rather than use the default unauthorized
application factory, which sends a response with a ``401
Unauthorized`` status code.
+
+Changing the Default Routes Context Factory
+-------------------------------------------
+
+The default Routes "context factory" (the object used to create
+context objects when you use ``<route..>`` statements in your ZCML) is
+``repoze.bfg.urldispatch.DefaultRoutesContext``. You may change the
+class used as the Routes "context factory" by placing the following
+ZCML in your ``configure.zcml`` file.
+
+.. code-block:: xml
+ :linenos:
+
+ <utility provides="repoze.bfg.interfaces.IRoutesContextFactory"
+ component="helloworld.factories.routes_context_factory"/>
+
+Replace ``helloworld.factories.routes_context_factory`` with the
+Python dotted name to the context factory you want to use. Here's
+some sample code that implements a minimal context factory:
+
+.. code-block:: python
+
+ class RoutesContextFactory(object):
+ def __init__(self, **kw):
+ self.__dict__.update(kw)
+
diff --git a/repoze/bfg/interfaces.py b/repoze/bfg/interfaces.py
index dbbfd78a5..5dadd252a 100644
--- a/repoze/bfg/interfaces.py
+++ b/repoze/bfg/interfaces.py
@@ -215,6 +215,10 @@ class IContextURL(Interface):
def __call__():
""" Return a URL that points to the context """
+class IRoutesContextFactory(Interface):
+ """ A marker interface used to look up the default routes context factory
+ """
+
# 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/tests/test_urldispatch.py b/repoze/bfg/tests/test_urldispatch.py
index e1640bfdf..e5ae483e7 100644
--- a/repoze/bfg/tests/test_urldispatch.py
+++ b/repoze/bfg/tests/test_urldispatch.py
@@ -1,6 +1,13 @@
import unittest
+from repoze.bfg.testing import cleanUp
class RoutesRootFactoryTests(unittest.TestCase):
+ def setUp(self):
+ cleanUp()
+
+ def tearDown(self):
+ cleanUp()
+
def _getEnviron(self, **kw):
environ = {'SERVER_NAME':'localhost',
'wsgi.url_scheme':'http'}
@@ -15,6 +22,32 @@ class RoutesRootFactoryTests(unittest.TestCase):
klass = self._getTargetClass()
return klass(get_root)
+ def test_init_custom_default_context_factory_dont_decorate(self):
+ from zope.component import getGlobalSiteManager
+ from repoze.bfg.interfaces import IRoutesContextFactory
+ class Dummy(object):
+ pass
+ gsm = getGlobalSiteManager()
+ gsm.registerUtility(Dummy, IRoutesContextFactory)
+ mapper = self._makeOne(None)
+ self.assertEqual(mapper.default_context_factory,
+ Dummy)
+ self.assertEqual(mapper.decorate_context, True)
+
+ def test_init_custom_default_context_factory_decorate(self):
+ from zope.component import getGlobalSiteManager
+ from repoze.bfg.interfaces import IRoutesContextFactory
+ from repoze.bfg.interfaces import IRoutesContext
+ from zope.interface import implements
+ class Dummy(object):
+ implements(IRoutesContext)
+ gsm = getGlobalSiteManager()
+ gsm.registerUtility(Dummy, IRoutesContextFactory)
+ mapper = self._makeOne(None)
+ self.assertEqual(mapper.default_context_factory,
+ Dummy)
+ self.assertEqual(mapper.decorate_context, False)
+
def test_no_route_matches(self):
marker = ()
get_root = make_get_root(marker)
@@ -80,12 +113,12 @@ class RoutesRootFactoryTests(unittest.TestCase):
self.assertEqual(routing_args[la.encode('utf-8')], 'id')
def test_no_fallback_get_root(self):
+ from repoze.bfg.urldispatch import RoutesContextNotFound
marker = ()
mapper = self._makeOne(None)
mapper.connect('wont', 'wont/:be/:found')
environ = self._getEnviron(PATH_INFO='/archives/action1/article1')
result = mapper(environ)
- from repoze.bfg.urldispatch import RoutesContextNotFound
self.failUnless(isinstance(result, RoutesContextNotFound))
def test_custom_factory(self):
@@ -111,6 +144,32 @@ class RoutesRootFactoryTests(unittest.TestCase):
self.failUnless(IDummy.providedBy(result))
self.failIf(hasattr(result, '_factory'))
+ def test_decorate_context_false(self):
+ from repoze.bfg.interfaces import IRoutesContext
+ class Dummy:
+ def __init__(self, **kw):
+ pass
+ mapper = self._makeOne(None)
+ mapper.connect('root', '')
+ environ = self._getEnviron(PATH_INFO='/')
+ mapper.decorate_context = False
+ mapper.default_context_factory = Dummy
+ result = mapper(environ)
+ self.failIf(IRoutesContext.providedBy(result))
+
+ def test_decorate_context_true(self):
+ from repoze.bfg.interfaces import IRoutesContext
+ class Dummy:
+ def __init__(self, **kw):
+ pass
+ mapper = self._makeOne(None)
+ mapper.connect('root', '')
+ environ = self._getEnviron(PATH_INFO='/')
+ mapper.decorate_context = True
+ mapper.default_context_factory = Dummy
+ result = mapper(environ)
+ self.failUnless(IRoutesContext.providedBy(result))
+
def test_has_routes(self):
mapper = self._makeOne(None)
self.assertEqual(mapper.has_routes(), False)
diff --git a/repoze/bfg/urldispatch.py b/repoze/bfg/urldispatch.py
index 2ad482c89..4c3bc2ed3 100644
--- a/repoze/bfg/urldispatch.py
+++ b/repoze/bfg/urldispatch.py
@@ -1,8 +1,11 @@
import re
+from zope.component import queryUtility
+
+from zope.deprecation import deprecated
+
from zope.interface import implements
from zope.interface import alsoProvides
-
from zope.interface import classProvides
from routes import Mapper
@@ -12,11 +15,10 @@ from routes import url_for
from repoze.bfg.interfaces import IContextNotFound
from repoze.bfg.interfaces import IContextURL
from repoze.bfg.interfaces import IRoutesContext
+from repoze.bfg.interfaces import IRoutesContextFactory
from repoze.bfg.interfaces import ITraverser
from repoze.bfg.interfaces import ITraverserFactory
-from zope.deprecation import deprecated
-
_marker = ()
class DefaultRoutesContext(object):
@@ -53,6 +55,7 @@ class RoutesRootFactory(Mapper):
present as Routes match arguments dictionary keys. If no Routes
route matches the current request, the 'fallback' get_root is
called."""
+ decorate_context = True
def __init__(self, get_root=None, **kw):
self.get_root = get_root
kw['controller_scan'] = None
@@ -61,6 +64,11 @@ class RoutesRootFactory(Mapper):
kw['explicit'] = True
Mapper.__init__(self, **kw)
self._regs_created = False
+ context_factory = queryUtility(IRoutesContextFactory,
+ default=DefaultRoutesContext)
+ if IRoutesContext.implementedBy(context_factory):
+ self.decorate_context = False
+ self.default_context_factory = context_factory
def has_routes(self):
return bool(self.matchlist)
@@ -103,8 +111,9 @@ class RoutesRootFactory(Mapper):
kw[k] = v
factory = route._factory
if factory is None:
- factory = DefaultRoutesContext
- context = factory(**kw)
+ context = self.default_context_factory(**kw)
+ if self.decorate_context:
+ alsoProvides(context, IRoutesContext)
else:
context = factory(**kw)
alsoProvides(context, IRoutesContext)