[Zope-dev] [Checkins] SVN: zope.interface/trunk/ Correct comparison of interfaces from different modules but with the same name.
Gediminas Paulauskas
menesis at pov.lt
Tue Jun 14 11:40:04 EDT 2011
Hello,
I ran tests in some zope modules with python3.2, and got an exception:
$ cd zope.proxy
$ python3.2 setup.py test
...
File "/home/menesis/src/zope.proxy/build/lib.linux-i686-3.2/zope/proxy/__init__.py", line 16, in <module>
from zope.interface import moduleProvides
File "/home/menesis/src/zope.proxy/zope.interface-3.6.3-py3.2-linux-i686.egg/zope/interface/__init__.py", line 53, in <module>
from zope.interface.interface import Interface, _wire
File "/home/menesis/src/zope.proxy/zope.interface-3.6.3-py3.2-linux-i686.egg/zope/interface/interface.py", line 710, in <module>
Interface = InterfaceClass("Interface", __module__ = 'zope.interface')
File "/home/menesis/src/zope.proxy/zope.interface-3.6.3-py3.2-linux-i686.egg/zope/interface/interface.py", line 479, in __init__
Specification.__init__(self, bases)
File "/home/menesis/src/zope.proxy/zope.interface-3.6.3-py3.2-linux-i686.egg/zope/interface/interface.py", line 266, in __init__
self.__bases__ = tuple(bases)
File "/home/menesis/src/zope.proxy/zope.interface-3.6.3-py3.2-linux-i686.egg/zope/interface/interface.py", line 290, in __setBases
self.changed(self)
File "/home/menesis/src/zope.proxy/zope.interface-3.6.3-py3.2-linux-i686.egg/zope/interface/interface.py", line 309, in changed
ancestors = ro(self)
File "/home/menesis/src/zope.proxy/zope.interface-3.6.3-py3.2-linux-i686.egg/zope/interface/ro.py", line 22, in ro
return mergeOrderings([_flatten(object)])
File "/home/menesis/src/zope.proxy/zope.interface-3.6.3-py3.2-linux-i686.egg/zope/interface/ro.py", line 51, in mergeOrderings
if o not in seen:
TypeError: unhashable type: 'InterfaceClass'
I found the following to explain what happens:
http://stackoverflow.com/questions/1608842/types-that-define-eq-are-unhashable-in-python-3-x
And a commit which does exactly that: define an __eq__ but not __hash__.
Adding a simple
def __hash__(self):
return id(self)
fixes the problem.
This change was released as zope.interface 3.6.3. Earlier version does not have this problem.
On Thu, 2011-05-26 12:10-0400, Tres Seaver wrote:
> Log message for revision 121819:
> Correct comparison of interfaces from different modules but with the same name.
>
> Fixes LP #570942.
>
>
> Changed:
> U zope.interface/trunk/CHANGES.txt
> U zope.interface/trunk/src/zope/interface/interface.py
> U zope.interface/trunk/src/zope/interface/tests/test_interface.py
> U zope.interface/trunk/src/zope/interface/tests/test_sorting.py
>
> -=-
> Modified: zope.interface/trunk/CHANGES.txt
> ===================================================================
> --- zope.interface/trunk/CHANGES.txt 2011-05-26 11:27:21 UTC (rev 121818)
> +++ zope.interface/trunk/CHANGES.txt 2011-05-26 16:10:57 UTC (rev 121819)
> @@ -1,7 +1,12 @@
> ``zope.interface Changelog``
> ============================
>
> +3.6.3 (unreleased)
> +------------------
>
> +- LP #570942: Now correctly compare interfaces from different modules but
> + with the same names.
> +
> 3.6.2 (2011-05-17)
> ------------------
>
>
> Modified: zope.interface/trunk/src/zope/interface/interface.py
> ===================================================================
> --- zope.interface/trunk/src/zope/interface/interface.py 2011-05-26 11:27:21 UTC (rev 121818)
> +++ zope.interface/trunk/src/zope/interface/interface.py 2011-05-26 16:10:57 UTC (rev 121819)
> @@ -670,32 +670,42 @@
> sort before None.
>
> """
> - if o1 == o2:
> - return 0
> -
> if o1 is None:
> return 1
> if o2 is None:
> return -1
>
> - n1 = (getattr(o1, '__name__', ''),
> - getattr(getattr(o1, '__module__', None), '__name__', ''))
> - n2 = (getattr(o2, '__name__', ''),
> - getattr(getattr(o2, '__module__', None), '__name__', ''))
> + n1 = (getattr(o1, '__name__', ''), getattr(o1, '__module__', ''))
> + n2 = (getattr(o2, '__name__', ''), getattr(o2, '__module__', ''))
>
> + # This spelling works under Python3, which doesn't have cmp().
> return (n1 > n2) - (n1 < n2)
>
> + def __eq__(self, other):
> + c = self.__cmp(self, other)
> + return c == 0
> +
> + def __ne__(self, other):
> + c = self.__cmp(self, other)
> + return c != 0
> +
> def __lt__(self, other):
> c = self.__cmp(self, other)
> - #print '<', self, other, c < 0, c
> return c < 0
>
> + def __le__(self, other):
> + c = self.__cmp(self, other)
> + return c <= 0
> +
> def __gt__(self, other):
> c = self.__cmp(self, other)
> - #print '>', self, other, c > 0, c
> return c > 0
>
> + def __ge__(self, other):
> + c = self.__cmp(self, other)
> + return c >= 0
>
> +
> Interface = InterfaceClass("Interface", __module__ = 'zope.interface')
>
> class Attribute(Element):
>
> Modified: zope.interface/trunk/src/zope/interface/tests/test_interface.py
> ===================================================================
> --- zope.interface/trunk/src/zope/interface/tests/test_interface.py 2011-05-26 11:27:21 UTC (rev 121818)
> +++ zope.interface/trunk/src/zope/interface/tests/test_interface.py 2011-05-26 16:10:57 UTC (rev 121819)
> @@ -348,8 +348,40 @@
> # Old style classes don't have a '__class__' attribute
> self.failUnlessRaises(AttributeError, I.providedBy, Bad)
>
> + def test_comparison_with_None(self):
> + from zope.interface import Interface
>
> + class IEmpty(Interface):
> + pass
>
> + self.failUnless(IEmpty < None)
> + self.failUnless(IEmpty <= None)
> + self.failIf(IEmpty == None)
> + self.failUnless(IEmpty != None)
> + self.failIf(IEmpty >= None)
> + self.failIf(IEmpty > None)
> +
> + self.failIf(None < IEmpty)
> + self.failIf(None <= IEmpty)
> + self.failIf(None == IEmpty)
> + self.failUnless(None != IEmpty)
> + self.failUnless(None >= IEmpty)
> + self.failUnless(None > IEmpty)
> +
> + def test_comparison_with_same_instance(self):
> + from zope.interface import Interface
> +
> + class IEmpty(Interface):
> + pass
> +
> + self.failIf(IEmpty < IEmpty)
> + self.failUnless(IEmpty <= IEmpty)
> + self.failUnless(IEmpty == IEmpty)
> + self.failIf(IEmpty != IEmpty)
> + self.failUnless(IEmpty >= IEmpty)
> + self.failIf(IEmpty > IEmpty)
> +
> +
> if sys.version_info >= (2, 4):
>
> def test_invariant_as_decorator():
>
> Modified: zope.interface/trunk/src/zope/interface/tests/test_sorting.py
> ===================================================================
> --- zope.interface/trunk/src/zope/interface/tests/test_sorting.py 2011-05-26 11:27:21 UTC (rev 121818)
> +++ zope.interface/trunk/src/zope/interface/tests/test_sorting.py 2011-05-26 16:10:57 UTC (rev 121819)
> @@ -37,6 +37,14 @@
> l = [I1, None, I3, I5, I6, I4, I2]
> l.sort()
> self.assertEqual(l, [I1, I2, I3, I4, I5, I6, None])
> +
> + def test_w_equal_names(self):
> + # interfaces with equal names but different modules should sort by
> + # module name
> + from zope.interface.tests.m1 import I1 as m1_I1
> + l = [I1, m1_I1]
> + l.sort()
> + self.assertEqual(l, [m1_I1, I1])
>
> def test_suite():
> return TestSuite((
More information about the Zope-Dev
mailing list