Skip to content

Commit 7aefdb2

Browse files
committed
Add support for the limited C API (Py_LIMITED_API)
Examples of API not available in the limited C API: * PyBytesWriter * PyConfig_Get(), PyConfig_GetInt(). * PyDict_ContainsString(). * PyFrame_GetBack(), PyFrame_GetVar() * PyLongWriter_Create() and PyLong_Export() * PyObject_VisitManagedDict(), PyObject_ClearManagedDict() * PyThreadState_GetUnchecked() * PyTime_t API. * PyUnicodeWriter * PyUnstable_SetImmortal(). * Py_SETREF(), Py_XSETREF(). Implementation notes: * PyUnicode_EqualToUTF8AndSize() has no ASCII fast path. * PyLong_GetSign(), PyLong_IsPositive(), PyLong_IsNegative() and PyLong_IsZero() are implemented with PyObject_RichCompareBool(). * PyBytes_Join() calls PyObject_CallMethod(sep, "join", iterable). * Add PYTHONCAPI_COMPAT_EXPECT_TYPE() macro to raise TypeError. There are 3 implementations depending on the API and Python version. test_pythoncapi_compat.py now reuses the setup module to list tests. Closes #183
1 parent ba68139 commit 7aefdb2

6 files changed

Lines changed: 555 additions & 236 deletions

File tree

‎docs/api.rst‎

Lines changed: 82 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ Python 3.15
4040

4141
See `PyBytesWriter documentation <https://docs.python.org/dev/c-api/bytes.html#pybyteswriter>`__.
4242

43+
Not available with the limited C API.
44+
4345
.. c:function:: PyObject* PySys_GetAttr(const char *name)
4446

4547
See `PySys_GetAttr() documentation <https://docs.python.org/dev/c-api/sys.html#c.PySys_GetAttr>`__.
@@ -60,17 +62,22 @@ Python 3.15
6062

6163
See `PyTuple_FromArray() documentation <https://docs.python.org/dev/c-api/tuple.html#c.PyTuple_FromArray>`__.
6264

65+
Not available with the limited C API.
66+
6367
.. c:function:: Py_hash_t PyUnstable_Unicode_GET_CACHED_HASH(PyObject *op)
6468

6569
See `PyUnstable_Unicode_GET_CACHED_HASH() documentation <https://docs.python.org/dev/c-api/unicode.html#c.PyUnstable_Unicode_GET_CACHED_HASH>`__.
6670

6771
On PyPy, always returns ``-1``.
6872

73+
Not available with the limited C API.
74+
6975
.. c:function:: int PyUnstable_SetImmortal(PyObject *op)
7076

7177
See `PyUnstable_SetImmortal() documentation <https://docs.python.org/dev/c-api/object.html#c.PyUnstable_SetImmortal>`__.
7278

73-
Availability: Python 3.13 and newer, not available on PyPy.
79+
Availability: Python 3.13 and newer, not available on PyPy, not available
80+
with the limited C API.
7481

7582
Python 3.14
7683
-----------
@@ -79,38 +86,56 @@ Python 3.14
7986

8087
See `PyLongLayout documentation <https://docs.python.org/dev/c-api/long.html#c.PyLongLayout>`__.
8188

89+
Not available with the limited C API.
90+
8291
.. c:function:: const PyLongLayout* PyLong_GetNativeLayout(void)
8392

8493
See `PyLong_GetNativeLayout() documentation <https://docs.python.org/dev/c-api/long.html#c.PyLong_GetNativeLayout>`__.
8594

95+
Not available with the limited C API.
96+
8697
.. c:struct:: PyLongExport
8798

8899
See `PyLongExport documentation <https://docs.python.org/dev/c-api/long.html#c.PyLongExport>`__.
89100

101+
Not available with the limited C API.
102+
90103
.. c:function:: int PyLong_Export(PyObject *obj, PyLongExport *export_long)
91104

92105
See `PyLong_Export() documentation <https://docs.python.org/dev/c-api/long.html#c.PyLong_Export>`__.
93106

107+
Not available with the limited C API.
108+
94109
.. c:function:: void PyLong_FreeExport(PyLongExport *export_long)
95110

96111
See `PyLong_FreeExport() documentation <https://docs.python.org/dev/c-api/long.html#c.PyLong_FreeExport>`__.
97112

113+
Not available with the limited C API.
114+
98115
.. c:struct:: PyLongWriter
99116

100117
See `PyLongWriter documentation <https://docs.python.org/dev/c-api/long.html#c.PyLongWriter>`__.
101118

119+
Not available with the limited C API.
120+
102121
.. c:function:: PyLongWriter* PyLongWriter_Create(int negative, Py_ssize_t ndigits, void **digits)
103122

104123
See `PyLongWriter_Create() documentation <https://docs.python.org/dev/c-api/long.html#c.PyLongWriter_Create>`__.
105124

125+
Not available with the limited C API.
126+
106127
.. c:function:: PyObject* PyLongWriter_Finish(PyLongWriter *writer)
107128

108129
See `PyLongWriter_Finish() documentation <https://docs.python.org/dev/c-api/long.html#c.PyLongWriter_Finish>`__.
109130

131+
Not available with the limited C API.
132+
110133
.. c:function:: void PyLongWriter_Discard(PyLongWriter *writer)
111134

112135
See `PyLongWriter_Discard() documentation <https://docs.python.org/dev/c-api/long.html#c.PyLongWriter_Discard>`__.
113136

137+
Not available with the limited C API.
138+
114139
.. c:function:: int PyLong_IsPositive(PyObject *obj)
115140

116141
See `PyLong_IsPositive() documentation <https://docs.python.org/dev/c-api/long.html#c.PyLong_IsPositive>`__.
@@ -147,46 +172,68 @@ Python 3.14
147172

148173
See `PyUnicodeWriter_Create() documentation <https://docs.python.org/dev/c-api/unicode.html#c.PyUnicodeWriter_Create>`__.
149174

175+
Not available with the limited C API.
176+
150177
.. c:function:: PyObject* PyUnicodeWriter_Finish(PyUnicodeWriter *writer)
151178

152179
See `PyUnicodeWriter_Finish() documentation <https://docs.python.org/dev/c-api/unicode.html#c.PyUnicodeWriter_Finish>`__.
153180

181+
Not available with the limited C API.
182+
154183
.. c:function:: void PyUnicodeWriter_Discard(PyUnicodeWriter *writer)
155184

156185
See `PyUnicodeWriter_Discard() documentation <https://docs.python.org/dev/c-api/unicode.html#c.PyUnicodeWriter_Discard>`__.
157186

187+
Not available with the limited C API.
188+
158189
.. c:function:: int PyUnicodeWriter_WriteChar(PyUnicodeWriter *writer, Py_UCS4 ch)
159190

160191
See `PyUnicodeWriter_WriteChar() documentation <https://docs.python.org/dev/c-api/unicode.html#c.PyUnicodeWriter_WriteChar>`__.
161192

193+
Not available with the limited C API.
194+
162195
.. c:function:: int PyUnicodeWriter_WriteUTF8(PyUnicodeWriter *writer, const char *str, Py_ssize_t size)
163196

164197
See `PyUnicodeWriter_WriteUTF8() documentation <https://docs.python.org/dev/c-api/unicode.html#c.PyUnicodeWriter_WriteUTF8>`__.
165198

199+
Not available with the limited C API.
200+
166201
.. c:function:: int PyUnicodeWriter_WriteASCII(PyUnicodeWriter *writer, const char *str, Py_ssize_t size)
167202

168203
See `PyUnicodeWriter_WriteASCII() documentation <https://docs.python.org/dev/c-api/unicode.html#c.PyUnicodeWriter_WriteASCII>`__.
169204

205+
Not available with the limited C API.
206+
170207
.. c:function:: int PyUnicodeWriter_WriteWideChar(PyUnicodeWriter *writer, const wchar_t *str, Py_ssize_t size)
171208

172209
See `PyUnicodeWriter_WriteWideChar() documentation <https://docs.python.org/dev/c-api/unicode.html#c.PyUnicodeWriter_WriteWideChar>`__.
173210

211+
Not available with the limited C API.
212+
174213
.. c:function:: int PyUnicodeWriter_WriteStr(PyUnicodeWriter *writer, PyObject *obj)
175214

176215
See `PyUnicodeWriter_WriteStr() documentation <https://docs.python.org/dev/c-api/unicode.html#c.PyUnicodeWriter_WriteStr>`__.
177216

217+
Not available with the limited C API.
218+
178219
.. c:function:: int PyUnicodeWriter_WriteRepr(PyUnicodeWriter *writer, PyObject *obj)
179220

180221
See `PyUnicodeWriter_WriteRepr() documentation <https://docs.python.org/dev/c-api/unicode.html#c.PyUnicodeWriter_WriteRepr>`__.
181222

223+
Not available with the limited C API.
224+
182225
.. c:function:: int PyUnicodeWriter_WriteSubstring(PyUnicodeWriter *writer, PyObject *str, Py_ssize_t start, Py_ssize_t end)
183226

184227
See `PyUnicodeWriter_WriteSubstring() documentation <https://docs.python.org/dev/c-api/unicode.html#c.PyUnicodeWriter_WriteSubstring>`__.
185228

229+
Not available with the limited C API.
230+
186231
.. c:function:: int PyUnicodeWriter_Format(PyUnicodeWriter *writer, const char *format, ...)
187232

188233
See `PyUnicodeWriter_Format() documentation <https://docs.python.org/dev/c-api/unicode.html#c.PyUnicodeWriter_Format>`__.
189234

235+
Not available with the limited C API.
236+
190237
.. c:function:: int PyLong_AsInt32(PyObject *obj, int32_t *pvalue)
191238

192239
See `PyLong_AsInt32() documentation <https://docs.python.org/dev/c-api/long.html#c.PyLong_AsInt32>`__.
@@ -231,16 +278,22 @@ Python 3.14
231278

232279
See `PyConfig_Get() documentation <https://docs.python.org/dev/c-api/init_config.html#c.PyConfig_Get>`__.
233280

281+
Not available with the limited C API.
282+
234283
.. c:function:: int PyConfig_GetInt(const char *name, int *value)
235284

236285
See `PyConfig_GetInt() documentation <https://docs.python.org/dev/c-api/init_config.html#c.PyConfig_GetInt>`__.
237286

287+
Not available with the limited C API.
288+
238289
.. c:function:: int PyUnstable_Object_IsUniquelyReferenced(PyObject *op)
239290

240291
See `PyUnstable_Object_IsUniquelyReferenced() documentation <https://docs.python.org/dev/c-api/object.html#c.PyUnstable_Object_IsUniquelyReferenced>`__.
241292

242293
Not available on PyPy. ``Py_REFCNT()`` semantics is different on PyPy.
243294

295+
Not available with the limited C API.
296+
244297
.. c:function:: int PyUnstable_TryIncRef(PyObject *op)
245298

246299
See `PyUnstable_TryIncRef() documentation <https://docs.python.org/dev/c-api/object.html#c.PyUnstable_TryIncRef>`__.
@@ -336,7 +389,7 @@ Python 3.13
336389
Return non-zero if the Python interpreter is shutting down, return 0
337390
otherwise.
338391

339-
Availability: Python 3.3 and newer, PyPy 7.3 and newer.
392+
Availability: Python 3.3 and newer, PyPy 7.3 and newer, limited C API 3.13.
340393

341394
See `Py_IsFinalizing() documentation <https://docs.python.org/dev/c-api/init.html#c.Py_IsFinalizing>`__.
342395

@@ -352,15 +405,19 @@ Python 3.13
352405

353406
See `PyObject_VisitManagedDict() documentation <https://docs.python.org/dev/c-api/object.html#c.PyObject_VisitManagedDict>`__.
354407

408+
Not available with the limited C API.
409+
355410
.. c:function:: void PyObject_ClearManagedDict(PyObject *obj)
356411

357412
See `PyObject_ClearManagedDict() documentation <https://docs.python.org/dev/c-api/object.html#c.PyObject_ClearManagedDict>`__.
358413

414+
Not available with the limited C API.
415+
359416
.. c:function:: PyThreadState* PyThreadState_GetUnchecked(void)
360417

361418
See `PyThreadState_GetUnchecked() documentation <https://docs.python.org/dev/c-api/init.html#c.PyThreadState_GetUnchecked>`__.
362419

363-
Available on Python 3.5.2 and newer.
420+
Available on Python 3.5.2 and newer. Not available with the limited C API.
364421

365422
.. c:function:: int PyUnicode_EqualToUTF8(PyObject *unicode, const char *str)
366423

@@ -390,35 +447,51 @@ Python 3.13
390447

391448
See `Py_HashPointer() documentation <https://docs.python.org/dev/c-api/hash.html#c.Py_HashPointer>`__.
392449

450+
Not available with the limited C API.
451+
393452
.. c:type:: PyTime_t
394453

395454
A timestamp or duration in nanoseconds, represented as a signed 64-bit
396455
integer.
397456

457+
Not available with the limited C API.
458+
398459
.. c:var:: PyTime_t PyTime_MIN
399460

400461
Minimum value of :c:type:`PyTime_t`.
401462

463+
Not available with the limited C API.
464+
402465
.. c:var:: PyTime_t PyTime_MAX
403466

404467
Maximum value of :c:type:`PyTime_t`.
405468

469+
Not available with the limited C API.
470+
406471
.. c:function:: double PyTime_AsSecondsDouble(PyTime_t t)
407472

408473
See `PyTime_AsSecondsDouble() documentation <https://docs.python.org/dev/c-api/time.html#c.PyTime_AsSecondsDouble>`__.
409474

475+
Not available with the limited C API.
476+
410477
.. c:function:: int PyTime_Monotonic(PyTime_t *result)
411478

412479
See `PyTime_Monotonic() documentation <https://docs.python.org/dev/c-api/time.html#c.PyTime_Monotonic>`__.
413480

481+
Not available with the limited C API.
482+
414483
.. c:function:: int PyTime_Time(PyTime_t *result)
415484

416485
See `PyTime_Time() documentation <https://docs.python.org/dev/c-api/time.html#c.PyTime_Time>`__.
417486

487+
Not available with the limited C API.
488+
418489
.. c:function:: int PyTime_PerfCounter(PyTime_t *result)
419490

420491
See `PyTime_PerfCounter() documentation <https://docs.python.org/dev/c-api/time.html#c.PyTime_PerfCounter>`__.
421492

493+
Not available with the limited C API.
494+
422495
.. c:function:: PyObject* PyList_GetItemRef(PyObject *op, Py_ssize_t index)
423496

424497
See `PyList_GetItemRef() documentation <https://docs.python.org/dev/c-api/list.html#c.PyList_GetItemRef>`__.
@@ -447,13 +520,13 @@ Python 3.12
447520

448521
See `PyFrame_GetVar() documentation <https://docs.python.org/dev/c-api/frame.html#c.PyFrame_GetVar>`__.
449522

450-
Not available on PyPy.
523+
Not available on PyPy nor with the limited C API.
451524

452525
.. c:function:: PyObject* PyFrame_GetVarString(PyFrameObject *frame, const char *name)
453526

454527
See `PyFrame_GetVarString() documentation <https://docs.python.org/dev/c-api/frame.html#c.PyFrame_GetVarString>`__.
455528

456-
Not available on PyPy.
529+
Not available on PyPy nor with the limited C API.
457530

458531
.. c:function:: PyObject* Py_GetConstant(unsigned int constant_id)
459532

@@ -689,7 +762,7 @@ PyFrameObject
689762

690763
See `PyFrame_GetBack() documentation <https://docs.python.org/dev/c-api/reflection.html#c.PyFrame_GetBack>`__.
691764

692-
Not available on PyPy
765+
Not available on PyPy nor with the limited C API.
693766

694767

695768
PyThreadState
@@ -838,7 +911,9 @@ part of the Python C API.
838911

839912
.. c:function:: PyFrameObject* _PyFrame_GetBackBorrow(PyFrameObject *frame)
840913

841-
:c:func:`PyFrame_GetBack` variant Not available on PyPy.
914+
:c:func:`PyFrame_GetBack` variant.
915+
916+
Not available on PyPy nor with the limited C API.
842917

843918
For example, ``tstate->frame`` can be replaced with
844919
``_PyThreadState_GetFrameBorrow(tstate)`` to avoid accessing directly

‎docs/changelog.rst‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
Changelog
22
=========
33

4+
* 2026-10-04: Add support for the limited C API (``Py_LIMITED_API``).
45
* 2026-09-23: ``PyUnstable_Object_IsUniquelyReferenced()``,
56
``PyUnstable_TryIncRef()`` and ``PyUnstable_EnableTryIncRef()`` are no longer
67
available on PyPy. ``Py_REFCNT()`` semantics is different on PyPy.

0 commit comments

Comments
 (0)