[Repoze-checkins] r1305 - in repoze.bfg/trunk: . repoze/bfg repoze/bfg/tests

Chris McDonough chrism at agendaless.com
Sun Jul 13 06:22:00 EDT 2008


Author: Chris McDonough <chrism at agendaless.com>
Date: Sun Jul 13 06:21:59 2008
New Revision: 1305

Log:
Use an application-local component registry.


Added:
   repoze.bfg/trunk/repoze/bfg/registry.py   (contents, props changed)
   repoze.bfg/trunk/repoze/bfg/tests/test_registry.py   (contents, props changed)
Modified:
   repoze.bfg/trunk/repoze/bfg/configure.zcml
   repoze.bfg/trunk/repoze/bfg/router.py
   repoze.bfg/trunk/repoze/bfg/tests/test_router.py
   repoze.bfg/trunk/setup.py

Modified: repoze.bfg/trunk/repoze/bfg/configure.zcml
==============================================================================
--- repoze.bfg/trunk/repoze/bfg/configure.zcml	(original)
+++ repoze.bfg/trunk/repoze/bfg/configure.zcml	Sun Jul 13 06:21:59 2008
@@ -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"

Added: repoze.bfg/trunk/repoze/bfg/registry.py
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/repoze/bfg/registry.py	Sun Jul 13 06:21:59 2008
@@ -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)

Modified: repoze.bfg/trunk/repoze/bfg/router.py
==============================================================================
--- repoze.bfg/trunk/repoze/bfg/router.py	(original)
+++ repoze.bfg/trunk/repoze/bfg/router.py	Sun Jul 13 06:21:59 2008
@@ -10,19 +10,24 @@
 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 @@
                                   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)
 
     

Added: repoze.bfg/trunk/repoze/bfg/tests/test_registry.py
==============================================================================
--- (empty file)
+++ repoze.bfg/trunk/repoze/bfg/tests/test_registry.py	Sun Jul 13 06:21:59 2008
@@ -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
+        

Modified: repoze.bfg/trunk/repoze/bfg/tests/test_router.py
==============================================================================
--- repoze.bfg/trunk/repoze/bfg/tests/test_router.py	(original)
+++ repoze.bfg/trunk/repoze/bfg/tests/test_router.py	Sun Jul 13 06:21:59 2008
@@ -52,7 +52,7 @@
         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 @@
         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 @@
         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 @@
         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 @@
         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])

Modified: repoze.bfg/trunk/setup.py
==============================================================================
--- repoze.bfg/trunk/setup.py	(original)
+++ repoze.bfg/trunk/setup.py	Sun Jul 13 06:21:59 2008
@@ -51,6 +51,7 @@
             'zope.interface',
             'zope.component',
             'zope.testing',
+            'zope.hookable',
             'WebOb',
             'Paste',
             'z3c.pt',
@@ -59,6 +60,7 @@
             'zope.interface',
             'zope.component',
             'zope.testing',
+            'zope.hookable',
             'WebOb',
             'Paste',
             'z3c.pt',


More information about the Repoze-checkins mailing list