summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/zope/interface/registry.py20
-rw-r--r--src/zope/interface/tests/test_registry.py22
2 files changed, 31 insertions, 11 deletions
diff --git a/src/zope/interface/registry.py b/src/zope/interface/registry.py
index 2e1b085..c2b588c 100644
--- a/src/zope/interface/registry.py
+++ b/src/zope/interface/registry.py
@@ -14,7 +14,7 @@
"""Basic components support
"""
from collections import defaultdict
-from weakref import WeakKeyDictionary
+import weakref
try:
from zope.event import notify
@@ -71,15 +71,18 @@ class _UnhashableComponentCounter(object):
class _UtilityRegistrations(object):
- _regs_for_components = WeakKeyDictionary()
+ _regs_for_components = {}
+ _weakrefs_for_components = {}
@classmethod
def for_components(cls, components):
# We manage these utility/subscription registrations as associated
# objects with a weakref to avoid making any changes to
- # the pickle format
+ # the pickle format. They are keyed off the id of the component because
+ # Components subclasses are not guaranteed to be hashable.
+ key = id(components)
try:
- regs = cls._regs_for_components[components]
+ regs = cls._regs_for_components[key]
except KeyError:
regs = None
else:
@@ -91,7 +94,14 @@ class _UtilityRegistrations(object):
if regs is None:
regs = cls(components.utilities, components._utility_registrations)
- cls._regs_for_components[components] = regs
+ cls._regs_for_components[key] = regs
+
+ if key not in cls._weakrefs_for_components:
+ def _cleanup(r):
+ cls._weakrefs_for_components.pop(key)
+ cls._regs_for_components.pop(key)
+
+ cls._weakrefs_for_components[key] = weakref.ref(components, _cleanup)
return regs
diff --git a/src/zope/interface/tests/test_registry.py b/src/zope/interface/tests/test_registry.py
index c2a940a..852034e 100644
--- a/src/zope/interface/tests/test_registry.py
+++ b/src/zope/interface/tests/test_registry.py
@@ -2133,6 +2133,15 @@ class ComponentsTests(unittest.TestCase):
self.assertEqual(_called_2, [bar])
+class UnhashableComponentsTests(ComponentsTests):
+
+ def _getTargetClass(self):
+ # Mimic what pyramid does to create an unhashable
+ # registry
+ class Components(super(UnhashableComponentsTests, self)._getTargetClass(), dict):
+ pass
+ return Components
+
# Test _getUtilityProvided, _getAdapterProvided, _getAdapterRequired via their
# callers (Component.registerUtility, Component.registerAdapter).
@@ -2646,9 +2655,10 @@ class _Monkey(object):
def test_suite():
return unittest.TestSuite((
- unittest.makeSuite(ComponentsTests),
- unittest.makeSuite(UtilityRegistrationTests),
- unittest.makeSuite(AdapterRegistrationTests),
- unittest.makeSuite(SubscriptionRegistrationTests),
- unittest.makeSuite(AdapterRegistrationTests),
- ))
+ unittest.makeSuite(ComponentsTests),
+ unittest.makeSuite(UnhashableComponentsTests),
+ unittest.makeSuite(UtilityRegistrationTests),
+ unittest.makeSuite(AdapterRegistrationTests),
+ unittest.makeSuite(SubscriptionRegistrationTests),
+ unittest.makeSuite(AdapterRegistrationTests),
+ ))