Re: [Checkins] SVN: zope.interface/trunk/ Correct comparison of interfaces from different modules but with the same name.

Gediminas Paulauskas <[email protected]>
Newsgroups gmane.comp.web.zope.devel
Message-ID <20110614154004.GA12442@luna>
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((
_______________________________________________
Zope-Dev maillist  -  [email protected]
https://mail.zope.org/mailman/listinfo/zope-dev
**  No cross posts or HTML encoding!  **
(Related lists - 
 https://mail.zope.org/mailman/listinfo/zope-announce
 https://mail.zope.org/mailman/listinfo/zope )
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.