diff -r 93888975606b Lib/_collections_abc.py --- a/Lib/_collections_abc.py Fri Jan 23 21:19:04 2015 +0000 +++ b/Lib/_collections_abc.py Sat Jan 24 18:45:22 2015 +0200 @@ -224,9 +224,6 @@ return NotImplemented return len(self) == len(other) and self.__le__(other) - def __ne__(self, other): - return not (self == other) - @classmethod def _from_iterable(cls, it): '''Construct an instance of the class from any iterable input. @@ -451,9 +448,6 @@ return NotImplemented return dict(self.items()) == dict(other.items()) - def __ne__(self, other): - return not (self == other) - Mapping.register(mappingproxy) diff -r 93888975606b Lib/doctest.py --- a/Lib/doctest.py Fri Jan 23 21:19:04 2015 +0000 +++ b/Lib/doctest.py Sat Jan 24 18:45:22 2015 +0200 @@ -481,9 +481,6 @@ self.options == other.options and \ self.exc_msg == other.exc_msg - def __ne__(self, other): - return not self == other - def __hash__(self): return hash((self.source, self.want, self.lineno, self.indent, self.exc_msg)) @@ -547,9 +544,6 @@ self.filename == other.filename and \ self.lineno == other.lineno - def __ne__(self, other): - return not self == other - def __hash__(self): return hash((self.docstring, self.name, self.filename, self.lineno)) @@ -2289,9 +2283,6 @@ self._dt_tearDown == other._dt_tearDown and \ self._dt_checker == other._dt_checker - def __ne__(self, other): - return not self == other - def __hash__(self): return hash((self._dt_optionflags, self._dt_setUp, self._dt_tearDown, self._dt_checker)) diff -r 93888975606b Lib/lib2to3/pytree.py --- a/Lib/lib2to3/pytree.py Fri Jan 23 21:19:04 2015 +0000 +++ b/Lib/lib2to3/pytree.py Sat Jan 24 18:45:22 2015 +0200 @@ -64,16 +64,6 @@ __hash__ = None # For Py3 compatibility. - def __ne__(self, other): - """ - Compare two nodes for inequality. - - This calls the method _eq(). - """ - if self.__class__ is not other.__class__: - return NotImplemented - return not self._eq(other) - def _eq(self, other): """ Compare two nodes for equality. diff -r 93888975606b Lib/numbers.py --- a/Lib/numbers.py Fri Jan 23 21:19:04 2015 +0000 +++ b/Lib/numbers.py Sat Jan 24 18:45:22 2015 +0200 @@ -141,11 +141,6 @@ """self == other""" raise NotImplementedError - def __ne__(self, other): - """self != other""" - # The default __ne__ doesn't negate __eq__ until 3.0. - return not (self == other) - Complex.register(complex) diff -r 93888975606b Lib/pathlib.py --- a/Lib/pathlib.py Fri Jan 23 21:19:04 2015 +0000 +++ b/Lib/pathlib.py Sat Jan 24 18:45:22 2015 +0200 @@ -665,9 +665,6 @@ return NotImplemented return self._cparts == other._cparts and self._flavour is other._flavour - def __ne__(self, other): - return not self == other - def __hash__(self): try: return self._hash diff -r 93888975606b Lib/test/test_binop.py --- a/Lib/test/test_binop.py Fri Jan 23 21:19:04 2015 +0000 +++ b/Lib/test/test_binop.py Sat Jan 24 18:45:22 2015 +0200 @@ -194,10 +194,6 @@ return float(self) == other return NotImplemented - def __ne__(self, other): - """Compare two Rats for inequality.""" - return not self == other - class RatTestCase(unittest.TestCase): """Unit tests for Rat class and its support utilities.""" diff -r 93888975606b Lib/test/test_compare.py --- a/Lib/test/test_compare.py Fri Jan 23 21:19:04 2015 +0000 +++ b/Lib/test/test_compare.py Sat Jan 24 18:45:22 2015 +0200 @@ -48,8 +48,69 @@ def test_ne_defaults_to_not_eq(self): a = Cmp(1) b = Cmp(1) - self.assertTrue(a == b) - self.assertFalse(a != b) + c = Cmp(2) + self.assertIs(a == b, True) + self.assertIs(a != b, False) + self.assertIs(a != c, True) + + def test_ne_high_priority(self): + """object.__ne__() should allow reflected __ne__() to be tried""" + calls = [] + class Left: + # Inherits object.__ne__() + def __eq__(*args): + calls.append('Left.__eq__') + return NotImplemented + class Right: + def __eq__(*args): + calls.append('Right.__eq__') + return NotImplemented + def __ne__(*args): + calls.append('Right.__ne__') + return NotImplemented + Left() != Right() + self.assertSequenceEqual(calls, ['Left.__eq__', 'Right.__ne__']) + + def test_ne_low_priority(self): + """object.__ne__() should not invoke reflected __eq__()""" + calls = [] + class Base: + # Inherits object.__ne__() + def __eq__(*args): + calls.append('Base.__eq__') + return NotImplemented + class Derived(Base): # Subclassing forces higher priority + def __eq__(*args): + calls.append('Derived.__eq__') + return NotImplemented + def __ne__(*args): + calls.append('Derived.__ne__') + return NotImplemented + Base() != Derived() + self.assertSequenceEqual(calls, ['Derived.__ne__', 'Base.__eq__']) + + def test_other_delegation(self): + """No default delegation between operations except __ne__()""" + ops = ( + ('__eq__', lambda a, b: a == b), + ('__lt__', lambda a, b: a < b), + ('__le__', lambda a, b: a <= b), + ('__gt__', lambda a, b: a > b), + ('__ge__', lambda a, b: a >= b), + ) + for name, func in ops: + with self.subTest(name): + def unexpected(*args): + self.fail('Unexpected operator method called') + class C: + __ne__ = unexpected + for other, _ in ops: + if other != name: + setattr(C, other, unexpected) + if name == '__eq__': + self.assertIs(func(C(), object()), False) + else: + self.assertRaises(TypeError, func, C(), object()) def test_issue_1393(self): x = lambda: None diff -r 93888975606b Lib/unittest/case.py --- a/Lib/unittest/case.py Fri Jan 23 21:19:04 2015 +0000 +++ b/Lib/unittest/case.py Sat Jan 24 18:45:22 2015 +0200 @@ -1342,9 +1342,6 @@ self._testFunc == other._testFunc and \ self._description == other._description - def __ne__(self, other): - return not self == other - def __hash__(self): return hash((type(self), self._setUpFunc, self._tearDownFunc, self._testFunc, self._description)) diff -r 93888975606b Lib/unittest/suite.py --- a/Lib/unittest/suite.py Fri Jan 23 21:19:04 2015 +0000 +++ b/Lib/unittest/suite.py Sat Jan 24 18:45:22 2015 +0200 @@ -31,9 +31,6 @@ return NotImplemented return list(self) == list(other) - def __ne__(self, other): - return not self == other - def __iter__(self): return iter(self._tests) diff -r 93888975606b Objects/typeobject.c --- a/Objects/typeobject.c Fri Jan 23 21:19:04 2015 +0000 +++ b/Objects/typeobject.c Sat Jan 24 18:45:22 2015 +0200 @@ -3348,9 +3348,14 @@ break; case Py_NE: - /* By default, != returns the opposite of ==, + /* By default, __ne__() delegates to __eq__() and inverts the result, unless the latter returns NotImplemented. */ - res = PyObject_RichCompare(self, other, Py_EQ); + if (self->ob_type->tp_richcompare == NULL) { + res = Py_NotImplemented; + Py_INCREF(res); + break; + } + res = (*self->ob_type->tp_richcompare)(self, other, Py_EQ); if (res != NULL && res != Py_NotImplemented) { int ok = PyObject_IsTrue(res); Py_DECREF(res);