diff options
author | Marius Gedminas <marius@gedmin.as> | 2016-09-05 09:10:12 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-09-05 09:10:11 +0300 |
commit | fe670a2df4634804a31ad8446b6e42f61a31694d (patch) | |
tree | 1e503365140693acc601b17b7d9f7435b1a1daa4 | |
parent | 69cacf26ff8f49a66b1396b8effe3f22e0e4d1a5 (diff) | |
parent | c0e980b4b986a95a7699d0f417d6f8ff185f48d7 (diff) | |
download | zope-interface-fe670a2df4634804a31ad8446b6e42f61a31694d.tar.gz |
Merge pull request #56 from zopefoundation/fix-55
Fix equality testing of implementedBy objects that have been proxied.
-rw-r--r-- | CHANGES.rst | 6 | ||||
-rw-r--r-- | src/zope/interface/declarations.py | 11 | ||||
-rw-r--r-- | src/zope/interface/tests/test_declarations.py | 40 |
3 files changed, 50 insertions, 7 deletions
diff --git a/CHANGES.rst b/CHANGES.rst index 3f562dc..2fbabbe 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,10 +1,11 @@ Changes ======= -4.4.0 (unreleased) +4.3.2 (unreleased) ------------------ -- Nothing changed yet. +- Fix equality testing of ``implementedBy`` objects and proxies. + (https://github.com/zopefoundation/zope.interface/issues/55) 4.3.1 (2016-08-31) @@ -31,6 +32,7 @@ Changes manipulate utilities in large registries at the cost of some additional memory usage. (https://github.com/zopefoundation/zope.interface/issues/46) + 4.2.0 (2016-06-10) ------------------ 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): |