diff options
| author | Chris McDonough <chrism@agendaless.com> | 2008-07-13 10:21:59 +0000 |
|---|---|---|
| committer | Chris McDonough <chrism@agendaless.com> | 2008-07-13 10:21:59 +0000 |
| commit | 3fd91222c6fb46bc2d5838229d7c54130619d73a (patch) | |
| tree | 0de22c7b5f576e72c7feff4ce7248b9a5e382ef5 | |
| parent | 04376ed2f05ecac4a4d20c2780a42764c76fa4ac (diff) | |
| download | pyramid-3fd91222c6fb46bc2d5838229d7c54130619d73a.tar.gz pyramid-3fd91222c6fb46bc2d5838229d7c54130619d73a.tar.bz2 pyramid-3fd91222c6fb46bc2d5838229d7c54130619d73a.zip | |
Use an application-local component registry.
| -rw-r--r-- | repoze/bfg/configure.zcml | 8 | ||||
| -rw-r--r-- | repoze/bfg/registry.py | 70 | ||||
| -rw-r--r-- | repoze/bfg/router.py | 24 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_registry.py | 96 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_router.py | 10 | ||||
| -rw-r--r-- | setup.py | 2 |
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]) @@ -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', |
