From 8f787d1e9db984ba4c2f25fe70aa3f5339035c12 Mon Sep 17 00:00:00 2001 From: vchamarthi Date: Wed, 17 Jun 2026 12:41:48 -0500 Subject: [PATCH 1/2] add free threading pythoon support --- .github/workflows/build-with-clang.yml | 2 +- .github/workflows/build-with-standard-clang.yml | 2 +- .github/workflows/build_pip.yml | 2 +- conda-recipe-cf/meta.yaml | 4 +--- conda-recipe/meta.yaml | 4 +--- mkl/_mklinitmodule.c | 6 ++++++ mkl/_py_mkl_service.pyx | 1 + pyproject.toml | 2 +- 8 files changed, 13 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build-with-clang.yml b/.github/workflows/build-with-clang.yml index 4af204a..9c2aa7e 100644 --- a/.github/workflows/build-with-clang.yml +++ b/.github/workflows/build-with-clang.yml @@ -55,7 +55,7 @@ jobs: - name: Install mkl-service dependencies run: | - pip install meson-python cython cmake ninja + pip install meson-python "cython>=3.1.0" cmake ninja - name: List oneAPI folder content run: ls ${{ env.ONEAPI_ROOT }}/compiler diff --git a/.github/workflows/build-with-standard-clang.yml b/.github/workflows/build-with-standard-clang.yml index 4652f89..7fcfa2f 100644 --- a/.github/workflows/build-with-standard-clang.yml +++ b/.github/workflows/build-with-standard-clang.yml @@ -46,7 +46,7 @@ jobs: - name: Install mkl-service dependencies run: | - pip install meson-python cython cmake ninja mkl-devel + pip install meson-python "cython>=3.1.0" cmake ninja mkl-devel - name: Build mkl-service run: | diff --git a/.github/workflows/build_pip.yml b/.github/workflows/build_pip.yml index 1a21d61..c51adfd 100644 --- a/.github/workflows/build_pip.yml +++ b/.github/workflows/build_pip.yml @@ -42,7 +42,7 @@ jobs: - name: Build conda package run: | - pip install --no-cache-dir meson-python ninja cmake cython + pip install --no-cache-dir meson-python ninja cmake "cython>=3.1.0" pip install -e ".[test]" --no-build-isolation --verbose pip list python -m pytest -v mkl/tests diff --git a/conda-recipe-cf/meta.yaml b/conda-recipe-cf/meta.yaml index 3dc85a4..daef60a 100644 --- a/conda-recipe-cf/meta.yaml +++ b/conda-recipe-cf/meta.yaml @@ -24,15 +24,13 @@ requirements: - cmake - ninja - python - - python-gil # [py>=314] - pip >=25.0 - mkl-devel # [not osx] - mkl-devel <2024 # [osx] - - cython + - cython >=3.1.0 - wheel >=0.45.1 run: - python - - python-gil # [py>=314] - {{ pin_compatible('mkl') }} test: diff --git a/conda-recipe/meta.yaml b/conda-recipe/meta.yaml index 577c792..3101306 100644 --- a/conda-recipe/meta.yaml +++ b/conda-recipe/meta.yaml @@ -23,15 +23,13 @@ requirements: - cmake - ninja - python - - python-gil # [py>=314] - python-build - pip >=25.0 - mkl-devel - - cython + - cython >=3.1.0 - wheel >=0.45.1 run: - python - - python-gil # [py>=314] - {{ pin_compatible('mkl') }} test: diff --git a/mkl/_mklinitmodule.c b/mkl/_mklinitmodule.c index 33abdf5..11571dd 100644 --- a/mkl/_mklinitmodule.c +++ b/mkl/_mklinitmodule.c @@ -200,6 +200,12 @@ PyMODINIT_FUNC PyInit__mklinit(void) return NULL; } +#ifdef Py_GIL_DISABLED + /* Declare that this module supports running without the GIL so the + * free-threaded interpreter does not re-enable it on import. */ + PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED); +#endif + return m; } #else diff --git a/mkl/_py_mkl_service.pyx b/mkl/_py_mkl_service.pyx index 975a454..72908fe 100644 --- a/mkl/_py_mkl_service.pyx +++ b/mkl/_py_mkl_service.pyx @@ -25,6 +25,7 @@ # distutils: language = c # cython: language_level=3 +# cython: freethreading_compatible=True import numbers import warnings diff --git a/pyproject.toml b/pyproject.toml index 3e89d35..ee76a6f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,7 +28,7 @@ build-backend = "mesonpy" requires = [ "meson-python>=0.13.0", "ninja", - "Cython", + "Cython>=3.1.0", "mkl-devel", "cmake" ] From 2a955b310207a09e1e95e08fdd8b64dc98086062 Mon Sep 17 00:00:00 2001 From: vchamarthi Date: Thu, 30 Jul 2026 18:05:16 -0500 Subject: [PATCH 2/2] fix pr comments and pin 3.14 and 3.14t abi tags explicitly in conda-packaging --- .github/AGENTS.md | 10 +- .github/workflows/build-with-clang.yml | 2 +- .../workflows/build-with-standard-clang.yml | 2 +- .github/workflows/build_pip.yml | 10 +- .github/workflows/conda-package-cf.yml | 126 +++++++++++++----- .github/workflows/conda-package.yml | 88 ++++++++---- AGENTS.md | 11 +- CHANGELOG.md | 11 ++ README.md | 2 +- conda-recipe/meta.yaml | 3 +- mkl/tests/test_mkl_service.py | 11 ++ pyproject.toml | 1 + 12 files changed, 205 insertions(+), 72 deletions(-) diff --git a/.github/AGENTS.md b/.github/AGENTS.md index a1041aa..a7fa27c 100644 --- a/.github/AGENTS.md +++ b/.github/AGENTS.md @@ -3,8 +3,10 @@ CI/CD workflows, automation, security scanning, and package distribution. ## Workflows -- **conda-package.yml** — main build/test pipeline (Linux/Windows, Python 3.10-3.14) -- **conda-package-cf.yml** — build/test using only conda-forge channel (Linux/Windows, Python 3.10-3.14) +All build/test workflows cover Python 3.10-3.14 plus free-threaded 3.14t. + +- **conda-package.yml** — main build/test pipeline (Linux/Windows) +- **conda-package-cf.yml** — build/test using only conda-forge channel (Linux/Windows) - **build-with-clang.yml** — Linux Clang compiler compatibility validation - **build-with-standard-clang.yml** — standard Clang compiler compatibility validation - **build_pip.yml** — validates editable build @@ -14,7 +16,9 @@ CI/CD workflows, automation, security scanning, and package distribution. ## CI/CD policy - Keep build matrix (Python versions, platforms) in workflow files only - Required checks: conda build + test on supported Python versions/platforms in CI -- Artifact naming: `$PACKAGE_NAME $OS Python $VERSION` +- Python 3.14 is expressed as two `include` rows carrying `python_spec` (`3.14.* *_cp314` and `3.14.* *_cp314t`); a bare `--python 3.14` has been observed to select the free-threaded ABI and must not be relied on +- `include` rows create new matrix combinations and inherit nothing, so `runner`/`experimental` must be repeated wherever the job reads them +- Artifact naming: `$PACKAGE_NAME $OS Python $VERSION`, where `$VERSION` is `python_tag` (`3.14` or `3.14t`) when set, otherwise `python` - Channels: `conda-forge`, `conda-forge/label/python_rc`, Intel channel ## Security diff --git a/.github/workflows/build-with-clang.yml b/.github/workflows/build-with-clang.yml index b9ffef5..14eca44 100644 --- a/.github/workflows/build-with-clang.yml +++ b/.github/workflows/build-with-clang.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: - python: ["3.10", "3.11", "3.12", "3.13", "3.14"] + python: ["3.10", "3.11", "3.12", "3.13", "3.14", "3.14t"] env: ONEAPI_ROOT: /opt/intel/oneapi diff --git a/.github/workflows/build-with-standard-clang.yml b/.github/workflows/build-with-standard-clang.yml index d4b3ed6..a2dd326 100644 --- a/.github/workflows/build-with-standard-clang.yml +++ b/.github/workflows/build-with-standard-clang.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: - python: ["3.10", "3.11", "3.12", "3.13", "3.14"] + python: ["3.10", "3.11", "3.12", "3.13", "3.14", "3.14t"] env: COMPILER_ROOT: /usr/bin diff --git a/.github/workflows/build_pip.yml b/.github/workflows/build_pip.yml index efd87a7..c399cd9 100644 --- a/.github/workflows/build_pip.yml +++ b/.github/workflows/build_pip.yml @@ -17,7 +17,13 @@ jobs: strategy: matrix: - python: ["3.10", "3.11", "3.12", "3.13", "3.14"] + python: ["3.10", "3.11", "3.12", "3.13"] + python_spec: [''] + include: + - python: '3.14' + python_spec: '3.14.* *_cp314' + - python: '3.14' + python_spec: '3.14.* *_cp314t' steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 @@ -33,7 +39,7 @@ jobs: - name: Install MKL run: | - conda install mkl-devel mkl + conda install mkl-devel mkl "python ${{ matrix.python_spec || matrix.python }}" - name: Build with pip run: | diff --git a/.github/workflows/conda-package-cf.yml b/.github/workflows/conda-package-cf.yml index c5ab663..522ff13 100644 --- a/.github/workflows/conda-package-cf.yml +++ b/.github/workflows/conda-package-cf.yml @@ -21,7 +21,15 @@ jobs: strategy: matrix: - python: ['3.10', '3.11', '3.12', '3.13', '3.14'] + python: ['3.10', '3.11', '3.12', '3.13'] + python_spec: [''] + include: + - python: '3.14' + python_spec: '3.14.* *_cp314' + python_tag: '3.14' + - python: '3.14' + python_spec: '3.14.* *_cp314t' + python_tag: '3.14t' steps: - name: Cancel Previous Runs @@ -44,9 +52,9 @@ jobs: with: path: ~/.conda/pkgs key: - ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}-${{hashFiles('**/meta.yaml') }} + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python_tag || matrix.python }}-${{hashFiles('**/meta.yaml') }} restore-keys: | - ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}- + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python_tag || matrix.python }}- ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}- - name: Add conda to system path @@ -63,7 +71,7 @@ jobs: - name: Build conda package run: | CHANNELS=(-c conda-forge -c conda-forge/label/python_rc --override-channels) - VERSIONS=(--python "${{ matrix.python }}") + VERSIONS=(--python "${{ matrix.python_spec || matrix.python }}") TEST=(--no-test) conda build \ @@ -75,7 +83,7 @@ jobs: - name: Upload artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python }} + name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python_tag || matrix.python }} path: ${{ env.CONDA_BLD }}${{ env.PACKAGE_NAME }}-*.conda build_windows: @@ -83,7 +91,15 @@ jobs: strategy: matrix: - python: ['3.10', '3.11', '3.12', '3.13', '3.14'] + python: ['3.10', '3.11', '3.12', '3.13'] + python_spec: [''] + include: + - python: '3.14' + python_spec: '3.14.* *_cp314' + python_tag: '3.14' + - python: '3.14' + python_spec: '3.14.* *_cp314t' + python_tag: '3.14t' steps: - name: Cancel Previous Runs @@ -116,9 +132,9 @@ jobs: with: path: /home/runner/conda_pkgs_dir key: - ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}-${{hashFiles('**/meta.yaml') }} + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python_tag || matrix.python }}-${{hashFiles('**/meta.yaml') }} restore-keys: | - ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}- + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python_tag || matrix.python }}- ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}- - name: Store conda paths as envs @@ -135,12 +151,12 @@ jobs: conda list -n base - name: Build conda package - run: conda build --no-test --python ${{ matrix.python }} -c conda-forge -c conda-forge/label/python_rc --override-channels conda-recipe-cf + run: conda build --no-test --python "${{ matrix.python_spec || matrix.python }}" -c conda-forge -c conda-forge/label/python_rc --override-channels conda-recipe-cf - name: Upload artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python }} + name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python_tag || matrix.python }} path: ${{ env.CONDA_BLD }}${{ env.PACKAGE_NAME }}-*.conda test_linux: @@ -149,9 +165,21 @@ jobs: strategy: matrix: - python: ['3.10', '3.11', '3.12', '3.13', '3.14'] + python: ['3.10', '3.11', '3.12', '3.13'] + python_spec: [''] experimental: [false] runner: [ubuntu-latest] + include: + - python: '3.14' + python_spec: '3.14.* *_cp314' + python_tag: '3.14' + experimental: false + runner: ubuntu-latest + - python: '3.14' + python_spec: '3.14.* *_cp314t' + python_tag: '3.14t' + experimental: false + runner: ubuntu-latest continue-on-error: ${{ matrix.experimental }} env: CHANNELS: -c conda-forge -c conda-forge/label/python_rc --override-channels @@ -160,7 +188,7 @@ jobs: - name: Download artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: - name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python }} + name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python_tag || matrix.python }} - name: Add conda to system path run: echo "$CONDA/bin" >> "$GITHUB_PATH" @@ -184,7 +212,7 @@ jobs: CHANNELS=(-c "$GITHUB_WORKSPACE/channel" -c conda-forge -c conda-forge/label/python_rc --override-channels) PACKAGE_VERSION="$(python -c "${VER_SCRIPT1} ${VER_SCRIPT2}")" export PACKAGE_VERSION - conda create -n "${{ env.TEST_ENV_NAME }}" "$PACKAGE_NAME=$PACKAGE_VERSION" "python=${{ matrix.python }}" "${CHANNELS[@]}" --only-deps --dry-run > lockfile + conda create -n "${{ env.TEST_ENV_NAME }}" "$PACKAGE_NAME=$PACKAGE_VERSION" "python ${{ matrix.python_spec || matrix.python }}" "${CHANNELS[@]}" --only-deps --dry-run > lockfile cat lockfile - name: Set pkgs_dirs @@ -198,9 +226,9 @@ jobs: with: path: ~/.conda/pkgs key: - ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}-${{hashFiles('lockfile') }} + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python_tag || matrix.python }}-${{hashFiles('lockfile') }} restore-keys: | - ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}- + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python_tag || matrix.python }}- ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}- - name: Install mkl-service @@ -209,7 +237,7 @@ jobs: CHANNELS=(-c "$GITHUB_WORKSPACE/channel" -c conda-forge -c conda-forge/label/python_rc --override-channels) PACKAGE_VERSION="$(python -c "${VER_SCRIPT1} ${VER_SCRIPT2}")" export PACKAGE_VERSION - conda create -n "${{ env.TEST_ENV_NAME }}" "$PACKAGE_NAME=$PACKAGE_VERSION" pytest "python=${{ matrix.python }}" "${CHANNELS[@]}" + conda create -n "${{ env.TEST_ENV_NAME }}" "$PACKAGE_NAME=$PACKAGE_VERSION" pytest "python ${{ matrix.python_spec || matrix.python }}" "${CHANNELS[@]}" # Test installed packages conda list @@ -225,9 +253,21 @@ jobs: strategy: matrix: - python: ['3.10', '3.11', '3.12', '3.13', '3.14'] + python: ['3.10', '3.11', '3.12', '3.13'] + python_spec: [''] experimental: [false] runner: [windows-latest] + include: + - python: '3.14' + python_spec: '3.14.* *_cp314' + python_tag: '3.14' + experimental: false + runner: windows-latest + - python: '3.14' + python_spec: '3.14.* *_cp314t' + python_tag: '3.14t' + experimental: false + runner: windows-latest continue-on-error: ${{ matrix.experimental }} env: CHANNELS: -c conda-forge -c conda-forge/label/python_rc --override-channels @@ -236,7 +276,7 @@ jobs: - name: Download artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: - name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python }} + name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python_tag || matrix.python }} - uses: conda-incubator/setup-miniconda@8ee1f361103df19b6f8c8655fd3967a8ecb162d5 # v4.0.1 with: miniforge-version: latest @@ -266,7 +306,7 @@ jobs: FOR /F "tokens=* USEBACKQ" %%F IN (`python -c "%SCRIPT%"`) DO ( SET PACKAGE_VERSION=%%F ) - conda install -n ${{ env.TEST_ENV_NAME }} ${{ env.PACKAGE_NAME }}=%PACKAGE_VERSION% python=${{ matrix.python }} -c ${{ env.GITHUB_WORKSPACE }}/channel ${{ env.CHANNELS }} --only-deps --dry-run > lockfile + conda install -n ${{ env.TEST_ENV_NAME }} ${{ env.PACKAGE_NAME }}=%PACKAGE_VERSION% "python ${{ matrix.python_spec || matrix.python }}" -c ${{ env.GITHUB_WORKSPACE }}/channel ${{ env.CHANNELS }} --only-deps --dry-run > lockfile more lockfile - name: Cache conda packages @@ -276,9 +316,9 @@ jobs: with: path: /home/runner/conda_pkgs_dir key: - ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}-${{hashFiles('lockfile') }} + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python_tag || matrix.python }}-${{hashFiles('lockfile') }} restore-keys: | - ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}- + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python_tag || matrix.python }}- ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}- - name: Install mkl-service @@ -290,7 +330,7 @@ jobs: FOR /F "tokens=* USEBACKQ" %%F IN (`python -c "%SCRIPT%"`) DO ( SET PACKAGE_VERSION=%%F ) - conda create -n ${{ env.TEST_ENV_NAME }} ${{ env.PACKAGE_NAME }}=%PACKAGE_VERSION% pytest python=${{ matrix.python }} -c ${{ env.GITHUB_WORKSPACE }}/channel ${{ env.CHANNELS }} + conda create -n ${{ env.TEST_ENV_NAME }} ${{ env.PACKAGE_NAME }}=%PACKAGE_VERSION% pytest "python ${{ matrix.python_spec || matrix.python }}" -c ${{ env.GITHUB_WORKSPACE }}/channel ${{ env.CHANNELS }} # Test installed packages conda list @@ -304,7 +344,15 @@ jobs: strategy: matrix: - python: ['3.10', '3.11', '3.12', '3.13', '3.14'] + python: ['3.10', '3.11', '3.12', '3.13'] + python_spec: [''] + include: + - python: '3.14' + python_spec: '3.14.* *_cp314' + python_tag: '3.14' + - python: '3.14' + python_spec: '3.14.* *_cp314t' + python_tag: '3.14t' steps: - name: Cancel Previous Runs @@ -330,9 +378,9 @@ jobs: with: path: /Users/runner/conda_pkgs_dir key: - ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}-${{hashFiles('**/meta.yaml') }} + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python_tag || matrix.python }}-${{hashFiles('**/meta.yaml') }} restore-keys: | - ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}- + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python_tag || matrix.python }}- ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}- - name: Install conda-build @@ -350,7 +398,7 @@ jobs: shell: bash -el {0} run: | CHANNELS=(-c conda-forge -c conda-forge/label/python_rc --override-channels) - VERSIONS=(--python "${{ matrix.python }}") + VERSIONS=(--python "${{ matrix.python_spec || matrix.python }}") TEST=(--no-test) conda build \ @@ -362,7 +410,7 @@ jobs: - name: Upload artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python }} + name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python_tag || matrix.python }} path: ${{ env.CONDA_BLD }}${{ env.PACKAGE_NAME }}-*.conda test_osx: @@ -371,9 +419,21 @@ jobs: strategy: matrix: - python: ['3.10', '3.11', '3.12', '3.13', '3.14'] + python: ['3.10', '3.11', '3.12', '3.13'] + python_spec: [''] experimental: [false] runner: [macos-26-intel] + include: + - python: '3.14' + python_spec: '3.14.* *_cp314' + python_tag: '3.14' + experimental: false + runner: macos-26-intel + - python: '3.14' + python_spec: '3.14.* *_cp314t' + python_tag: '3.14t' + experimental: false + runner: macos-26-intel continue-on-error: ${{ matrix.experimental }} env: CHANNELS: -c conda-forge -c conda-forge/label/python_rc --override-channels @@ -382,7 +442,7 @@ jobs: - name: Download artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: - name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python }} + name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python_tag || matrix.python }} - uses: conda-incubator/setup-miniconda@8ee1f361103df19b6f8c8655fd3967a8ecb162d5 # v4.0.1 with: @@ -411,7 +471,7 @@ jobs: CHANNELS=(-c "$GITHUB_WORKSPACE/channel" -c conda-forge -c conda-forge/label/python_rc --override-channels) PACKAGE_VERSION="$(python -c "${VER_SCRIPT1} ${VER_SCRIPT2}")" export PACKAGE_VERSION - conda create -n "${{ env.TEST_ENV_NAME }}" "$PACKAGE_NAME=$PACKAGE_VERSION" "python=${{ matrix.python }}" "${CHANNELS[@]}" --only-deps --dry-run > lockfile + conda create -n "${{ env.TEST_ENV_NAME }}" "$PACKAGE_NAME=$PACKAGE_VERSION" "python ${{ matrix.python_spec || matrix.python }}" "${CHANNELS[@]}" --only-deps --dry-run > lockfile cat lockfile - name: Cache conda packages @@ -421,9 +481,9 @@ jobs: with: path: /Users/runner/conda_pkgs_dir key: - ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}-${{hashFiles('lockfile') }} + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python_tag || matrix.python }}-${{hashFiles('lockfile') }} restore-keys: | - ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}- + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python_tag || matrix.python }}- ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}- - name: Install mkl-service @@ -432,7 +492,7 @@ jobs: CHANNELS=(-c "$GITHUB_WORKSPACE/channel" -c conda-forge -c conda-forge/label/python_rc --override-channels) PACKAGE_VERSION="$(python -c "${VER_SCRIPT1} ${VER_SCRIPT2}")" export PACKAGE_VERSION - conda create -n "${{ env.TEST_ENV_NAME }}" "$PACKAGE_NAME=$PACKAGE_VERSION" pytest "python=${{ matrix.python }}" "${CHANNELS[@]}" + conda create -n "${{ env.TEST_ENV_NAME }}" "$PACKAGE_NAME=$PACKAGE_VERSION" pytest "python ${{ matrix.python_spec || matrix.python }}" "${CHANNELS[@]}" # Test installed packages conda list -n "${{ env.TEST_ENV_NAME }}" diff --git a/.github/workflows/conda-package.yml b/.github/workflows/conda-package.yml index 4b1d037..289dcb1 100644 --- a/.github/workflows/conda-package.yml +++ b/.github/workflows/conda-package.yml @@ -21,7 +21,15 @@ jobs: strategy: matrix: - python: ['3.10', '3.11', '3.12', '3.13', '3.14'] + python: ['3.10', '3.11', '3.12', '3.13'] + python_spec: [''] + include: + - python: '3.14' + python_spec: '3.14.* *_cp314' + python_tag: '3.14' + - python: '3.14' + python_spec: '3.14.* *_cp314t' + python_tag: '3.14t' steps: - name: Cancel Previous Runs @@ -44,9 +52,9 @@ jobs: with: path: ~/.conda/pkgs key: - ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}-${{hashFiles('**/meta.yaml') }} + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python_tag || matrix.python }}-${{hashFiles('**/meta.yaml') }} restore-keys: | - ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}- + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python_tag || matrix.python }}- ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}- - name: Add conda to system path @@ -64,7 +72,7 @@ jobs: - name: Build conda package run: | CHANNELS=(-c conda-forge -c conda-forge/label/python_rc -c https://software.repos.intel.com/python/conda --override-channels) - VERSIONS=(--python "${{ matrix.python }}") + VERSIONS=(--python "${{ matrix.python_spec || matrix.python }}") TEST=(--no-test) conda build \ @@ -76,13 +84,13 @@ jobs: - name: Upload artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python }} + name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python_tag || matrix.python }} path: ${{ env.CONDA_BLD }}${{ env.PACKAGE_NAME }}-*.conda - name: Upload wheels artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Wheels Python ${{ matrix.python }} + name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Wheels Python ${{ matrix.python_tag || matrix.python }} path: ${{ env.WHEELS_OUTPUT_FOLDER }}mkl_service-*.whl build_windows: @@ -90,7 +98,15 @@ jobs: strategy: matrix: - python: ['3.10', '3.11', '3.12', '3.13', '3.14'] + python: ['3.10', '3.11', '3.12', '3.13'] + python_spec: [''] + include: + - python: '3.14' + python_spec: '3.14.* *_cp314' + python_tag: '3.14' + - python: '3.14' + python_spec: '3.14.* *_cp314t' + python_tag: '3.14t' steps: - name: Cancel Previous Runs @@ -115,9 +131,9 @@ jobs: with: path: /home/runner/conda_pkgs_dir key: - ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}-${{hashFiles('**/meta.yaml') }} + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python_tag || matrix.python }}-${{hashFiles('**/meta.yaml') }} restore-keys: | - ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}- + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python_tag || matrix.python }}- ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}- - name: Store conda paths as envs @@ -132,18 +148,18 @@ jobs: conda list -n base - name: Build conda package - run: conda build --no-test --python ${{ matrix.python }} -c https://software.repos.intel.com/python/conda -c conda-forge -c conda-forge/label/python_rc --override-channels conda-recipe + run: conda build --no-test --python "${{ matrix.python_spec || matrix.python }}" -c https://software.repos.intel.com/python/conda -c conda-forge -c conda-forge/label/python_rc --override-channels conda-recipe - name: Upload artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python }} + name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python_tag || matrix.python }} path: ${{ env.CONDA_BLD }}${{ env.PACKAGE_NAME }}-*.conda - name: Upload wheels artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Wheels Python ${{ matrix.python }} + name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Wheels Python ${{ matrix.python_tag || matrix.python }} path: ${{ env.WHEELS_OUTPUT_FOLDER }}mkl_service-*.whl test_linux: @@ -152,9 +168,21 @@ jobs: strategy: matrix: - python: ['3.10', '3.11', '3.12', '3.13', '3.14'] + python: ['3.10', '3.11', '3.12', '3.13'] + python_spec: [''] experimental: [false] runner: [ubuntu-latest] + include: + - python: '3.14' + python_spec: '3.14.* *_cp314' + python_tag: '3.14' + experimental: false + runner: ubuntu-latest + - python: '3.14' + python_spec: '3.14.* *_cp314t' + python_tag: '3.14t' + experimental: false + runner: ubuntu-latest continue-on-error: ${{ matrix.experimental }} env: CHANNELS: -c conda-forge -c conda-forge/label/python_rc -c https://software.repos.intel.com/python/conda --override-channels @@ -163,7 +191,7 @@ jobs: - name: Download artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: - name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python }} + name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python_tag || matrix.python }} - name: Add conda to system path run: echo "$CONDA/bin" >> "$GITHUB_PATH" @@ -187,7 +215,7 @@ jobs: CHANNELS=(-c "$GITHUB_WORKSPACE/channel" -c conda-forge -c conda-forge/label/python_rc -c https://software.repos.intel.com/python/conda --override-channels) PACKAGE_VERSION="$(python -c "${VER_SCRIPT1} ${VER_SCRIPT2}")" export PACKAGE_VERSION - conda create -n "${{ env.TEST_ENV_NAME }}" "$PACKAGE_NAME=$PACKAGE_VERSION" "python=${{ matrix.python }}" "${CHANNELS[@]}" --only-deps --dry-run > lockfile + conda create -n "${{ env.TEST_ENV_NAME }}" "$PACKAGE_NAME=$PACKAGE_VERSION" "python ${{ matrix.python_spec || matrix.python }}" "${CHANNELS[@]}" --only-deps --dry-run > lockfile cat lockfile - name: Set pkgs_dirs @@ -201,9 +229,9 @@ jobs: with: path: ~/.conda/pkgs key: - ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}-${{hashFiles('lockfile') }} + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python_tag || matrix.python }}-${{hashFiles('lockfile') }} restore-keys: | - ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}- + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python_tag || matrix.python }}- ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}- - name: Install mkl-service @@ -212,7 +240,7 @@ jobs: CHANNELS=(-c "$GITHUB_WORKSPACE/channel" -c conda-forge -c conda-forge/label/python_rc -c https://software.repos.intel.com/python/conda --override-channels) PACKAGE_VERSION="$(python -c "${VER_SCRIPT1} ${VER_SCRIPT2}")" export PACKAGE_VERSION - conda create -n "${{ env.TEST_ENV_NAME }}" "$PACKAGE_NAME=$PACKAGE_VERSION" pytest "python=${{ matrix.python }}" "${CHANNELS[@]}" + conda create -n "${{ env.TEST_ENV_NAME }}" "$PACKAGE_NAME=$PACKAGE_VERSION" pytest "python ${{ matrix.python_spec || matrix.python }}" "${CHANNELS[@]}" # Test installed packages conda list @@ -228,9 +256,21 @@ jobs: strategy: matrix: - python: ['3.10', '3.11', '3.12', '3.13', '3.14'] + python: ['3.10', '3.11', '3.12', '3.13'] + python_spec: [''] experimental: [false] runner: [windows-latest] + include: + - python: '3.14' + python_spec: '3.14.* *_cp314' + python_tag: '3.14' + experimental: false + runner: windows-latest + - python: '3.14' + python_spec: '3.14.* *_cp314t' + python_tag: '3.14t' + experimental: false + runner: windows-latest continue-on-error: ${{ matrix.experimental }} env: CHANNELS: -c conda-forge -c conda-forge/label/python_rc -c https://software.repos.intel.com/python/conda --override-channels @@ -239,7 +279,7 @@ jobs: - name: Download artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: - name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python }} + name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python_tag || matrix.python }} - uses: conda-incubator/setup-miniconda@8ee1f361103df19b6f8c8655fd3967a8ecb162d5 # v4.0.1 with: miniforge-version: latest @@ -269,7 +309,7 @@ jobs: FOR /F "tokens=* USEBACKQ" %%F IN (`python -c "%SCRIPT%"`) DO ( SET PACKAGE_VERSION=%%F ) - conda install -n ${{ env.TEST_ENV_NAME }} ${{ env.PACKAGE_NAME }}=%PACKAGE_VERSION% python=${{ matrix.python }} -c ${{ env.GITHUB_WORKSPACE }}/channel ${{ env.CHANNELS }} --only-deps --dry-run > lockfile + conda install -n ${{ env.TEST_ENV_NAME }} ${{ env.PACKAGE_NAME }}=%PACKAGE_VERSION% "python ${{ matrix.python_spec || matrix.python }}" -c ${{ env.GITHUB_WORKSPACE }}/channel ${{ env.CHANNELS }} --only-deps --dry-run > lockfile more lockfile - name: Cache conda packages @@ -279,9 +319,9 @@ jobs: with: path: /home/runner/conda_pkgs_dir key: - ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}-${{hashFiles('lockfile') }} + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python_tag || matrix.python }}-${{hashFiles('lockfile') }} restore-keys: | - ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}- + ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python_tag || matrix.python }}- ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}- # add intel-openmp as an explicit dependency @@ -296,7 +336,7 @@ jobs: SET PACKAGE_VERSION=%%F ) SET "WORKAROUND_DEPENDENCIES=intel-openmp" - conda create -n ${{ env.TEST_ENV_NAME }} ${{ env.PACKAGE_NAME }}=%PACKAGE_VERSION% %WORKAROUND_DEPENDENCIES% pytest python=${{ matrix.python }} -c ${{ env.GITHUB_WORKSPACE }}/channel ${{ env.CHANNELS }} + conda create -n ${{ env.TEST_ENV_NAME }} ${{ env.PACKAGE_NAME }}=%PACKAGE_VERSION% %WORKAROUND_DEPENDENCIES% pytest "python ${{ matrix.python_spec || matrix.python }}" -c ${{ env.GITHUB_WORKSPACE }}/channel ${{ env.CHANNELS }} # Test installed packages conda list diff --git a/AGENTS.md b/AGENTS.md index 67ee6b0..55f57d7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -26,18 +26,18 @@ Originally part of Intel® Distribution for Python*, now a standalone package av - meson-python - CMake - Ninja -- Cython +- Cython 3.1+ (required for the `freethreading_compatible` directive) - Python 3.10+ **Build against an existing `mkl` installation:** Install the build dependencies via Conda: ```bash -conda install -c conda-forge mkl-devel cython meson-python cmake ninja +conda install -c conda-forge mkl-devel "cython>=3.1.0" meson-python cmake ninja ``` or via pip: ```bash -python -m pip install mkl-devel cython meson-python cmake ninja +python -m pip install mkl-devel "cython>=3.1.0" meson-python cmake ninja ``` then build without pulling a fresh `mkl` into an isolated build: ```bash @@ -45,8 +45,9 @@ python -m pip install --no-deps --no-build-isolation . ``` ## CI/CD -- **Platforms in CI workflows:** Linux, Windows -- **Python versions:** 3.10, 3.11, 3.12, 3.13, 3.14 +- **Platforms in CI workflows:** Linux, Windows, macOS (conda-forge workflow only) +- **Python versions:** 3.10, 3.11, 3.12, 3.13, 3.14, and free-threaded 3.14t +- **Python 3.14 ABI selection:** conda jobs must request an explicit ABI, `3.14.* *_cp314` (GIL) or `3.14.* *_cp314t` (free-threaded). Once the recipes stopped constraining `python-gil`, a bare `--python 3.14` was observed to resolve to the free-threaded build, so it must not be relied on. - **Workflows:** `.github/workflows/` - `conda-package.yml` — main conda build/test pipeline - `conda-package-cf.yml` — conda build/test using only conda-forge channel diff --git a/CHANGELOG.md b/CHANGELOG.md index 4588616..a4fbbf6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,17 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +### Added +* Added support for free-threaded (GIL-disabled) CPython builds: the Cython extension is compiled with `freethreading_compatible=True` and `_mklinit` declares `Py_MOD_GIL_NOT_USED`, so importing `mkl` no longer re-enables the GIL [gh-213](https://github.com/IntelPython/mkl-service/pull/213) + +### Changed +* Raised the minimum build-time `Cython` requirement to `3.1.0`, the first release providing the `freethreading_compatible` directive [gh-213](https://github.com/IntelPython/mkl-service/pull/213) + +### Removed +* Removed the `python-gil` constraint from the conda recipes, which pinned `mkl-service` to GIL-enabled Python 3.14 builds [gh-213](https://github.com/IntelPython/mkl-service/pull/213) + ## [2.8.0] (07/23/2026) ### Changed diff --git a/README.md b/README.md index 72a4208..52620af 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ If you already have `mkl` installed (from your system or a Conda environment) an want to reuse it instead of pulling a fresh copy into an isolated build, first install the build dependencies: ```sh -python -m pip install mkl-devel meson-python cmake ninja cython +python -m pip install mkl-devel meson-python cmake ninja "cython>=3.1.0" ``` then build against the existing installation with: diff --git a/conda-recipe/meta.yaml b/conda-recipe/meta.yaml index d1755da..3242bb7 100644 --- a/conda-recipe/meta.yaml +++ b/conda-recipe/meta.yaml @@ -22,8 +22,7 @@ requirements: - cmake - ninja - python - - python-build - - python-gil # [py>=314] + - python-build >=1.2.2 - pip >=25.0 - mkl-devel - cython >=3.1.0 diff --git a/mkl/tests/test_mkl_service.py b/mkl/tests/test_mkl_service.py index b84f0fc..985a9f8 100644 --- a/mkl/tests/test_mkl_service.py +++ b/mkl/tests/test_mkl_service.py @@ -25,6 +25,9 @@ # pylint: disable=no-member +import sys +import sysconfig + import pytest import mkl @@ -199,6 +202,14 @@ def test_set_memory_limit(): mkl.set_memory_limit(2**16) +@pytest.mark.skipif( + not sysconfig.get_config_var("Py_GIL_DISABLED"), + reason="requires a free-threaded (GIL-disabled) Python build", +) +def test_import_does_not_reenable_gil(): + assert sys._is_gil_enabled() is False + + def check_cbwr(branch, cnr_const): status = mkl.cbwr_set(branch=branch) if status == "success": diff --git a/pyproject.toml b/pyproject.toml index 884c499..cfbbf33 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,6 +47,7 @@ classifiers = [ "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", + "Programming Language :: Python :: Free Threading :: 2 - Beta", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Software Development", "Topic :: Utilities",