[Checkins] SVN: zope.interface/trunk/ Work around buggy behavior in some subclasses of `InterfaceClass``
Tres Seaver
tseaver at palladion.com
Thu Aug 11 15:49:19 EDT 2011
Log message for revision 122546:
Work around buggy behavior in some subclasses of `InterfaceClass``
Some sublcasses invoke '__hash__' before initializing '__module__' and
'__name__'. The workaround returns a fixed constant hash in such cases, and
issues a UserWarning.
Addresses LP #811792.
Changed:
U zope.interface/trunk/CHANGES.txt
U zope.interface/trunk/src/zope/interface/interface.py
A zope.interface/trunk/src/zope/interface/tests/ifoo_other.py
U zope.interface/trunk/src/zope/interface/tests/test_interface.py
-=-
Modified: zope.interface/trunk/CHANGES.txt
===================================================================
--- zope.interface/trunk/CHANGES.txt 2011-08-11 19:24:13 UTC (rev 122545)
+++ zope.interface/trunk/CHANGES.txt 2011-08-11 19:49:19 UTC (rev 122546)
@@ -4,6 +4,11 @@
3.6.5 (unreleased)
------------------
+- LP #811792: work around buggy behavior in some subclasses of
+ ``zope.interface.interface.InterfaceClass``, which invoke ``__hash__``
+ before initializing ``__module__`` and ``__name__``. The workaround
+ returns a fixed constant hash in such cases, and issues a ``UserWarning``.
+
- LP #804832: Under PyPy, ``zope.interface`` should not build its C
extension. Also, prevent attempting to build it under Jython.
Modified: zope.interface/trunk/src/zope/interface/interface.py
===================================================================
--- zope.interface/trunk/src/zope/interface/interface.py 2011-08-11 19:24:13 UTC (rev 122545)
+++ zope.interface/trunk/src/zope/interface/interface.py 2011-08-11 19:49:19 UTC (rev 122546)
@@ -17,6 +17,7 @@
import sys
from types import FunctionType
+import warnings
import weakref
from zope.interface.exceptions import Invalid
@@ -682,6 +683,10 @@
return (n1 > n2) - (n1 < n2)
def __hash__(self):
+ d = self.__dict__
+ if '__module__' not in d or '__name__' not in d:
+ warnings.warn('Hashing uninitialized InterfaceClass instance')
+ return 1
return hash((self.__name__, self.__module__))
def __eq__(self, other):
Copied: zope.interface/trunk/src/zope/interface/tests/ifoo_other.py (from rev 122541, zope.interface/trunk/src/zope/interface/tests/ifoo.py)
===================================================================
--- zope.interface/trunk/src/zope/interface/tests/ifoo_other.py (rev 0)
+++ zope.interface/trunk/src/zope/interface/tests/ifoo_other.py 2011-08-11 19:49:19 UTC (rev 122546)
@@ -0,0 +1,26 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""IFoo test module
+"""
+from zope.interface import Interface
+
+class IFoo(Interface):
+ """
+ Dummy interface for unit tests.
+ """
+
+ def bar(baz):
+ """
+ Just a note.
+ """
Modified: zope.interface/trunk/src/zope/interface/tests/test_interface.py
===================================================================
--- zope.interface/trunk/src/zope/interface/tests/test_interface.py 2011-08-11 19:24:13 UTC (rev 122545)
+++ zope.interface/trunk/src/zope/interface/tests/test_interface.py 2011-08-11 19:49:19 UTC (rev 122546)
@@ -387,16 +387,37 @@
self.failUnless(IEmpty >= IEmpty)
self.failIf(IEmpty > IEmpty)
- def test_hash(self):
- from zope.interface import Interface
+ def test_comparison_with_same_named_instance_in_other_module(self):
+ from zope.interface.tests.ifoo import IFoo as IFoo1
+ from zope.interface.tests.ifoo_other import IFoo as IFoo2
- class IEmpty(Interface):
- pass
+ self.failUnless(IFoo1 < IFoo2)
+ self.failUnless(IFoo1 <= IFoo2)
+ self.failIf(IFoo1 == IFoo2)
+ self.failUnless(IFoo1 != IFoo2)
+ self.failIf(IFoo1 >= IFoo2)
+ self.failIf(IFoo1 > IFoo2)
- self.assertEqual(hash(IEmpty),
- hash((IEmpty.__name__, IEmpty.__module__)))
+ def test_hash_normal(self):
+ from zope.interface.tests.ifoo import IFoo
+ self.assertEqual(hash(IFoo),
+ hash((('IFoo', 'zope.interface.tests.ifoo'))))
+ def test_hash_missing_required_attrs(self):
+ from warnings import catch_warnings
+ from zope.interface.interface import InterfaceClass
+ class Derived(InterfaceClass):
+ def __init__(self):
+ pass # Don't call base class.
+ derived = Derived()
+ with catch_warnings(record=True) as warned:
+ self.assertEqual(hash(derived), 1)
+ self.assertEqual(len(warned), 1)
+ self.failUnless(warned[0].category is UserWarning)
+ self.assertEqual(str(warned[0].message),
+ 'Hashing uninitialized InterfaceClass instance')
+
if sys.version_info >= (2, 4):
def test_invariant_as_decorator():
More information about the checkins
mailing list