diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a77b1c5f..b086d751 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -164,6 +164,30 @@ jobs: PYTHON_VERSION: "3.11" CC_OUTER_LOOP: "gcc" CC_INNER_LOOP: "clang-18" + # Linux + conda-forge Python RC, extra deps from PyPI. + # OpenCV is omitted: no wheels for the current RC ABI yet. + - name: pyrc_pip + os: ubuntu-latest + PACKAGER: "pip" + # Using the "*" marker does not select the latest RC release + # from the conda-forge `python_rc` channel hence the need to pin + # a specific Python version when testing against an RC release. + PYTHON_VERSION: "3.15" + PYTHON_RC: "true" + CC_OUTER_LOOP: "gcc" + CC_INNER_LOOP: "gcc" + # Linux + conda-forge free-threaded Python RC, extra deps from PyPI. + - name: pyrc_ft_pip + os: ubuntu-latest + PACKAGER: "pip" + # Using the "*" marker does not select the latest RC release + # from the conda-forge `python_rc` channel hence the need to pin + # a specific Python version when testing against an RC release. + PYTHON_VERSION: "3.15" + PYTHON_RC: "true" + FREETHREADING: "1" + CC_OUTER_LOOP: "gcc" + CC_INNER_LOOP: "gcc" # Linux environment with numpy from conda-forge channel and openblas-openmp - name: pylatest_conda_forge os: ubuntu-latest diff --git a/CHANGES.md b/CHANGES.md index 2529e3bc..d7a4bb27 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,9 @@ quite a bit of overhead. https://github.com/joblib/threadpoolctl/pull/250 +- Added official support for Python 3.15, and declared support for Python 3.14 + in package metadata. + https://github.com/joblib/threadpoolctl/issues/251 3.7.0 (2026-09-15) ================== diff --git a/continuous_integration/install.sh b/continuous_integration/install.sh index 42c551ba..01190bdb 100755 --- a/continuous_integration/install.sh +++ b/continuous_integration/install.sh @@ -43,7 +43,7 @@ make_conda() { if [[ "$FREETHREADING" == "1" ]]; then TO_INSTALL="$TO_INSTALL python-freethreading" - elif [[ "$PYTHON_VERSION" == "*" ]]; then + elif [[ "$PYTHON_VERSION" == "*" || "$PYTHON_RC" == "true" ]]; then # Avoid installing free-threaded python TO_INSTALL="$TO_INSTALL python-gil" fi @@ -53,6 +53,12 @@ make_conda() { # prevent mixing conda channels conda config --set channel_priority strict conda config --add channels $CHANNEL + if [[ "$PYTHON_RC" == "true" ]]; then + # Python RC builds are on conda-forge main but depend on _python_rc, + # which is only published on this label. Keep the label at lower + # priority than conda-forge so the interpreter still comes from main. + conda config --append channels conda-forge/label/python_rc + fi conda update -n base conda conda-libmamba-solver -q --yes conda config --set solver libmamba @@ -134,6 +140,7 @@ if [[ "$UNAMESTR" == "Linux" && "$NO_NUMPY" != "true" ]]; then fi python --version +python -c "import sys, sysconfig; print('Py_GIL_DISABLED', sysconfig.get_config_var('Py_GIL_DISABLED')); print('sys._is_gil_enabled', getattr(sys, '_is_gil_enabled', lambda: 'n/a')())" python -c "import numpy; print(f'numpy {numpy.__version__}')" || echo "no numpy" python -c "import scipy; print(f'scipy {scipy.__version__}')" || echo "no scipy" diff --git a/continuous_integration/run_tests.sh b/continuous_integration/run_tests.sh index 97814b8d..6b127711 100755 --- a/continuous_integration/run_tests.sh +++ b/continuous_integration/run_tests.sh @@ -16,10 +16,20 @@ elif [[ "$PACKAGER" == "ubuntu" ]]; then pip list fi +if [[ "$FREETHREADING" == "1" ]]; then + python -c "import sys; assert hasattr(sys, '_is_gil_enabled') and not sys._is_gil_enabled(), 'expected a free-threaded interpreter with the GIL disabled'" +elif [[ "$PYTHON_RC" == "true" ]]; then + python -c "import sys, sysconfig; assert sysconfig.get_config_var('Py_GIL_DISABLED') in (0, None) and sys._is_gil_enabled(), 'expected a GIL-enabled Python RC'" +fi + # Use the CLI to display the effective runtime environment prior to # launching the tests: python -m threadpoolctl -i numpy scipy.linalg tests._openmp_test_helper.openmp_helpers_inner +if [[ "$FREETHREADING" == "1" ]]; then + python -c "import sys, numpy, scipy.linalg, tests._openmp_test_helper.openmp_helpers_inner as _; assert not sys._is_gil_enabled(), 'GIL was re-enabled after importing native extensions'" +fi + # Introspect API scope: PYTHONPATH=. python -X faulthandler tests/empirical_scope_observation.py blas PYTHONPATH=. python -X faulthandler tests/empirical_scope_observation.py openmp diff --git a/pyproject.toml b/pyproject.toml index e2a35c6a..f2ff8a65 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,6 +17,8 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", + "Programming Language :: Python :: 3.15", "Topic :: Software Development :: Libraries :: Python Modules", ]