Index: Objects/dictobject.c =================================================================== --- Objects/dictobject.c (revision 57414) +++ Objects/dictobject.c (working copy) @@ -2371,6 +2371,7 @@ # define PyDictViewSet_Check(obj) \ (PyDictKeys_Check(obj) || PyDictItems_Check(obj)) +/* Return 1 if self is a subset of other */ static int all_contained_in(PyObject *self, PyObject *other) { @@ -2398,41 +2399,61 @@ static PyObject * dictview_richcompare(PyObject *self, PyObject *other, int op) { + Py_ssize_t len_self, len_other; + PyObject *result; + assert(self != NULL); assert(PyDictViewSet_Check(self)); assert(other != NULL); - if ((op == Py_EQ || op == Py_NE) && - (PyAnySet_Check(other) || PyDictViewSet_Check(other))) - { - Py_ssize_t len_self, len_other; - int ok; - PyObject *result; - len_self = PyObject_Size(self); - if (len_self < 0) - return NULL; - len_other = PyObject_Size(other); - if (len_other < 0) - return NULL; - if (len_self != len_other) - ok = 0; - else if (len_self == 0) - ok = 1; - else - ok = all_contained_in(self, other); - if (ok < 0) - return NULL; - if (ok == (op == Py_EQ)) - result = Py_True; - else - result = Py_False; - Py_INCREF(result); - return result; - } - else { + if (!PyAnySet_Check(other) && !PyDictViewSet_Check(other)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; - } + } + + len_self = PyObject_Size(self); + if (len_self < 0) + return NULL; + len_other = PyObject_Size(other); + if (len_other < 0) + return NULL; + + result = Py_False; + switch(op) { + case Py_NE: + if (len_self != len_other || + len_self == 0 || + !all_contained_in(self, other)) + result = Py_True; + break; + case Py_EQ: + if (len_self == len_other && + (len_self == 0 || all_contained_in(self, other))) + result = Py_True; + break; + case Py_LT: + if (len_self < len_other && + all_contained_in(self, other)) + result = Py_True; + break; + case Py_LE: + if (len_self <= len_other && + all_contained_in(self, other)) + result = Py_True; + break; + case Py_GT: + if (len_self > len_other && + all_contained_in(other, self)) + result = Py_True; + break; + case Py_GE: + if (len_self >= len_other && + all_contained_in(other, self)) + result = Py_True; + break; + } + Py_INCREF(result); + return result; } /*** dict_keys ***/ Index: Lib/test/test_dict.py =================================================================== --- Lib/test/test_dict.py (revision 57414) +++ Lib/test/test_dict.py (working copy) @@ -398,6 +398,47 @@ else: self.fail("< didn't raise Exc") + def test_keys_contained(self): + # Test rich comparisons against dict key views, which should behave the + # same as sets. + empty = dict() + empty2 = dict() + smaller = {1:1, 2:2} + larger = {1:1, 2:2, 3:3} + larger2 = {1:1, 2:2, 3:3} + larger3 = {4:1, 2:2, 3:3} + + self.assert_(smaller.keys() < larger.keys()) + self.assert_(smaller.keys() <= larger.keys()) + self.assert_(larger.keys() > smaller.keys()) + self.assert_(larger.keys() >= smaller.keys()) + + self.assertFalse(smaller.keys() >= larger.keys()) + self.assertFalse(smaller.keys() > larger.keys()) + self.assertFalse(larger.keys() <= smaller.keys()) + self.assertFalse(larger.keys() < smaller.keys()) + + self.assertFalse(smaller.keys() < larger3.keys()) + self.assertFalse(smaller.keys() <= larger3.keys()) + self.assertFalse(larger3.keys() > smaller.keys()) + self.assertFalse(larger3.keys() >= smaller.keys()) + + # Inequality strictness + self.assertTrue(larger2.keys() >= larger.keys()) + self.assertTrue(larger2.keys() <= larger.keys()) + self.assertFalse(larger2.keys() > larger.keys()) + self.assertFalse(larger2.keys() < larger.keys()) + + self.assertEquals(larger.keys(), larger2.keys()) + self.assertNotEquals(smaller.keys(), larger.keys()) + + # There is an optimization on the zero-element case. + self.assertEquals(empty.keys(), empty2.keys()) + self.assertNotEquals(empty.keys(), smaller.keys()) + + # With the same size, an elementwise compare happens + self.assertNotEquals(larger.keys(), larger3.keys()) + def test_missing(self): # Make sure dict doesn't have a __missing__ method self.assertEqual(hasattr(dict, "__missing__"), False)