Skip to content
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

Build Python 3.13 wheels (not free-threaded) #711

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
7 changes: 4 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,13 @@ jobs:
env:
CIBW_TEST_REQUIRES: "pytest msgpack pyyaml tomli tomli_w"
CIBW_TEST_COMMAND: "pytest {project}/tests"
CIBW_BUILD: "cp38-* cp39-* cp310-* cp311-* cp312-*"
CIBW_BUILD: "cp38-* cp39-* cp310-* cp311-* cp312-* cp13-*"
CIBW_SKIP: "*-win32 *_i686 *_s390x *_ppc64le"
CIBW_ARCHS_MACOS: "x86_64 arm64"
CIBW_ARCHS_LINUX: "x86_64 aarch64"
CIBW_TEST_SKIP: "*_arm64 *-musllinux_*"
CIBW_ENVIRONMENT: "CFLAGS=-g0"
CIBW_PRERELEASE_PYTHONS: "true"

steps:
- uses: actions/checkout@v2
Expand All @@ -99,10 +100,10 @@ jobs:
- name: Set up Environment
if: github.event_name != 'release'
run: |
echo "CIBW_SKIP=${CIBW_SKIP} *-musllinux_* cp38-*_aarch64 cp39-*_aarch64 cp311-*_aarch64 cp312-*_aarch64" >> $GITHUB_ENV
echo "CIBW_SKIP=${CIBW_SKIP} *-musllinux_* cp38-*_aarch64 cp39-*_aarch64 cp311-*_aarch64 cp312-*_aarch64 cp313-*" >> $GITHUB_ENV
edgarrmondragon marked this conversation as resolved.
Show resolved Hide resolved

- name: Build & Test Wheels
uses: pypa/cibuildwheel@v2.16.5
uses: pypa/cibuildwheel@v2.19.2

- name: Upload artifact
uses: actions/upload-artifact@v2
Expand Down
40 changes: 31 additions & 9 deletions msgspec/_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#define PY310_PLUS (PY_VERSION_HEX >= 0x030a0000)
#define PY311_PLUS (PY_VERSION_HEX >= 0x030b0000)
#define PY312_PLUS (PY_VERSION_HEX >= 0x030c0000)
#define PY313_PLUS (PY_VERSION_HEX >= 0x030d0000)

/* Hint to the compiler not to store `x` in a register since it is likely to
* change. Results in much higher performance on GCC, with smaller benefits on
Expand Down Expand Up @@ -497,7 +498,7 @@ find_keyword(PyObject *kwnames, PyObject *const *kwstack, PyObject *key)
for (i = 0; i < nkwargs; i++) {
PyObject *kwname = PyTuple_GET_ITEM(kwnames, i);
assert(PyUnicode_Check(kwname));
if (_PyUnicode_EQ(kwname, key)) {
if (PyUnicode_Compare(kwname, key) == 0) {
return kwstack[i];
}
}
Expand Down Expand Up @@ -4440,16 +4441,21 @@ typenode_collect_convert_structs(TypeNodeCollectState *state) {
*/
PyObject *tag_mapping = NULL, *tag_field = NULL, *set_item = NULL;
PyObject *struct_info = NULL;
Py_ssize_t set_pos = 0;
Py_hash_t set_hash;
bool array_like = false;
bool tags_are_strings = true;
int status = -1;

tag_mapping = PyDict_New();
if (tag_mapping == NULL) goto cleanup;

#if PY313_PLUS
PyObject *iter_set = PyObject_GetIter(state->structs_set);
while ((set_item = PyIter_Next(iter_set)) != NULL) {
#else
Py_ssize_t set_pos = 0;
Py_hash_t set_hash;
while (_PySet_NextEntry(state->structs_set, &set_pos, &set_item, &set_hash)) {
#endif
struct_info = StructInfo_Convert(set_item);
if (struct_info == NULL) goto cleanup;

Expand Down Expand Up @@ -7322,7 +7328,7 @@ Struct_vectorcall(PyTypeObject *cls, PyObject *const *args, size_t nargsf, PyObj
* check for parameters passed both as arg and kwarg */
for (field_index = 0; field_index < nfields; field_index++) {
PyObject *field = PyTuple_GET_ITEM(fields, field_index);
if (_PyUnicode_EQ(kwname, field)) {
if (PyUnicode_Compare(kwname, field) == 0) {
if (MS_UNLIKELY(field_index < nargs)) {
PyErr_Format(
PyExc_TypeError,
Expand Down Expand Up @@ -7729,7 +7735,7 @@ struct_replace(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject
}
for (field_index = 0; field_index < nfields; field_index++) {
PyObject *field = PyTuple_GET_ITEM(fields, field_index);
if (_PyUnicode_EQ(kwname, field)) goto kw_found;
if (PyUnicode_Compare(kwname, field) == 0) goto kw_found;
}

/* Unknown keyword */
Expand Down Expand Up @@ -11255,7 +11261,11 @@ ms_uuid_to_16_bytes(MsgspecState *mod, PyObject *obj, unsigned char *buf) {
PyErr_SetString(PyExc_TypeError, "uuid.int must be an int");
return -1;
}
#if PY313_PLUS
int out = _PyLong_AsByteArray((PyLongObject *)int128, buf, 16, 0, 0, 1);
#else
int out = _PyLong_AsByteArray((PyLongObject *)int128, buf, 16, 0, 0);
#endif
Py_DECREF(int128);
return out;
}
Expand Down Expand Up @@ -12404,8 +12414,7 @@ mpack_encode_list(EncoderState *self, PyObject *obj)
static int
mpack_encode_set(EncoderState *self, PyObject *obj)
{
Py_ssize_t len, ppos = 0;
Py_hash_t hash;
Py_ssize_t len = 0;
PyObject *item;
int status = -1;

Expand All @@ -12424,7 +12433,14 @@ mpack_encode_set(EncoderState *self, PyObject *obj)

if (mpack_encode_array_header(self, len, "set") < 0) return -1;
if (Py_EnterRecursiveCall(" while serializing an object")) return -1;
#if PY313_PLUS
PyObject *iter_set = PyObject_GetIter(obj);
while ((item = PyIter_Next(iter_set)) != NULL) {
#else
Py_ssize_t ppos = 0;
Py_hash_t hash;
while (_PySet_NextEntry(obj, &ppos, &item, &hash)) {
#endif
if (mpack_encode_inline(self, item) < 0) goto cleanup;
}
status = 0;
Expand Down Expand Up @@ -13707,8 +13723,7 @@ json_encode_tuple(EncoderState *self, PyObject *obj)
static int
json_encode_set(EncoderState *self, PyObject *obj)
{
Py_ssize_t len, ppos = 0;
Py_hash_t hash;
Py_ssize_t len = 0;
PyObject *item;
int status = -1;

Expand All @@ -13727,7 +13742,14 @@ json_encode_set(EncoderState *self, PyObject *obj)

if (ms_write(self, "[", 1) < 0) return -1;
if (Py_EnterRecursiveCall(" while serializing an object")) return -1;
#if PY313_PLUS
PyObject *iter_set = PyObject_GetIter(obj);
while ((item = PyIter_Next(iter_set)) != NULL) {
#else
Py_ssize_t ppos = 0;
Py_hash_t hash;
while (_PySet_NextEntry(obj, &ppos, &item, &hash)) {
#endif
if (json_encode_inline(self, item) < 0) goto cleanup;
if (ms_write(self, ",", 1) < 0) goto cleanup;
}
Expand Down
1 change: 1 addition & 0 deletions msgspec/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ def get_class_annotations(obj):
value = type(None)
elif isinstance(value, str):
value = _forward_ref(value)
# TODO: Pass `type_params` to `_eval_type` to fix deprecation warning
Copy link
Author

@edgarrmondragon edgarrmondragon Jul 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This missing parameter is causing a ton of warnings like this:

msgspec/_utils.py:130: DeprecationWarning: Failing to pass a value to the 'type_params' parameter of 'typing._eval_type' is deprecated, as it leads to incorrect behaviour when calling typing._eval_type on a stringified annotation that references a PEP 695 type parameter. It will be disallowed in Python 3.15.

python/cpython#118418

value = typing._eval_type(value, cls_locals, cls_globals)
if mapping is not None:
value = _apply_params(value, mapping)
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
],
extras_require=extras_require,
license="BSD",
Expand Down