summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/zope/interface/declarations.py11
-rw-r--r--src/zope/interface/tests/test_declarations.py40
2 files changed, 46 insertions, 5 deletions
diff --git a/src/zope/interface/declarations.py b/src/zope/interface/declarations.py
index d770fa0..48e459a 100644
--- a/src/zope/interface/declarations.py
+++ b/src/zope/interface/declarations.py
@@ -176,11 +176,12 @@ class Implements(Declaration):
def __hash__(self):
return Declaration.__hash__(self)
- def __eq__(self, other):
- return self is other
-
- def __ne__(self, other):
- return self is not other
+ # We want equality to be based on identity. However, we can't actually
+ # implement __eq__/__ne__ to do this because sometimes we get wrapped in a proxy.
+ # We need to let the proxy types implement these methods so they can handle unwrapping
+ # and then rely on: (1) the interpreter automatically changing `implements == proxy` into
+ # `proxy == implements` (which will call proxy.__eq__ to do the unwrapping) and then
+ # (2) the default equality semantics being identity based.
def __lt__(self, other):
c = self.__cmp(other)
diff --git a/src/zope/interface/tests/test_declarations.py b/src/zope/interface/tests/test_declarations.py
index 83da6fa..702a677 100644
--- a/src/zope/interface/tests/test_declarations.py
+++ b/src/zope/interface/tests/test_declarations.py
@@ -283,6 +283,46 @@ class TestImplements(unittest.TestCase):
self.assertTrue(implementedBy(A) >= IFoo)
self.assertTrue(implementedBy(A) != IFoo)
+ def test_proxy_equality(self):
+ # https://github.com/zopefoundation/zope.interface/issues/55
+ class Proxy(object):
+ def __init__(self, wrapped):
+ self._wrapped = wrapped
+
+ def __getattr__(self, name):
+ return getattr(self._wrapped, name)
+
+ def __eq__(self, other):
+ return self._wrapped == other
+
+ def __ne__(self, other):
+ return self._wrapped != other
+
+ from zope.interface.declarations import implementedBy
+ class A(object):
+ pass
+
+ class B(object):
+ pass
+
+ implementedByA = implementedBy(A)
+ implementedByB = implementedBy(B)
+ proxy = Proxy(implementedByA)
+
+ # The order of arguments to the operators matters,
+ # test both
+ self.assertTrue(implementedByA == implementedByA)
+ self.assertTrue(implementedByA != implementedByB)
+ self.assertTrue(implementedByB != implementedByA)
+
+ self.assertTrue(proxy == implementedByA)
+ self.assertTrue(implementedByA == proxy)
+ self.assertFalse(proxy != implementedByA)
+ self.assertFalse(implementedByA != proxy)
+
+ self.assertTrue(proxy != implementedByB)
+ self.assertTrue(implementedByB != proxy)
+
class Test_implementedByFallback(unittest.TestCase):