[Python-checkins] r79337 - in python/branches/release26-maint: Lib/_abcoll.py Lib/abc.py Lib/test/test_collections.py Misc/NEWS

florent.xicluna python-checkins at python.org
Tue Mar 23 13:37:30 CET 2010


Author: florent.xicluna
Date: Tue Mar 23 13:37:29 2010
New Revision: 79337
Log:
Merged revisions 78800 via svnmerge from 
svn+ssh://pythondev@svn.python.org/python/trunk
........
 r78800 | florent.xicluna | 2010年03月08日 16:20:28 +0100 (lun, 08 mar 2010) | 2 lines
 
 #7624: Fix isinstance(foo(), collections.Callable) for old-style classes.
........
Modified:
 python/branches/release26-maint/ (props changed)
 python/branches/release26-maint/Lib/_abcoll.py
 python/branches/release26-maint/Lib/abc.py
 python/branches/release26-maint/Lib/test/test_collections.py
 python/branches/release26-maint/Misc/NEWS
Modified: python/branches/release26-maint/Lib/_abcoll.py
==============================================================================
--- python/branches/release26-maint/Lib/_abcoll.py	(original)
+++ python/branches/release26-maint/Lib/_abcoll.py	Tue Mar 23 13:37:29 2010
@@ -21,6 +21,14 @@
 
 ### ONE-TRICK PONIES ###
 
+def _hasattr(C, attr):
+ try:
+ return any(attr in B.__dict__ for B in C.__mro__)
+ except AttributeError:
+ # Old-style class
+ return hasattr(C, attr)
+
+
 class Hashable:
 __metaclass__ = ABCMeta
 
@@ -31,11 +39,16 @@
 @classmethod
 def __subclasshook__(cls, C):
 if cls is Hashable:
- for B in C.__mro__:
- if "__hash__" in B.__dict__:
- if B.__dict__["__hash__"]:
- return True
- break
+ try:
+ for B in C.__mro__:
+ if "__hash__" in B.__dict__:
+ if B.__dict__["__hash__"]:
+ return True
+ break
+ except AttributeError:
+ # Old-style class
+ if getattr(C, "__hash__", None):
+ return True
 return NotImplemented
 
 
@@ -50,7 +63,7 @@
 @classmethod
 def __subclasshook__(cls, C):
 if cls is Iterable:
- if any("__iter__" in B.__dict__ for B in C.__mro__):
+ if _hasattr(C, "__iter__"):
 return True
 return NotImplemented
 
@@ -69,7 +82,7 @@
 @classmethod
 def __subclasshook__(cls, C):
 if cls is Iterator:
- if any("next" in B.__dict__ for B in C.__mro__):
+ if _hasattr(C, "next"):
 return True
 return NotImplemented
 
@@ -84,7 +97,7 @@
 @classmethod
 def __subclasshook__(cls, C):
 if cls is Sized:
- if any("__len__" in B.__dict__ for B in C.__mro__):
+ if _hasattr(C, "__len__"):
 return True
 return NotImplemented
 
@@ -99,7 +112,7 @@
 @classmethod
 def __subclasshook__(cls, C):
 if cls is Container:
- if any("__contains__" in B.__dict__ for B in C.__mro__):
+ if _hasattr(C, "__contains__"):
 return True
 return NotImplemented
 
@@ -114,7 +127,7 @@
 @classmethod
 def __subclasshook__(cls, C):
 if cls is Callable:
- if any("__call__" in B.__dict__ for B in C.__mro__):
+ if _hasattr(C, "__call__"):
 return True
 return NotImplemented
 
Modified: python/branches/release26-maint/Lib/abc.py
==============================================================================
--- python/branches/release26-maint/Lib/abc.py	(original)
+++ python/branches/release26-maint/Lib/abc.py	Tue Mar 23 13:37:29 2010
@@ -4,6 +4,11 @@
 """Abstract Base Classes (ABCs) according to PEP 3119."""
 
 
+# Instance of old-style class
+class _C: pass
+_InstanceType = type(_C())
+
+
 def abstractmethod(funcobj):
 """A decorator indicating abstract methods.
 
@@ -124,6 +129,9 @@
 if subclass in cls._abc_cache:
 return True
 subtype = type(instance)
+ # Old-style instances
+ if subtype is _InstanceType:
+ subtype = subclass
 if subtype is subclass or subclass is None:
 if (cls._abc_negative_cache_version ==
 ABCMeta._abc_invalidation_counter and
Modified: python/branches/release26-maint/Lib/test/test_collections.py
==============================================================================
--- python/branches/release26-maint/Lib/test/test_collections.py	(original)
+++ python/branches/release26-maint/Lib/test/test_collections.py	Tue Mar 23 13:37:29 2010
@@ -210,6 +210,27 @@
 C = type('C', (abc,), stubs)
 self.assertRaises(TypeError, C, name)
 
+ def validate_isinstance(self, abc, name):
+ stub = lambda s, *args: 0
+
+ # new-style class
+ C = type('C', (object,), {name: stub})
+ self.assertTrue(isinstance(C(), abc))
+ self.assertTrue(issubclass(C, abc))
+ # old-style class
+ class C: pass
+ setattr(C, name, stub)
+ self.assertTrue(isinstance(C(), abc))
+ self.assertTrue(issubclass(C, abc))
+
+ # new-style class
+ C = type('C', (object,), {'__hash__': None})
+ self.assertFalse(isinstance(C(), abc))
+ self.assertFalse(issubclass(C, abc))
+ # old-style class
+ class C: pass
+ self.assertFalse(isinstance(C(), abc))
+ self.assertFalse(issubclass(C, abc))
 
 class TestOneTrickPonyABCs(ABCTestCase):
 
@@ -238,6 +259,7 @@
 self.assertEqual(hash(H()), 0)
 self.failIf(issubclass(int, H))
 self.validate_abstract_methods(Hashable, '__hash__')
+ self.validate_isinstance(Hashable, '__hash__')
 
 def test_Iterable(self):
 # Check some non-iterables
@@ -262,6 +284,7 @@
 self.assertEqual(list(I()), [])
 self.failIf(issubclass(str, I))
 self.validate_abstract_methods(Iterable, '__iter__')
+ self.validate_isinstance(Iterable, '__iter__')
 
 def test_Iterator(self):
 non_samples = [None, 42, 3.14, 1j, "".encode('ascii'), "", (), [],
@@ -281,6 +304,7 @@
 self.failUnless(isinstance(x, Iterator), repr(x))
 self.failUnless(issubclass(type(x), Iterator), repr(type(x)))
 self.validate_abstract_methods(Iterator, 'next')
+ self.validate_isinstance(Iterator, 'next')
 
 def test_Sized(self):
 non_samples = [None, 42, 3.14, 1j,
@@ -298,6 +322,7 @@
 self.failUnless(isinstance(x, Sized), repr(x))
 self.failUnless(issubclass(type(x), Sized), repr(type(x)))
 self.validate_abstract_methods(Sized, '__len__')
+ self.validate_isinstance(Sized, '__len__')
 
 def test_Container(self):
 non_samples = [None, 42, 3.14, 1j,
@@ -315,6 +340,7 @@
 self.failUnless(isinstance(x, Container), repr(x))
 self.failUnless(issubclass(type(x), Container), repr(type(x)))
 self.validate_abstract_methods(Container, '__contains__')
+ self.validate_isinstance(Container, '__contains__')
 
 def test_Callable(self):
 non_samples = [None, 42, 3.14, 1j,
@@ -334,6 +360,7 @@
 self.failUnless(isinstance(x, Callable), repr(x))
 self.failUnless(issubclass(type(x), Callable), repr(type(x)))
 self.validate_abstract_methods(Callable, '__call__')
+ self.validate_isinstance(Callable, '__call__')
 
 def test_direct_subclassing(self):
 for B in Hashable, Iterable, Iterator, Sized, Container, Callable:
@@ -475,7 +502,7 @@
 self.validate_abstract_methods(MutableSequence, '__contains__', '__iter__',
 '__len__', '__getitem__', '__setitem__', '__delitem__', 'insert')
 
-import doctest, collections
+import collections
 
 def test_main(verbose=None):
 NamedTupleDocs = doctest.DocTestSuite(module=collections)
Modified: python/branches/release26-maint/Misc/NEWS
==============================================================================
--- python/branches/release26-maint/Misc/NEWS	(original)
+++ python/branches/release26-maint/Misc/NEWS	Tue Mar 23 13:37:29 2010
@@ -23,6 +23,9 @@
 Library
 -------
 
+- Issue #7624: Fix isinstance(foo(), collections.Callable) for old-style
+ classes.
+
 - Issue #7512: shutil.copystat() could raise an OSError when the filesystem
 didn't support chflags() (for example ZFS under FreeBSD). The error is
 now silenced.


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /