From 8e13de6725943ce7e80bf96bc5f6bd330be428a7 Mon Sep 17 00:00:00 2001 From: Benjamin Peterson Date: Fri, 21 May 2010 21:05:45 +0000 Subject: [PATCH] Merged revisions 81417 via svnmerge from svn+ssh://pythondev@svn.python.org/python/branches/py3k ................ r81417 | benjamin.peterson | 2010-05-21 15:55:22 -0500 (Fri, 21 May 2010) | 9 lines Merged revisions 81414 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r81414 | benjamin.peterson | 2010-05-21 15:51:45 -0500 (Fri, 21 May 2010) | 1 line return NotImplemented from Mapping when comparing to a non-mapping #8729 ........ ................ --- Lib/_abcoll.py | 5 ++-- Lib/test/test_collections.py | 49 +++++++++++++++++++++++++++++++++++- Misc/NEWS | 3 +++ 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/Lib/_abcoll.py b/Lib/_abcoll.py index a60d91e7cb..e9f06a5ed3 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 ded8b70e00..33deb78ff2 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]: diff --git a/Misc/NEWS b/Misc/NEWS index 23046064bb..27dd6a463d 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -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 -- 2.40.0