Skip to content

Commit 4bb387f

Browse files
committed
Fix Python 3.13+ by calling CPython API
1 parent 5346404 commit 4bb387f

3 files changed

Lines changed: 26 additions & 4 deletions

File tree

mypyc/lib-rt/static_data.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ intern_strings(void) {
5555
INTERN_STRING(endswith, "endswith");
5656
INTERN_STRING(get_type_hints, "get_type_hints");
5757
INTERN_STRING(keys, "keys");
58+
INTERN_STRING(lower, "lower");
5859
INTERN_STRING(items, "items");
5960
INTERN_STRING(join, "join");
6061
INTERN_STRING(register_, "register");
@@ -66,6 +67,7 @@ intern_strings(void) {
6667
INTERN_STRING(throw_, "throw");
6768
INTERN_STRING(translate, "translate");
6869
INTERN_STRING(update, "update");
70+
INTERN_STRING(upper, "upper");
6971
INTERN_STRING(values, "values");
7072
return 0;
7173
}

mypyc/lib-rt/static_data.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ typedef struct mypyc_interned_str_struct {
4747
PyObject *endswith;
4848
PyObject *get_type_hints;
4949
PyObject *keys;
50+
PyObject *lower;
5051
PyObject *items;
5152
PyObject *join;
5253
PyObject *register_;
@@ -58,6 +59,7 @@ typedef struct mypyc_interned_str_struct {
5859
PyObject *throw_;
5960
PyObject *translate;
6061
PyObject *update;
62+
PyObject *upper;
6163
PyObject *values;
6264
} mypyc_interned_str_struct;
6365

mypyc/lib-rt/str_ops.c

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@
77
#include <Python.h>
88
#include "CPy.h"
99

10-
// On 3.13+, _PyUnicode_CheckConsistency and _PyUnicode_ToLowerFull/ToUpperFull
11-
// were moved from the public API to internal/pycore_unicodeobject.h.
10+
// The _PyUnicode_CheckConsistency definition has been moved to the internal API
1211
// https://github.com/python/cpython/pull/106398
13-
#if CPY_3_13_FEATURES
12+
#if defined(Py_DEBUG) && CPY_3_13_FEATURES
1413
#include "internal/pycore_unicodeobject.h"
1514
#endif
1615

@@ -684,7 +683,12 @@ static int CPy_ASCII_Upper(unsigned char c) { return Py_TOUPPER(c); }
684683

685684
static PyObject *CPyStr_ChangeCase(PyObject *self,
686685
int (*ascii_func)(unsigned char),
687-
int (*unicode_func)(Py_UCS4, Py_UCS4 *)) {
686+
#if CPY_3_13_FEATURES
687+
PyObject *method_name
688+
#else
689+
int (*unicode_func)(Py_UCS4, Py_UCS4 *)
690+
#endif
691+
) {
688692
Py_ssize_t len = PyUnicode_GET_LENGTH(self);
689693
if (len == 0) {
690694
Py_INCREF(self);
@@ -703,6 +707,11 @@ static PyObject *CPyStr_ChangeCase(PyObject *self,
703707
return res;
704708
}
705709

710+
#if CPY_3_13_FEATURES
711+
// On 3.13+, _PyUnicode_ToLowerFull/ToUpperFull are no longer exported,
712+
// so fall back to CPython's method implementation for non-ASCII strings.
713+
return PyObject_CallMethodNoArgs(self, method_name);
714+
#else
706715
// General Unicode: unicode_func handles 1-to-N expansion.
707716
// Worst case: each codepoint expands to 3 (per Unicode standard).
708717
// The tmp buffer is short-lived, and PyUnicode_FromKindAndData
@@ -724,14 +733,23 @@ static PyObject *CPyStr_ChangeCase(PyObject *self,
724733
PyObject *res = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, tmp, out_len);
725734
PyMem_Free(tmp);
726735
return res;
736+
#endif
727737
}
728738

729739
PyObject *CPyStr_Lower(PyObject *self) {
740+
#if CPY_3_13_FEATURES
741+
return CPyStr_ChangeCase(self, CPy_ASCII_Lower, mypyc_interned_str.lower);
742+
#else
730743
return CPyStr_ChangeCase(self, CPy_ASCII_Lower, _PyUnicode_ToLowerFull);
744+
#endif
731745
}
732746

733747
PyObject *CPyStr_Upper(PyObject *self) {
748+
#if CPY_3_13_FEATURES
749+
return CPyStr_ChangeCase(self, CPy_ASCII_Upper, mypyc_interned_str.upper);
750+
#else
734751
return CPyStr_ChangeCase(self, CPy_ASCII_Upper, _PyUnicode_ToUpperFull);
752+
#endif
735753
}
736754

737755
bool CPyStr_IsDigit(PyObject *str) {

0 commit comments

Comments
 (0)