diff options
-rw-r--r-- | Lib/_abcoll.py | 5 | ||||
-rw-r--r-- | Lib/test/test_collections.py | 49 | ||||
-rw-r--r-- | Misc/NEWS | 3 |
3 files changed, 54 insertions, 3 deletions
diff --git a/Lib/_abcoll.py b/Lib/_abcoll.py index a60d91e..e9f06a5 100644 --- a/Lib/_abcoll.py +++ b/Lib/_abcoll.py @@ -376,8 +376,9 @@ class Mapping(Sized, Iterable, Container): return ValuesView(self) 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) diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py index ded8b70..33deb78 100644 --- a/Lib/test/test_collections.py +++ b/Lib/test/test_collections.py @@ -1,6 +1,6 @@ """Unit tests for collections.py.""" -import unittest, doctest +import unittest, doctest, operator import inspect from test import support from collections import namedtuple, Counter, OrderedDict @@ -230,6 +230,37 @@ class ABCTestCase(unittest.TestCase): self.assertRaises(TypeError, C, name) + 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): @@ -398,6 +429,14 @@ class TestCollectionABCs(ABCTestCase): self.assertTrue(isinstance(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): @@ -461,6 +500,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]: @@ -54,6 +54,9 @@ C-API Library ------- +- Issue #8729: Return NotImplemented from collections.Mapping.__eq__ when + comparing to a non-mapping. + - Issue #8774: tabnanny uses the encoding cookie (#coding:...) to use the correct encoding |