diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index de35339b..bb2be7d2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,17 +41,18 @@ jobs: fi wheels: - name: Build / ${{ matrix.os }} / Python 3.${{ matrix.python.minor }} + name: Build / ${{ matrix.os }} / Python 3.${{ matrix.python.minor }} / FT${{ matrix.python.ft }} needs: matrix_config strategy: fail-fast: false matrix: os: ${{ fromJson(needs.matrix_config.outputs.matrix_os) }} python: - - {minor: 10, req_build: 'requirements-build-3_11.txt', req_test: 'requirements-dev-3_11.txt'} - - {minor: 11, req_build: 'requirements-build-3_11.txt', req_test: 'requirements-dev-3_11.txt'} - - {minor: 12, req_build: 'requirements-build-3_12.txt', req_test: 'requirements-dev-3_12.txt'} - - {minor: 13, req_build: 'requirements-build-3_13.txt', req_test: 'requirements-dev-3_13.txt'} + - {minor: 10, req_build: 'requirements-build-3_11.txt', req_test: 'requirements-dev-3_11.txt', ft: '0'} + - {minor: 11, req_build: 'requirements-build-3_11.txt', req_test: 'requirements-dev-3_11.txt', ft: '0'} + - {minor: 12, req_build: 'requirements-build-3_12.txt', req_test: 'requirements-dev-3_12.txt', ft: '0'} + - {minor: 13, req_build: 'requirements-build-3_13.txt', req_test: 'requirements-dev-3_13.txt', ft: '0'} + - {minor: 13t, req_build: 'requirements-build-3_13.txt', req_test: 'requirements-dev-3_13.txt', ft: '1'} runs-on: ${{ matrix.os }} outputs: @@ -75,6 +76,7 @@ jobs: CIBW_BEFORE_BUILD: pip install -r {project}/${{ matrix.python.req_build }} CIBW_BEFORE_TEST: pip install -r {project}/${{ matrix.python.req_test }} CIBW_TEST_COMMAND: pytest {project}/test + CIBW_ENABLE: ${{ matrix.python.ft == '1' && 'cpython-freethreading' || '' }} - run: pip install pipx if: matrix.os == 'macos-13-xlarge' @@ -87,10 +89,11 @@ jobs: CIBW_BEFORE_BUILD: pip install -r {project}/${{ matrix.python.req_build }} CIBW_BEFORE_TEST: pip install -r {project}/${{ matrix.python.req_test }} CIBW_TEST_COMMAND: pytest {project}/test + CIBW_ENABLE: ${{ matrix.python.ft == '1' && 'cpython-freethreading' || '' }} - uses: actions/upload-artifact@v4 with: - name: dist-wheels-${{ matrix.os }}-py3${{ matrix.python.minor }} # Unique artifact name + name: dist-wheels-${{ matrix.os }}-py3${{ matrix.python.minor }}-t${{ matrix.python.ft }} # Unique artifact name path: dist/* upload: @@ -105,11 +108,6 @@ jobs: path: dist merge-multiple: true - # - name: Flatten dist directory - # run: | - # find dist -mindepth 2 -type f \( -name '*.whl' -o -name '*.tar.gz' \) \ - # -exec mv {} dist/ \; - - uses: pypa/gh-action-pypi-publish@release/v1 with: password: ${{ secrets.PYPI_TOKEN }} diff --git a/requirements-build-3_13.txt b/requirements-build-3_13.txt index dd8af061..467a95b6 100644 --- a/requirements-build-3_13.txt +++ b/requirements-build-3_13.txt @@ -1,2 +1,2 @@ -numpy==2.2.5 +numpy==2.3.1 setuptools==80.* diff --git a/requirements-dev-3_13.txt b/requirements-dev-3_13.txt index c0f0285b..e029979c 100644 --- a/requirements-dev-3_13.txt +++ b/requirements-dev-3_13.txt @@ -1,4 +1,4 @@ -numpy==2.2.5 +numpy==2.3.1 pytest==8.3.3 invoke==2.2.0 hypothesis==6.131.16 diff --git a/src/_arraykit.c b/src/_arraykit.c index 1646a0ca..7ce767ad 100644 --- a/src/_arraykit.c +++ b/src/_arraykit.c @@ -72,7 +72,7 @@ static struct PyModuleDef arraykit_module = { .m_methods = arraykit_methods, }; -PyObject * +PyObject* PyInit__arraykit(void) { import_array(); @@ -134,6 +134,9 @@ PyInit__arraykit(void) Py_XDECREF(m); return NULL; } +#ifdef Py_GIL_DISABLED + PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED); +#endif return m; } diff --git a/src/auto_map.c b/src/auto_map.c index 64b65fb5..cc05795a 100644 --- a/src/auto_map.c +++ b/src/auto_map.c @@ -426,8 +426,13 @@ fami_iternext(FAMIObject *self) else { PyObject* t = PyTuple_New(2); if (!t) { return NULL; } +#if PY_VERSION_HEX >= 0x030D0000 // Python 3.13+ + PyObject* k = PyList_GetItemRef(self->fam->keys, index); +#else PyObject* k = PyList_GET_ITEM(self->fam->keys, index); - Py_INCREF(k); + Py_XINCREF(k); +#endif + if (!k) { return NULL; } PyTuple_SET_ITEM(t, 0, k); PyTuple_SET_ITEM(t, 1, PyLong_FromSsize_t(index)); return t; @@ -438,8 +443,13 @@ fami_iternext(FAMIObject *self) return PyArray_ToScalar(PyArray_GETPTR1(self->keys_array, index), self->keys_array); } else { +#if PY_VERSION_HEX >= 0x030D0000 // Python 3.13+ + PyObject* yield = PyList_GetItemRef(self->fam->keys, index); +#else PyObject* yield = PyList_GET_ITEM(self->fam->keys, index); - Py_INCREF(yield); + Py_XINCREF(yield); +#endif + if (!yield) { return NULL; } return yield; } } @@ -1302,11 +1312,11 @@ lookup(FAMObject *self, PyObject *key) { return self->table[table_pos].keys_pos; } -// Insert a key_pos, hash pair into the table. Assumes table already has appropriate size. When inserting a new itme, `hash` is -1, forcing a fresh hash to be computed here. Return 0 on success, -1 on error. +// Insert a key_pos, hash pair into the table. Assumes table already has appropriate size. When inserting a new item, `hash` is -1, forcing a fresh hash to be computed here. Return 0 on success, -1 on error. static int insert_obj( FAMObject *self, - PyObject *key, + PyObject *key, // NOTE: a borrowed reference Py_ssize_t keys_pos, Py_hash_t hash) {