|
|
|
|
@@ -0,0 +1,300 @@
|
|
|
|
|
From 7ade46952adea22f3b2bb9c2b8b3139e4f2831b7 Mon Sep 17 00:00:00 2001
|
|
|
|
|
From: =?UTF-8?q?Edgar=20Ram=C3=ADrez=20Mondrag=C3=B3n?=
|
|
|
|
|
<16805946+edgarrmondragon@users.noreply.github.com>
|
|
|
|
|
Date: Sun, 13 Oct 2024 13:25:41 -0600
|
|
|
|
|
Subject: [PATCH] Support Python 3.13 (not free-threaded) (#711)
|
|
|
|
|
|
|
|
|
|
* Build Python 3.13 wheels (not free-threaded)
|
|
|
|
|
|
|
|
|
|
* Include cp313 wheels for testing
|
|
|
|
|
|
|
|
|
|
* Build Python 3.13 wheels only for testing
|
|
|
|
|
|
|
|
|
|
* Remove trove classifier
|
|
|
|
|
|
|
|
|
|
* Update for Python 3.13.0rc1
|
|
|
|
|
|
|
|
|
|
* Clean up
|
|
|
|
|
|
|
|
|
|
* Bump cibuildwheel to 2.21.1
|
|
|
|
|
|
|
|
|
|
* Upgrade deprecated artifact actions
|
|
|
|
|
|
|
|
|
|
* Update for Python 3.13.0rc3
|
|
|
|
|
|
|
|
|
|
* Bump cibuildwheel to 2.21.3 to use Python 3.13.0 final
|
|
|
|
|
|
|
|
|
|
* Squash _eval_type warning
|
|
|
|
|
|
|
|
|
|
* Still use _PyUnicode_EQ for older pythons
|
|
|
|
|
|
|
|
|
|
Keeps around the semantic meaning for when this function is added back
|
|
|
|
|
in Python 3.14.
|
|
|
|
|
|
|
|
|
|
* Use `PyObject_GetIter` for all versions
|
|
|
|
|
|
|
|
|
|
* Use PyLong_AsNativeBytes on Py3.13
|
|
|
|
|
|
|
|
|
|
* Suppress hashing error when parsing annotated types
|
|
|
|
|
|
|
|
|
|
---------
|
|
|
|
|
|
|
|
|
|
Co-authored-by: Jim Crist-Harif <jcristharif@gmail.com>
|
|
|
|
|
---
|
|
|
|
|
.github/workflows/ci.yml | 11 +++++---
|
|
|
|
|
msgspec/_core.c | 56 ++++++++++++++++++++++++++++++----------
|
|
|
|
|
msgspec/_utils.py | 11 +++++++-
|
|
|
|
|
setup.cfg | 2 ++
|
|
|
|
|
4 files changed, 61 insertions(+), 19 deletions(-)
|
|
|
|
|
|
|
|
|
|
Index: msgspec-0.18.6/.github/workflows/ci.yml
|
|
|
|
|
===================================================================
|
|
|
|
|
--- msgspec-0.18.6.orig/.github/workflows/ci.yml
|
|
|
|
|
+++ msgspec-0.18.6/.github/workflows/ci.yml
|
|
|
|
|
@@ -80,7 +80,7 @@ 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-* cp313-*"
|
|
|
|
|
CIBW_SKIP: "*-win32 *_i686 *_s390x *_ppc64le"
|
|
|
|
|
CIBW_ARCHS_MACOS: "x86_64 arm64"
|
|
|
|
|
CIBW_ARCHS_LINUX: "x86_64 aarch64"
|
|
|
|
|
@@ -129,6 +129,7 @@ jobs:
|
|
|
|
|
- name: Upload artifact
|
|
|
|
|
uses: actions/upload-artifact@v2
|
|
|
|
|
with:
|
|
|
|
|
+ name: artifact-sdist
|
|
|
|
|
path: dist/*.tar.gz
|
|
|
|
|
|
|
|
|
|
upload_pypi:
|
|
|
|
|
@@ -138,8 +139,9 @@ jobs:
|
|
|
|
|
steps:
|
|
|
|
|
- uses: actions/download-artifact@v2
|
|
|
|
|
with:
|
|
|
|
|
- name: artifact
|
|
|
|
|
+ merge-multiple: true
|
|
|
|
|
path: dist
|
|
|
|
|
+ pattern: artifact-*
|
|
|
|
|
|
|
|
|
|
- uses: pypa/gh-action-pypi-publish@master
|
|
|
|
|
with:
|
|
|
|
|
Index: msgspec-0.18.6/msgspec/_core.c
|
|
|
|
|
===================================================================
|
|
|
|
|
--- msgspec-0.18.6.orig/msgspec/_core.c
|
|
|
|
|
+++ msgspec-0.18.6/msgspec/_core.c
|
|
|
|
|
@@ -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
|
|
|
|
|
@@ -56,6 +57,12 @@ ms_popcount(uint64_t i) {
|
|
|
|
|
#define SET_SIZE(obj, size) (((PyVarObject *)obj)->ob_size = size)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
+#if PY313_PLUS
|
|
|
|
|
+#define MS_UNICODE_EQ(a, b) (PyUnicode_Compare(a, b) == 0)
|
|
|
|
|
+#else
|
|
|
|
|
+#define MS_UNICODE_EQ(a, b) _PyUnicode_EQ(a, b)
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
|
|
#define DIV_ROUND_CLOSEST(n, d) ((((n) < 0) == ((d) < 0)) ? (((n) + (d)/2)/(d)) : (((n) - (d)/2)/(d)))
|
|
|
|
|
|
|
|
|
|
/* These macros are used to manually unroll some loops */
|
|
|
|
|
@@ -497,7 +504,7 @@ find_keyword(PyObject *kwnames, PyObject
|
|
|
|
|
for (i = 0; i < nkwargs; i++) {
|
|
|
|
|
PyObject *kwname = PyTuple_GET_ITEM(kwnames, i);
|
|
|
|
|
assert(PyUnicode_Check(kwname));
|
|
|
|
|
- if (_PyUnicode_EQ(kwname, key)) {
|
|
|
|
|
+ if (MS_UNICODE_EQ(kwname, key)) {
|
|
|
|
|
return kwstack[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -4438,10 +4445,8 @@ typenode_collect_convert_structs(TypeNod
|
|
|
|
|
*
|
|
|
|
|
* If any of these checks fails, an appropriate error is returned.
|
|
|
|
|
*/
|
|
|
|
|
- PyObject *tag_mapping = NULL, *tag_field = NULL, *set_item = NULL;
|
|
|
|
|
+ PyObject *tag_mapping = NULL, *tag_field = NULL, *set_iter = 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;
|
|
|
|
|
@@ -4449,7 +4454,8 @@ typenode_collect_convert_structs(TypeNod
|
|
|
|
|
tag_mapping = PyDict_New();
|
|
|
|
|
if (tag_mapping == NULL) goto cleanup;
|
|
|
|
|
|
|
|
|
|
- while (_PySet_NextEntry(state->structs_set, &set_pos, &set_item, &set_hash)) {
|
|
|
|
|
+ set_iter = PyObject_GetIter(state->structs_set);
|
|
|
|
|
+ while ((set_item = PyIter_Next(set_iter))) {
|
|
|
|
|
struct_info = StructInfo_Convert(set_item);
|
|
|
|
|
if (struct_info == NULL) goto cleanup;
|
|
|
|
|
|
|
|
|
|
@@ -4557,6 +4563,7 @@ typenode_collect_convert_structs(TypeNod
|
|
|
|
|
status = 0;
|
|
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
|
+ Py_XDECREF(set_iter);
|
|
|
|
|
Py_XDECREF(tag_mapping);
|
|
|
|
|
Py_XDECREF(struct_info);
|
|
|
|
|
return status;
|
|
|
|
|
@@ -4612,11 +4619,15 @@ typenode_origin_args_metadata(
|
|
|
|
|
* abstract -> concrete mapping. If present, this is an unparametrized
|
|
|
|
|
* collection of some form. This helps avoid compatibility issues in
|
|
|
|
|
* Python 3.8, where unparametrized collections still have __args__. */
|
|
|
|
|
- origin = PyDict_GetItem(state->mod->concrete_types, t);
|
|
|
|
|
+ origin = PyDict_GetItemWithError(state->mod->concrete_types, t);
|
|
|
|
|
if (origin != NULL) {
|
|
|
|
|
Py_INCREF(origin);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
+ else {
|
|
|
|
|
+ /* Ignore all errors in this initial check */
|
|
|
|
|
+ PyErr_Clear();
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
/* If `t` is a type instance, no need to inspect further */
|
|
|
|
|
if (PyType_CheckExact(t)) {
|
|
|
|
|
@@ -7313,7 +7324,7 @@ Struct_vectorcall(PyTypeObject *cls, PyO
|
|
|
|
|
* 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 (MS_UNICODE_EQ(kwname, field)) {
|
|
|
|
|
if (MS_UNLIKELY(field_index < nargs)) {
|
|
|
|
|
PyErr_Format(
|
|
|
|
|
PyExc_TypeError,
|
|
|
|
|
@@ -7720,7 +7731,7 @@ struct_replace(PyObject *self, 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 (MS_UNICODE_EQ(kwname, field)) goto kw_found;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Unknown keyword */
|
|
|
|
|
@@ -11251,7 +11262,16 @@ ms_uuid_to_16_bytes(MsgspecState *mod, P
|
|
|
|
|
PyErr_SetString(PyExc_TypeError, "uuid.int must be an int");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
+#if PY313_PLUS
|
|
|
|
|
+ int out = (int)PyLong_AsNativeBytes(
|
|
|
|
|
+ int128,
|
|
|
|
|
+ buf,
|
|
|
|
|
+ 16,
|
|
|
|
|
+ Py_ASNATIVEBYTES_BIG_ENDIAN | Py_ASNATIVEBYTES_UNSIGNED_BUFFER
|
|
|
|
|
+ );
|
|
|
|
|
+#else
|
|
|
|
|
int out = _PyLong_AsByteArray((PyLongObject *)int128, buf, 16, 0, 0);
|
|
|
|
|
+#endif
|
|
|
|
|
Py_DECREF(int128);
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
@@ -12403,8 +12423,7 @@ mpack_encode_list(EncoderState *self, Py
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
@@ -12423,13 +12442,18 @@ mpack_encode_set(EncoderState *self, PyO
|
|
|
|
|
|
|
|
|
|
if (mpack_encode_array_header(self, len, "set") < 0) return -1;
|
|
|
|
|
if (Py_EnterRecursiveCall(" while serializing an object")) return -1;
|
|
|
|
|
- while (_PySet_NextEntry(obj, &ppos, &item, &hash)) {
|
|
|
|
|
+
|
|
|
|
|
+ PyObject *iter = PyObject_GetIter(obj);
|
|
|
|
|
+ if (iter == NULL) goto cleanup;
|
|
|
|
|
+
|
|
|
|
|
+ while ((item = PyIter_Next(iter))) {
|
|
|
|
|
if (mpack_encode_inline(self, item) < 0) goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
status = 0;
|
|
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
|
Py_LeaveRecursiveCall();
|
|
|
|
|
+ Py_XDECREF(iter);
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -13725,8 +13749,7 @@ json_encode_tuple(EncoderState *self, Py
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
@@ -13745,7 +13768,11 @@ json_encode_set(EncoderState *self, PyOb
|
|
|
|
|
|
|
|
|
|
if (ms_write(self, "[", 1) < 0) return -1;
|
|
|
|
|
if (Py_EnterRecursiveCall(" while serializing an object")) return -1;
|
|
|
|
|
- while (_PySet_NextEntry(obj, &ppos, &item, &hash)) {
|
|
|
|
|
+
|
|
|
|
|
+ PyObject *iter = PyObject_GetIter(obj);
|
|
|
|
|
+ if (iter == NULL) goto cleanup;
|
|
|
|
|
+
|
|
|
|
|
+ while ((item = PyIter_Next(iter))) {
|
|
|
|
|
if (json_encode_inline(self, item) < 0) goto cleanup;
|
|
|
|
|
if (ms_write(self, ",", 1) < 0) goto cleanup;
|
|
|
|
|
}
|
|
|
|
|
@@ -13754,6 +13781,7 @@ json_encode_set(EncoderState *self, PyOb
|
|
|
|
|
status = 0;
|
|
|
|
|
cleanup:
|
|
|
|
|
Py_LeaveRecursiveCall();
|
|
|
|
|
+ Py_XDECREF(iter);
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Index: msgspec-0.18.6/msgspec/_utils.py
|
|
|
|
|
===================================================================
|
|
|
|
|
--- msgspec-0.18.6.orig/msgspec/_utils.py
|
|
|
|
|
+++ msgspec-0.18.6/msgspec/_utils.py
|
|
|
|
|
@@ -51,6 +51,15 @@ else:
|
|
|
|
|
return typing.ForwardRef(value, is_argument=False, is_class=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+# Python 3.13 adds a new mandatory type_params kwarg to _eval_type
|
|
|
|
|
+if sys.version_info >= (3, 13):
|
|
|
|
|
+
|
|
|
|
|
+ def _eval_type(t, globalns, localns):
|
|
|
|
|
+ return typing._eval_type(t, globalns, localns, ())
|
|
|
|
|
+else:
|
|
|
|
|
+ _eval_type = typing._eval_type
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
def _apply_params(obj, mapping):
|
|
|
|
|
if params := getattr(obj, "__parameters__", None):
|
|
|
|
|
args = tuple(mapping.get(p, p) for p in params)
|
|
|
|
|
@@ -127,7 +136,7 @@ def get_class_annotations(obj):
|
|
|
|
|
value = type(None)
|
|
|
|
|
elif isinstance(value, str):
|
|
|
|
|
value = _forward_ref(value)
|
|
|
|
|
- value = typing._eval_type(value, cls_locals, cls_globals)
|
|
|
|
|
+ value = _eval_type(value, cls_locals, cls_globals)
|
|
|
|
|
if mapping is not None:
|
|
|
|
|
value = _apply_params(value, mapping)
|
|
|
|
|
hints[name] = value
|
|
|
|
|
Index: msgspec-0.18.6/setup.cfg
|
|
|
|
|
===================================================================
|
|
|
|
|
--- msgspec-0.18.6.orig/setup.cfg
|
|
|
|
|
+++ msgspec-0.18.6/setup.cfg
|
|
|
|
|
@@ -12,6 +12,8 @@ omit =
|
|
|
|
|
markers =
|
|
|
|
|
mypy
|
|
|
|
|
pyright
|
|
|
|
|
+filterwarnings =
|
|
|
|
|
+ error
|
|
|
|
|
|
|
|
|
|
[versioneer]
|
|
|
|
|
VCS = git
|