[Checkins] SVN: zope.interface/branches/regebro-python3/ back-merged trunk

Thomas Lotze tl at gocept.com
Sat Sep 12 06:10:41 EDT 2009


Log message for revision 103857:
  back-merged trunk

Changed:
  U   zope.interface/branches/regebro-python3/CHANGES.txt
  U   zope.interface/branches/regebro-python3/README.txt
  U   zope.interface/branches/regebro-python3/setup.py
  U   zope.interface/branches/regebro-python3/src/zope/interface/adapter.py
  U   zope.interface/branches/regebro-python3/src/zope/interface/tests/test_adapter.py

-=-
Modified: zope.interface/branches/regebro-python3/CHANGES.txt
===================================================================
--- zope.interface/branches/regebro-python3/CHANGES.txt	2009-09-12 01:51:11 UTC (rev 103856)
+++ zope.interface/branches/regebro-python3/CHANGES.txt	2009-09-12 10:10:41 UTC (rev 103857)
@@ -2,15 +2,26 @@
 *******
 
 ==================
-3.5.2 (unreleased)
+3.5.3 (unreleased)
 ==================
 
-- ...
+...
 
+
 ==================
-3.5.1 (2009-10-13)
+3.5.2 (2009-07-01)
 ==================
 
+- BaseAdapterRegistry.unregister, unsubscribe: Remove empty portions of
+  the data structures when something is removed.  This avoids leaving
+  references to global objects (interfaces) that may be slated for
+  removal from the calling application.
+
+
+==================
+3.5.1 (2009-03-18)
+==================
+
 - verifyObject: use getattr instead of hasattr to test for object attributes
   in order to let exceptions other than AttributeError raised by properties
   propagate to the caller

Modified: zope.interface/branches/regebro-python3/README.txt
===================================================================
--- zope.interface/branches/regebro-python3/README.txt	2009-09-12 01:51:11 UTC (rev 103856)
+++ zope.interface/branches/regebro-python3/README.txt	2009-09-12 10:10:41 UTC (rev 103857)
@@ -1,3 +1,6 @@
+*This package is intended to be independently reusable in any Python
+project. It is maintained by the* `Zope Toolkit project <http://docs.zope.org/zopetoolkit/>`_.
+
 This package provides an implementation of `object interfaces` for Python.
 Interfaces are a mechanism for labeling objects as conforming to a given
 API or contract. So, this package can be considered as implementation of

Modified: zope.interface/branches/regebro-python3/setup.py
===================================================================
--- zope.interface/branches/regebro-python3/setup.py	2009-09-12 01:51:11 UTC (rev 103856)
+++ zope.interface/branches/regebro-python3/setup.py	2009-09-12 10:10:41 UTC (rev 103857)
@@ -11,6 +11,11 @@
 # FOR A PARTICULAR PURPOSE.
 #
 ##############################################################################
+# This package is developed by the Zope Toolkit project, documented here:
+# http://docs.zope.org/zopetoolkit
+# When developing and releasing this package, please follow the documented
+# Zope Toolkit policies as described by this documentation.
+##############################################################################
 """Setup for zope.interface package
 
 $Id$
@@ -96,7 +101,7 @@
         from build_ext_2 import optional_build_ext
     
 setup(name='zope.interface',
-      version = '3.5.2dev',
+      version = '3.5.3dev',
       url='http://pypi.python.org/pypi/zope.interface',
       license='ZPL 2.1',
       description='Interfaces for Python',

Modified: zope.interface/branches/regebro-python3/src/zope/interface/adapter.py
===================================================================
--- zope.interface/branches/regebro-python3/src/zope/interface/adapter.py	2009-09-12 01:51:11 UTC (rev 103856)
+++ zope.interface/branches/regebro-python3/src/zope/interface/adapter.py	2009-09-12 10:10:41 UTC (rev 103857)
@@ -39,6 +39,13 @@
         #   {provided -> {name -> valie}}
         # but for order == 2, we have:
         #   {r1 -> {r2 -> {provided -> {name -> valie}}}}
+        #
+        # XXX ^^^ what does the above comment have to do with any code
+        # in this method?  and.. "interfaces is really a nested key"?
+        # i don't see "interfaces" mentioned.  does it mean
+        # "provided"?  what are r1 and r2?  why is the structure just
+        # below this a list?  is this comment 100% bitrotten or just a
+        # little? /XXX
         self._adapters = []
 
         # {order -> {required -> {provided -> {name -> [value]}}}}
@@ -64,6 +71,8 @@
         #     so have to check the generations of base registries to determine
         #     if their cache data are current
 
+        # ^^^ XXX what are the above comments describing? /XXX
+
         # Base registries:
         self.__bases__ = bases
         
@@ -146,10 +155,13 @@
         components = byorder[order]
         key = required + (provided,)
         
+        # Keep track of how we got to `components`:
+        lookups = []
         for k in key:
             d = components.get(k)
             if d is None:
                 return
+            lookups.append((components, k))
             components = d
 
         old = components.get(name)
@@ -159,6 +171,20 @@
             return
 
         del components[name]
+        if not components:
+            # Clean out empty containers, since we don't want our keys
+            # to reference global objects (interfaces) unnecessarily.
+            # This is often a problem when an interface is slated for
+            # removal; a hold-over entry in the registry can make it
+            # difficult to remove such interfaces.
+            for comp, k in reversed(lookups):
+                d = comp[k]
+                if d:
+                    break
+                else:
+                    del comp[k]
+            while byorder and not byorder[-1]:
+                del byorder[-1]
         n = self._provided[provided] - 1
         if n == 0:
             del self._provided[provided]
@@ -168,9 +194,6 @@
 
         self.changed(self)
 
-        return
-
-
     def subscribe(self, required, provided, value):
         required = tuple(map(_convert_None_to_Interface, required))
         name = u''
@@ -207,10 +230,13 @@
         components = byorder[order]
         key = required + (provided,)
         
+        # Keep track of how we got to `components`:
+        lookups = []
         for k in key:
             d = components.get(k)
             if d is None:
                 return
+            lookups.append((components, k))
             components = d
 
         old = components.get(u'')
@@ -224,9 +250,27 @@
 
         if new == old:
             return
-        
-        components[u''] = new
 
+        if new:
+            components[u''] = new
+        else:
+            # Instead of setting components[u''] = new, we clean out
+            # empty containers, since we don't want our keys to
+            # reference global objects (interfaces) unnecessarily.  This
+            # is often a problem when an interface is slated for
+            # removal; a hold-over entry in the registry can make it
+            # difficult to remove such interfaces.
+            if u'' in components:
+                del components[u'']
+            for comp, k in reversed(lookups):
+                d = comp[k]
+                if d:
+                    break
+                else:
+                    del comp[k]
+            while byorder and not byorder[-1]:
+                del byorder[-1]
+
         if provided is not None:
             n = self._provided[provided] + len(new) - len(old)
             if n == 0:

Modified: zope.interface/branches/regebro-python3/src/zope/interface/tests/test_adapter.py
===================================================================
--- zope.interface/branches/regebro-python3/src/zope/interface/tests/test_adapter.py	2009-09-12 01:51:11 UTC (rev 103856)
+++ zope.interface/branches/regebro-python3/src/zope/interface/tests/test_adapter.py	2009-09-12 10:10:41 UTC (rev 103857)
@@ -344,6 +344,63 @@
 
     """
 
+def test_unregister_cleans_up_empties():
+    """
+    >>> class I(zope.interface.Interface):
+    ...     pass
+    >>> class IP(zope.interface.Interface):
+    ...     pass
+    >>> class C(object):
+    ...     pass
+
+    >>> registry = AdapterRegistry()
+
+    >>> registry.register([], IP, '', C)
+    >>> registry.register([I], IP, '', C)
+    >>> registry.register([I], IP, 'name', C)
+    >>> registry.register([I, I], IP, '', C)
+    >>> len(registry._adapters)
+    3
+    >>> map(len, registry._adapters)
+    [1, 1, 1]
+
+    >>> registry.unregister([], IP, '', C)
+    >>> registry.unregister([I], IP, '', C)
+    >>> registry.unregister([I], IP, 'name', C)
+    >>> registry.unregister([I, I], IP, '', C)
+    >>> registry._adapters
+    []
+
+    """
+
+def test_unsubscribe_cleans_up_empties():
+    """
+    >>> class I1(zope.interface.Interface):
+    ...     pass
+    >>> class I2(zope.interface.Interface):
+    ...     pass
+    >>> class IP(zope.interface.Interface):
+    ...     pass
+
+    >>> registry = AdapterRegistry()
+    >>> def handler(event):
+    ...     pass
+
+    >>> registry.subscribe([I1], I1, handler)
+    >>> registry.subscribe([I2], I1, handler)
+    >>> len(registry._subscribers)
+    2
+    >>> map(len, registry._subscribers)
+    [0, 2]
+
+    >>> registry.unsubscribe([I1], I1, handler)
+    >>> registry.unsubscribe([I2], I1, handler)
+    >>> registry._subscribers
+    []
+
+    """
+
+
 def test_suite():
     import doctest
     return unittest.TestSuite((



More information about the checkins mailing list