[Python-checkins] python/nondist/sandbox/datetime obj_delta.c,1.17,1.18 test_both.py,1.18,1.19
tim_one@users.sourceforge.net
tim_one@users.sourceforge.net
Mon, 02 Dec 2002 13:17:32 -0800
Update of /cvsroot/python/python/nondist/sandbox/datetime
In directory sc8-pr-cvs1:/tmp/cvs-serv20656
Modified Files:
obj_delta.c test_both.py
Log Message:
Repair comparison for timedelta objects. tp_compare is ignored by
try_3way_compare because a timedelta isn't an old-style instance, so
its tp_compare didn't get called at all unless both comparands were
timedelta. This caused, e.g., comparing a timedelta and a dict to
compare via type string name instead of raising the intended TypeError.
As suggested by Guido, repaired via getting rid of tp_compare and
adding tp_richcompare.
The test suite didn't provoke these problems, so added a new test that
does.
I'm sure that date and datetime objects still suffer a similar problem.
Index: obj_delta.c
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/obj_delta.c,v
retrieving revision 1.17
retrieving revision 1.18
diff -C2 -d -r1.17 -r1.18
*** obj_delta.c 2 Dec 2002 20:42:53 -0000 1.17
--- obj_delta.c 2 Dec 2002 21:17:14 -0000 1.18
***************
*** 246,278 ****
}
! /* XXX This routine is never entered unless self and other are both
! * XXX PyDateTime_Delta. For whatever reason, Python's try_3way_compare
! * XXX ignores tp_compare unless PyInstance_Check returns true, but
! * XXX these aren't old-style classes.
*/
! static int
! delta_compare(PyDateTime_Delta *self, PyObject *other)
{
! int result = -1;
if (! PyObject_TypeCheck(other, &PyDateTime_DeltaType)) {
- /* XXX Dead code! See note above. */
PyErr_Format(PyExc_TypeError,
"can't compare %s to %s instance",
self->ob_type->tp_name, other->ob_type->tp_name);
}
! else {
! long diff = GET_TD_DAYS(self) - GET_TD_DAYS(other);
! if (diff == 0) {
! diff = GET_TD_SECONDS(self) - GET_TD_SECONDS(other);
! if (diff == 0)
! diff = GET_TD_MICROSECONDS(self) -
! GET_TD_MICROSECONDS(other);
! }
if (diff == 0)
! result = 0;
! else if (diff > 0)
! result = 1;
}
return result;
}
--- 246,285 ----
}
! /* This is more natural as a tp_compare, but doesn't work then: for whatever
! * reason, Python's try_3way_compare ignores tp_compare unless
! * PyInstance_Check returns true, but these aren't old-style classes.
*/
! static PyObject *
! delta_richcompare(PyDateTime_Delta *self, PyObject *other, int op)
{
! PyObject *result;
! long diff;
! int istrue;
if (! PyObject_TypeCheck(other, &PyDateTime_DeltaType)) {
PyErr_Format(PyExc_TypeError,
"can't compare %s to %s instance",
self->ob_type->tp_name, other->ob_type->tp_name);
+ return NULL;
}
! diff = GET_TD_DAYS(self) - GET_TD_DAYS(other);
! if (diff == 0) {
! diff = GET_TD_SECONDS(self) - GET_TD_SECONDS(other);
if (diff == 0)
! diff = GET_TD_MICROSECONDS(self) -
! GET_TD_MICROSECONDS(other);
! }
! switch (op) {
! case Py_EQ: istrue = diff == 0; break;
! case Py_NE: istrue = diff != 0; break;
! case Py_LE: istrue = diff <= 0; break;
! case Py_GE: istrue = diff >= 0; break;
! case Py_LT: istrue = diff < 0; break;
! case Py_GT: istrue = diff > 0; break;
! default:
! assert(! "op unknown");
}
+ result = istrue ? Py_True : Py_False;
+ Py_INCREF(result);
return result;
}
***************
*** 668,672 ****
0, /* tp_getattr */
0, /* tp_setattr */
! (cmpfunc)delta_compare, /* tp_compare */
(reprfunc)delta_repr, /* tp_repr */
&delta_as_number, /* tp_as_number */
--- 675,679 ----
0, /* tp_getattr */
0, /* tp_setattr */
! 0, /* tp_compare */
(reprfunc)delta_repr, /* tp_repr */
&delta_as_number, /* tp_as_number */
***************
*** 683,687 ****
0, /* tp_traverse */
0, /* tp_clear */
! 0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
--- 690,694 ----
0, /* tp_traverse */
0, /* tp_clear */
! delta_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
Index: test_both.py
===================================================================
RCS file: /cvsroot/python/python/nondist/sandbox/datetime/test_both.py,v
retrieving revision 1.18
retrieving revision 1.19
diff -C2 -d -r1.18 -r1.19
*** test_both.py 2 Dec 2002 19:40:42 -0000 1.18
--- test_both.py 2 Dec 2002 21:17:18 -0000 1.19
***************
*** 146,149 ****
--- 146,192 ----
self.assertEqual(orig, derived)
+ def test_compare(self):
+ t1 = timedelta(2, 3, 4)
+ t2 = timedelta(2, 3, 4)
+ self.failUnless(t1 == t2)
+ self.failUnless(t1 <= t2)
+ self.failUnless(t1 >= t2)
+ self.failUnless(not t1 != t2)
+ self.failUnless(not t1 < t2)
+ self.failUnless(not t1 > t2)
+ self.assertEqual(cmp(t1, t2), 0)
+ self.assertEqual(cmp(t2, t1), 0)
+
+ for args in (3, 3, 3), (2, 4, 4), (2, 3, 5):
+ t2 = timedelta(*args) # this is larger than t1
+ self.failUnless(t1 < t2)
+ self.failUnless(t2 > t1)
+ self.failUnless(t1 <= t2)
+ self.failUnless(t2 >= t1)
+ self.failUnless(t1 != t2)
+ self.failUnless(t2 != t1)
+ self.failUnless(not t1 == t2)
+ self.failUnless(not t2 == t1)
+ self.failUnless(not t1 > t2)
+ self.failUnless(not t2 < t1)
+ self.failUnless(not t1 >= t2)
+ self.failUnless(not t2 <= t1)
+ self.assertEqual(cmp(t1, t2), -1)
+ self.assertEqual(cmp(t2, t1), 1)
+
+ for badarg in 10, 10L, 34.5, "abc", {}, [], ():
+ self.assertRaises(TypeError, lambda: t1 == badarg)
+ self.assertRaises(TypeError, lambda: t1 != badarg)
+ self.assertRaises(TypeError, lambda: t1 <= badarg)
+ self.assertRaises(TypeError, lambda: t1 < badarg)
+ self.assertRaises(TypeError, lambda: t1 > badarg)
+ self.assertRaises(TypeError, lambda: t1 >= badarg)
+ self.assertRaises(TypeError, lambda: badarg == t1)
+ self.assertRaises(TypeError, lambda: badarg != t1)
+ self.assertRaises(TypeError, lambda: badarg <= t1)
+ self.assertRaises(TypeError, lambda: badarg < t1)
+ self.assertRaises(TypeError, lambda: badarg > t1)
+ self.assertRaises(TypeError, lambda: badarg >= t1)
+
#############################################################################
# date tests