[Python-checkins] r69182 - in python/branches/release30-maint: Lib/test/test_descr.py Lib/test/test_funcattrs.py Lib/test/test_parser.py Modules/_csv.c Modules/_elementtree.c Modules/_localemodule.c Modules/_pickle.c Modules/_tkinter.c Modules/parsermodule.c Modules/pyexpat.c Objects/cellobject.c Objects/descrobject.c Objects/rangeobject.c Objects/setobject.c PC/winreg.c

mark.dickinson python-checkins at python.org
Sun Feb 1 11:41:18 CET 2009


Author: mark.dickinson
Date: Sun Feb  1 11:41:18 2009
New Revision: 69182

Log:
Merged revisions 69181 via svnmerge from 
svn+ssh://pythondev@svn.python.org/python/branches/py3k

........
  r69181 | mark.dickinson | 2009-02-01 10:28:51 +0000 (Sun, 01 Feb 2009) | 3 lines
  
  Issue #1717, stage 2: remove uses of tp_compare in Modules and most
  Objects.
........


Modified:
   python/branches/release30-maint/   (props changed)
   python/branches/release30-maint/Lib/test/test_descr.py
   python/branches/release30-maint/Lib/test/test_funcattrs.py
   python/branches/release30-maint/Lib/test/test_parser.py
   python/branches/release30-maint/Modules/_csv.c
   python/branches/release30-maint/Modules/_elementtree.c
   python/branches/release30-maint/Modules/_localemodule.c
   python/branches/release30-maint/Modules/_pickle.c
   python/branches/release30-maint/Modules/_tkinter.c
   python/branches/release30-maint/Modules/parsermodule.c
   python/branches/release30-maint/Modules/pyexpat.c
   python/branches/release30-maint/Objects/cellobject.c
   python/branches/release30-maint/Objects/descrobject.c
   python/branches/release30-maint/Objects/rangeobject.c
   python/branches/release30-maint/Objects/setobject.c
   python/branches/release30-maint/PC/winreg.c

Modified: python/branches/release30-maint/Lib/test/test_descr.py
==============================================================================
--- python/branches/release30-maint/Lib/test/test_descr.py	(original)
+++ python/branches/release30-maint/Lib/test/test_descr.py	Sun Feb  1 11:41:18 2009
@@ -3885,7 +3885,7 @@
         # Testing method-wrapper objects...
         # <type 'method-wrapper'> did not support any reflection before 2.5
 
-        return # XXX should methods really support __eq__?
+        # XXX should methods really support __eq__?
 
         l = []
         self.assertEqual(l.__add__, l.__add__)

Modified: python/branches/release30-maint/Lib/test/test_funcattrs.py
==============================================================================
--- python/branches/release30-maint/Lib/test/test_funcattrs.py	(original)
+++ python/branches/release30-maint/Lib/test/test_funcattrs.py	Sun Feb  1 11:41:18 2009
@@ -224,10 +224,41 @@
         del self.b.__doc__
         self.assertEqual(self.b.__doc__, None)
 
+def cell(value):
+    """Create a cell containing the given value."""
+    def f():
+        print(a)
+    a = value
+    return f.__closure__[0]
+
+def empty_cell(empty=True):
+    """Create an empty cell."""
+    def f():
+        print(a)
+    # the intent of the following line is simply "if False:";  it's
+    # spelt this way to avoid the danger that a future optimization
+    # might simply remove an "if False:" code block.
+    if not empty:
+        a = 1729
+    return f.__closure__[0]
+
+class CellTest(unittest.TestCase):
+    def test_comparison(self):
+        # These tests are here simply to exercise the comparison code;
+        # their presence should not be interpreted as providing any
+        # guarantees about the semantics (or even existence) of cell
+        # comparisons in future versions of CPython.
+        self.assert_(cell(2) < cell(3))
+        self.assert_(empty_cell() < cell('saturday'))
+        self.assert_(empty_cell() == empty_cell())
+        self.assert_(cell(-36) == cell(-36.0))
+        self.assert_(cell(True) > empty_cell())
+
+
 def test_main():
     support.run_unittest(FunctionPropertiesTest, ImplicitReferencesTest,
                               ArbitraryFunctionAttrTest, FunctionDictsTest,
-                              FunctionDocstringTest)
+                              FunctionDocstringTest, CellTest)
 
 if __name__ == "__main__":
     test_main()

Modified: python/branches/release30-maint/Lib/test/test_parser.py
==============================================================================
--- python/branches/release30-maint/Lib/test/test_parser.py	(original)
+++ python/branches/release30-maint/Lib/test/test_parser.py	Sun Feb  1 11:41:18 2009
@@ -2,6 +2,7 @@
 import os
 import unittest
 import sys
+import operator
 from test import support
 
 #
@@ -496,12 +497,81 @@
               file=sys.stderr)
         self.assertRaises(MemoryError, parser.expr, e)
 
+class STObjectTestCase(unittest.TestCase):
+    """Test operations on ST objects themselves"""
+
+    def test_comparisons(self):
+        # ST objects should support order and equality comparisons
+        st1 = parser.expr('2 + 3')
+        st2 = parser.suite('x = 2; y = x + 3')
+        st3 = parser.expr('list(x**3 for x in range(20))')
+        st1_copy = parser.expr('2 + 3')
+        st2_copy = parser.suite('x = 2; y = x + 3')
+        st3_copy = parser.expr('list(x**3 for x in range(20))')
+
+        # exercise fast path for object identity
+        self.assertEquals(st1 == st1, True)
+        self.assertEquals(st2 == st2, True)
+        self.assertEquals(st3 == st3, True)
+        # slow path equality
+        self.assertEqual(st1, st1_copy)
+        self.assertEqual(st2, st2_copy)
+        self.assertEqual(st3, st3_copy)
+        self.assertEquals(st1 == st2, False)
+        self.assertEquals(st1 == st3, False)
+        self.assertEquals(st2 == st3, False)
+        self.assertEquals(st1 != st1, False)
+        self.assertEquals(st2 != st2, False)
+        self.assertEquals(st3 != st3, False)
+        self.assertEquals(st1 != st1_copy, False)
+        self.assertEquals(st2 != st2_copy, False)
+        self.assertEquals(st3 != st3_copy, False)
+        self.assertEquals(st2 != st1, True)
+        self.assertEquals(st1 != st3, True)
+        self.assertEquals(st3 != st2, True)
+        # we don't particularly care what the ordering is;  just that
+        # it's usable and self-consistent
+        self.assertEquals(st1 < st2, not (st2 <= st1))
+        self.assertEquals(st1 < st3, not (st3 <= st1))
+        self.assertEquals(st2 < st3, not (st3 <= st2))
+        self.assertEquals(st1 < st2, st2 > st1)
+        self.assertEquals(st1 < st3, st3 > st1)
+        self.assertEquals(st2 < st3, st3 > st2)
+        self.assertEquals(st1 <= st2, st2 >= st1)
+        self.assertEquals(st3 <= st1, st1 >= st3)
+        self.assertEquals(st2 <= st3, st3 >= st2)
+        # transitivity
+        bottom = min(st1, st2, st3)
+        top = max(st1, st2, st3)
+        mid = sorted([st1, st2, st3])[1]
+        self.assert_(bottom < mid)
+        self.assert_(bottom < top)
+        self.assert_(mid < top)
+        self.assert_(bottom <= mid)
+        self.assert_(bottom <= top)
+        self.assert_(mid <= top)
+        self.assert_(bottom <= bottom)
+        self.assert_(mid <= mid)
+        self.assert_(top <= top)
+        # interaction with other types
+        self.assertEquals(st1 == 1588.602459, False)
+        self.assertEquals('spanish armada' != st2, True)
+        self.assertRaises(TypeError, operator.ge, st3, None)
+        self.assertRaises(TypeError, operator.le, False, st1)
+        self.assertRaises(TypeError, operator.lt, st1, 1815)
+        self.assertRaises(TypeError, operator.gt, b'waterloo', st2)
+
+
+    # XXX tests for pickling and unpickling of ST objects should go here
+
+
 def test_main():
     support.run_unittest(
         RoundtripLegalSyntaxTestCase,
         IllegalSyntaxTestCase,
         CompileTestCase,
         ParserStackLimitTestCase,
+        STObjectTestCase,
     )
 
 

Modified: python/branches/release30-maint/Modules/_csv.c
==============================================================================
--- python/branches/release30-maint/Modules/_csv.c	(original)
+++ python/branches/release30-maint/Modules/_csv.c	Sun Feb  1 11:41:18 2009
@@ -443,7 +443,7 @@
 	(printfunc)0,                           /* tp_print */
 	(getattrfunc)0,                         /* tp_getattr */
 	(setattrfunc)0,                         /* tp_setattr */
-	(cmpfunc)0,                             /* tp_compare */
+	0,                                      /* tp_compare */
 	(reprfunc)0,                            /* tp_repr */
 	0,                                      /* tp_as_number */
 	0,                                      /* tp_as_sequence */
@@ -864,7 +864,7 @@
 	(printfunc)0,                           /*tp_print*/
 	(getattrfunc)0,                         /*tp_getattr*/
 	(setattrfunc)0,                         /*tp_setattr*/
-	(cmpfunc)0,                             /*tp_compare*/
+	0,                                     /*tp_compare*/
 	(reprfunc)0,                            /*tp_repr*/
 	0,                                      /*tp_as_number*/
 	0,                                      /*tp_as_sequence*/
@@ -1286,7 +1286,7 @@
 	(printfunc)0,                           /*tp_print*/
 	(getattrfunc)0,                         /*tp_getattr*/
 	(setattrfunc)0,                         /*tp_setattr*/
-	(cmpfunc)0,                             /*tp_compare*/
+	0,                                      /*tp_compare*/
 	(reprfunc)0,                            /*tp_repr*/
 	0,                                      /*tp_as_number*/
 	0,                                      /*tp_as_sequence*/

Modified: python/branches/release30-maint/Modules/_elementtree.c
==============================================================================
--- python/branches/release30-maint/Modules/_elementtree.c	(original)
+++ python/branches/release30-maint/Modules/_elementtree.c	Sun Feb  1 11:41:18 2009
@@ -761,7 +761,7 @@
     for (i = 0; i < self->extra->length; i++) {
         PyObject* item = self->extra->children[i];
         if (Element_CheckExact(item) &&
-            PyObject_Compare(((ElementObject*)item)->tag, tag) == 0) {
+            PyObject_RichCompareBool(((ElementObject*)item)->tag, tag, Py_EQ) == 1) {
             Py_INCREF(item);
             return item;
         }
@@ -792,7 +792,8 @@
 
     for (i = 0; i < self->extra->length; i++) {
         ElementObject* item = (ElementObject*) self->extra->children[i];
-        if (Element_CheckExact(item) && !PyObject_Compare(item->tag, tag)) {
+        if (Element_CheckExact(item) && (PyObject_RichCompareBool(item->tag, tag, Py_EQ) == 1)) {
+
             PyObject* text = element_get_text(item);
             if (text == Py_None)
                 return PyBytes_FromString("");
@@ -830,7 +831,7 @@
     for (i = 0; i < self->extra->length; i++) {
         PyObject* item = self->extra->children[i];
         if (Element_CheckExact(item) &&
-            PyObject_Compare(((ElementObject*)item)->tag, tag) == 0) {
+            PyObject_RichCompareBool(((ElementObject*)item)->tag, tag, Py_EQ) == 1) {
             if (PyList_Append(out, item) < 0) {
                 Py_DECREF(out);
                 return NULL;
@@ -1102,7 +1103,7 @@
     for (i = 0; i < self->extra->length; i++) {
         if (self->extra->children[i] == element)
             break;
-        if (PyObject_Compare(self->extra->children[i], element) == 0)
+        if (PyObject_RichCompareBool(self->extra->children[i], element, Py_EQ) == 1)
             break;
     }
 

Modified: python/branches/release30-maint/Modules/_localemodule.c
==============================================================================
--- python/branches/release30-maint/Modules/_localemodule.c	(original)
+++ python/branches/release30-maint/Modules/_localemodule.c	Sun Feb  1 11:41:18 2009
@@ -272,7 +272,9 @@
 
 #ifdef HAVE_WCSXFRM
 PyDoc_STRVAR(strxfrm__doc__,
-"string -> string. Returns a string that behaves for cmp locale-aware.");
+"strxfrm(string) -> string.\n\
+\n\
+Return a string that can be used as a key for locale-aware comparisons.");
 
 static PyObject*
 PyLocale_strxfrm(PyObject* self, PyObject* args)

Modified: python/branches/release30-maint/Modules/_pickle.c
==============================================================================
--- python/branches/release30-maint/Modules/_pickle.c	(original)
+++ python/branches/release30-maint/Modules/_pickle.c	Sun Feb  1 11:41:18 2009
@@ -715,7 +715,7 @@
     i = 0;
     module_name = NULL;
     while ((j = PyDict_Next(modules_dict, &i, &module_name, &module))) {
-        if (PyObject_Compare(module_name, main_str) == 0)
+        if (PyObject_RichCompareBool(module_name, main_str, Py_EQ) == 1)
             continue;
 
         obj = PyObject_GetAttr(module, global_name);

Modified: python/branches/release30-maint/Modules/_tkinter.c
==============================================================================
--- python/branches/release30-maint/Modules/_tkinter.c	(original)
+++ python/branches/release30-maint/Modules/_tkinter.c	Sun Feb  1 11:41:18 2009
@@ -788,15 +788,59 @@
 	                            self->value->typePtr->name, self->value);
 }
 
-static int
-PyTclObject_cmp(PyTclObject *self, PyTclObject *other)
+#define TEST_COND(cond) ((cond) ? Py_True : Py_False)
+
+static PyObject *
+PyTclObject_richcompare(PyObject *self, PyObject *other, int op)
 {
-	int res;
-	res = strcmp(Tcl_GetString(self->value),
-		     Tcl_GetString(other->value));
-	if (res < 0) return -1;
-	if (res > 0) return 1;
-	return 0;
+	int result;
+	PyObject *v;
+
+	/* neither argument should be NULL, unless something's gone wrong */
+	if (self == NULL || other == NULL) {
+		PyErr_BadInternalCall();
+		return NULL;
+	}
+
+	/* both arguments should be instances of PyTclObject */
+	if (!PyTclObject_Check(self) || !PyTclObject_Check(other)) {
+		v = Py_NotImplemented;
+		goto finished;
+	}
+
+	if (self == other)
+		/* fast path when self and other are identical */
+		result = 0;
+	else
+		result = strcmp(Tcl_GetString(((PyTclObject *)self)->value),
+				Tcl_GetString(((PyTclObject *)other)->value));
+	/* Convert return value to a Boolean */
+	switch (op) {
+	case Py_EQ:
+		v = TEST_COND(result == 0);
+		break;
+	case Py_NE:
+		v = TEST_COND(result != 0);
+		break;
+	case Py_LE:
+		v = TEST_COND(result <= 0);
+		break;
+	case Py_GE:
+		v = TEST_COND(result >= 0);
+		break;
+	case Py_LT:
+		v = TEST_COND(result < 0);
+		break;
+	case Py_GT:
+		v = TEST_COND(result > 0);
+		break;
+	default:
+		PyErr_BadArgument();
+		return NULL;
+	}
+  finished:
+	Py_INCREF(v);
+	return v;
 }
 
 PyDoc_STRVAR(get_typename__doc__, "name of the Tcl type");
@@ -818,45 +862,45 @@
 static PyTypeObject PyTclObject_Type = {
 	PyVarObject_HEAD_INIT(NULL, 0)
 	"_tkinter.Tcl_Obj",		/*tp_name*/
-	sizeof(PyTclObject),	/*tp_basicsize*/
-	0,			/*tp_itemsize*/
+	sizeof(PyTclObject),		/*tp_basicsize*/
+	0,				/*tp_itemsize*/
 	/* methods */
-	(destructor)PyTclObject_dealloc, /*tp_dealloc*/
-	0,			/*tp_print*/
-	0,			/*tp_getattr*/
-	0,			/*tp_setattr*/
-	(cmpfunc)PyTclObject_cmp,	/*tp_compare*/
+	(destructor)PyTclObject_dealloc,/*tp_dealloc*/
+	0,				/*tp_print*/
+	0,				/*tp_getattr*/
+	0,				/*tp_setattr*/
+	0,				/*tp_compare*/
 	(reprfunc)PyTclObject_repr,	/*tp_repr*/
-	0,			/*tp_as_number*/
-	0,			/*tp_as_sequence*/
-	0,			/*tp_as_mapping*/
-	0,			/*tp_hash*/
-        0,                      /*tp_call*/
-        (reprfunc)PyTclObject_str,        /*tp_str*/
-        PyObject_GenericGetAttr,/*tp_getattro*/
-        0,                      /*tp_setattro*/
-        0,                      /*tp_as_buffer*/
-        Py_TPFLAGS_DEFAULT,     /*tp_flags*/
-        0,                      /*tp_doc*/
-        0,                      /*tp_traverse*/
-        0,                      /*tp_clear*/
-        0,                      /*tp_richcompare*/
-        0,                      /*tp_weaklistoffset*/
-        0,                      /*tp_iter*/
-        0,                      /*tp_iternext*/
-        0,    /*tp_methods*/
-        0,			/*tp_members*/
-        PyTclObject_getsetlist, /*tp_getset*/
-        0,                      /*tp_base*/
-        0,                      /*tp_dict*/
-        0,                      /*tp_descr_get*/
-        0,                      /*tp_descr_set*/
-        0,                      /*tp_dictoffset*/
-        0,                      /*tp_init*/
-        0,                      /*tp_alloc*/
-        0,                      /*tp_new*/
-        0,                      /*tp_free*/
-        0,                      /*tp_is_gc*/
+	0,				/*tp_as_number*/
+	0,				/*tp_as_sequence*/
+	0,				/*tp_as_mapping*/
+	0,				/*tp_hash*/
+	0,				/*tp_call*/
+	(reprfunc)PyTclObject_str,	/*tp_str*/
+	PyObject_GenericGetAttr,	/*tp_getattro*/
+	0,				/*tp_setattro*/
+	0,				/*tp_as_buffer*/
+	Py_TPFLAGS_DEFAULT,		/*tp_flags*/
+	0,				/*tp_doc*/
+	0,				/*tp_traverse*/
+	0,				/*tp_clear*/
+	PyTclObject_richcompare,	/*tp_richcompare*/
+	0,				/*tp_weaklistoffset*/
+	0,				/*tp_iter*/
+	0,				/*tp_iternext*/
+	0,				/*tp_methods*/
+	0,				/*tp_members*/
+	PyTclObject_getsetlist,		/*tp_getset*/
+	0,				/*tp_base*/
+	0,				/*tp_dict*/
+	0,				/*tp_descr_get*/
+	0,				/*tp_descr_set*/
+	0,				/*tp_dictoffset*/
+	0,				/*tp_init*/
+	0,				/*tp_alloc*/
+	0,				/*tp_new*/
+	0,				/*tp_free*/
+	0,				/*tp_is_gc*/
 };
 
 static Tcl_Obj*

Modified: python/branches/release30-maint/Modules/parsermodule.c
==============================================================================
--- python/branches/release30-maint/Modules/parsermodule.c	(original)
+++ python/branches/release30-maint/Modules/parsermodule.c	Sun Feb  1 11:41:18 2009
@@ -169,7 +169,7 @@
 
 
 static void parser_free(PyST_Object *st);
-static int parser_compare(PyST_Object *left, PyST_Object *right);
+static PyObject* parser_richcompare(PyObject *left, PyObject *right, int op);
 static PyObject* parser_compilest(PyST_Object *, PyObject *, PyObject *);
 static PyObject* parser_isexpr(PyST_Object *, PyObject *, PyObject *);
 static PyObject* parser_issuite(PyST_Object *, PyObject *, PyObject *);
@@ -203,7 +203,7 @@
     0,                                  /* tp_print             */
     0,                                  /* tp_getattr           */
     0,                                  /* tp_setattr           */
-    (cmpfunc)parser_compare,            /* tp_compare           */
+    0,                                  /* tp_compare          */
     0,                                  /* tp_repr              */
     0,                                  /* tp_as_number         */
     0,                                  /* tp_as_sequence       */
@@ -223,7 +223,7 @@
     "Intermediate representation of a Python parse tree.",
     0,                                  /* tp_traverse */
     0,                                  /* tp_clear */
-    0,                                  /* tp_richcompare */
+    parser_richcompare,                 /* tp_richcompare */
     0,                                  /* tp_weaklistoffset */
     0,                                  /* tp_iter */
     0,                                  /* tp_iternext */
@@ -231,6 +231,9 @@
 };  /* PyST_Type */
 
 
+/* PyST_Type isn't subclassable, so just check ob_type */
+#define PyST_Object_Check(v) ((v)->ob_type == &PyST_Type)
+
 static int
 parser_compare_nodes(node *left, node *right)
 {
@@ -260,26 +263,69 @@
     return (0);
 }
 
-
-/*  int parser_compare(PyST_Object* left, PyST_Object* right)
+/*  parser_richcompare(PyObject* left, PyObject* right, int op)
  *
  *  Comparison function used by the Python operators ==, !=, <, >, <=, >=
  *  This really just wraps a call to parser_compare_nodes() with some easy
  *  checks and protection code.
  *
  */
-static int
-parser_compare(PyST_Object *left, PyST_Object *right)
+
+#define TEST_COND(cond) ((cond) ? Py_True : Py_False)
+
+static PyObject *
+parser_richcompare(PyObject *left, PyObject *right, int op)
 {
-    if (left == right)
-        return (0);
+    int result;
+    PyObject *v;
 
-    if ((left == 0) || (right == 0))
-        return (-1);
+    /* neither argument should be NULL, unless something's gone wrong */
+    if (left == NULL || right == NULL) {
+        PyErr_BadInternalCall();
+        return NULL;
+    }
 
-    return (parser_compare_nodes(left->st_node, right->st_node));
-}
+    /* both arguments should be instances of PyST_Object */
+    if (!PyST_Object_Check(left) || !PyST_Object_Check(right)) {
+        v = Py_NotImplemented;
+        goto finished;
+    }
 
+    if (left == right)
+        /* if arguments are identical, they're equal */
+        result = 0;
+    else
+        result = parser_compare_nodes(((PyST_Object *)left)->st_node,
+                                      ((PyST_Object *)right)->st_node);
+
+    /* Convert return value to a Boolean */
+    switch (op) {
+    case Py_EQ:
+        v = TEST_COND(result == 0);
+        break;
+    case Py_NE:
+        v = TEST_COND(result != 0);
+        break;
+    case Py_LE:
+        v = TEST_COND(result <= 0);
+        break;
+    case Py_GE:
+        v = TEST_COND(result >= 0);
+        break;
+    case Py_LT:
+        v = TEST_COND(result < 0);
+        break;
+    case Py_GT:
+        v = TEST_COND(result > 0);
+        break;
+    default:
+        PyErr_BadArgument();
+        return NULL;
+    }
+  finished:
+    Py_INCREF(v);
+    return v;
+}
 
 /*  parser_newstobject(node* st)
  *

Modified: python/branches/release30-maint/Modules/pyexpat.c
==============================================================================
--- python/branches/release30-maint/Modules/pyexpat.c	(original)
+++ python/branches/release30-maint/Modules/pyexpat.c	Sun Feb  1 11:41:18 2009
@@ -1622,7 +1622,7 @@
 	(printfunc)0,		/*tp_print*/
 	0,			/*tp_getattr*/
 	(setattrfunc)xmlparse_setattr,	/*tp_setattr*/
-	(cmpfunc)0,		/*tp_compare*/
+	0,			/*tp_compare*/
 	(reprfunc)0,		/*tp_repr*/
 	0,			/*tp_as_number*/
 	0,		/*tp_as_sequence*/

Modified: python/branches/release30-maint/Objects/cellobject.c
==============================================================================
--- python/branches/release30-maint/Objects/cellobject.c	(original)
+++ python/branches/release30-maint/Objects/cellobject.c	Sun Feb  1 11:41:18 2009
@@ -51,16 +51,56 @@
 	PyObject_GC_Del(op);
 }
 
-static int
-cell_compare(PyCellObject *a, PyCellObject *b)
+#define TEST_COND(cond) ((cond) ? Py_True : Py_False)
+
+static PyObject *
+cell_richcompare(PyObject *a, PyObject *b, int op)
 {
-	if (a->ob_ref == NULL) {
-		if (b->ob_ref == NULL)
-			return 0;
-		return -1;
-	} else if (b->ob_ref == NULL)
-		return 1;
-	return PyObject_Compare(a->ob_ref, b->ob_ref);
+	int result;
+	PyObject *v;
+
+	/* neither argument should be NULL, unless something's gone wrong */
+	assert(a != NULL && b != NULL);
+
+	/* both arguments should be instances of PyCellObject */
+	if (!PyCell_Check(a) || !PyCell_Check(b)) {
+		v = Py_NotImplemented;
+		Py_INCREF(v);
+		return v;
+	}
+
+	/* compare cells by contents; empty cells come before anything else */
+	a = ((PyCellObject *)a)->ob_ref;
+	b = ((PyCellObject *)b)->ob_ref;
+	if (a != NULL && b != NULL)
+		return PyObject_RichCompare(a, b, op);
+
+	result = (b == NULL) - (a == NULL);
+	switch (op) {
+	case Py_EQ:
+		v = TEST_COND(result == 0);
+		break;
+	case Py_NE:
+		v = TEST_COND(result != 0);
+		break;
+	case Py_LE:
+		v = TEST_COND(result <= 0);
+		break;
+	case Py_GE:
+		v = TEST_COND(result >= 0);
+		break;
+	case Py_LT:
+		v = TEST_COND(result < 0);
+		break;
+	case Py_GT:
+		v = TEST_COND(result > 0);
+		break;
+	default:
+		PyErr_BadArgument();
+		return NULL;
+	}
+	Py_INCREF(v);
+	return v;
 }
 
 static PyObject *
@@ -114,7 +154,7 @@
 	0,                                      /* tp_print */
 	0,	                                /* tp_getattr */
 	0,					/* tp_setattr */
-	(cmpfunc)cell_compare,					/* tp_compare */
+	0,					/* tp_compare */
 	(reprfunc)cell_repr,			/* tp_repr */
 	0,					/* tp_as_number */
 	0,			                /* tp_as_sequence */
@@ -129,7 +169,7 @@
  	0,					/* tp_doc */
  	(traverseproc)cell_traverse,		/* tp_traverse */
  	(inquiry)cell_clear,			/* tp_clear */
-	0,					/* tp_richcompare */
+	cell_richcompare,			/* tp_richcompare */
 	0,					/* tp_weaklistoffset */
 	0, 					/* tp_iter */
 	0,					/* tp_iternext */

Modified: python/branches/release30-maint/Objects/descrobject.c
==============================================================================
--- python/branches/release30-maint/Objects/descrobject.c	(original)
+++ python/branches/release30-maint/Objects/descrobject.c	Sun Feb  1 11:41:18 2009
@@ -774,12 +774,6 @@
 	return 0;
 }
 
-static int
-proxy_compare(proxyobject *v, PyObject *w)
-{
-	return PyObject_Compare(v->dict, w);
-}
-
 static PyObject *
 proxy_richcompare(proxyobject *v, PyObject *w, int op)
 {
@@ -796,7 +790,7 @@
 	0,					/* tp_print */
 	0,					/* tp_getattr */
 	0,					/* tp_setattr */
-	(cmpfunc)proxy_compare,			/* tp_compare */
+	0,					/* tp_compare */
 	0,					/* tp_repr */
 	0,					/* tp_as_number */
 	&proxy_as_sequence,			/* tp_as_sequence */
@@ -844,12 +838,17 @@
 /* This has no reason to be in this file except that adding new files is a
    bit of a pain */
 
+/* forward */
+static PyTypeObject wrappertype;
+
 typedef struct {
 	PyObject_HEAD
 	PyWrapperDescrObject *descr;
 	PyObject *self;
 } wrapperobject;
 
+#define Wrapper_Check(v) (Py_TYPE(v) == &wrappertype)
+
 static void
 wrapper_dealloc(wrapperobject *wp)
 {
@@ -861,13 +860,60 @@
 	Py_TRASHCAN_SAFE_END(wp)
 }
 
-static int
-wrapper_compare(wrapperobject *a, wrapperobject *b)
+#define TEST_COND(cond) ((cond) ? Py_True : Py_False)
+
+static PyObject *
+wrapper_richcompare(PyObject *a, PyObject *b, int op)
 {
-	if (a->descr == b->descr)
-		return PyObject_Compare(a->self, b->self);
-	else
-		return (a->descr < b->descr) ? -1 : 1;
+	int result;
+	PyObject *v;
+	PyWrapperDescrObject *a_descr, *b_descr;
+
+	assert(a != NULL && b != NULL);
+
+	/* both arguments should be wrapperobjects */
+	if (!Wrapper_Check(a) || !Wrapper_Check(b)) {
+		v = Py_NotImplemented;
+		Py_INCREF(v);
+		return v;
+	}
+
+	/* compare by descriptor address; if the descriptors are the same,
+	   compare by the objects they're bound to */
+	a_descr = ((wrapperobject *)a)->descr;
+	b_descr = ((wrapperobject *)b)->descr;
+	if (a_descr == b_descr) {
+		a = ((wrapperobject *)a)->self;
+		b = ((wrapperobject *)b)->self;
+		return PyObject_RichCompare(a, b, op);
+	}
+
+	result = a_descr - b_descr;
+	switch (op) {
+	case Py_EQ:
+		v = TEST_COND(result == 0);
+		break;
+	case Py_NE:
+		v = TEST_COND(result != 0);
+		break;
+	case Py_LE:
+		v = TEST_COND(result <= 0);
+		break;
+	case Py_GE:
+		v = TEST_COND(result >= 0);
+		break;
+	case Py_LT:
+		v = TEST_COND(result < 0);
+		break;
+	case Py_GT:
+		v = TEST_COND(result > 0);
+		break;
+	default:
+		PyErr_BadArgument();
+		return NULL;
+	}
+	Py_INCREF(v);
+	return v;
 }
 
 static long
@@ -977,7 +1023,7 @@
 	0,					/* tp_print */
 	0,					/* tp_getattr */
 	0,					/* tp_setattr */
-	(cmpfunc)wrapper_compare,		/* tp_compare */
+	0,					/* tp_compare */
 	(reprfunc)wrapper_repr,			/* tp_repr */
 	0,					/* tp_as_number */
 	0,					/* tp_as_sequence */
@@ -992,7 +1038,7 @@
  	0,					/* tp_doc */
 	wrapper_traverse,			/* tp_traverse */
  	0,					/* tp_clear */
-	0,					/* tp_richcompare */
+	wrapper_richcompare,			/* tp_richcompare */
 	0,					/* tp_weaklistoffset */
 	0,					/* tp_iter */
 	0,					/* tp_iternext */

Modified: python/branches/release30-maint/Objects/rangeobject.c
==============================================================================
--- python/branches/release30-maint/Objects/rangeobject.c	(original)
+++ python/branches/release30-maint/Objects/rangeobject.c	Sun Feb  1 11:41:18 2009
@@ -123,7 +123,7 @@
     Algorithm is equal to that of get_len_of_range(), but it operates
     on PyObjects (which are assumed to be PyLong or PyInt objects).
     ---------------------------------------------------------------*/
-    int cmp_result, cmp_call;
+    int cmp_result;
     PyObject *lo, *hi;
     PyObject *step = NULL;
     PyObject *diff = NULL;
@@ -134,13 +134,12 @@
     PyObject *zero = PyLong_FromLong(0);
     if (zero == NULL)
         return NULL;
-    cmp_call = PyObject_Cmp(r->step, zero, &cmp_result);
+    cmp_result = PyObject_RichCompareBool(r->step, zero, Py_GT);
     Py_DECREF(zero);
-    if (cmp_call == -1)
+    if (cmp_result == -1)
         return NULL;
 
-    assert(cmp_result != 0);
-    if (cmp_result > 0) {
+    if (cmp_result == 1) {
         lo = r->start;
         hi = r->stop;
         step = r->step;
@@ -154,7 +153,7 @@
     }
 
     /* if (lo >= hi), return length of 0. */
-    if (PyObject_Compare(lo, hi) >= 0) {
+    if (PyObject_RichCompareBool(lo, hi, Py_GE) == 1) {
         Py_XDECREF(step);
         return PyLong_FromLong(0);
     }

Modified: python/branches/release30-maint/Objects/setobject.c
==============================================================================
--- python/branches/release30-maint/Objects/setobject.c	(original)
+++ python/branches/release30-maint/Objects/setobject.c	Sun Feb  1 11:41:18 2009
@@ -1824,13 +1824,6 @@
 	return Py_NotImplemented;
 }
 
-static int
-set_nocmp(PyObject *self, PyObject *other)
-{
-	PyErr_SetString(PyExc_TypeError, "cannot compare sets using cmp()");
-	return -1;
-}
-
 static PyObject *
 set_add(PySetObject *so, PyObject *key)
 {
@@ -2111,7 +2104,7 @@
 	0,				/* tp_print */
 	0,				/* tp_getattr */
 	0,				/* tp_setattr */
-	set_nocmp,			/* tp_compare */
+	0,				/* tp_compare */
 	(reprfunc)set_repr,		/* tp_repr */
 	&set_as_number,			/* tp_as_number */
 	&set_as_sequence,		/* tp_as_sequence */
@@ -2208,7 +2201,7 @@
 	0,				/* tp_print */
 	0,				/* tp_getattr */
 	0,				/* tp_setattr */
-	set_nocmp,			/* tp_compare */
+	0,				/* tp_compare */
 	(reprfunc)set_repr,		/* tp_repr */
 	&frozenset_as_number,		/* tp_as_number */
 	&set_as_sequence,		/* tp_as_sequence */

Modified: python/branches/release30-maint/PC/winreg.c
==============================================================================
--- python/branches/release30-maint/PC/winreg.c	(original)
+++ python/branches/release30-maint/PC/winreg.c	Sun Feb  1 11:41:18 2009
@@ -326,7 +326,7 @@
 "Operations:\n"
 "__bool__ - Handles with an open object return true, otherwise false.\n"
 "__int__ - Converting a handle to an integer returns the Win32 handle.\n"
-"__cmp__ - Handle objects are compared using the handle value.");
+"rich comparison - Handle objects are compared using the handle value.");
 
 
 PyDoc_STRVAR(PyHKEY_Close_doc,
@@ -485,7 +485,7 @@
 	0,				/* tp_print */
 	0,				/* tp_getattr */
 	0,				/* tp_setattr */
-	PyHKEY_compareFunc,		/* tp_compare */
+	0,				/* tp_compare */
 	0,				/* tp_repr */
 	&PyHKEY_NumberMethods,		/* tp_as_number */
 	0,				/* tp_as_sequence */


More information about the Python-checkins mailing list