[Python-checkins] python/dist/src/Objects object.c,2.175,2.176
gvanrossum@users.sourceforge.net
gvanrossum@users.sourceforge.net
Fri, 31 May 2002 13:03:56 -0700
Update of /cvsroot/python/python/dist/src/Objects
In directory usw-pr-cvs1:/tmp/cvs-serv27720
Modified Files:
object.c
Log Message:
Implement the intention of SF patch 472523 (but coded differently).
In the past, an object's tp_compare could return any value. In 2.2
the docs were tightened to require it to return -1, 0 or 1; and -1 for
an error.
We now issue a warning if the value is not in this range. When an
exception is raised, we allow -1 or -2 as return value, since -2 will
the recommended return value for errors in the future. (Eventually
tp_compare will also be allowed to return +2, to indicate
NotImplemented; but that can only be implemented once we know all
extensions return a value in [-2...1]. Or perhaps it will require the
type to set a flag bit.)
I haven't decided yet whether to backport this to 2.2.x. The patch
applies fine. But is it fair to start warning in 2.2.2 about code
that worked flawlessly in 2.2.1?
Index: object.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/object.c,v
retrieving revision 2.175
retrieving revision 2.176
diff -C2 -d -r2.175 -r2.176
*** object.c 24 May 2002 19:01:58 -0000 2.175
--- object.c 31 May 2002 20:03:54 -0000 2.176
***************
*** 354,357 ****
--- 354,397 ----
+ /* Helper to warn about deprecated tp_compare return values. Return:
+ -2 for an exception;
+ -1 if v < w;
+ 0 if v == w;
+ 1 if v > w.
+ (This function cannot return 2.)
+ */
+ static int
+ adjust_tp_compare(int c)
+ {
+ if (PyErr_Occurred()) {
+ if (c != -1 && c != -2) {
+ PyObject *t, *v, *tb;
+ PyErr_Fetch(&t, &v, &tb);
+ if (PyErr_Warn(PyExc_RuntimeWarning,
+ "tp_compare didn't return -1 or -2 "
+ "for exception") < 0) {
+ Py_XDECREF(t);
+ Py_XDECREF(v);
+ Py_XDECREF(tb);
+ }
+ else
+ PyErr_Restore(t, v, tb);
+ }
+ return -2;
+ }
+ else if (c < -1 || c > 1) {
+ if (PyErr_Warn(PyExc_RuntimeWarning,
+ "tp_compare didn't return -1, 0 or 1") < 0)
+ return -2;
+ else
+ return c < -1 ? -1 : 1;
+ }
+ else {
+ assert(c >= -1 && c <= 1);
+ return c;
+ }
+ }
+
+
/* Macro to get the tp_richcompare field of a type if defined */
#define RICHCOMPARE(t) (PyType_HasFeature((t), Py_TPFLAGS_HAVE_RICHCOMPARE) \
***************
*** 481,487 ****
if (f != NULL && f == w->ob_type->tp_compare) {
c = (*f)(v, w);
! if (c < 0 && PyErr_Occurred())
! return -1;
! return c < 0 ? -1 : c > 0 ? 1 : 0;
}
--- 521,525 ----
if (f != NULL && f == w->ob_type->tp_compare) {
c = (*f)(v, w);
! return adjust_tp_compare(c);
}
***************
*** 503,509 ****
Py_DECREF(v);
Py_DECREF(w);
! if (c < 0 && PyErr_Occurred())
! return -2;
! return c < 0 ? -1 : c > 0 ? 1 : 0;
}
--- 541,545 ----
Py_DECREF(v);
Py_DECREF(w);
! return adjust_tp_compare(c);
}
***************
*** 513,519 ****
Py_DECREF(v);
Py_DECREF(w);
! if (c < 0 && PyErr_Occurred())
! return -2;
! return c < 0 ? 1 : c > 0 ? -1 : 0; /* negated! */
}
--- 549,557 ----
Py_DECREF(v);
Py_DECREF(w);
! c = adjust_tp_compare(c);
! if (c >= -1)
! return -c; /* Swapped! */
! else
! return c;
}
***************
*** 592,600 ****
/* Do a 3-way comparison, by hook or by crook. Return:
! -2 for an exception;
-1 if v < w;
0 if v == w;
1 if v > w;
! If the object implements a tp_compare function, it returns
whatever this function returns (whether with an exception or not).
*/
--- 630,638 ----
/* Do a 3-way comparison, by hook or by crook. Return:
! -2 for an exception (but see below);
-1 if v < w;
0 if v == w;
1 if v > w;
! BUT: if the object implements a tp_compare function, it returns
whatever this function returns (whether with an exception or not).
*/
***************
*** 608,614 ****
&& (f = v->ob_type->tp_compare) != NULL) {
c = (*f)(v, w);
! if (c != 2 || !PyInstance_Check(v))
! return c;
}
c = try_rich_to_3way_compare(v, w);
if (c < 2)
--- 646,665 ----
&& (f = v->ob_type->tp_compare) != NULL) {
c = (*f)(v, w);
! if (PyInstance_Check(v)) {
! /* Instance tp_compare has a different signature.
! But if it returns undefined we fall through. */
! if (c != 2)
! return c;
! /* Else fall throug to try_rich_to_3way_compare() */
! }
! else
! return adjust_tp_compare(c);
}
+ /* We only get here if one of the following is true:
+ a) v and w have different types
+ b) v and w have the same type, which doesn't have tp_compare
+ c) v and w are instances, and either __cmp__ is not defined or
+ __cmp__ returns NotImplemented
+ */
c = try_rich_to_3way_compare(v, w);
if (c < 2)
***************
*** 903,907 ****
if (fcmp != NULL) {
int c = (*fcmp)(v, w);
! if (c < 0 && PyErr_Occurred()) {
res = NULL;
goto Done;
--- 954,959 ----
if (fcmp != NULL) {
int c = (*fcmp)(v, w);
! c = adjust_tp_compare(c);
! if (c == -2) {
res = NULL;
goto Done;