Commit 2294c2a7 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #900 from Daetalus/test_operator

Implment some PyNumber_XXX function, to enable "test_operator"
parents f96c49ab 5bacdd4b
# expected: fail
import operator
import unittest
......
......@@ -1078,6 +1078,30 @@ static PyObject* binary_op(PyObject* v, PyObject* w, const int op_slot, const ch
return result;
}
static PyObject* binary_iop1(PyObject* v, PyObject* w, const int iop_slot, const int op_slot) {
PyNumberMethods* mv = v->cls->tp_as_number;
if (mv != NULL && PyType_HasFeature((v)->cls, Py_TPFLAGS_HAVE_INPLACEOPS)) {
binaryfunc slot = NB_BINOP(mv, iop_slot);
if (slot) {
PyObject* x = (slot)(v, w);
if (x != Py_NotImplemented) {
return x;
}
Py_DECREF(x);
}
}
return binary_op1(v, w, op_slot);
}
static PyObject* binary_iop(PyObject* v, PyObject* w, const int iop_slot, const int op_slot, const char* op_name) {
PyObject* result = binary_iop1(v, w, iop_slot, op_slot);
if (result == Py_NotImplemented) {
Py_DECREF(result);
return binop_type_error(v, w, op_name);
}
return result;
}
/*
Calling scheme used for ternary operations:
......@@ -1436,18 +1460,77 @@ Fail:
}
extern "C" PyObject* PySequence_Repeat(PyObject* o, Py_ssize_t count) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
return nullptr;
PySequenceMethods* m;
if (o == NULL)
return null_error();
m = o->cls->tp_as_sequence;
if (m && m->sq_repeat)
return m->sq_repeat(o, count);
/* Instances of user classes defining a __mul__() method only
have an nb_multiply slot, not an sq_repeat slot. so we fall back
to nb_multiply if o appears to be a sequence. */
if (PySequence_Check(o)) {
PyObject* n, *result;
n = PyInt_FromSsize_t(count);
if (n == NULL)
return NULL;
result = binary_op1(o, n, NB_SLOT(nb_multiply));
Py_DECREF(n);
if (result != Py_NotImplemented)
return result;
Py_DECREF(result);
}
return type_error("'%.200s' object can't be repeated", o);
}
extern "C" PyObject* PySequence_InPlaceConcat(PyObject* o1, PyObject* o2) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
return nullptr;
extern "C" PyObject* PySequence_InPlaceConcat(PyObject* s, PyObject* o) noexcept {
PySequenceMethods* m;
if (s == NULL || o == NULL)
return null_error();
m = s->cls->tp_as_sequence;
if (m && PyType_HasFeature((s)->cls, Py_TPFLAGS_HAVE_INPLACEOPS) && m->sq_inplace_concat)
return m->sq_inplace_concat(s, o);
if (m && m->sq_concat)
return m->sq_concat(s, o);
if (PySequence_Check(s) && PySequence_Check(o)) {
PyObject* result = binary_iop1(s, o, NB_SLOT(nb_inplace_add), NB_SLOT(nb_add));
if (result != Py_NotImplemented)
return result;
Py_DECREF(result);
}
return type_error("'%.200s' object can't be concatenated", s);
}
extern "C" PyObject* PySequence_InPlaceRepeat(PyObject* o, Py_ssize_t count) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
return nullptr;
PySequenceMethods* m;
if (o == NULL)
return null_error();
m = o->cls->tp_as_sequence;
if (m && PyType_HasFeature((o)->cls, Py_TPFLAGS_HAVE_INPLACEOPS) && m->sq_inplace_repeat)
return m->sq_inplace_repeat(o, count);
if (m && m->sq_repeat)
return m->sq_repeat(o, count);
if (PySequence_Check(o)) {
PyObject* n, *result;
n = PyInt_FromSsize_t(count);
if (n == NULL)
return NULL;
result = binary_iop1(o, n, NB_SLOT(nb_inplace_multiply), NB_SLOT(nb_multiply));
Py_DECREF(n);
if (result != Py_NotImplemented)
return result;
Py_DECREF(result);
}
return type_error("'%.200s' object can't be repeated", o);
}
extern "C" PyObject* PySequence_GetItem(PyObject* s, Py_ssize_t i) noexcept {
......@@ -1523,29 +1606,117 @@ extern "C" PyObject* PySequence_GetSlice(PyObject* s, Py_ssize_t i1, Py_ssize_t
return type_error("'%.200s' object is unsliceable", s);
}
extern "C" int PySequence_SetItem(PyObject* o, Py_ssize_t i, PyObject* v) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
extern "C" int PySequence_SetItem(PyObject* s, Py_ssize_t i, PyObject* o) noexcept {
PySequenceMethods* m;
if (s == NULL) {
null_error();
return -1;
}
m = s->cls->tp_as_sequence;
if (m && m->sq_ass_item) {
if (i < 0) {
if (m->sq_length) {
Py_ssize_t l = (*m->sq_length)(s);
if (l < 0)
return -1;
i += l;
}
}
return m->sq_ass_item(s, i, o);
}
type_error("'%.200s' object does not support item assignment", s);
return -1;
}
extern "C" int PySequence_DelItem(PyObject* o, Py_ssize_t i) noexcept {
try {
// Not sure if this is really the same:
delitem(o, boxInt(i));
return 0;
} catch (ExcInfo e) {
setCAPIException(e);
extern "C" int PySequence_DelItem(PyObject* s, Py_ssize_t i) noexcept {
PySequenceMethods* m;
if (s == NULL) {
null_error();
return -1;
}
m = s->cls->tp_as_sequence;
if (m && m->sq_ass_item) {
if (i < 0) {
if (m->sq_length) {
Py_ssize_t l = (*m->sq_length)(s);
if (l < 0)
return -1;
i += l;
}
}
return m->sq_ass_item(s, i, (PyObject*)NULL);
}
type_error("'%.200s' object doesn't support item deletion", s);
return -1;
}
extern "C" int PySequence_SetSlice(PyObject* o, Py_ssize_t i1, Py_ssize_t i2, PyObject* v) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
extern "C" int PySequence_SetSlice(PyObject* s, Py_ssize_t i1, Py_ssize_t i2, PyObject* o) noexcept {
PySequenceMethods* m;
PyMappingMethods* mp;
if (s == NULL) {
null_error();
return -1;
}
m = s->cls->tp_as_sequence;
if (m && m->sq_ass_slice) {
if (i1 < 0 || i2 < 0) {
if (m->sq_length) {
Py_ssize_t l = (*m->sq_length)(s);
if (l < 0)
return -1;
if (i1 < 0)
i1 += l;
if (i2 < 0)
i2 += l;
}
}
return m->sq_ass_slice(s, i1, i2, o);
} else if ((mp = s->cls->tp_as_mapping) && mp->mp_ass_subscript) {
int res;
PyObject* slice = _PySlice_FromIndices(i1, i2);
if (!slice)
return -1;
res = mp->mp_ass_subscript(s, slice, o);
Py_DECREF(slice);
return res;
}
type_error("'%.200s' object doesn't support slice assignment", s);
return -1;
}
extern "C" int PySequence_DelSlice(PyObject* o, Py_ssize_t i1, Py_ssize_t i2) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
PySequenceMethods* m;
if (o == NULL) {
null_error();
return -1;
}
m = o->cls->tp_as_sequence;
if (m && m->sq_ass_slice) {
if (i1 < 0 || i2 < 0) {
if (m->sq_length) {
Py_ssize_t l = (*m->sq_length)(o);
if (l < 0)
return -1;
if (i1 < 0)
i1 += l;
if (i2 < 0)
i2 += l;
}
}
return m->sq_ass_slice(o, i1, i2, (PyObject*)NULL);
}
type_error("'%.200s' object doesn't support slice deletion", o);
return -1;
}
......@@ -1657,7 +1828,7 @@ extern "C" int PyNumber_Check(PyObject* obj) noexcept {
assert(obj && obj->cls);
// Our check, since we don't currently fill in tp_as_number:
if (PyInt_Check(obj) || PyLong_Check(obj) || PyFloat_Check(obj))
if (PyInt_Check(obj) || PyLong_Check(obj) || PyFloat_Check(obj) || PyComplex_Check(obj))
return true;
// The CPython check:
......@@ -1669,7 +1840,7 @@ extern "C" PyObject* PyNumber_Add(PyObject* lhs, PyObject* rhs) noexcept {
return binop(lhs, rhs, AST_TYPE::Add);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
return nullptr;
}
}
......@@ -1677,7 +1848,7 @@ extern "C" PyObject* PyNumber_Subtract(PyObject* lhs, PyObject* rhs) noexcept {
try {
return binop(lhs, rhs, AST_TYPE::Sub);
} catch (ExcInfo e) {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
setCAPIException(e);
return nullptr;
}
}
......@@ -1686,7 +1857,7 @@ extern "C" PyObject* PyNumber_Multiply(PyObject* lhs, PyObject* rhs) noexcept {
try {
return binop(lhs, rhs, AST_TYPE::Mult);
} catch (ExcInfo e) {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
setCAPIException(e);
return nullptr;
}
}
......@@ -1695,14 +1866,18 @@ extern "C" PyObject* PyNumber_Divide(PyObject* lhs, PyObject* rhs) noexcept {
try {
return binop(lhs, rhs, AST_TYPE::Div);
} catch (ExcInfo e) {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
setCAPIException(e);
return nullptr;
}
}
extern "C" PyObject* PyNumber_FloorDivide(PyObject*, PyObject*) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
return nullptr;
extern "C" PyObject* PyNumber_FloorDivide(PyObject* lhs, PyObject* rhs) noexcept {
try {
return binop(lhs, rhs, AST_TYPE::FloorDiv);
} catch (ExcInfo e) {
setCAPIException(e);
return nullptr;
}
}
extern "C" PyObject* PyNumber_TrueDivide(PyObject* lhs, PyObject* rhs) noexcept {
......@@ -1710,7 +1885,7 @@ extern "C" PyObject* PyNumber_TrueDivide(PyObject* lhs, PyObject* rhs) noexcept
return binop(lhs, rhs, AST_TYPE::TrueDiv);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
return nullptr;
}
}
......@@ -1718,7 +1893,7 @@ extern "C" PyObject* PyNumber_Remainder(PyObject* lhs, PyObject* rhs) noexcept {
try {
return binop(lhs, rhs, AST_TYPE::Mod);
} catch (ExcInfo e) {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
setCAPIException(e);
return nullptr;
}
}
......@@ -1749,11 +1924,21 @@ extern "C" PyObject* PyNumber_Negative(PyObject* o) noexcept {
}
extern "C" PyObject* PyNumber_Positive(PyObject* o) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
return nullptr;
PyNumberMethods* m;
if (o == NULL)
return null_error();
m = o->cls->tp_as_number;
if (m && m->nb_positive)
return (*m->nb_positive)(o);
return type_error("bad operand type for unary +: '%.200s'", o);
}
extern "C" PyObject* PyNumber_Absolute(PyObject* o) noexcept {
if (o == Py_None)
return type_error("bad operand type for abs(): '%.200s'", o);
try {
return abs_(o);
} catch (ExcInfo e) {
......@@ -1775,7 +1960,7 @@ extern "C" PyObject* PyNumber_Lshift(PyObject* lhs, PyObject* rhs) noexcept {
try {
return binop(lhs, rhs, AST_TYPE::LShift);
} catch (ExcInfo e) {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
setCAPIException(e);
return nullptr;
}
}
......@@ -1784,7 +1969,7 @@ extern "C" PyObject* PyNumber_Rshift(PyObject* lhs, PyObject* rhs) noexcept {
try {
return binop(lhs, rhs, AST_TYPE::RShift);
} catch (ExcInfo e) {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
setCAPIException(e);
return nullptr;
}
}
......@@ -1793,7 +1978,7 @@ extern "C" PyObject* PyNumber_And(PyObject* lhs, PyObject* rhs) noexcept {
try {
return binop(lhs, rhs, AST_TYPE::BitAnd);
} catch (ExcInfo e) {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
setCAPIException(e);
return nullptr;
}
}
......@@ -1802,7 +1987,8 @@ extern "C" PyObject* PyNumber_Xor(PyObject* lhs, PyObject* rhs) noexcept {
try {
return binop(lhs, rhs, AST_TYPE::BitXor);
} catch (ExcInfo e) {
Py_FatalError("unimplemented");
setCAPIException(e);
return nullptr;
}
}
......@@ -1810,73 +1996,117 @@ extern "C" PyObject* PyNumber_Or(PyObject* lhs, PyObject* rhs) noexcept {
try {
return binop(lhs, rhs, AST_TYPE::BitOr);
} catch (ExcInfo e) {
Py_FatalError("unimplemented");
setCAPIException(e);
return nullptr;
}
}
extern "C" PyObject* PyNumber_InPlaceAdd(PyObject* v, PyObject* w) noexcept {
PyObject* result = binary_iop1(v, w, NB_SLOT(nb_inplace_add), NB_SLOT(nb_add));
if (result == Py_NotImplemented) {
PySequenceMethods* m = v->cls->tp_as_sequence;
Py_DECREF(result);
if (m != NULL) {
binaryfunc f = NULL;
if (PyType_HasFeature((v)->cls, Py_TPFLAGS_HAVE_INPLACEOPS))
f = m->sq_inplace_concat;
if (f == NULL)
f = m->sq_concat;
if (f != NULL)
return (*f)(v, w);
}
result = binop_type_error(v, w, "+=");
}
return result;
}
extern "C" PyObject* PyNumber_InPlaceAdd(PyObject*, PyObject*) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
return nullptr;
extern "C" PyObject* PyNumber_InPlaceSubtract(PyObject* v, PyObject* w) noexcept {
return binary_iop(v, w, NB_SLOT(nb_inplace_subtract), NB_SLOT(nb_subtract), "-=");
}
extern "C" PyObject* PyNumber_InPlaceSubtract(PyObject*, PyObject*) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
return nullptr;
static PyObject* sequence_repeat(ssizeargfunc repeatfunc, PyObject* seq, PyObject* n) {
Py_ssize_t count;
if (PyIndex_Check(n)) {
count = PyNumber_AsSsize_t(n, PyExc_OverflowError);
if (count == -1 && PyErr_Occurred())
return NULL;
} else {
return type_error("can't multiply sequence by "
"non-int of type '%.200s'",
n);
}
return (*repeatfunc)(seq, count);
}
extern "C" PyObject* PyNumber_InPlaceMultiply(PyObject*, PyObject*) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
return nullptr;
extern "C" PyObject* PyNumber_InPlaceMultiply(PyObject* v, PyObject* w) noexcept {
PyObject* result = binary_iop1(v, w, NB_SLOT(nb_inplace_multiply), NB_SLOT(nb_multiply));
if (result == Py_NotImplemented) {
ssizeargfunc f = NULL;
PySequenceMethods* mv = v->cls->tp_as_sequence;
PySequenceMethods* mw = w->cls->tp_as_sequence;
Py_DECREF(result);
if (mv != NULL) {
if (PyType_HasFeature((v)->cls, Py_TPFLAGS_HAVE_INPLACEOPS))
f = mv->sq_inplace_repeat;
if (f == NULL)
f = mv->sq_repeat;
if (f != NULL)
return sequence_repeat(f, v, w);
} else if (mw != NULL) {
/* Note that the right hand operand should not be
* mutated in this case so sq_inplace_repeat is not
* used. */
if (mw->sq_repeat)
return sequence_repeat(mw->sq_repeat, w, v);
}
result = binop_type_error(v, w, "*=");
}
return result;
}
extern "C" PyObject* PyNumber_InPlaceDivide(PyObject*, PyObject*) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
return nullptr;
extern "C" PyObject* PyNumber_InPlaceDivide(PyObject* v, PyObject* w) noexcept {
return binary_iop(v, w, NB_SLOT(nb_inplace_divide), NB_SLOT(nb_divide), "/=");
}
extern "C" PyObject* PyNumber_InPlaceFloorDivide(PyObject*, PyObject*) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
return nullptr;
extern "C" PyObject* PyNumber_InPlaceFloorDivide(PyObject* v, PyObject* w) noexcept {
return binary_iop(v, w, NB_SLOT(nb_inplace_floor_divide), NB_SLOT(nb_floor_divide), "//=");
}
extern "C" PyObject* PyNumber_InPlaceTrueDivide(PyObject*, PyObject*) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
return nullptr;
extern "C" PyObject* PyNumber_InPlaceTrueDivide(PyObject* v, PyObject* w) noexcept {
return binary_iop(v, w, NB_SLOT(nb_inplace_true_divide), NB_SLOT(nb_true_divide), "/=");
}
extern "C" PyObject* PyNumber_InPlaceRemainder(PyObject*, PyObject*) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
return nullptr;
extern "C" PyObject* PyNumber_InPlaceRemainder(PyObject* v, PyObject* w) noexcept {
return binary_iop(v, w, NB_SLOT(nb_inplace_remainder), NB_SLOT(nb_remainder), "%=");
}
extern "C" PyObject* PyNumber_InPlacePower(PyObject*, PyObject*, PyObject* o3) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
return nullptr;
extern "C" PyObject* PyNumber_InPlacePower(PyObject* v, PyObject* w, PyObject* z) noexcept {
if (PyType_HasFeature((v)->cls, Py_TPFLAGS_HAVE_INPLACEOPS) && v->cls->tp_as_number
&& v->cls->tp_as_number->nb_inplace_power != NULL) {
return ternary_op(v, w, z, NB_SLOT(nb_inplace_power), "**=");
} else {
return ternary_op(v, w, z, NB_SLOT(nb_power), "**=");
}
}
extern "C" PyObject* PyNumber_InPlaceLshift(PyObject*, PyObject*) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
return nullptr;
extern "C" PyObject* PyNumber_InPlaceLshift(PyObject* v, PyObject* w) noexcept {
return binary_iop(v, w, NB_SLOT(nb_inplace_lshift), NB_SLOT(nb_lshift), "<<=");
}
extern "C" PyObject* PyNumber_InPlaceRshift(PyObject*, PyObject*) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
return nullptr;
extern "C" PyObject* PyNumber_InPlaceRshift(PyObject* v, PyObject* w) noexcept {
return binary_iop(v, w, NB_SLOT(nb_inplace_rshift), NB_SLOT(nb_rshift), ">>=");
}
extern "C" PyObject* PyNumber_InPlaceAnd(PyObject*, PyObject*) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
return nullptr;
extern "C" PyObject* PyNumber_InPlaceAnd(PyObject* v, PyObject* w) noexcept {
return binary_iop(v, w, NB_SLOT(nb_inplace_and), NB_SLOT(nb_and), "%=");
}
extern "C" PyObject* PyNumber_InPlaceXor(PyObject*, PyObject*) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
return nullptr;
extern "C" PyObject* PyNumber_InPlaceXor(PyObject* v, PyObject* w) noexcept {
return binary_iop(v, w, NB_SLOT(nb_inplace_xor), NB_SLOT(nb_xor), "^=");
}
extern "C" PyObject* PyNumber_InPlaceOr(PyObject*, PyObject*) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
return nullptr;
extern "C" PyObject* PyNumber_InPlaceOr(PyObject* v, PyObject* w) noexcept {
return binary_iop(v, w, NB_SLOT(nb_inplace_or), NB_SLOT(nb_or), "|=");
}
extern "C" int PyNumber_Coerce(PyObject** pv, PyObject** pw) noexcept {
......
......@@ -567,7 +567,7 @@ extern "C" int PyObject_IsTrue(PyObject* o) noexcept {
try {
return o->nonzeroIC();
} catch (ExcInfo e) {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
setCAPIException(e);
return -1;
}
}
......
......@@ -490,6 +490,9 @@ static inline void listSetitemSliceInt64(BoxedList* self, i64 start, i64 stop, i
v_size = 0;
v_elts = NULL;
} else {
if (self == v) // handle self assignment by creating a copy
v = _listSlice(self, 0, self->size, 1, self->size);
v_as_seq = RootedBox(PySequence_Fast(v, "can only assign an iterable"));
if (v_as_seq == NULL)
throwCAPIException();
......@@ -502,9 +505,6 @@ static inline void listSetitemSliceInt64(BoxedList* self, i64 start, i64 stop, i
v_elts = NULL;
}
if (self == v) // handle self assignment by creating a copy
v = _listSlice(self, 0, self->size, 1, self->size);
int delts = v_size - (stop - start);
int remaining_elts = self->size - stop;
self->ensure(delts);
......
......@@ -54,7 +54,6 @@ test_list longs as slice indices
test_long sys.long_info
test_module unicode docstrings
test_mutants unknown failure
test_operator PyNumber_Absolute()
test_optparse assertion instead of exceptions for long("invalid number")
test_pep277 segfaults
test_pep352 various unique bugs
......
......@@ -20,3 +20,6 @@ for op in sorted(dir(operator)):
if op.startswith("_"):
continue
print getattr(operator, op).__name__
a = range(4)
operator.setitem(a, 1, 3)
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