summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2008-07-13 10:21:59 +0000
committerChris McDonough <chrism@agendaless.com>2008-07-13 10:21:59 +0000
commit3fd91222c6fb46bc2d5838229d7c54130619d73a (patch)
tree0de22c7b5f576e72c7feff4ce7248b9a5e382ef5
parent04376ed2f05ecac4a4d20c2780a42764c76fa4ac (diff)
downloadpyramid-3fd91222c6fb46bc2d5838229d7c54130619d73a.tar.gz
pyramid-3fd91222c6fb46bc2d5838229d7c54130619d73a.tar.bz2
pyramid-3fd91222c6fb46bc2d5838229d7c54130619d73a.zip
Use an application-local component registry.
-rw-r--r--repoze/bfg/configure.zcml8
-rw-r--r--repoze/bfg/registry.py70
-rw-r--r--repoze/bfg/router.py24
-rw-r--r--repoze/bfg/tests/test_registry.py96
-rw-r--r--repoze/bfg/tests/test_router.py10
-rw-r--r--setup.py2
6 files changed, 183 insertions, 27 deletions
diff --git a/repoze/bfg/configure.zcml b/repoze/bfg/configure.zcml
index 2a9eea9dc..0223e25ba 100644
--- a/repoze/bfg/configure.zcml
+++ b/repoze/bfg/configure.zcml
@@ -4,14 +4,6 @@
<include package="z3c.pt" />
<include package="zope.security" file="meta.zcml"/>
- <!-- enable when we figure out app-local registries
- <adapter
- factory=".router.app_component_registry"
- provides="zope.component.interfaces.IComponentLookup"
- for="zope.configuration.interfaces.IConfigurationContext"
- />
- -->
-
<permission
id="repoze.view"
title="View"
diff --git a/repoze/bfg/registry.py b/repoze/bfg/registry.py
new file mode 100644
index 000000000..acb5a4abc
--- /dev/null
+++ b/repoze/bfg/registry.py
@@ -0,0 +1,70 @@
+import threading
+import zope.component
+
+from zope.component import getGlobalSiteManager
+from zope.component.interfaces import ComponentLookupError
+from zope.component.interfaces import IComponentLookup
+from zope.component.registry import Components
+from zope.component import getSiteManager as original_getSiteManager
+
+from zope.configuration import xmlconfig
+
+class ThreadLocalRegistryManager(threading.local):
+ registry = getGlobalSiteManager()
+ def set(self, registry):
+ self.registry = registry
+
+ def get(self):
+ return self.registry
+
+ def clear(self):
+ self.registry = getGlobalSiteManager()
+
+registry_manager = ThreadLocalRegistryManager()
+
+def setRegistryManager(manager): # for unit tests
+ global registry_manager
+ old_registry_manager = registry_manager
+ registry_manager = manager
+ return old_registry_manager
+
+def makeRegistry(filename, package, lock=threading.Lock()):
+ # This is absurd and probably not worth it. We want to try to
+ # push our ZCML-defined configuration into an app-local component
+ # registry in order to allow more than one bfg app to live in the
+ # same process space without one unnecessarily stomping on the
+ # other's component registrations (although I suspect directives
+ # that side effects are going to fail). The only way to do that
+ # currently is to override zope.component.getGlobalSiteManager for
+ # the duration of the ZCML includes. We acquire a lock in case
+ # another make_app runs in a different thread simultaneously, in a
+ # vain attempt to prevent mixing of registrations. There's not
+ # much we can do about non-make_app code that tries to use the
+ # global site manager API directly in a different thread while we
+ # hold the lock. Those registrations will end up in our
+ # application's registry.
+ lock.acquire()
+ try:
+ # Do I actually want a globalregistry.BaseGlobalComponents?
+ registry = Components(package.__name__)
+ registry_manager.set(registry)
+ original_getSiteManager.sethook(getSiteManager)
+ zope.component.getGlobalSiteManager = registry_manager.get
+ context = xmlconfig.file(filename, package=package)
+ return context, registry
+ finally:
+ lock.release()
+ zope.component.getGlobalSiteManager = getGlobalSiteManager
+ registry_manager.clear()
+
+def getSiteManager(context=None):
+ if context is None:
+ return registry_manager.get()
+ else:
+ try:
+ return IComponentLookup(context)
+ except TypeError, error:
+ raise ComponentLookupError(*error.args)
+
+from zope.testing.cleanup import addCleanUp
+addCleanUp(original_getSiteManager.reset)
diff --git a/repoze/bfg/router.py b/repoze/bfg/router.py
index 599007833..ff5c878a2 100644
--- a/repoze/bfg/router.py
+++ b/repoze/bfg/router.py
@@ -10,19 +10,24 @@ from repoze.bfg.interfaces import IViewFactory
from repoze.bfg.interfaces import IWSGIApplicationFactory
from repoze.bfg.interfaces import IRequest
+from repoze.bfg.registry import registry_manager
+
_marker = ()
class Router:
- def __init__(self, root_policy, app_context):
+ def __init__(self, root_policy, app_context, app_registry):
self.root_policy = root_policy
self.app_context = app_context
+ self.app_registry = app_registry
def __call__(self, environ, start_response):
+ registry_manager.set(self.app_registry)
request = Request(environ)
directlyProvides(request, IRequest)
root = self.root_policy(environ)
path = environ.get('PATH_INFO', '/')
- traverser = getMultiAdapter((root, request), IPublishTraverserFactory)
+ traverser = getMultiAdapter((root, request),
+ IPublishTraverserFactory)
context, name, subpath = traverser(path)
request.subpath = subpath
request.view_name = name
@@ -35,18 +40,9 @@ class Router:
IWSGIApplicationFactory)
return app(environ, start_response)
-# enable the below when we figure out app-local registries
-
-## def app_component_registry(app_context):
-## registry = getattr(app_context, 'registry', None)
-## if registry is None:
-## from zope.component.registry import Components
-## app_context.registry = Components()
-## return app_context.registry
-
def make_app(root_policy, package=None, filename='configure.zcml'):
- import zope.configuration.xmlconfig
- context = zope.configuration.xmlconfig.file(filename, package=package)
- return Router(root_policy, context)
+ from repoze.bfg.registry import makeRegistry
+ context, registry = makeRegistry(filename, package)
+ return Router(root_policy, context, registry)
diff --git a/repoze/bfg/tests/test_registry.py b/repoze/bfg/tests/test_registry.py
new file mode 100644
index 000000000..11770824a
--- /dev/null
+++ b/repoze/bfg/tests/test_registry.py
@@ -0,0 +1,96 @@
+import unittest
+
+from zope.component.testing import PlacelessSetup
+
+class TestMakeRegistry(unittest.TestCase, PlacelessSetup):
+ def setUp(self):
+ PlacelessSetup.setUp(self)
+
+ def tearDown(self):
+ PlacelessSetup.tearDown(self)
+
+ def _getFUT(self):
+ from repoze.bfg.registry import makeRegistry
+ return makeRegistry
+
+ def test_it(self):
+ from repoze.bfg.tests import fixtureapp
+ makeRegistry = self._getFUT()
+ dummylock = DummyLock()
+ dummyregmgr = DummyRegistrationManager()
+ import repoze.bfg.registry
+ try:
+ old = repoze.bfg.registry.setRegistryManager(dummyregmgr)
+ context, registry = makeRegistry('configure.zcml',
+ fixtureapp,
+ lock=dummylock)
+ self.assertEqual(context.package, fixtureapp)
+ from zope.component.registry import Components
+ self.failUnless(isinstance(registry, Components))
+ self.assertEqual(dummylock.acquired, True)
+ self.assertEqual(dummylock.released, True)
+ self.assertEqual(dummyregmgr.registry, registry)
+ finally:
+ repoze.bfg.registry.setRegistryManager(old)
+
+class TestThreadLocalRegistryManager(unittest.TestCase, PlacelessSetup):
+ def setUp(self):
+ PlacelessSetup.setUp(self)
+
+ def tearDown(self):
+ PlacelessSetup.tearDown(self)
+
+ def _getTargetClass(self):
+ from repoze.bfg.registry import ThreadLocalRegistryManager
+ return ThreadLocalRegistryManager
+
+ def _makeOne(self):
+ return self._getTargetClass()()
+
+ def test_init(self):
+ local = self._makeOne()
+ from zope.component import getGlobalSiteManager
+ self.assertEqual(local.registry, getGlobalSiteManager())
+
+ def test_set_get_and_clear(self):
+ local = self._makeOne()
+ from zope.component import getGlobalSiteManager
+ local.set(None)
+ self.failIfEqual(local.registry, getGlobalSiteManager())
+ self.assertEqual(local.get(), None)
+ local.clear()
+ self.assertEqual(local.registry, getGlobalSiteManager())
+
+class GetSiteManagerTests(unittest.TestCase):
+ def _getFUT(self):
+ from repoze.bfg.registry import getSiteManager
+ return getSiteManager
+
+ def test_no_context(self):
+ gsm = self._getFUT()
+ from zope.component import getGlobalSiteManager
+ self.assertEqual(gsm(), getGlobalSiteManager())
+
+ def test_with_context(self):
+ gsm = self._getFUT()
+ from zope.component.interfaces import ComponentLookupError
+ self.assertRaises(ComponentLookupError, gsm, object)
+
+class DummyRegistrationManager:
+ registry = None
+ def set(self, registry):
+ self.registry = registry
+
+ def get(self):
+ return self.registry
+
+ def clear(self):
+ self.cleared = True
+
+class DummyLock:
+ def acquire(self):
+ self.acquired = True
+
+ def release(self):
+ self.released = True
+
diff --git a/repoze/bfg/tests/test_router.py b/repoze/bfg/tests/test_router.py
index 1f884acb6..ca3cf5ade 100644
--- a/repoze/bfg/tests/test_router.py
+++ b/repoze/bfg/tests/test_router.py
@@ -52,7 +52,7 @@ class RouterTests(unittest.TestCase, PlacelessSetup):
traversalfactory = make_traversal_factory(context, '', [])
self._registerTraverserFactory(traversalfactory, '', None, None)
app_context = make_appcontext()
- router = self._makeOne(rootpolicy, app_context)
+ router = self._makeOne(rootpolicy, app_context, None)
start_response = DummyStartResponse()
result = router(environ, start_response)
headers = start_response.headers
@@ -73,7 +73,7 @@ class RouterTests(unittest.TestCase, PlacelessSetup):
self._registerViewFactory(viewfactory, '', None, None)
self._registerWSGIFactory(wsgifactory, '', None, None, None)
app_context = make_appcontext()
- router = self._makeOne(rootpolicy, app_context)
+ router = self._makeOne(rootpolicy, app_context, None)
start_response = DummyStartResponse()
result = router(environ, start_response)
self.assertEqual(result, ['Hello world'])
@@ -95,7 +95,7 @@ class RouterTests(unittest.TestCase, PlacelessSetup):
self._registerViewFactory(viewfactory, 'foo', None, None)
self._registerWSGIFactory(wsgifactory, '', None, None, None)
app_context = make_appcontext()
- router = self._makeOne(rootpolicy, app_context)
+ router = self._makeOne(rootpolicy, app_context, None)
start_response = DummyStartResponse()
result = router(environ, start_response)
self.assertEqual(result, ['Hello world'])
@@ -123,7 +123,7 @@ class RouterTests(unittest.TestCase, PlacelessSetup):
self._registerViewFactory(viewfactory, '', IContext, IRequest)
self._registerWSGIFactory(wsgifactory, '', None, None, None)
app_context = make_appcontext()
- router = self._makeOne(rootpolicy, app_context)
+ router = self._makeOne(rootpolicy, app_context, None)
start_response = DummyStartResponse()
result = router(environ, start_response)
self.assertEqual(result, ['Hello world'])
@@ -153,7 +153,7 @@ class RouterTests(unittest.TestCase, PlacelessSetup):
self._registerViewFactory(viewfactory, '', IContext, IRequest)
self._registerWSGIFactory(wsgifactory, '', None, None, None)
app_context = make_appcontext()
- router = self._makeOne(rootpolicy, app_context)
+ router = self._makeOne(rootpolicy, app_context, None)
start_response = DummyStartResponse()
result = router(environ, start_response)
self.failUnless('404' in result[0])
diff --git a/setup.py b/setup.py
index 3a18fce1b..264a26946 100644
--- a/setup.py
+++ b/setup.py
@@ -51,6 +51,7 @@ setup(name='repoze.bfg',
'zope.interface',
'zope.component',
'zope.testing',
+ 'zope.hookable',
'WebOb',
'Paste',
'z3c.pt',
@@ -59,6 +60,7 @@ setup(name='repoze.bfg',
'zope.interface',
'zope.component',
'zope.testing',
+ 'zope.hookable',
'WebOb',
'Paste',
'z3c.pt',