https://github.com/python/cpython/commit/4c7ec78092ece6de3e58d88f2b9d1557f7d30249
commit: 4c7ec78092ece6de3e58d88f2b9d1557f7d30249
branch: main
author: Sergey B Kirpichev <[email protected]>
committer: vstinner <[email protected]>
date: 2026-01-21T14:47:14+01:00
summary:

gh-143869: Add PEP 757 functions to the limited API (#143906)

Co-authored-by: Petr Viktorin <[email protected]>

files:
A Misc/NEWS.d/next/C_API/2026-01-16-15-04-26.gh-issue-143869.vf94km.rst
M Doc/c-api/long.rst
M Doc/data/stable_abi.dat
M Include/cpython/longintrepr.h
M Include/longobject.h
M Lib/test/test_stable_abi_ctypes.py
M Misc/stable_abi.toml
M PC/python3dll.c

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..510e683c87e8b9 100644
--- a/Doc/data/stable_abi.dat
+++ b/Doc/data/stable_abi.dat
@@ -389,8 +389,14 @@ func,PyList_SetSlice,3.2,,
 func,PyList_Size,3.2,,
 func,PyList_Sort,3.2,,
 data,PyList_Type,3.2,,
+type,PyLongExport,3.15,,full-abi
+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 +415,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 +433,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..63fd83868b644f 100644
--- a/Misc/stable_abi.toml
+++ b/Misc/stable_abi.toml
@@ -41,6 +41,8 @@
 #   - 'full-abi': All of the struct is part of the ABI, including the size
 #     (users may define arrays of these structs).
 #     Typically used for initialization, rather than at runtime.
+#     Any members whose names start with an underscore are not part of the
+#     limited API; they're for CPython's use only.
 #   - 'opaque': No members are part of the ABI, nor is the size. The Limited
 #     API only handles these via pointers. The C definition should be
 #     incomplete (opaque).
@@ -2664,3 +2666,29 @@
 [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'
+    # Note: The `_reserved` member of this struct is for interal use only.
+    # (The definition of 'full-abi' was clarified when this entry was added.)
+    struct_abi_kind = 'full-abi'
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)

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to