Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 211c625

Browse files
committed
Issue #1717, stage 2: remove uses of tp_compare in Modules and most
Objects.
1 parent 776e701 commit 211c625

15 files changed

Lines changed: 385 additions & 113 deletions

Lib/test/test_descr.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3885,7 +3885,7 @@ def test_method_wrapper(self):
38853885
# Testing method-wrapper objects...
38863886
# <type 'method-wrapper'> did not support any reflection before 2.5
38873887

3888-
return # XXX should methods really support __eq__?
3888+
# XXX should methods really support __eq__?
38893889

38903890
l = []
38913891
self.assertEqual(l.__add__, l.__add__)

Lib/test/test_funcattrs.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,10 +224,41 @@ def test_delete_docstring(self):
224224
del self.b.__doc__
225225
self.assertEqual(self.b.__doc__, None)
226226

227+
def cell(value):
228+
"""Create a cell containing the given value."""
229+
def f():
230+
print(a)
231+
a = value
232+
return f.__closure__[0]
233+
234+
def empty_cell(empty=True):
235+
"""Create an empty cell."""
236+
def f():
237+
print(a)
238+
# the intent of the following line is simply "if False:"; it's
239+
# spelt this way to avoid the danger that a future optimization
240+
# might simply remove an "if False:" code block.
241+
if not empty:
242+
a = 1729
243+
return f.__closure__[0]
244+
245+
class CellTest(unittest.TestCase):
246+
def test_comparison(self):
247+
# These tests are here simply to exercise the comparison code;
248+
# their presence should not be interpreted as providing any
249+
# guarantees about the semantics (or even existence) of cell
250+
# comparisons in future versions of CPython.
251+
self.assert_(cell(2) < cell(3))
252+
self.assert_(empty_cell() < cell('saturday'))
253+
self.assert_(empty_cell() == empty_cell())
254+
self.assert_(cell(-36) == cell(-36.0))
255+
self.assert_(cell(True) > empty_cell())
256+
257+
227258
def test_main():
228259
support.run_unittest(FunctionPropertiesTest, ImplicitReferencesTest,
229260
ArbitraryFunctionAttrTest, FunctionDictsTest,
230-
FunctionDocstringTest)
261+
FunctionDocstringTest, CellTest)
231262

232263
if __name__ == "__main__":
233264
test_main()

Lib/test/test_parser.py

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import os
33
import unittest
44
import sys
5+
import operator
56
from test import support
67

78
#
@@ -496,12 +497,81 @@ def test_trigger_memory_error(self):
496497
file=sys.stderr)
497498
self.assertRaises(MemoryError, parser.expr, e)
498499

500+
class STObjectTestCase(unittest.TestCase):
501+
"""Test operations on ST objects themselves"""
502+
503+
def test_comparisons(self):
504+
# ST objects should support order and equality comparisons
505+
st1 = parser.expr('2 + 3')
506+
st2 = parser.suite('x = 2; y = x + 3')
507+
st3 = parser.expr('list(x**3 for x in range(20))')
508+
st1_copy = parser.expr('2 + 3')
509+
st2_copy = parser.suite('x = 2; y = x + 3')
510+
st3_copy = parser.expr('list(x**3 for x in range(20))')
511+
512+
# exercise fast path for object identity
513+
self.assertEquals(st1 == st1, True)
514+
self.assertEquals(st2 == st2, True)
515+
self.assertEquals(st3 == st3, True)
516+
# slow path equality
517+
self.assertEqual(st1, st1_copy)
518+
self.assertEqual(st2, st2_copy)
519+
self.assertEqual(st3, st3_copy)
520+
self.assertEquals(st1 == st2, False)
521+
self.assertEquals(st1 == st3, False)
522+
self.assertEquals(st2 == st3, False)
523+
self.assertEquals(st1 != st1, False)
524+
self.assertEquals(st2 != st2, False)
525+
self.assertEquals(st3 != st3, False)
526+
self.assertEquals(st1 != st1_copy, False)
527+
self.assertEquals(st2 != st2_copy, False)
528+
self.assertEquals(st3 != st3_copy, False)
529+
self.assertEquals(st2 != st1, True)
530+
self.assertEquals(st1 != st3, True)
531+
self.assertEquals(st3 != st2, True)
532+
# we don't particularly care what the ordering is; just that
533+
# it's usable and self-consistent
534+
self.assertEquals(st1 < st2, not (st2 <= st1))
535+
self.assertEquals(st1 < st3, not (st3 <= st1))
536+
self.assertEquals(st2 < st3, not (st3 <= st2))
537+
self.assertEquals(st1 < st2, st2 > st1)
538+
self.assertEquals(st1 < st3, st3 > st1)
539+
self.assertEquals(st2 < st3, st3 > st2)
540+
self.assertEquals(st1 <= st2, st2 >= st1)
541+
self.assertEquals(st3 <= st1, st1 >= st3)
542+
self.assertEquals(st2 <= st3, st3 >= st2)
543+
# transitivity
544+
bottom = min(st1, st2, st3)
545+
top = max(st1, st2, st3)
546+
mid = sorted([st1, st2, st3])[1]
547+
self.assert_(bottom < mid)
548+
self.assert_(bottom < top)
549+
self.assert_(mid < top)
550+
self.assert_(bottom <= mid)
551+
self.assert_(bottom <= top)
552+
self.assert_(mid <= top)
553+
self.assert_(bottom <= bottom)
554+
self.assert_(mid <= mid)
555+
self.assert_(top <= top)
556+
# interaction with other types
557+
self.assertEquals(st1 == 1588.602459, False)
558+
self.assertEquals('spanish armada' != st2, True)
559+
self.assertRaises(TypeError, operator.ge, st3, None)
560+
self.assertRaises(TypeError, operator.le, False, st1)
561+
self.assertRaises(TypeError, operator.lt, st1, 1815)
562+
self.assertRaises(TypeError, operator.gt, b'waterloo', st2)
563+
564+
565+
# XXX tests for pickling and unpickling of ST objects should go here
566+
567+
499568
def test_main():
500569
support.run_unittest(
501570
RoundtripLegalSyntaxTestCase,
502571
IllegalSyntaxTestCase,
503572
CompileTestCase,
504573
ParserStackLimitTestCase,
574+
STObjectTestCase,
505575
)
506576

507577

Modules/_csv.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -443,7 +443,7 @@ static PyTypeObject Dialect_Type = {
443443
(printfunc)0, /* tp_print */
444444
(getattrfunc)0, /* tp_getattr */
445445
(setattrfunc)0, /* tp_setattr */
446-
(cmpfunc)0, /* tp_compare */
446+
0, /* tp_compare */
447447
(reprfunc)0, /* tp_repr */
448448
0, /* tp_as_number */
449449
0, /* tp_as_sequence */
@@ -864,7 +864,7 @@ static PyTypeObject Reader_Type = {
864864
(printfunc)0, /*tp_print*/
865865
(getattrfunc)0, /*tp_getattr*/
866866
(setattrfunc)0, /*tp_setattr*/
867-
(cmpfunc)0, /*tp_compare*/
867+
0, /*tp_compare*/
868868
(reprfunc)0, /*tp_repr*/
869869
0, /*tp_as_number*/
870870
0, /*tp_as_sequence*/
@@ -1286,7 +1286,7 @@ static PyTypeObject Writer_Type = {
12861286
(printfunc)0, /*tp_print*/
12871287
(getattrfunc)0, /*tp_getattr*/
12881288
(setattrfunc)0, /*tp_setattr*/
1289-
(cmpfunc)0, /*tp_compare*/
1289+
0, /*tp_compare*/
12901290
(reprfunc)0, /*tp_repr*/
12911291
0, /*tp_as_number*/
12921292
0, /*tp_as_sequence*/

Modules/_elementtree.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,7 @@ element_find(ElementObject* self, PyObject* args)
761761
for (i = 0; i < self->extra->length; i++) {
762762
PyObject* item = self->extra->children[i];
763763
if (Element_CheckExact(item) &&
764-
PyObject_Compare(((ElementObject*)item)->tag, tag) == 0) {
764+
PyObject_RichCompareBool(((ElementObject*)item)->tag, tag, Py_EQ) == 1) {
765765
Py_INCREF(item);
766766
return item;
767767
}
@@ -792,7 +792,8 @@ element_findtext(ElementObject* self, PyObject* args)
792792

793793
for (i = 0; i < self->extra->length; i++) {
794794
ElementObject* item = (ElementObject*) self->extra->children[i];
795-
if (Element_CheckExact(item) && !PyObject_Compare(item->tag, tag)) {
795+
if (Element_CheckExact(item) && (PyObject_RichCompareBool(item->tag, tag, Py_EQ) == 1)) {
796+
796797
PyObject* text = element_get_text(item);
797798
if (text == Py_None)
798799
return PyBytes_FromString("");
@@ -830,7 +831,7 @@ element_findall(ElementObject* self, PyObject* args)
830831
for (i = 0; i < self->extra->length; i++) {
831832
PyObject* item = self->extra->children[i];
832833
if (Element_CheckExact(item) &&
833-
PyObject_Compare(((ElementObject*)item)->tag, tag) == 0) {
834+
PyObject_RichCompareBool(((ElementObject*)item)->tag, tag, Py_EQ) == 1) {
834835
if (PyList_Append(out, item) < 0) {
835836
Py_DECREF(out);
836837
return NULL;
@@ -1102,7 +1103,7 @@ element_remove(ElementObject* self, PyObject* args)
11021103
for (i = 0; i < self->extra->length; i++) {
11031104
if (self->extra->children[i] == element)
11041105
break;
1105-
if (PyObject_Compare(self->extra->children[i], element) == 0)
1106+
if (PyObject_RichCompareBool(self->extra->children[i], element, Py_EQ) == 1)
11061107
break;
11071108
}
11081109

Modules/_localemodule.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,9 @@ PyLocale_strcoll(PyObject* self, PyObject* args)
272272

273273
#ifdef HAVE_WCSXFRM
274274
PyDoc_STRVAR(strxfrm__doc__,
275-
"string -> string. Returns a string that behaves for cmp locale-aware.");
275+
"strxfrm(string) -> string.\n\
276+
\n\
277+
Return a string that can be used as a key for locale-aware comparisons.");
276278

277279
static PyObject*
278280
PyLocale_strxfrm(PyObject* self, PyObject* args)

Modules/_pickle.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -715,7 +715,7 @@ whichmodule(PyObject *global, PyObject *global_name)
715715
i = 0;
716716
module_name = NULL;
717717
while ((j = PyDict_Next(modules_dict, &i, &module_name, &module))) {
718-
if (PyObject_Compare(module_name, main_str) == 0)
718+
if (PyObject_RichCompareBool(module_name, main_str, Py_EQ) == 1)
719719
continue;
720720

721721
obj = PyObject_GetAttr(module, global_name);

Modules/_tkinter.c

Lines changed: 89 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -788,15 +788,59 @@ PyTclObject_repr(PyTclObject *self)
788788
self->value->typePtr->name, self->value);
789789
}
790790

791-
static int
792-
PyTclObject_cmp(PyTclObject *self, PyTclObject *other)
791+
#define TEST_COND(cond) ((cond) ? Py_True : Py_False)
792+
793+
static PyObject *
794+
PyTclObject_richcompare(PyObject *self, PyObject *other, int op)
793795
{
794-
int res;
795-
res = strcmp(Tcl_GetString(self->value),
796-
Tcl_GetString(other->value));
797-
if (res < 0) return -1;
798-
if (res > 0) return 1;
799-
return 0;
796+
int result;
797+
PyObject *v;
798+
799+
/* neither argument should be NULL, unless something's gone wrong */
800+
if (self == NULL || other == NULL) {
801+
PyErr_BadInternalCall();
802+
return NULL;
803+
}
804+
805+
/* both arguments should be instances of PyTclObject */
806+
if (!PyTclObject_Check(self) || !PyTclObject_Check(other)) {
807+
v = Py_NotImplemented;
808+
goto finished;
809+
}
810+
811+
if (self == other)
812+
/* fast path when self and other are identical */
813+
result = 0;
814+
else
815+
result = strcmp(Tcl_GetString(((PyTclObject *)self)->value),
816+
Tcl_GetString(((PyTclObject *)other)->value));
817+
/* Convert return value to a Boolean */
818+
switch (op) {
819+
case Py_EQ:
820+
v = TEST_COND(result == 0);
821+
break;
822+
case Py_NE:
823+
v = TEST_COND(result != 0);
824+
break;
825+
case Py_LE:
826+
v = TEST_COND(result <= 0);
827+
break;
828+
case Py_GE:
829+
v = TEST_COND(result >= 0);
830+
break;
831+
case Py_LT:
832+
v = TEST_COND(result < 0);
833+
break;
834+
case Py_GT:
835+
v = TEST_COND(result > 0);
836+
break;
837+
default:
838+
PyErr_BadArgument();
839+
return NULL;
840+
}
841+
finished:
842+
Py_INCREF(v);
843+
return v;
800844
}
801845

802846
PyDoc_STRVAR(get_typename__doc__, "name of the Tcl type");
@@ -818,45 +862,45 @@ static PyGetSetDef PyTclObject_getsetlist[] = {
818862
static PyTypeObject PyTclObject_Type = {
819863
PyVarObject_HEAD_INIT(NULL, 0)
820864
"_tkinter.Tcl_Obj", /*tp_name*/
821-
sizeof(PyTclObject), /*tp_basicsize*/
822-
0, /*tp_itemsize*/
865+
sizeof(PyTclObject), /*tp_basicsize*/
866+
0, /*tp_itemsize*/
823867
/* methods */
824-
(destructor)PyTclObject_dealloc, /*tp_dealloc*/
825-
0, /*tp_print*/
826-
0, /*tp_getattr*/
827-
0, /*tp_setattr*/
828-
(cmpfunc)PyTclObject_cmp, /*tp_compare*/
868+
(destructor)PyTclObject_dealloc,/*tp_dealloc*/
869+
0, /*tp_print*/
870+
0, /*tp_getattr*/
871+
0, /*tp_setattr*/
872+
0, /*tp_compare*/
829873
(reprfunc)PyTclObject_repr, /*tp_repr*/
830-
0, /*tp_as_number*/
831-
0, /*tp_as_sequence*/
832-
0, /*tp_as_mapping*/
833-
0, /*tp_hash*/
834-
0, /*tp_call*/
835-
(reprfunc)PyTclObject_str, /*tp_str*/
836-
PyObject_GenericGetAttr,/*tp_getattro*/
837-
0, /*tp_setattro*/
838-
0, /*tp_as_buffer*/
839-
Py_TPFLAGS_DEFAULT, /*tp_flags*/
840-
0, /*tp_doc*/
841-
0, /*tp_traverse*/
842-
0, /*tp_clear*/
843-
0, /*tp_richcompare*/
844-
0, /*tp_weaklistoffset*/
845-
0, /*tp_iter*/
846-
0, /*tp_iternext*/
847-
0, /*tp_methods*/
848-
0, /*tp_members*/
849-
PyTclObject_getsetlist, /*tp_getset*/
850-
0, /*tp_base*/
851-
0, /*tp_dict*/
852-
0, /*tp_descr_get*/
853-
0, /*tp_descr_set*/
854-
0, /*tp_dictoffset*/
855-
0, /*tp_init*/
856-
0, /*tp_alloc*/
857-
0, /*tp_new*/
858-
0, /*tp_free*/
859-
0, /*tp_is_gc*/
874+
0, /*tp_as_number*/
875+
0, /*tp_as_sequence*/
876+
0, /*tp_as_mapping*/
877+
0, /*tp_hash*/
878+
0, /*tp_call*/
879+
(reprfunc)PyTclObject_str, /*tp_str*/
880+
PyObject_GenericGetAttr, /*tp_getattro*/
881+
0, /*tp_setattro*/
882+
0, /*tp_as_buffer*/
883+
Py_TPFLAGS_DEFAULT, /*tp_flags*/
884+
0, /*tp_doc*/
885+
0, /*tp_traverse*/
886+
0, /*tp_clear*/
887+
PyTclObject_richcompare, /*tp_richcompare*/
888+
0, /*tp_weaklistoffset*/
889+
0, /*tp_iter*/
890+
0, /*tp_iternext*/
891+
0, /*tp_methods*/
892+
0, /*tp_members*/
893+
PyTclObject_getsetlist, /*tp_getset*/
894+
0, /*tp_base*/
895+
0, /*tp_dict*/
896+
0, /*tp_descr_get*/
897+
0, /*tp_descr_set*/
898+
0, /*tp_dictoffset*/
899+
0, /*tp_init*/
900+
0, /*tp_alloc*/
901+
0, /*tp_new*/
902+
0, /*tp_free*/
903+
0, /*tp_is_gc*/
860904
};
861905

862906
static Tcl_Obj*

0 commit comments

Comments
 (0)