Skip to content

Commit 731d379

Browse files
authored
Merge branch 'main' into chore/upgrade-spidermonkey-to-4bdfb2c
2 parents db0fae5 + 38309a3 commit 731d379

28 files changed

+611
-341
lines changed

.github/workflows/test-and-publish.yaml

+2-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ on:
3030
- '3.10'
3131
- '3.11'
3232
- '3.12'
33+
- '3.13'
3334
build_type:
3435
type: choice
3536
description: 'Choose the build type to use'
@@ -132,7 +133,7 @@ jobs:
132133
fail-fast: false
133134
matrix:
134135
os: [ 'ubuntu-20.04', 'macos-12', 'macos-14', 'windows-2022', 'pi' ]
135-
python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12' ]
136+
python_version: [ '3.8', '3.9', '3.10', '3.11', '3.12', '3.13' ]
136137
runs-on: ${{ matrix.os }}
137138
steps:
138139
- uses: actions/checkout@v4

include/JSArrayProxy.hh

+3-4
Original file line numberDiff line numberDiff line change
@@ -251,11 +251,10 @@ public:
251251
*
252252
* @param self - The JSArrayProxy
253253
* @param args - arguments to the sort method (not used)
254-
* @param nargs - number of arguments to the sort method
255-
* @param kwnames - keyword arguments to the sort method (reverse=True|False, key=keyfunction)
254+
* @param kwargs - keyword arguments to the sort method (reverse=True|False, key=keyfunction)
256255
* @return PyObject* NULL on exception, None otherwise
257256
*/
258-
static PyObject *JSArrayProxy_sort(JSArrayProxy *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames);
257+
static PyObject *JSArrayProxy_sort(JSArrayProxy *self, PyObject *args, PyObject *kwargs);
259258

260259
/**
261260
* @brief tp_traverse
@@ -404,7 +403,7 @@ static PyMethodDef JSArrayProxy_methods[] = {
404403
{"index", (PyCFunction)JSArrayProxyMethodDefinitions::JSArrayProxy_index, METH_FASTCALL, list_index__doc__},
405404
{"count", (PyCFunction)JSArrayProxyMethodDefinitions::JSArrayProxy_count, METH_O, list_count__doc__},
406405
{"reverse", (PyCFunction)JSArrayProxyMethodDefinitions::JSArrayProxy_reverse, METH_NOARGS, list_reverse__doc__},
407-
{"sort", (PyCFunction)JSArrayProxyMethodDefinitions::JSArrayProxy_sort, METH_FASTCALL|METH_KEYWORDS, list_sort__doc__},
406+
{"sort", (PyCFunction)JSArrayProxyMethodDefinitions::JSArrayProxy_sort, METH_VARARGS|METH_KEYWORDS, list_sort__doc__},
408407
{NULL, NULL} /* sentinel */
409408
};
410409

include/JSObjectItemsProxy.hh

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <jsapi.h>
1515

1616
#include <Python.h>
17+
#include "include/pyshim.hh"
1718

1819

1920
/**

include/JSObjectKeysProxy.hh

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <jsapi.h>
1515

1616
#include <Python.h>
17+
#include "include/pyshim.hh"
1718

1819

1920
/**

include/JSObjectValuesProxy.hh

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <jsapi.h>
1515

1616
#include <Python.h>
17+
#include "include/pyshim.hh"
1718

1819

1920
/**

include/StrType.hh

-2
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ public:
3636
*/
3737
static PyObject *getPyObject(JSContext *cx, JS::HandleValue str);
3838

39-
static const char *getValue(JSContext *cx, JS::HandleValue str);
40-
4139
static PyObject *proxifyString(JSContext *cx, JS::HandleValue str);
4240
};
4341

include/pyshim.hh

+145
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
/**
2+
* @file pyshim.hh
3+
* @author Tom Tang ([email protected])
4+
* @brief Python's C APIs are constantly changing in different versions of CPython.
5+
* PythonMonkey has a wide variety of CPython versions' support. (Currently Python 3.8-3.13)
6+
* This file helps our Python API calls work with different Python versions in the same code base.
7+
* @date 2024-09-20
8+
*
9+
* @copyright Copyright (c) 2024 Distributive Corp.
10+
*
11+
*/
12+
13+
#ifndef PythonMonkey_py_version_shim_
14+
#define PythonMonkey_py_version_shim_
15+
16+
#include <Python.h>
17+
18+
/**
19+
* @brief `_Py_IsFinalizing` becomes a stable API in Python 3.13,
20+
* and renames to `Py_IsFinalizing`
21+
*/
22+
#if PY_VERSION_HEX >= 0x030d0000 // Python version is greater than 3.13
23+
#define Py_IsFinalizing Py_IsFinalizing
24+
#else
25+
#define Py_IsFinalizing _Py_IsFinalizing
26+
#endif
27+
28+
/**
29+
* @brief `_PyDictViewObject` type definition moved from Python's public API
30+
* to the **internal** header file `internal/pycore_dict.h` in Python 3.13.
31+
*
32+
* @see https://github.com/python/cpython/blob/v3.13.0rc1/Include/internal/pycore_dict.h#L64-L72
33+
*/
34+
#if PY_VERSION_HEX >= 0x030d0000 // Python version is greater than 3.13
35+
typedef struct {
36+
PyObject_HEAD
37+
PyDictObject *dv_dict;
38+
} _PyDictViewObject;
39+
#endif
40+
41+
/**
42+
* @brief Shim for `_PyArg_CheckPositional`.
43+
* Since Python 3.13, `_PyArg_CheckPositional` function became an internal API.
44+
* @see Modified from https://github.com/python/cpython/blob/v3.13.0rc1/Python/getargs.c#L2738-L2780
45+
*/
46+
#if PY_VERSION_HEX >= 0x030d0000 // Python version is greater than 3.13
47+
inline int _PyArg_CheckPositional(const char *name, Py_ssize_t nargs, Py_ssize_t min, Py_ssize_t max) {
48+
if (!name) { // _PyArg_CheckPositional may also be when unpacking a tuple
49+
name = "unpacked tuple"; // https://github.com/python/cpython/blob/v3.13.0rc1/Python/getargs.c#L2746
50+
}
51+
52+
if (nargs < min) {
53+
PyErr_Format(
54+
PyExc_TypeError,
55+
"%.200s expected %s%zd argument%s, got %zd",
56+
name, (min == max ? "" : "at least "), min, min == 1 ? "" : "s", nargs);
57+
return 0;
58+
}
59+
60+
if (nargs == 0) {
61+
return 1;
62+
}
63+
64+
if (nargs > max) {
65+
PyErr_Format(
66+
PyExc_TypeError,
67+
"%.200s expected %s%zd argument%s, got %zd",
68+
name, (min == max ? "" : "at most "), max, max == 1 ? "" : "s", nargs);
69+
return 0;
70+
}
71+
72+
return 1;
73+
}
74+
#endif
75+
76+
/**
77+
* @brief Shim for `_PyDictView_New`.
78+
* Since Python 3.13, `_PyDictView_New` function became an internal API.
79+
* @see Modified from https://github.com/python/cpython/blob/v3.13.0rc1/Objects/dictobject.c#L5806-L5827
80+
*/
81+
inline PyObject *PyDictView_New(PyObject *dict, PyTypeObject *type) {
82+
#if PY_VERSION_HEX < 0x030d0000 // Python version is lower than 3.13
83+
return _PyDictView_New(dict, type);
84+
#else
85+
_PyDictViewObject *dv;
86+
dv = PyObject_GC_New(_PyDictViewObject, type);
87+
if (dv == NULL)
88+
return NULL;
89+
Py_INCREF(dict);
90+
dv->dv_dict = (PyDictObject *)dict;
91+
PyObject_GC_Track(dv);
92+
return (PyObject *)dv;
93+
#endif
94+
}
95+
96+
/**
97+
* @brief Shim for `_PyErr_SetKeyError`.
98+
* Since Python 3.13, `_PyErr_SetKeyError` function became an internal API.
99+
*/
100+
inline void PyErr_SetKeyError(PyObject *key) {
101+
// Use the provided API when possible, as `PyErr_SetObject`'s behaviour is more complex than originally thought
102+
// see also: https://github.com/python/cpython/issues/101578
103+
#if PY_VERSION_HEX < 0x030d0000 // Python version is lower than 3.13
104+
return _PyErr_SetKeyError(key);
105+
#else
106+
return PyErr_SetObject(PyExc_KeyError, key);
107+
#endif
108+
}
109+
110+
/**
111+
* @brief Shim for `Py_SET_SIZE`.
112+
* `Py_SET_SIZE` is not available in Python < 3.9
113+
*/
114+
#ifndef Py_SET_SIZE
115+
static inline void _Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size) {
116+
ob->ob_size = size;
117+
}
118+
#define Py_SET_SIZE(ob, size) _Py_SET_SIZE((PyVarObject *)(ob), size)
119+
#endif
120+
121+
/**
122+
* @brief Shim for `PyObject_CallOneArg`.
123+
* `PyObject_CallOneArg` is not available in Python < 3.9
124+
*/
125+
#if PY_VERSION_HEX < 0x03090000 // Python version is less than 3.9
126+
inline PyObject *PyObject_CallOneArg(PyObject *func, PyObject *arg) {
127+
return PyObject_CallFunction(func, "O", arg);
128+
}
129+
#endif
130+
131+
/**
132+
* @brief Shim for `_PyLong_AsByteArray`.
133+
* Python 3.13.0a4 added a new public API `PyLong_AsNativeBytes()` to replace the private `_PyLong_AsByteArray()`.
134+
* But this change also modified the function signature of `_PyLong_AsByteArray()`.
135+
* @see https://github.com/python/cpython/issues/111140
136+
*/
137+
inline int PyLong_AsByteArray(PyLongObject *v, unsigned char *bytes, size_t n, bool little_endian, bool is_signed) {
138+
#if PY_VERSION_HEX >= 0x030d0000 // Python version is 3.13 or higher
139+
return _PyLong_AsByteArray(v, bytes, n, little_endian, is_signed, /*with_exceptions*/ false);
140+
#else
141+
return _PyLong_AsByteArray(v, bytes, n, little_endian, is_signed);
142+
#endif
143+
}
144+
145+
#endif // #ifndef PythonMonkey_py_version_shim_

0 commit comments

Comments
 (0)