diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst index ed9b37dc1721f2..790ec8da109ba8 100644 --- a/Doc/c-api/long.rst +++ b/Doc/c-api/long.rst @@ -687,7 +687,7 @@ Export API .. versionadded:: 3.14 -.. c:struct:: PyLongLayout +.. c:type:: PyLongLayout Layout of an array of "digits" ("limbs" in the GMP terminology), used to represent absolute value for arbitrary precision integers. @@ -727,7 +727,7 @@ Export API Get the native layout of Python :class:`int` objects. - See the :c:struct:`PyLongLayout` structure. + See the :c:type:`PyLongLayout` structure. The function must not be called before Python initialization nor after Python finalization. The returned layout is valid until Python is @@ -735,7 +735,7 @@ Export API in a process, and so it can be cached. -.. c:struct:: PyLongExport +.. c:type:: PyLongExport Export of a Python :class:`int` object. @@ -769,7 +769,7 @@ Export API Export a Python :class:`int` object. - *export_long* must point to a :c:struct:`PyLongExport` structure allocated + *export_long* must point to a :c:type:`PyLongExport` structure allocated by the caller. It must not be ``NULL``. On success, fill in *\*export_long* and return ``0``. @@ -799,7 +799,7 @@ The :c:type:`PyLongWriter` API can be used to import an integer. .. versionadded:: 3.14 -.. c:struct:: PyLongWriter +.. c:type:: PyLongWriter A Python :class:`int` writer instance. @@ -827,7 +827,7 @@ The :c:type:`PyLongWriter` API can be used to import an integer. The layout of *digits* is described by :c:func:`PyLong_GetNativeLayout`. Digits must be in the range [``0``; ``(1 << bits_per_digit) - 1``] - (where the :c:struct:`~PyLongLayout.bits_per_digit` is the number of bits + (where the :c:type:`~PyLongLayout.bits_per_digit` is the number of bits per digit). Any unused most significant digits must be set to ``0``. diff --git a/Doc/data/stable_abi.dat b/Doc/data/stable_abi.dat index 9c5fdcefaf81d0..3fd34f1e47221a 100644 --- a/Doc/data/stable_abi.dat +++ b/Doc/data/stable_abi.dat @@ -389,8 +389,18 @@ func,PyList_SetSlice,3.2,, func,PyList_Size,3.2,, func,PyList_Sort,3.2,, data,PyList_Type,3.2,, +type,PyLongExport,3.15,,members +member,PyLongExport.value,3.15,, +member,PyLongExport.negative,3.15,, +member,PyLongExport.ndigits,3.15,, +member,PyLongExport.digits,3.15,, +type,PyLongLayout,3.15,,full-abi type,PyLongObject,3.2,,opaque data,PyLongRangeIter_Type,3.2,, +type,PyLongWriter,3.15,,opaque +func,PyLongWriter_Create,3.15,, +func,PyLongWriter_Discard,3.15,, +func,PyLongWriter_Finish,3.15,, func,PyLong_AsDouble,3.2,, func,PyLong_AsInt,3.13,, func,PyLong_AsInt32,3.14,, @@ -409,6 +419,8 @@ func,PyLong_AsUnsignedLongLong,3.2,, func,PyLong_AsUnsignedLongLongMask,3.2,, func,PyLong_AsUnsignedLongMask,3.2,, func,PyLong_AsVoidPtr,3.2,, +func,PyLong_Export,3.15,, +func,PyLong_FreeExport,3.15,, func,PyLong_FromDouble,3.2,, func,PyLong_FromInt32,3.14,, func,PyLong_FromInt64,3.14,, @@ -425,6 +437,7 @@ func,PyLong_FromUnsignedLongLong,3.2,, func,PyLong_FromUnsignedNativeBytes,3.14,, func,PyLong_FromVoidPtr,3.2,, func,PyLong_GetInfo,3.2,, +func,PyLong_GetNativeLayout,3.15,, data,PyLong_Type,3.2,, macro,PyMODEXPORT_FUNC,3.15,, data,PyMap_Type,3.2,, diff --git a/Include/cpython/longintrepr.h b/Include/cpython/longintrepr.h index 4b6f97a5e475d6..804c1e9427e063 100644 --- a/Include/cpython/longintrepr.h +++ b/Include/cpython/longintrepr.h @@ -138,45 +138,6 @@ _PyLong_CompactValue(const PyLongObject *op) #define PyUnstable_Long_CompactValue _PyLong_CompactValue - -/* --- Import/Export API -------------------------------------------------- */ - -typedef struct PyLongLayout { - uint8_t bits_per_digit; - uint8_t digit_size; - int8_t digits_order; - int8_t digit_endianness; -} PyLongLayout; - -PyAPI_FUNC(const PyLongLayout*) PyLong_GetNativeLayout(void); - -typedef struct PyLongExport { - int64_t value; - uint8_t negative; - Py_ssize_t ndigits; - const void *digits; - // Member used internally, must not be used for other purpose. - Py_uintptr_t _reserved; -} PyLongExport; - -PyAPI_FUNC(int) PyLong_Export( - PyObject *obj, - PyLongExport *export_long); -PyAPI_FUNC(void) PyLong_FreeExport( - PyLongExport *export_long); - - -/* --- PyLongWriter API --------------------------------------------------- */ - -typedef struct PyLongWriter PyLongWriter; - -PyAPI_FUNC(PyLongWriter*) PyLongWriter_Create( - int negative, - Py_ssize_t ndigits, - void **digits); -PyAPI_FUNC(PyObject*) PyLongWriter_Finish(PyLongWriter *writer); -PyAPI_FUNC(void) PyLongWriter_Discard(PyLongWriter *writer); - #ifdef __cplusplus } #endif diff --git a/Include/longobject.h b/Include/longobject.h index 19f06977036d05..38673bc18785fa 100644 --- a/Include/longobject.h +++ b/Include/longobject.h @@ -166,6 +166,44 @@ PyAPI_FUNC(PyObject *) PyLong_FromString(const char *, char **, int); PyAPI_FUNC(unsigned long) PyOS_strtoul(const char *, char **, int); PyAPI_FUNC(long) PyOS_strtol(const char *, char **, int); +/* --- Import/Export API -------------------------------------------------- */ + +typedef struct PyLongLayout { + uint8_t bits_per_digit; + uint8_t digit_size; + int8_t digits_order; + int8_t digit_endianness; +} PyLongLayout; + +PyAPI_FUNC(const PyLongLayout*) PyLong_GetNativeLayout(void); + +typedef struct PyLongExport { + int64_t value; + uint8_t negative; + Py_ssize_t ndigits; + const void *digits; + // Member used internally, must not be used for other purpose. + Py_uintptr_t _reserved; +} PyLongExport; + +PyAPI_FUNC(int) PyLong_Export( + PyObject *obj, + PyLongExport *export_long); +PyAPI_FUNC(void) PyLong_FreeExport( + PyLongExport *export_long); + + +/* --- PyLongWriter API --------------------------------------------------- */ + +typedef struct PyLongWriter PyLongWriter; + +PyAPI_FUNC(PyLongWriter*) PyLongWriter_Create( + int negative, + Py_ssize_t ndigits, + void **digits); +PyAPI_FUNC(PyObject*) PyLongWriter_Finish(PyLongWriter *writer); +PyAPI_FUNC(void) PyLongWriter_Discard(PyLongWriter *writer); + #ifndef Py_LIMITED_API # define Py_CPYTHON_LONGOBJECT_H # include "cpython/longobject.h" diff --git a/Lib/test/test_stable_abi_ctypes.py b/Lib/test/test_stable_abi_ctypes.py index 2e93ac08f82868..28f5dd11130c70 100644 --- a/Lib/test/test_stable_abi_ctypes.py +++ b/Lib/test/test_stable_abi_ctypes.py @@ -391,6 +391,9 @@ def test_windows_feature_macros(self): "PyList_Sort", "PyList_Type", "PyLongRangeIter_Type", + "PyLongWriter_Create", + "PyLongWriter_Discard", + "PyLongWriter_Finish", "PyLong_AsDouble", "PyLong_AsInt", "PyLong_AsInt32", @@ -409,6 +412,8 @@ def test_windows_feature_macros(self): "PyLong_AsUnsignedLongLongMask", "PyLong_AsUnsignedLongMask", "PyLong_AsVoidPtr", + "PyLong_Export", + "PyLong_FreeExport", "PyLong_FromDouble", "PyLong_FromInt32", "PyLong_FromInt64", @@ -425,6 +430,7 @@ def test_windows_feature_macros(self): "PyLong_FromUnsignedNativeBytes", "PyLong_FromVoidPtr", "PyLong_GetInfo", + "PyLong_GetNativeLayout", "PyLong_Type", "PyMap_Type", "PyMapping_Check", diff --git a/Misc/NEWS.d/next/C_API/2026-01-16-15-04-26.gh-issue-143869.vf94km.rst b/Misc/NEWS.d/next/C_API/2026-01-16-15-04-26.gh-issue-143869.vf94km.rst new file mode 100644 index 00000000000000..60b0c1ec13062b --- /dev/null +++ b/Misc/NEWS.d/next/C_API/2026-01-16-15-04-26.gh-issue-143869.vf94km.rst @@ -0,0 +1,5 @@ +Added :c:func:`PyLong_GetNativeLayout`, :c:struct:`PyLongLayout`, +:c:struct:`PyLongExport`, :c:func:`PyLong_Export`, +:c:func:`PyLong_FreeExport`, :c:struct:`PyLongWriter`, +:c:func:`PyLongWriter_Create`, :c:func:`PyLongWriter_Finish` and +:c:func:`PyLongWriter_Discard` to the limited API. diff --git a/Misc/stable_abi.toml b/Misc/stable_abi.toml index 31d22e64b846ba..8519db9056da5f 100644 --- a/Misc/stable_abi.toml +++ b/Misc/stable_abi.toml @@ -2664,3 +2664,28 @@ [function.Py_SET_SIZE] # Before 3.15, this was a macro that accessed the PyObject member added = '3.15' + +# PEP 757 import/export API. + +[function.PyLong_GetNativeLayout] + added = '3.15' +[function.PyLong_Export] + added = '3.15' +[function.PyLong_FreeExport] + added = '3.15' +[function.PyLongWriter_Create] + added = '3.15' +[function.PyLongWriter_Finish] + added = '3.15' +[function.PyLongWriter_Discard] + added = '3.15' +[struct.PyLongWriter] + added = '3.15' + struct_abi_kind = 'opaque' +[struct.PyLongLayout] + added = '3.15' + struct_abi_kind = 'full-abi' +[struct.PyLongExport] + added = '3.15' + struct_abi_kind = 'members' + members = ['value', 'negative', 'ndigits', 'digits'] diff --git a/PC/python3dll.c b/PC/python3dll.c index 0d9e7e9a1bac93..b23bc2b8f4382f 100755 --- a/PC/python3dll.c +++ b/PC/python3dll.c @@ -366,6 +366,8 @@ EXPORT_FUNC(PyLong_AsUnsignedLongLong) EXPORT_FUNC(PyLong_AsUnsignedLongLongMask) EXPORT_FUNC(PyLong_AsUnsignedLongMask) EXPORT_FUNC(PyLong_AsVoidPtr) +EXPORT_FUNC(PyLong_Export) +EXPORT_FUNC(PyLong_FreeExport) EXPORT_FUNC(PyLong_FromDouble) EXPORT_FUNC(PyLong_FromInt32) EXPORT_FUNC(PyLong_FromInt64) @@ -382,6 +384,10 @@ EXPORT_FUNC(PyLong_FromUnsignedLongLong) EXPORT_FUNC(PyLong_FromUnsignedNativeBytes) EXPORT_FUNC(PyLong_FromVoidPtr) EXPORT_FUNC(PyLong_GetInfo) +EXPORT_FUNC(PyLong_GetNativeLayout) +EXPORT_FUNC(PyLongWriter_Create) +EXPORT_FUNC(PyLongWriter_Discard) +EXPORT_FUNC(PyLongWriter_Finish) EXPORT_FUNC(PyMapping_Check) EXPORT_FUNC(PyMapping_GetItemString) EXPORT_FUNC(PyMapping_GetOptionalItem)