Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Doc/c-api/number.rst
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,9 @@ Number Protocol

See the built-in function :func:`pow`. Returns ``NULL`` on failure. The operation
is done *in-place* when *o1* supports it. This is the equivalent of the Python
statement ``o1 **= o2`` when o3 is :c:data:`Py_None`, or an in-place variant of
``pow(o1, o2, o3)`` otherwise. If *o3* is to be ignored, pass :c:data:`Py_None`
statement ``o1 **= o2`` when o3 is :c:data:`Py_None`, or hypothetical in-place variant of
``pow(o1, o2, o3)`` (not supported in Python) otherwise.
If *o3* is to be ignored, pass :c:data:`Py_None`
in its place (passing ``NULL`` for *o3* would cause an illegal memory access).


Expand Down
7 changes: 7 additions & 0 deletions Doc/reference/datamodel.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3389,6 +3389,13 @@ left undefined.
:ref:`faq-augmented-assignment-tuple-error`), but this behavior is in fact
part of the data model.

Note that :meth:`__ipow__` should be defined to accept an optional third
argument if the third non-``None`` argument of
:c:func:`PyNumber_InPlacePower` is to be supported.

.. versionchanged:: next
:meth:`!__ipow__` can now be called with three arguments in
:c:func:`!PyNumber_InPlacePower`.

.. method:: object.__neg__(self)
object.__pos__(self)
Expand Down
5 changes: 5 additions & 0 deletions Doc/whatsnew/3.15.rst
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ New features
Other language changes
======================

* The :meth:`~object.__ipow__` method should be defined to accept an optional
third argument (as it was documented) to support non-``None`` third argument
in :c:func:`PyNumber_InPlacePower` which no longer ignored if
:meth:`!__ipow__` is defined.
(Contributed by Serhiy Storchaka in :gh:`86069`.)


New modules
Expand Down
3 changes: 1 addition & 2 deletions Lib/test/test_capi/test_number.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,7 @@ def __ipow__(*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))
self.assertEqual(inplacepower(x, 11, 5), (x, 11, 5))

def test_long(self):
# Test PyNumber_Long()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
The default implementation of the
:c:member:`~PyNumberMethods.nb_inplace_power` slot no longer ignores the
third argument, but passes it to the :meth:`~object.__ipow__` method if its
value is not ``None``.
10 changes: 8 additions & 2 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -10081,8 +10081,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 (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 *)
Expand Down
Loading