[Checkins] SVN: zope.app.component/tags/3.4.x/ - Fix empty __bases__ on LocalSiteManager objects loaded from old databases,

Marius Gedminas marius at pov.lt
Wed Jul 15 14:46:00 EDT 2009


Log message for revision 101931:
  - Fix empty __bases__ on LocalSiteManager objects loaded from old databases,
    which causes queryNextUtility to never see global utilites and therefore
    broke minor things like the whole authentication framework.
  
  - Fix KeyError: 'base' on startup in zope/app/component/back35.py after
    an inept attempt to fix the above error.
  
  I would strongly appreciate some review of this code, since I don't know much
  about the internals of local site registries.
  
  

Changed:
  U   zope.app.component/tags/3.4.x/CHANGES.txt
  U   zope.app.component/tags/3.4.x/src/zope/app/component/back35.py
  U   zope.app.component/tags/3.4.x/src/zope/app/component/site.py
  U   zope.app.component/tags/3.4.x/src/zope/app/component/tests/test_registration.py

-=-
Modified: zope.app.component/tags/3.4.x/CHANGES.txt
===================================================================
--- zope.app.component/tags/3.4.x/CHANGES.txt	2009-07-15 18:34:35 UTC (rev 101930)
+++ zope.app.component/tags/3.4.x/CHANGES.txt	2009-07-15 18:45:59 UTC (rev 101931)
@@ -2,6 +2,16 @@
 CHANGES
 =======
 
+3.4.2 (unreleased)
+------------------
+
+- Fix empty __bases__ on LocalSiteManager objects loaded from old databases,
+  which causes queryNextUtility to never see global utilites and therefore
+  broke minor things like the whole authentication framework.
+- Fix KeyError: 'base' on startup in zope/app/component/back35.py after
+  an inept attempt to fix the above error.
+
+
 3.4.1 (2007-10-31)
 ------------------
 

Modified: zope.app.component/tags/3.4.x/src/zope/app/component/back35.py
===================================================================
--- zope.app.component/tags/3.4.x/src/zope/app/component/back35.py	2009-07-15 18:34:35 UTC (rev 101930)
+++ zope.app.component/tags/3.4.x/src/zope/app/component/back35.py	2009-07-15 18:45:59 UTC (rev 101931)
@@ -889,7 +889,7 @@
 class _LocalAdapterRegistryGeneration3SupportMixin(object):
 
     def __setstate__(self, state):
-        if '_registrations' in state:
+        if '_registrations' in state and '__bases__' not in state:
             # convert data to generation 3 data structure:
             next = state.get('next')
             if next is None:

Modified: zope.app.component/tags/3.4.x/src/zope/app/component/site.py
===================================================================
--- zope.app.component/tags/3.4.x/src/zope/app/component/site.py	2009-07-15 18:34:35 UTC (rev 101930)
+++ zope.app.component/tags/3.4.x/src/zope/app/component/site.py	2009-07-15 18:45:59 UTC (rev 101931)
@@ -192,6 +192,12 @@
         zope.event.notify(ObjectCreatedEvent(folder))
         self['default'] = folder
 
+    def __setstate__(self, state):
+        if not state.get('__bases__'):
+            next = zope.component.getGlobalSiteManager()
+            state['__bases__'] = (next, )
+        super(LocalSiteManager, self).__setstate__(state)
+
     def _init_registries(self):
         self.adapters = _LocalAdapterRegistry()
         self.utilities = _LocalAdapterRegistry()

Modified: zope.app.component/tags/3.4.x/src/zope/app/component/tests/test_registration.py
===================================================================
--- zope.app.component/tags/3.4.x/src/zope/app/component/tests/test_registration.py	2009-07-15 18:34:35 UTC (rev 101930)
+++ zope.app.component/tags/3.4.x/src/zope/app/component/tests/test_registration.py	2009-07-15 18:45:59 UTC (rev 101931)
@@ -63,6 +63,7 @@
 
 def setUp(test):
     placelesssetup.setUp(test)
+    zope.component.provideUtility(Foo(), provides=IFoo, name='globalfoo')
     test.globs['showwarning'] = warnings.showwarning
     warnings.showwarning = lambda *a, **k: None
 
@@ -137,6 +138,13 @@
     >>> sm3.getUtility(IFoo, '5') is sm3['default']['5']
     True
 
+The bases are loaded correctly and therefore we can look up global utilities
+
+    >>> sm1.queryUtility(IFoo, 'globalfoo') is not None
+    True
+    >>> zope.app.component.queryNextUtility(sm1, IFoo, 'globalfoo') is not None
+    True
+
 and we get registration info:
 
     >>> sorted([r.name for r in sm2.registeredUtilities()])
@@ -343,7 +351,7 @@
     >>> all.remove(sm3['default']['4'])
     >>> all.remove(sm3['default']['5'])
     >>> len(all)
-    2
+    3
 
 Cleanup:
 
@@ -352,6 +360,45 @@
 """
 
 
+def test_old_databases_backward_compat_shoot_self_in_foot():
+    """
+
+    >>> fs = oldfs()
+    >>> demo = DemoStorage(base=fs)
+    >>> db = DB(demo)
+    >>> tm = transaction.TransactionManager()
+    >>> root = db.open(transaction_manager=tm).root()
+    >>> _ = tm.begin()
+
+When I did this in production, in a vain attempt to fix the queryNextUtility
+problem:
+
+    >>> sm1 = root['Application'].getSiteManager()
+    >>> sm1.__bases__ = (zope.component.getGlobalSiteManager(), )
+    >>> tm.commit()
+
+I started getting KeyError: 'base' in _LocalAdapterRegistryGeneration3SupportMixin
+__setstate__ which didn't expect the registry to be pickled without someone
+carefully removing the _registrations attribute it left in place.
+
+    >>> tm2 = transaction.TransactionManager()
+    >>> root2 = db.open(transaction_manager=tm2).root()
+    >>> _ = tm2.begin()
+    >>> sm1 = root2['Application'].getSiteManager()
+    >>> len(sm1.__bases__)
+    1
+    >>> sm1.queryUtility(IFoo, 'globalfoo') is not None
+    True
+    >>> zope.app.component.queryNextUtility(sm1, IFoo, 'globalfoo') is not None
+    True
+
+Cleanup:
+
+    >>> db.close()
+
+"""
+
+
 class GlobalRegistry:
     pass
 



More information about the Checkins mailing list