Commit f7367f15 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #763 from Daetalus/old_style_class

Numeric binary operator support for old style class
parents eb8e5c4d d4ad2f78
# expected: fail
# Augmented assignment test.
from test.test_support import run_unittest, check_py3k_warnings
......
......@@ -735,6 +735,182 @@ static Box* instanceNext(BoxedInstance* inst) {
return r;
}
static PyObject* generic_binary_op(PyObject* v, PyObject* w, char* opname) {
PyObject* result;
PyObject* args;
PyObject* func = PyObject_GetAttrString(v, opname);
if (func == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return NULL;
PyErr_Clear();
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
args = PyTuple_Pack(1, w);
if (args == NULL) {
Py_DECREF(func);
return NULL;
}
result = PyEval_CallObject(func, args);
Py_DECREF(args);
Py_DECREF(func);
return result;
}
static PyObject* coerce_obj;
/* Try one half of a binary operator involving a class instance. */
static PyObject* half_binop(PyObject* v, PyObject* w, char* opname, binaryfunc thisfunc, int swapped) noexcept {
PyObject* args;
PyObject* coercefunc;
PyObject* coerced = NULL;
PyObject* v1;
PyObject* result;
if (!PyInstance_Check(v)) {
Py_INCREF(Py_NotImplemented);
return Py_NotImplemented;
}
if (coerce_obj == NULL) {
coerce_obj = PyString_InternFromString("__coerce__");
if (coerce_obj == NULL)
return NULL;
}
coercefunc = PyObject_GetAttr(v, coerce_obj);
if (coercefunc == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return NULL;
PyErr_Clear();
return generic_binary_op(v, w, opname);
}
args = PyTuple_Pack(1, w);
if (args == NULL) {
Py_DECREF(coercefunc);
return NULL;
}
coerced = PyEval_CallObject(coercefunc, args);
Py_DECREF(args);
Py_DECREF(coercefunc);
if (coerced == NULL) {
return NULL;
}
if (coerced == Py_None || coerced == Py_NotImplemented) {
Py_DECREF(coerced);
return generic_binary_op(v, w, opname);
}
if (!PyTuple_Check(coerced) || PyTuple_Size(coerced) != 2) {
Py_DECREF(coerced);
PyErr_SetString(PyExc_TypeError, "coercion should return None or 2-tuple");
return NULL;
}
v1 = PyTuple_GetItem(coerced, 0);
w = PyTuple_GetItem(coerced, 1);
if (v1->cls == v->cls && PyInstance_Check(v)) {
/* prevent recursion if __coerce__ returns self as the first
* argument */
result = generic_binary_op(v1, w, opname);
} else {
if (Py_EnterRecursiveCall(" after coercion"))
return NULL;
if (swapped)
result = (thisfunc)(w, v1);
else
result = (thisfunc)(v1, w);
Py_LeaveRecursiveCall();
}
Py_DECREF(coerced);
return result;
}
/* Implement a binary operator involving at least one class instance. */
static PyObject* do_binop(PyObject* v, PyObject* w, char* opname, char* ropname, binaryfunc thisfunc) noexcept {
PyObject* result = half_binop(v, w, opname, thisfunc, 0);
if (result == Py_NotImplemented) {
Py_DECREF(result);
result = half_binop(w, v, ropname, thisfunc, 1);
}
return result;
}
static PyObject* do_binop_inplace(PyObject* v, PyObject* w, char* iopname, char* opname, char* ropname,
binaryfunc thisfunc) noexcept {
PyObject* result = half_binop(v, w, iopname, thisfunc, 0);
if (result == Py_NotImplemented) {
Py_DECREF(result);
result = do_binop(v, w, opname, ropname, thisfunc);
}
return result;
}
static PyObject* bin_power(PyObject* v, PyObject* w) noexcept {
return PyNumber_Power(v, w, Py_None);
}
/* This version is for ternary calls only (z != None) */
static PyObject* instance_pow(PyObject* v, PyObject* w, PyObject* z) noexcept {
static BoxedString* pow_str = internStringImmortal("__pow__");
static BoxedString* ipow_str = internStringImmortal("__ipow__");
static BoxedString* rpow_str = internStringImmortal("__rpow__");
if (z == Py_None) {
return do_binop(v, w, pow_str->data(), rpow_str->data(), bin_power);
} else {
PyObject* func;
PyObject* args;
PyObject* result;
/* XXX Doesn't do coercions... */
func = PyObject_GetAttrString(v, pow_str->data());
if (func == NULL)
return NULL;
args = PyTuple_Pack(2, w, z);
if (args == NULL) {
Py_DECREF(func);
return NULL;
}
result = PyEval_CallObject(func, args);
Py_DECREF(func);
Py_DECREF(args);
return result;
}
}
static PyObject* bin_inplace_power(PyObject* v, PyObject* w) noexcept {
return PyNumber_InPlacePower(v, w, Py_None);
}
static PyObject* instance_ipow(PyObject* v, PyObject* w, PyObject* z) noexcept {
static BoxedString* pow_str = internStringImmortal("__pow__");
static BoxedString* ipow_str = internStringImmortal("__ipow__");
static BoxedString* rpow_str = internStringImmortal("__rpow__");
if (z == Py_None) {
return do_binop_inplace(v, w, ipow_str->data(), pow_str->data(), rpow_str->data(), bin_inplace_power);
} else {
/* XXX Doesn't do coercions... */
PyObject* func;
PyObject* args;
PyObject* result;
func = PyObject_GetAttrString(v, ipow_str->data());
if (func == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return NULL;
PyErr_Clear();
return instance_pow(v, w, z);
}
args = PyTuple_Pack(2, w, z);
if (args == NULL) {
Py_DECREF(func);
return NULL;
}
result = PyEval_CallObject(func, args);
Py_DECREF(func);
Py_DECREF(args);
return result;
}
}
static PyObject* instance_index(PyObject* self) noexcept {
PyObject* func, *res;
......@@ -803,6 +979,212 @@ Box* instanceNe(Box* _inst, Box* other) {
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceAdd(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__add__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceSub(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__sub__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceMul(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__mul__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceFloordiv(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__floordiv__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceMod(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__mod__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceDivMod(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__divmod__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instancePow(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__pow__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceLshift(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__lshift__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceRshift(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__rshift__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceAnd(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__and__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceXor(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__xor__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceOr(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__or__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceDiv(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__div__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceTruediv(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__truediv__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceRadd(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__radd__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceRsub(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__rsub__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceRmul(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__rmul__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceRdiv(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__rdiv__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceRtruediv(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__rtruediv__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceRfloordiv(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__rfloordiv__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceRmod(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__rmod__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceRdivmod(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__rdivmod__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceRpow(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__rpow__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceRlshift(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__rlshift__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceRrshift(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__rrshift__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceRand(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__rand__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceRxor(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__rxor__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceRor(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__ror__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceIadd(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__iadd__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceIsub(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__isub__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceImul(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__imul__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceIdiv(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__idiv__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceItruediv(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__itruediv__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceIfloordiv(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__ifloordiv__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceImod(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__imod__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceIpow(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__ipow__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceIlshift(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__ilshift__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceIrshift(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__irshift__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceIand(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__iand__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceIxor(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__ixor__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceIor(Box* _inst, Box* other) {
static BoxedString* attr_str = internStringImmortal("__ior__");
return _instanceBinary(_inst, other, attr_str);
}
Box* instanceCall(Box* _inst, Box* _args, Box* _kwargs) {
assert(_inst->cls == instance_cls);
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);
......@@ -914,11 +1296,56 @@ void setupClassobj() {
instance_cls->giveAttr("__le__", new BoxedFunction(boxRTFunction((void*)instanceLe, UNKNOWN, 2)));
instance_cls->giveAttr("__gt__", new BoxedFunction(boxRTFunction((void*)instanceGt, UNKNOWN, 2)));
instance_cls->giveAttr("__ge__", new BoxedFunction(boxRTFunction((void*)instanceGe, UNKNOWN, 2)));
instance_cls->giveAttr("__add__", new BoxedFunction(boxRTFunction((void*)instanceAdd, UNKNOWN, 2)));
instance_cls->giveAttr("__sub__", new BoxedFunction(boxRTFunction((void*)instanceSub, UNKNOWN, 2)));
instance_cls->giveAttr("__mul__", new BoxedFunction(boxRTFunction((void*)instanceMul, UNKNOWN, 2)));
instance_cls->giveAttr("__floordiv__", new BoxedFunction(boxRTFunction((void*)instanceFloordiv, UNKNOWN, 2)));
instance_cls->giveAttr("__mod__", new BoxedFunction(boxRTFunction((void*)instanceMod, UNKNOWN, 2)));
instance_cls->giveAttr("__divmod__", new BoxedFunction(boxRTFunction((void*)instanceDivMod, UNKNOWN, 2)));
instance_cls->giveAttr("__pow__", new BoxedFunction(boxRTFunction((void*)instancePow, UNKNOWN, 2)));
instance_cls->giveAttr("__lshift__", new BoxedFunction(boxRTFunction((void*)instanceLshift, UNKNOWN, 2)));
instance_cls->giveAttr("__rshift__", new BoxedFunction(boxRTFunction((void*)instanceRshift, UNKNOWN, 2)));
instance_cls->giveAttr("__and__", new BoxedFunction(boxRTFunction((void*)instanceAnd, UNKNOWN, 2)));
instance_cls->giveAttr("__xor__", new BoxedFunction(boxRTFunction((void*)instanceXor, UNKNOWN, 2)));
instance_cls->giveAttr("__or__", new BoxedFunction(boxRTFunction((void*)instanceOr, UNKNOWN, 2)));
instance_cls->giveAttr("__div__", new BoxedFunction(boxRTFunction((void*)instanceDiv, UNKNOWN, 2)));
instance_cls->giveAttr("__truediv__", new BoxedFunction(boxRTFunction((void*)instanceTruediv, UNKNOWN, 2)));
instance_cls->giveAttr("__radd__", new BoxedFunction(boxRTFunction((void*)instanceRadd, UNKNOWN, 2)));
instance_cls->giveAttr("__rsub__", new BoxedFunction(boxRTFunction((void*)instanceRsub, UNKNOWN, 2)));
instance_cls->giveAttr("__rmul__", new BoxedFunction(boxRTFunction((void*)instanceRmul, UNKNOWN, 2)));
instance_cls->giveAttr("__rdiv__", new BoxedFunction(boxRTFunction((void*)instanceRdiv, UNKNOWN, 2)));
instance_cls->giveAttr("__rtruediv__", new BoxedFunction(boxRTFunction((void*)instanceRtruediv, UNKNOWN, 2)));
instance_cls->giveAttr("__rfloordiv__", new BoxedFunction(boxRTFunction((void*)instanceRfloordiv, UNKNOWN, 2)));
instance_cls->giveAttr("__rmod__", new BoxedFunction(boxRTFunction((void*)instanceRmod, UNKNOWN, 2)));
instance_cls->giveAttr("__rdivmod__", new BoxedFunction(boxRTFunction((void*)instanceRdivmod, UNKNOWN, 2)));
instance_cls->giveAttr("__rpow__", new BoxedFunction(boxRTFunction((void*)instanceRpow, UNKNOWN, 2)));
instance_cls->giveAttr("__rlshift__", new BoxedFunction(boxRTFunction((void*)instanceRlshift, UNKNOWN, 2)));
instance_cls->giveAttr("__rrshift__", new BoxedFunction(boxRTFunction((void*)instanceRrshift, UNKNOWN, 2)));
instance_cls->giveAttr("__rand__", new BoxedFunction(boxRTFunction((void*)instanceRand, UNKNOWN, 2)));
instance_cls->giveAttr("__rxor__", new BoxedFunction(boxRTFunction((void*)instanceRxor, UNKNOWN, 2)));
instance_cls->giveAttr("__ror__", new BoxedFunction(boxRTFunction((void*)instanceRor, UNKNOWN, 2)));
instance_cls->giveAttr("__iadd__", new BoxedFunction(boxRTFunction((void*)instanceIadd, UNKNOWN, 2)));
instance_cls->giveAttr("__isub__", new BoxedFunction(boxRTFunction((void*)instanceIsub, UNKNOWN, 2)));
instance_cls->giveAttr("__imul__", new BoxedFunction(boxRTFunction((void*)instanceImul, UNKNOWN, 2)));
instance_cls->giveAttr("__idiv__", new BoxedFunction(boxRTFunction((void*)instanceIdiv, UNKNOWN, 2)));
instance_cls->giveAttr("__itruediv__", new BoxedFunction(boxRTFunction((void*)instanceItruediv, UNKNOWN, 2)));
instance_cls->giveAttr("__ifloordiv__", new BoxedFunction(boxRTFunction((void*)instanceIfloordiv, UNKNOWN, 2)));
instance_cls->giveAttr("__imod__", new BoxedFunction(boxRTFunction((void*)instanceImod, UNKNOWN, 2)));
instance_cls->giveAttr("__ipow__", new BoxedFunction(boxRTFunction((void*)instanceIpow, UNKNOWN, 2)));
instance_cls->giveAttr("__ilshift__", new BoxedFunction(boxRTFunction((void*)instanceIlshift, UNKNOWN, 2)));
instance_cls->giveAttr("__irshift__", new BoxedFunction(boxRTFunction((void*)instanceIrshift, UNKNOWN, 2)));
instance_cls->giveAttr("__iand__", new BoxedFunction(boxRTFunction((void*)instanceIand, UNKNOWN, 2)));
instance_cls->giveAttr("__ixor__", new BoxedFunction(boxRTFunction((void*)instanceIxor, UNKNOWN, 2)));
instance_cls->giveAttr("__ior__", new BoxedFunction(boxRTFunction((void*)instanceIor, UNKNOWN, 2)));
instance_cls->freeze();
instance_cls->tp_getattro = instance_getattro;
instance_cls->tp_setattro = instance_setattro;
instance_cls->tp_as_number->nb_index = instance_index;
instance_cls->tp_as_number->nb_power = instance_pow;
instance_cls->tp_as_number->nb_inplace_power = instance_ipow;
instance_cls->tp_dealloc = instance_dealloc;
instance_cls->has_safe_tp_dealloc = false;
}
......
......@@ -128,6 +128,88 @@ print issubclass(OldStyleClass, object)
print isinstance(OldStyleClass(), OldStyleClass)
print issubclass(OldStyleClass, OldStyleClass)
class G:
def __init__(self, n):
self._n = n
def __pow__(self, other, modulo=None):
print "pow in instance"
def __rpow__(self, other):
print "rpow in instance"
def __ipow__(self, other, modulo=None):
print "ipow in instance"
p1 = G(3)
p2 = G(4)
p1 ** p2
4 ** p2
None ** p2
p2 ** None
pow(p1, p2)
pow(p1, None)
pow(None, p1)
pow(p1, p2, p2)
pow(p1, p2, None)
p1.__ipow__(p1, p2)
p1 **= p2
class H:
def __init__(self, n):
self._n = n
p3 = H(3)
p4 = H(4)
p5 = G(5)
pow(p5, p3)
pow(p3, p5)
try:
pow(p3, p4)
except Exception as e:
print type(e), e.message
try:
pow(p3, p4, p4)
except Exception as e:
assert type(e) in (AttributeError, TypeError)
# mixed calling
class I(object):
def __init__(self, n):
self._n = n
def __pow__(self, other, modulo=None):
print "pow in object"
def __rpow__(self, n):
print "rpow in object"
def __ipow__(self, other, modulo=None):
print "ipow in object"
p5 = I(3)
try:
pow(p3, p5)
except Exception as e:
print type(e), e.message
try:
p3 ** p5
except Exception as e:
print type(e), e.message
class LessEqualTest:
def __init__(self, a):
self._a = a
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment