From a92ea635bc552de1cb79b00e87d65da229b25e18 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 14 Feb 2025 13:48:26 +0200 Subject: [PATCH 1/2] gh-86069: Add more PyNumber_InPlacePower() tests --- Lib/test/test_capi/test_number.py | 36 ++++++++++++++++++++++++++++++- Objects/typeobject.c | 10 +++++++-- 2 files changed, 43 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_capi/test_number.py b/Lib/test/test_capi/test_number.py index 04f85d2395083a..b915dee37c7ca6 100644 --- a/Lib/test/test_capi/test_number.py +++ b/Lib/test/test_capi/test_number.py @@ -205,8 +205,9 @@ def test_misc_multiply(self): self.assertRaises(MemoryError, inplacemultiply, [1, 2], PY_SSIZE_T_MAX//2 + 1) def test_misc_power(self): - # PyNumber_Power() + # PyNumber_Power(), PyNumber_InPlacePower() power = _testcapi.number_power + inplacepower = _testcapi.number_inplacepower class HasPow(WithDunder): methname = '__pow__' @@ -216,6 +217,39 @@ class HasPow(WithDunder): self.assertRaises(TypeError, power, 4, 11, 1.25) self.assertRaises(TypeError, power, 4, 11, HasPow.with_val(NotImplemented)) self.assertRaises(TypeError, power, 4, 11, object()) + self.assertEqual(inplacepower(4, 11, 5), pow(4, 11, 5)) + self.assertRaises(TypeError, inplacepower, 4, 11, 1.25) + self.assertRaises(TypeError, inplacepower, 4, 11, object()) + + class X: + def __pow__(*args): + return args + + x = X() + self.assertEqual(power(x, 11), (x, 11)) + self.assertEqual(inplacepower(x, 11), (x, 11)) + self.assertEqual(power(x, 11, 5), (x, 11, 5)) + self.assertEqual(inplacepower(x, 11, 5), (x, 11, 5)) + + class X: + def __rpow__(*args): + return args + + x = X() + self.assertEqual(power(4, x), (x, 4)) + self.assertEqual(inplacepower(4, x), (x, 4)) + # XXX: Three-arg power doesn't use __rpow__. + self.assertRaises(TypeError, power, 4, x, 5) + self.assertRaises(TypeError, inplacepower, 4, x, 5) + + class X: + def __ipow__(*args): + return args + + x = X() + self.assertEqual(inplacepower(x, 11), (x, 11)) + # XXX: In-place power doesn't pass the third arg to __ipow__. + self.assertEqual(inplacepower(x, 11, 5), (x, 11)) def test_long(self): # Test PyNumber_Long() diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 818a00708b5d3d..e7736c1a14339b 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -9906,8 +9906,14 @@ SLOT1(slot_nb_inplace_remainder, __imod__, PyObject *) static PyObject * slot_nb_inplace_power(PyObject *self, PyObject * arg1, PyObject *arg2) { - PyObject *stack[2] = {self, arg1}; - return vectorcall_method(&_Py_ID(__ipow__), stack, 2); + if (1||arg2 == Py_None) { + PyObject *stack[2] = {self, arg1}; + return vectorcall_method(&_Py_ID(__ipow__), stack, 2); + } + else { + PyObject *stack[3] = {self, arg1, arg2}; + return vectorcall_method(&_Py_ID(__ipow__), stack, 3); + } } SLOT1(slot_nb_inplace_lshift, __ilshift__, PyObject *) SLOT1(slot_nb_inplace_rshift, __irshift__, PyObject *) From ec2bbefc4441ed9f90fd281458e63f05ef3585af Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 16 Feb 2025 11:47:27 +0200 Subject: [PATCH 2/2] Remove unintentional changes in code. --- Objects/typeobject.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index e7736c1a14339b..818a00708b5d3d 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -9906,14 +9906,8 @@ SLOT1(slot_nb_inplace_remainder, __imod__, PyObject *) static PyObject * slot_nb_inplace_power(PyObject *self, PyObject * arg1, PyObject *arg2) { - if (1||arg2 == Py_None) { - PyObject *stack[2] = {self, arg1}; - return vectorcall_method(&_Py_ID(__ipow__), stack, 2); - } - else { - PyObject *stack[3] = {self, arg1, arg2}; - return vectorcall_method(&_Py_ID(__ipow__), stack, 3); - } + PyObject *stack[2] = {self, arg1}; + return vectorcall_method(&_Py_ID(__ipow__), stack, 2); } SLOT1(slot_nb_inplace_lshift, __ilshift__, PyObject *) SLOT1(slot_nb_inplace_rshift, __irshift__, PyObject *)