return NotImplemented from Mapping when comparing to a non-mapping #8729
This commit is contained in:
parent
16fd5cdfeb
commit
eb318d3b16
|
@ -369,8 +369,9 @@ class Mapping(Sized, Iterable, Container):
|
|||
__hash__ = None
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, Mapping) and \
|
||||
dict(self.items()) == dict(other.items())
|
||||
if not isinstance(other, Mapping):
|
||||
return NotImplemented
|
||||
return dict(self.items()) == dict(other.items())
|
||||
|
||||
def __ne__(self, other):
|
||||
return not (self == other)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
import unittest, doctest
|
||||
import unittest, doctest, operator
|
||||
import inspect
|
||||
from test import test_support
|
||||
from collections import namedtuple, Counter, OrderedDict
|
||||
|
@ -253,6 +253,37 @@ class ABCTestCase(unittest.TestCase):
|
|||
self.assertNotIsInstance(C(), abc)
|
||||
self.assertFalse(issubclass(C, abc))
|
||||
|
||||
def validate_comparison(self, instance):
|
||||
ops = ['lt', 'gt', 'le', 'ge', 'ne', 'or', 'and', 'xor', 'sub']
|
||||
operators = {}
|
||||
for op in ops:
|
||||
name = '__' + op + '__'
|
||||
operators[name] = getattr(operator, name)
|
||||
|
||||
class Other:
|
||||
def __init__(self):
|
||||
self.right_side = False
|
||||
def __eq__(self, other):
|
||||
self.right_side = True
|
||||
return True
|
||||
__lt__ = __eq__
|
||||
__gt__ = __eq__
|
||||
__le__ = __eq__
|
||||
__ge__ = __eq__
|
||||
__ne__ = __eq__
|
||||
__ror__ = __eq__
|
||||
__rand__ = __eq__
|
||||
__rxor__ = __eq__
|
||||
__rsub__ = __eq__
|
||||
|
||||
for name, op in operators.items():
|
||||
if not hasattr(instance, name):
|
||||
continue
|
||||
other = Other()
|
||||
op(instance, other)
|
||||
self.assertTrue(other.right_side,'Right side not called for %s.%s'
|
||||
% (type(instance), name))
|
||||
|
||||
class TestOneTrickPonyABCs(ABCTestCase):
|
||||
|
||||
def test_Hashable(self):
|
||||
|
@ -430,6 +461,14 @@ class TestCollectionABCs(ABCTestCase):
|
|||
self.assertIsInstance(sample(), Set)
|
||||
self.assertTrue(issubclass(sample, Set))
|
||||
self.validate_abstract_methods(Set, '__contains__', '__iter__', '__len__')
|
||||
class MySet(Set):
|
||||
def __contains__(self, x):
|
||||
return False
|
||||
def __len__(self):
|
||||
return 0
|
||||
def __iter__(self):
|
||||
return iter([])
|
||||
self.validate_comparison(MySet())
|
||||
|
||||
def test_hash_Set(self):
|
||||
class OneTwoThreeSet(Set):
|
||||
|
@ -493,6 +532,14 @@ class TestCollectionABCs(ABCTestCase):
|
|||
self.assertTrue(issubclass(sample, Mapping))
|
||||
self.validate_abstract_methods(Mapping, '__contains__', '__iter__', '__len__',
|
||||
'__getitem__')
|
||||
class MyMapping(collections.Mapping):
|
||||
def __len__(self):
|
||||
return 0
|
||||
def __getitem__(self, i):
|
||||
raise IndexError
|
||||
def __iter__(self):
|
||||
return iter(())
|
||||
self.validate_comparison(MyMapping())
|
||||
|
||||
def test_MutableMapping(self):
|
||||
for sample in [dict]:
|
||||
|
|
|
@ -29,6 +29,9 @@ C-API
|
|||
Library
|
||||
-------
|
||||
|
||||
- Issue #8729: Return NotImplemented from collections.Mapping.__eq__ when
|
||||
comparing to a non-mapping.
|
||||
|
||||
- Issue #8759: Fixed user paths in sysconfig for posix and os2 schemes.
|
||||
|
||||
- Issue #1285086: Speed up urllib.quote and urllib.unquote for simple cases.
|
||||
|
|
Loading…
Reference in New Issue