From 4dc442fb012f821678b9b64dfa6ecc56e9bc57bd Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com> Date: Tue, 12 May 2026 20:48:26 +0300 Subject: [PATCH] Don't force PYTHON_GIL=0, instead fail if anything re-enables --- .ci/install.sh | 4 ++-- .github/workflows/test.yml | 5 ----- Tests/conftest.py | 29 +++++++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/.ci/install.sh b/.ci/install.sh index 9553eb8f4..cc104c45f 100755 --- a/.ci/install.sh +++ b/.ci/install.sh @@ -39,8 +39,8 @@ python3 -m pip install --only-binary=:all: pyarrow || true # PyQt6 doesn't support PyPy3 if [[ $GHA_PYTHON_VERSION == 3.* ]]; then sudo apt-get -qq install libegl1 libxcb-cursor0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-shape0 libxkbcommon-x11-0 - # TODO Update condition when pyqt6 supports free-threading - if ! [[ "$PYTHON_GIL" == "0" ]]; then python3 -m pip install pyqt6 ; fi + # pyqt6 doesn't yet support free-threading; only install if a wheel is available + python3 -m pip install --only-binary=:all: pyqt6 || true fi # webp diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index dc9c33743..362412e94 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -73,11 +73,6 @@ jobs: ".ci/*.sh" "pyproject.toml" - - name: Set PYTHON_GIL - if: endsWith(matrix.python-version, 't') - run: | - echo "PYTHON_GIL=0" >> $GITHUB_ENV - - name: Build system information run: python3 .github/workflows/system-info.py diff --git a/Tests/conftest.py b/Tests/conftest.py index e00d1f019..8d12a0e14 100644 --- a/Tests/conftest.py +++ b/Tests/conftest.py @@ -1,9 +1,17 @@ from __future__ import annotations import io +import sys +import sysconfig import pytest +FREE_THREADED_BUILD = bool(sysconfig.get_config_var("Py_GIL_DISABLED")) + +gil_enabled_at_start = True +if FREE_THREADED_BUILD: + gil_enabled_at_start = sys._is_gil_enabled() # type: ignore[attr-defined] + def pytest_report_header(config: pytest.Config) -> str: try: @@ -16,6 +24,27 @@ def pytest_report_header(config: pytest.Config) -> str: return f"pytest_report_header failed: {e}" +def pytest_terminal_summary( + terminalreporter: pytest.TerminalReporter, exitstatus: int, config: pytest.Config +) -> None: + if ( + FREE_THREADED_BUILD + and not gil_enabled_at_start + and sys._is_gil_enabled() # type: ignore[attr-defined] + ): + tr = terminalreporter + tr.ensure_newline() + tr.section("GIL re-enabled", sep="=", red=True, bold=True) + tr.line("The GIL was re-enabled at runtime during the tests.") + tr.line("This can happen with no test failures if the RuntimeWarning") + tr.line("raised by Python when this happens is filtered by a test.") + tr.line("") + tr.line("Please ensure all new C modules declare support for running") + tr.line("without the GIL. Any new tests that intentionally imports") + tr.line("code that re-enables the GIL should do so in a subprocess.") + pytest.exit("GIL re-enabled during tests", returncode=1) + + def pytest_configure(config: pytest.Config) -> None: config.addinivalue_line( "markers",