mirror of https://github.com/python/cpython
Dima Dorfman's patch for coercion/comparison of C types (patch #995939), with
a minor change after the coercion, to accept two objects not necessarily of the same type but with the same tp_compare.
This commit is contained in:
parent
0a6864ecc5
commit
a174813113
|
@ -125,9 +125,45 @@ def do_prefix_binops():
|
||||||
else:
|
else:
|
||||||
print '=', format_result(x)
|
print '=', format_result(x)
|
||||||
|
|
||||||
|
# New-style class version of CoerceNumber
|
||||||
|
class CoerceTo(object):
|
||||||
|
def __init__(self, arg):
|
||||||
|
self.arg = arg
|
||||||
|
def __coerce__(self, other):
|
||||||
|
if isinstance(other, CoerceTo):
|
||||||
|
return self.arg, other.arg
|
||||||
|
else:
|
||||||
|
return self.arg, other
|
||||||
|
|
||||||
|
def assert_(expr, msg=None):
|
||||||
|
if not expr:
|
||||||
|
raise AssertionError, msg
|
||||||
|
|
||||||
|
def do_cmptypes():
|
||||||
|
# Built-in tp_compare slots expect their arguments to have the
|
||||||
|
# same type, but a user-defined __coerce__ doesn't have to obey.
|
||||||
|
# SF #980352
|
||||||
|
evil_coercer = CoerceTo(42)
|
||||||
|
# Make sure these don't crash any more
|
||||||
|
assert_(cmp(u'fish', evil_coercer) != 0)
|
||||||
|
assert_(cmp(slice(1), evil_coercer) != 0)
|
||||||
|
# ...but that this still works
|
||||||
|
class WackyComparer(object):
|
||||||
|
def __cmp__(self, other):
|
||||||
|
assert_(other == 42, 'expected evil_coercer, got %r' % other)
|
||||||
|
return 0
|
||||||
|
assert_(cmp(WackyComparer(), evil_coercer) == 0)
|
||||||
|
# ...and classic classes too, since that code path is a little different
|
||||||
|
class ClassicWackyComparer:
|
||||||
|
def __cmp__(self, other):
|
||||||
|
assert_(other == 42, 'expected evil_coercer, got %r' % other)
|
||||||
|
return 0
|
||||||
|
assert_(cmp(ClassicWackyComparer(), evil_coercer) == 0)
|
||||||
|
|
||||||
warnings.filterwarnings("ignore",
|
warnings.filterwarnings("ignore",
|
||||||
r'complex divmod\(\), // and % are deprecated',
|
r'complex divmod\(\), // and % are deprecated',
|
||||||
DeprecationWarning,
|
DeprecationWarning,
|
||||||
r'test.test_coercion$')
|
r'test.test_coercion$')
|
||||||
do_infix_binops()
|
do_infix_binops()
|
||||||
do_prefix_binops()
|
do_prefix_binops()
|
||||||
|
do_cmptypes()
|
||||||
|
|
|
@ -606,33 +606,28 @@ try_3way_compare(PyObject *v, PyObject *w)
|
||||||
w->ob_type->tp_compare == _PyObject_SlotCompare)
|
w->ob_type->tp_compare == _PyObject_SlotCompare)
|
||||||
return _PyObject_SlotCompare(v, w);
|
return _PyObject_SlotCompare(v, w);
|
||||||
|
|
||||||
/* Try coercion; if it fails, give up */
|
/* If we're here, v and w,
|
||||||
|
a) are not instances;
|
||||||
|
b) have different types or a type without tp_compare; and
|
||||||
|
c) don't have a user-defined tp_compare.
|
||||||
|
tp_compare implementations in C assume that both arguments
|
||||||
|
have their type, so we give up if the coercion fails or if
|
||||||
|
it yields types which are still incompatible (which can
|
||||||
|
happen with a user-defined nb_coerce).
|
||||||
|
*/
|
||||||
c = PyNumber_CoerceEx(&v, &w);
|
c = PyNumber_CoerceEx(&v, &w);
|
||||||
if (c < 0)
|
if (c < 0)
|
||||||
return -2;
|
return -2;
|
||||||
if (c > 0)
|
if (c > 0)
|
||||||
return 2;
|
return 2;
|
||||||
|
f = v->ob_type->tp_compare;
|
||||||
/* Try v's comparison, if defined */
|
if (f != NULL && f == w->ob_type->tp_compare) {
|
||||||
if ((f = v->ob_type->tp_compare) != NULL) {
|
|
||||||
c = (*f)(v, w);
|
c = (*f)(v, w);
|
||||||
Py_DECREF(v);
|
Py_DECREF(v);
|
||||||
Py_DECREF(w);
|
Py_DECREF(w);
|
||||||
return adjust_tp_compare(c);
|
return adjust_tp_compare(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try w's comparison, if defined */
|
|
||||||
if ((f = w->ob_type->tp_compare) != NULL) {
|
|
||||||
c = (*f)(w, v); /* swapped! */
|
|
||||||
Py_DECREF(v);
|
|
||||||
Py_DECREF(w);
|
|
||||||
c = adjust_tp_compare(c);
|
|
||||||
if (c >= -1)
|
|
||||||
return -c; /* Swapped! */
|
|
||||||
else
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* No comparison defined */
|
/* No comparison defined */
|
||||||
Py_DECREF(v);
|
Py_DECREF(v);
|
||||||
Py_DECREF(w);
|
Py_DECREF(w);
|
||||||
|
|
Loading…
Reference in New Issue