import unittest
from test import support
+from operator import eq, ne, lt, gt, le, ge
def gcd(a, b):
"""Greatest common divisor using Euclid's algorithm."""
# XXX Ran out of steam; TO DO: divmod, div, future division
-def test_main():
- support.run_unittest(RatTestCase)
+class OperationLogger:
+ """Base class for classes with operation logging."""
+ def __init__(self, logger):
+ self.logger = logger
+ def log_operation(self, *args):
+ self.logger(*args)
+
+def op_sequence(op, *classes):
+ """Return the sequence of operations that results from applying
+ the operation `op` to instances of the given classes."""
+ log = []
+ instances = []
+ for c in classes:
+ instances.append(c(log.append))
+
+ try:
+ op(*instances)
+ except TypeError:
+ pass
+ return log
+
+class A(OperationLogger):
+ def __eq__(self, other):
+ self.log_operation('A.__eq__')
+ return NotImplemented
+ def __le__(self, other):
+ self.log_operation('A.__le__')
+ return NotImplemented
+ def __ge__(self, other):
+ self.log_operation('A.__ge__')
+ return NotImplemented
+
+class B(OperationLogger):
+ def __eq__(self, other):
+ self.log_operation('B.__eq__')
+ return NotImplemented
+ def __le__(self, other):
+ self.log_operation('B.__le__')
+ return NotImplemented
+ def __ge__(self, other):
+ self.log_operation('B.__ge__')
+ return NotImplemented
+
+class C(B):
+ def __eq__(self, other):
+ self.log_operation('C.__eq__')
+ return NotImplemented
+ def __le__(self, other):
+ self.log_operation('C.__le__')
+ return NotImplemented
+ def __ge__(self, other):
+ self.log_operation('C.__ge__')
+ return NotImplemented
+
+class OperationOrderTests(unittest.TestCase):
+ def test_comparison_orders(self):
+ self.assertEqual(op_sequence(eq, A, A), ['A.__eq__', 'A.__eq__'])
+ self.assertEqual(op_sequence(eq, A, B), ['A.__eq__', 'B.__eq__'])
+ self.assertEqual(op_sequence(eq, B, A), ['B.__eq__', 'A.__eq__'])
+ # C is a subclass of B, so C.__eq__ is called first
+ self.assertEqual(op_sequence(eq, B, C), ['C.__eq__', 'B.__eq__'])
+ self.assertEqual(op_sequence(eq, C, B), ['C.__eq__', 'B.__eq__'])
+
+ self.assertEqual(op_sequence(le, A, A), ['A.__le__', 'A.__ge__'])
+ self.assertEqual(op_sequence(le, A, B), ['A.__le__', 'B.__ge__'])
+ self.assertEqual(op_sequence(le, B, A), ['B.__le__', 'A.__ge__'])
+ self.assertEqual(op_sequence(le, B, C), ['C.__ge__', 'B.__le__'])
+ self.assertEqual(op_sequence(le, C, B), ['C.__le__', 'B.__ge__'])
+
+def test_main():
+ support.run_unittest(RatTestCase, OperationOrderTests)
if __name__ == "__main__":
test_main()
};
static PyObject *
-half_richcompare(PyObject *self, PyObject *other, int op)
+slot_tp_richcompare(PyObject *self, PyObject *other, int op)
{
PyObject *func, *args, *res;
static PyObject *op_str[6];
return res;
}
-static PyObject *
-slot_tp_richcompare(PyObject *self, PyObject *other, int op)
-{
- PyObject *res;
-
- if (Py_TYPE(self)->tp_richcompare == slot_tp_richcompare) {
- res = half_richcompare(self, other, op);
- if (res != Py_NotImplemented)
- return res;
- Py_DECREF(res);
- }
- if (Py_TYPE(other)->tp_richcompare == slot_tp_richcompare) {
- res = half_richcompare(other, self, _Py_SwappedOp[op]);
- if (res != Py_NotImplemented) {
- return res;
- }
- Py_DECREF(res);
- }
- Py_INCREF(Py_NotImplemented);
- return Py_NotImplemented;
-}
-
static PyObject *
slot_tp_iter(PyObject *self)
{