Skip to content

Commit

Permalink
Implement support for the free-threaded build of CPython 3.13
Browse files Browse the repository at this point in the history
PR #1015

Co-authored-by: J. Nick Koston <[email protected]>
Co-authored-by: Sviatoslav Sydorenko <[email protected]>
  • Loading branch information
3 people authored Oct 19, 2024
1 parent 217d16e commit 888553e
Show file tree
Hide file tree
Showing 8 changed files with 1,631 additions and 10 deletions.
40 changes: 39 additions & 1 deletion .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ jobs:
strategy:
matrix:
pyver:
- 3.13-freethreading
- 3.13
- 3.12
- 3.11
Expand All @@ -163,6 +164,10 @@ jobs:
no-extensions: Y
- os: windows
no-extensions: Y
- os: macos
pyver: 3.13-freethreading # this is still tested within cibuildwheel
- os: windows
pyver: 3.13-freethreading # this is still tested within cibuildwheel
include:
- pyver: pypy-3.8
no-extensions: Y
Expand Down Expand Up @@ -195,11 +200,44 @@ jobs:
path: dist

- name: Setup Python ${{ matrix.pyver }}
id: python-install
if: >-
!endsWith(matrix.pyver, '-freethreading')
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.pyver }}
allow-prereleases: true
- name: Setup Python ${{ matrix.pyver }}
if: endsWith(matrix.pyver, '-freethreading')
uses: deadsnakes/[email protected]
with:
python-version: 3.13-dev
nogil: true
- name: Compute runtime Python version
id: python-install
run: |
import sys
from os import environ
from pathlib import Path
FILE_APPEND_MODE = 'a'
python_version_str = ".".join(
map(str, sys.version_info[:3]),
)
freethreading_suffix = (
'' if sys.version_info < (3, 13) or sys._is_gil_enabled()
else 't'
)
with Path(environ['GITHUB_OUTPUT']).open(
mode=FILE_APPEND_MODE,
) as outputs_file:
print(
f'python-version={python_version_str}{freethreading_suffix}',
file=outputs_file,
)
shell: python

- name: Get pip cache dir
id: pip-cache
run: |
Expand Down
1 change: 1 addition & 0 deletions CHANGES/1015.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Implemented support for the free-threaded build of CPython 3.13 -- by :user:`lysnikolaou`.
1 change: 1 addition & 0 deletions CHANGES/1015.packaging.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Started publishing wheels made for the free-threaded build of CPython 3.13 -- by :user:`lysnikolaou`.
1 change: 1 addition & 0 deletions docs/spelling_wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ cChardet
changelog
charset
charsetdetect
CPython
criterias
css
ctor
Expand Down
23 changes: 18 additions & 5 deletions multidict/_multidict.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "Python.h"
#include "structmember.h"

#include "_multilib/pythoncapi_compat.h"

// Include order important
#include "_multilib/defs.h"
#include "_multilib/istr.h"
Expand Down Expand Up @@ -155,13 +157,17 @@ _multidict_append_items_seq(MultiDictObject *self, PyObject *arg,
Py_INCREF(value);
}
else if (PyList_CheckExact(item)) {
if (PyList_GET_SIZE(item) != 2) {
if (PyList_Size(item) != 2) {
goto invalid_type;
}
key = PyList_GetItemRef(item, 0);
if (key == NULL) {
goto invalid_type;
}
value = PyList_GetItemRef(item, 1);
if (value == NULL) {
goto invalid_type;
}
key = PyList_GET_ITEM(item, 0);
Py_INCREF(key);
value = PyList_GET_ITEM(item, 1);
Py_INCREF(value);
}
else if (PySequence_Check(item)) {
if (PySequence_Size(item) != 2) {
Expand Down Expand Up @@ -2070,6 +2076,13 @@ PyInit__multidict(void)

/* Instantiate this module */
module = PyModule_Create(&multidict_module);
if (module == NULL) {
goto fail;
}

#ifdef Py_GIL_DISABLED
PyUnstable_Module_SetGIL(module, Py_MOD_GIL_NOT_USED);
#endif

Py_INCREF(&istr_type);
if (PyModule_AddObject(
Expand Down
48 changes: 44 additions & 4 deletions multidict/_multilib/pair_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -916,13 +916,18 @@ _pair_list_post_update(pair_list_t *list, PyObject* used_keys, Py_ssize_t pos)

for (; pos < list->size; pos++) {
pair = pair_list_get(list, pos);
tmp = PyDict_GetItem(used_keys, pair->identity);
if (tmp == NULL) {
int status = PyDict_GetItemRef(used_keys, pair->identity, &tmp);
if (status == -1) {
// exception set
return -1;
}
else if (status == 0) {
// not found
continue;
}

num = PyLong_AsSsize_t(tmp);
Py_DECREF(tmp);
if (num == -1) {
if (!PyErr_Occurred()) {
PyErr_SetString(PyExc_RuntimeError, "invalid internal state");
Expand Down Expand Up @@ -955,12 +960,18 @@ _pair_list_update(pair_list_t *list, PyObject *key,
int found;
int ident_cmp_res;

item = PyDict_GetItem(used_keys, identity);
if (item == NULL) {
int status = PyDict_GetItemRef(used_keys, identity, &item);
if (status == -1) {
// exception set
return -1;
}
else if (status == 0) {
// not found
pos = 0;
}
else {
pos = PyLong_AsSsize_t(item);
Py_DECREF(item);
if (pos == -1) {
if (!PyErr_Occurred()) {
PyErr_SetString(PyExc_RuntimeError, "invalid internal state");
Expand Down Expand Up @@ -1087,18 +1098,28 @@ pair_list_update_from_seq(pair_list_t *list, PyObject *seq)
}

// Convert item to sequence, and verify length 2.
#ifdef Py_GIL_DISABLED
if (!PySequence_Check(item)) {
#else
fast = PySequence_Fast(item, "");
if (fast == NULL) {
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
#endif
PyErr_Format(PyExc_TypeError,
"multidict cannot convert sequence element #%zd"
" to a sequence",
i);
#ifndef Py_GIL_DISABLED
}
#endif
goto fail_1;
}

#ifdef Py_GIL_DISABLED
n = PySequence_Size(item);
#else
n = PySequence_Fast_GET_SIZE(fast);
#endif
if (n != 2) {
PyErr_Format(PyExc_ValueError,
"multidict update sequence element #%zd "
Expand All @@ -1107,10 +1128,27 @@ pair_list_update_from_seq(pair_list_t *list, PyObject *seq)
goto fail_1;
}

#ifdef Py_GIL_DISABLED
key = PySequence_ITEM(item, 0);
if (key == NULL) {
PyErr_Format(PyExc_ValueError,
"multidict update sequence element #%zd's "
"key could not be fetched", i);
goto fail_1;
}
value = PySequence_ITEM(item, 1);
if (value == NULL) {
PyErr_Format(PyExc_ValueError,
"multidict update sequence element #%zd's "
"value could not be fetched", i);
goto fail_1;
}
#else
key = PySequence_Fast_GET_ITEM(fast, 0);
value = PySequence_Fast_GET_ITEM(fast, 1);
Py_INCREF(key);
Py_INCREF(value);
#endif

identity = pair_list_calc_identity(list, key);
if (identity == NULL) {
Expand All @@ -1128,7 +1166,9 @@ pair_list_update_from_seq(pair_list_t *list, PyObject *seq)

Py_DECREF(key);
Py_DECREF(value);
#ifndef Py_GIL_DISABLED
Py_DECREF(fast);
#endif
Py_DECREF(item);
Py_DECREF(identity);
}
Expand Down
Loading

0 comments on commit 888553e

Please sign in to comment.