-
Notifications
You must be signed in to change notification settings - Fork 38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
python 3.13 support #442
base: main
Are you sure you want to change the base?
python 3.13 support #442
Conversation
NumPy 2.1.0 added support for Python 3.13, but drops support for Python 3.9. See https://numpy.org/news/#numpy-210-released
…om the public API. We have to re-export it.
…ion to private API
…e function signature of the `_PyLong_AsByteArray` API See python/cpython#111140 and capi-workgroup/decisions#31
`_Py_IsFinalizing` becomes a stable API in Python 3.13, and is renamed to `Py_IsFinalizing` https://docs.python.org/3.13/c-api/init.html#c.Py_IsFinalizing
Since Python 3.13, `_PyDictView_New` function became an internal API.
Python 3.13 moved this undocumented function to private API. See python/cpython#108607
This reverts commit dc4442d.
This reverts commit d6e4cff.
…Keywords` instead
…Keywords` instead
…hread_state->asyncio_running_loop`
…o a dict Python 3.13 dramatically changed how the namespace in `exec`/`eval` works. See https://docs.python.org/3.13/whatsnew/3.13.html#defined-mutation-semantics-for-locals
56aed76
to
46909e3
Compare
46909e3
to
623d83e
Compare
`_PyErr_SetKeyError` is more complex than originally thought, use the provided API when possible See also python/cpython#101578
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed that only on python 3.13, the eval-test.simple
test says
"Exception ignored in: <_io.BufferedReader name='/home/runner/work/PythonMonkey/PythonMonkey/tests/js/resources/eval-test.js'>"
I looked into it briefly, looks to be something to do with the file being closed more than once somehow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looks great, just some minor changes
# Python 3.13 dramatically changed how the namespace in `exec`/`eval` works | ||
# See https://docs.python.org/3.13/whatsnew/3.13.html#defined-mutation-semantics-for-locals | ||
_locals = {} # keep the local variables inside `eval`/`exec` to a dict | ||
globalThis.python.eval = lambda x: eval(x, None, _locals) | ||
globalThis.python.exec = lambda x: exec(x, None, _locals) | ||
globalThis.python.getenv = os.getenv |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# Python 3.13 dramatically changed how the namespace in `exec`/`eval` works | |
# See https://docs.python.org/3.13/whatsnew/3.13.html#defined-mutation-semantics-for-locals | |
_locals = {} # keep the local variables inside `eval`/`exec` to a dict | |
globalThis.python.eval = lambda x: eval(x, None, _locals) | |
globalThis.python.exec = lambda x: exec(x, None, _locals) | |
globalThis.python.getenv = os.getenv | |
# Python 3.13 dramatically changed how the namespace in `exec`/`eval` works | |
# See https://docs.python.org/3.13/whatsnew/3.13.html#defined-mutation-semantics-for-locals | |
globalThis.python.eval = lambda x: eval(x, None, sys._getframe(1).f_locals) | |
globalThis.python.exec = lambda x: exec(x, None, sys._getframe(1).f_locals) |
Without the above change, pythonmonkey would lose the ability to mutate parent scope variables with pm.eval. On main the following assert passes, but it currently fails on this branch. We should add a test to ensure this behaviour as well.
import pythonmonkey as pm
a = 42
pm.eval("python.exec('a = 43')")
assert a == 43
While on the subject, the following currently fails on main, but probably shouldn't. The above change fixes that as well.
import pythonmonkey as pm
def foo():
b = 42
pm.eval("python.exec('b = 43')")
assert b == 43
foo()
#if PY_VERSION_HEX >= 0x030d0000 // Python version is greater than 3.13 | ||
_PyLong_AsByteArray((PyLongObject *)pyObject, bytes, byteCount, /*is_little_endian*/ false, false, false); | ||
#else | ||
_PyLong_AsByteArray((PyLongObject *)pyObject, bytes, byteCount, /*is_little_endian*/ false, false); | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#if PY_VERSION_HEX >= 0x030d0000 // Python version is greater than 3.13 | |
_PyLong_AsByteArray((PyLongObject *)pyObject, bytes, byteCount, /*is_little_endian*/ false, false, false); | |
#else | |
_PyLong_AsByteArray((PyLongObject *)pyObject, bytes, byteCount, /*is_little_endian*/ false, false); | |
#endif | |
PyLong_AsByteArray((PyLongObject *)pyObject, bytes, byteCount, /*is_little_endian*/ false, false, false); |
Since we're making a shim now, it might be best to include a shim for this as well, like:
/**
* @brief Shim for `_PyLong_AsByteArray`.
* Since Python 3.13, `_PyLong_AsByteArray`'s signature changed.
* @see https://github.com/python/cpython/issues/111140
*/
inline int PyLong_AsByteArray(PyLongObject *v,
unsigned char *bytes, size_t n,
int little_endian, int is_signed, int with_exceptions) {
#if PY_VERSION_HEX >= 0x030d0000 // Python version is 3.13 or higher
return _PyLong_AsByteArray(v, bytes, n, little_endian, is_signed, with_exceptions);
#else
return _PyLong_AsByteArray(v, bytes, n, little_endian, is_signed);
#endif
}
* Since Python 3.13, `_PyDictView_New` function became an internal API. | ||
* @see Modified from https://github.com/python/cpython/blob/v3.13.0rc1/Objects/dictobject.c#L5806-L5827 | ||
*/ | ||
inline PyObject *PyDictViewObject_new(PyObject *dict, PyTypeObject *type) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
inline PyObject *PyDictViewObject_new(PyObject *dict, PyTypeObject *type) { | |
inline PyObject *PyDictView_New(PyObject *dict, PyTypeObject *type) { |
I think this would be a better name for this shim
ts_dict = _PyThreadState_GetDict(tstate); // borrowed reference | ||
#else // Python 3.8 | ||
PyObject *ts_dict = tstate->dict; // see https://github.com/python/cpython/blob/v3.8.17/Modules/_asynciomodule.c#L244-L245 | ||
ts_dict = tstate->dict; // see https://github.com/python/cpython/blob/v3.8.17/Modules/_asynciomodule.c#L244-L245 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could potentially make a shim for _PyThreadState_GetDict
here for 3.8
#endif | ||
} | ||
|
||
#endif // #ifndef PythonMonkey_py_version_shim_ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#endif // #ifndef PythonMonkey_py_version_shim_ | |
/** | |
* @brief Shim for `PyObject_CallOneArg`. | |
* `PyObject_CallOneArg` does not exist in Python 3.8. | |
*/ | |
#if PY_VERSION_HEX < 0x03090000 // Python version is less than 3.9 | |
inline PyObject *PyObject_CallOneArg(PyObject *func, PyObject *arg) { | |
return PyObject_CallFunction(func, "O", arg); | |
} | |
#endif | |
#endif // #ifndef PythonMonkey_py_version_shim_ |
This shim can be used to simplify code at ExceptionType.cc:32, IntType.cc:106, and PromiseType.cc:41
#endif | ||
} | ||
|
||
#endif // #ifndef PythonMonkey_py_version_shim_ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#endif // #ifndef PythonMonkey_py_version_shim_ | |
/** | |
* @brief Shim for `Py_SET_SIZE`. | |
* `Py_SET_SIZE` does not exist in Python 3.8. | |
*/ | |
#if PY_VERSION_HEX < 0x03090000 // Python version is less than 3.9 | |
inline void Py_SET_SIZE(PyVarObject *o, Py_ssize_t size) { | |
o->ob_size = size; | |
} | |
#endif | |
#endif // #ifndef PythonMonkey_py_version_shim_ |
This shim can be used to simplify code at IntType.cc:48
#endif | ||
} | ||
|
||
#endif // #ifndef PythonMonkey_py_version_shim_ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#endif // #ifndef PythonMonkey_py_version_shim_ | |
#if PY_VERSION_HEX < 0x03090000 // Python version is less than 3.9 | |
inline PyObject *PyObject_CallNoArgs(PyObject *func) { | |
return _PyObject_CallNoArg(func); | |
} | |
#endif | |
#endif // #ifndef PythonMonkey_py_version_shim_ |
This shim can be used to simplify code at jsTypeFactory.cc:398
In order to make PythonMonkey support the upcoming (October 1, 2024) Python 3.13 release, the following changes/actions need to be made in the codebase:
Python 3.13 added a
PyLong_AsNativeBytes API
, but also changed the function signature of the_PyLong_AsByteArray
API( C API: Consider adding public PyLong_AsByteArray() and PyLong_FromByteArray() functions python/cpython#111140)
_Py_IsFinalizing
becomes a stable API in Python 3.13, and is renamed toPy_IsFinalizing
Python 3.13 moved several undocumented APIs to private and internal-only, i.e. removed from public use.
_PyDictView*
APIs are removed._PyArg_CheckPositional
API is removed._PyErr_SetKeyError
API is removed. gh-106320: Remove private _PyErr_SetKeyError() python/cpython#108607_PyThreadState_GetDict(tstate)
API gets removed.Closes #441