Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
6 changes: 6 additions & 0 deletions Doc/c-api/arg.rst
Original file line number Diff line number Diff line change
Expand Up @@ -274,13 +274,19 @@ small to receive the value.
Convert a Python integer to a C :c:expr:`unsigned long` without
overflow checking.

.. versionchanged:: next
Use :meth:`~object.__index__` if available.

``L`` (:class:`int`) [long long]
Convert a Python integer to a C :c:expr:`long long`.

``K`` (:class:`int`) [unsigned long long]
Convert a Python integer to a C :c:expr:`unsigned long long`
without overflow checking.

.. versionchanged:: next
Use :meth:`~object.__index__` if available.

``n`` (:class:`int`) [:c:type:`Py_ssize_t`]
Convert a Python integer to a C :c:type:`Py_ssize_t`.

Expand Down
5 changes: 5 additions & 0 deletions Doc/whatsnew/3.14.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2073,6 +2073,11 @@ New features
Adding ``?`` after any format unit makes ``None`` be accepted as a value.
(Contributed by Serhiy Storchaka in :gh:`112068`.)

* The ``k`` and ``K`` formats in :c:func:`PyArg_ParseTuple` and
similar functions use now :meth:`~object.__index__` if available,
as all other integer formats.
(Contributed by Serhiy Storchaka in :gh:`112068`.)

* Add macros :c:func:`Py_PACK_VERSION` and :c:func:`Py_PACK_FULL_VERSION` for
bit-packing Python version numbers.
(Contributed by Petr Viktorin in :gh:`128629`.)
Expand Down
12 changes: 7 additions & 5 deletions Lib/test/test_capi/test_getargs.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,12 +267,12 @@ def test_I(self):
def test_k(self):
from _testcapi import getargs_k
# k returns 'unsigned long', no range checking
# it does not accept float, or instances with __int__
self.assertRaises(TypeError, getargs_k, 3.14)
self.assertRaises(TypeError, getargs_k, Index())
self.assertEqual(99, getargs_k(Index()))
self.assertEqual(0, getargs_k(IndexIntSubclass()))
self.assertRaises(TypeError, getargs_k, BadIndex())
self.assertRaises(TypeError, getargs_k, BadIndex2())
with self.assertWarns(DeprecationWarning):
self.assertEqual(1, getargs_k(BadIndex2()))
self.assertEqual(0, getargs_k(BadIndex3()))
self.assertRaises(TypeError, getargs_k, Int())
self.assertEqual(0, getargs_k(IntSubclass()))
Expand Down Expand Up @@ -419,10 +419,11 @@ def test_K(self):
from _testcapi import getargs_K
# K return 'unsigned long long', no range checking
self.assertRaises(TypeError, getargs_K, 3.14)
self.assertRaises(TypeError, getargs_K, Index())
self.assertEqual(99, getargs_K(Index()))
self.assertEqual(0, getargs_K(IndexIntSubclass()))
self.assertRaises(TypeError, getargs_K, BadIndex())
self.assertRaises(TypeError, getargs_K, BadIndex2())
with self.assertWarns(DeprecationWarning):
self.assertEqual(1, getargs_K(BadIndex2()))
self.assertEqual(0, getargs_K(BadIndex3()))
self.assertRaises(TypeError, getargs_K, Int())
self.assertEqual(0, getargs_K(IntSubclass()))
Expand All @@ -432,6 +433,7 @@ def test_K(self):

self.assertEqual(ULLONG_MAX, getargs_K(ULLONG_MAX))
self.assertEqual(0, getargs_K(0))
self.assertEqual(ULLONG_MAX, getargs_K(ULLONG_MAX))
self.assertEqual(0, getargs_K(ULLONG_MAX+1))

self.assertEqual(42, getargs_K(42))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
The ``k`` and ``K`` formats in :c:func:`PyArg_Parse` support now the
:meth:`~object.__index__` special method, as all other integer formats.
6 changes: 3 additions & 3 deletions Modules/clinic/_cursesmodule.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions Modules/clinic/_testclinic.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Modules/clinic/fcntlmodule.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions Modules/clinic/posixmodule.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Modules/clinic/signalmodule.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 12 additions & 6 deletions Python/getargs.c
Original file line number Diff line number Diff line change
Expand Up @@ -839,10 +839,13 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
unsigned long *p = va_arg(*p_va, unsigned long *);
HANDLE_NULLABLE;
unsigned long ival;
if (PyLong_Check(arg))
ival = PyLong_AsUnsignedLongMask(arg);
else
if (!PyIndex_Check(arg)) {
return converterr(nullable, "int", arg, msgbuf, bufsize);
}
ival = PyLong_AsUnsignedLongMask(arg);
if (ival == (unsigned long)(long)-1 && PyErr_Occurred()) {
RETURN_ERR_OCCURRED;
}
*p = ival;
break;
}
Expand All @@ -862,10 +865,13 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
unsigned long long *p = va_arg(*p_va, unsigned long long *);
HANDLE_NULLABLE;
unsigned long long ival;
if (PyLong_Check(arg))
ival = PyLong_AsUnsignedLongLongMask(arg);
else
if (!PyIndex_Check(arg)) {
return converterr(nullable, "int", arg, msgbuf, bufsize);
}
ival = PyLong_AsUnsignedLongLongMask(arg);
if (ival == (unsigned long long)(long long)-1 && PyErr_Occurred()) {
RETURN_ERR_OCCURRED;
}
*p = ival;
break;
}
Expand Down
4 changes: 2 additions & 2 deletions Tools/clinic/libclinic/converters.py
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ def use_converter(self) -> None:
def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> str | None:
if self.format_unit == 'k':
return self.format_code("""
if (!PyLong_Check({argname})) {{{{
if (!PyIndex_Check({argname})) {{{{
{bad_argument}
goto exit;
}}}}
Expand Down Expand Up @@ -444,7 +444,7 @@ def use_converter(self) -> None:
def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> str | None:
if self.format_unit == 'K':
return self.format_code("""
if (!PyLong_Check({argname})) {{{{
if (!PyIndex_Check({argname})) {{{{
{bad_argument}
goto exit;
}}}}
Expand Down
Loading