diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 73de905d..2a92b6e2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,6 +20,7 @@ jobs: - '3.11' - '3.12' - '3.13' + - '3.13t' arch: - 'arm64' - 'x86' @@ -58,6 +59,8 @@ jobs: # Activate Python development mode so we get warnings. PYTHONDEVMODE: '1' steps: + - uses: actions/checkout@v4 + - name: Set up Python uses: actions/setup-python@v5 with: @@ -65,13 +68,11 @@ jobs: architecture: ${{ matrix.arch }} - name: Install Rust - if: matrix.arch == 'x64' + if: matrix.arch == 'x64' && !startsWith(matrix.py, '3.13') uses: dtolnay/rust-toolchain@v1 with: toolchain: stable - - uses: actions/checkout@v4 - - name: Install Dependencies shell: bash run: | @@ -79,14 +80,14 @@ jobs: # TODO enable once PyO3 supports 3.13. - name: Build (Rust) - if: matrix.arch == 'x64' && matrix.py != '3.13' + if: matrix.arch == 'x64' && !startsWith(matrix.py, '3.13') env: PIP_CONSTRAINT: 'ci/constraints.txt' run: | python -m pip install --config-settings='--build-option=--rust-backend' -e . - name: Build (No Rust) - if: matrix.arch != 'x64' || matrix.py == '3.13' + if: matrix.arch != 'x64' || startsWith(matrix.py, '3.13') run: | python -m pip install -e . @@ -95,13 +96,15 @@ jobs: pytest --numprocesses=auto --hypothesis-profile=${HYPOTHESIS_PROFILE} -v tests/ - name: Test CFFI Backend + # CFFI doesn't yet support the free-threaded build of CPython + if: matrix.py != '3.13t' env: PYTHON_ZSTANDARD_IMPORT_POLICY: 'cffi' run: | pytest --numprocesses=auto --hypothesis-profile=${HYPOTHESIS_PROFILE} -v tests/ - name: Test Rust Backend - if: matrix.arch == 'x64' + if: matrix.arch == 'x64' && !startsWith(matrix.py, '3.13') # Rust backend is currently experimental. So ignore failures in it. continue-on-error: true env: diff --git a/c-ext/backend_c.c b/c-ext/backend_c.c index aabe30bc..a01187ec 100644 --- a/c-ext/backend_c.c +++ b/c-ext/backend_c.c @@ -210,6 +210,10 @@ void zstd_module_init(PyObject *m) { Py_DECREF(feature); #endif +#ifdef Py_GIL_DISABLED + PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED); +#endif + if (PyObject_SetAttrString(m, "backend_features", features) == -1) { return; } @@ -313,7 +317,7 @@ size_t roundpow2(size_t i) { int safe_pybytes_resize(PyObject **obj, Py_ssize_t size) { PyObject *tmp; - if ((*obj)->ob_refcnt == 1) { + if (Py_REFCNT(*obj) == 1) { return _PyBytes_Resize(obj, size); } diff --git a/docs/installing.rst b/docs/installing.rst index 1f3f464d..ac7b8fe8 100644 --- a/docs/installing.rst +++ b/docs/installing.rst @@ -44,6 +44,10 @@ One way to do this is to depend on the ``zstandard[cffi]`` dependency. e.g. ``pip install 'zstandard[cffi]'`` or add ``zstandard[cffi]`` to your pip requirements file. +CFFI does not yet support the free-threaded build of CPython so the CFFI +backend is disabled at build time for free-threaded Python regardless of +whether or not the ``cffi`` is specified. + Legacy Format Support ===================== @@ -84,7 +88,8 @@ All Install Arguments Do not compile the CFFI-based backend. ``--rust-backend`` - Compile the Rust backend (not yet feature complete). + Compile the Rust backend (not yet feature complete and not supported + on the free-threaded build or Python 3.13). If you invoke ``setup.py``, simply pass the aforementioned arguments. e.g. ``python3.9 setup.py --no-cffi-backend``. If using ``pip``, use the diff --git a/setup.py b/setup.py index 61156754..70954c1f 100755 --- a/setup.py +++ b/setup.py @@ -10,6 +10,7 @@ import os import platform import sys +import sysconfig from setuptools import setup @@ -36,7 +37,6 @@ ext_suffix = os.environ.get("SETUPTOOLS_EXT_SUFFIX") if ext_suffix: - import sysconfig # setuptools._distutils.command.build_ext doesn't use # SETUPTOOLS_EXT_SUFFIX like setuptools.command.build_ext does. # Work around the issue so that cross-compilation can work @@ -55,22 +55,27 @@ if py39compat: py39compat.add_ext_suffix = lambda vars: None -try: - import cffi - - # PyPy (and possibly other distros) have CFFI distributed as part of - # them. - cffi_version = LooseVersion(cffi.__version__) - if cffi_version < LooseVersion(MINIMUM_CFFI_VERSION): - print( - "CFFI %s or newer required (%s found); " - "not building CFFI backend" % (MINIMUM_CFFI_VERSION, cffi_version), - file=sys.stderr, - ) - cffi = None - -except ImportError: +if bool(sysconfig.get_config_var("Py_GIL_DISABLED")): + # cffi does not yet support the free-threaded build so we + # disable the cffi backend cffi = None +else: + try: + import cffi + + # PyPy (and possibly other distros) have CFFI distributed as part of + # them. + cffi_version = LooseVersion(cffi.__version__) + if cffi_version < LooseVersion(MINIMUM_CFFI_VERSION): + print( + "CFFI %s or newer required (%s found); " + "not building CFFI backend" % (MINIMUM_CFFI_VERSION, cffi_version), + file=sys.stderr, + ) + cffi = None + + except ImportError: + cffi = None sys.path.insert(0, ".")