diff --git a/.github/workflows/conda-package-cf.yml b/.github/workflows/conda-package-cf.yml
new file mode 100644
index 00000000000..a21c66f5172
--- /dev/null
+++ b/.github/workflows/conda-package-cf.yml
@@ -0,0 +1,462 @@
+name: Conda package (conda-forge)
+
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+
+permissions: read-all
+
+env:
+ package-name: dpnp
+ recipe-dir: conda-recipe-cf
+ channels-list: '-c conda-forge --override-channels'
+ ver-script-part1: "import json; f = open('version.json', 'r'); j = json.load(f); f.close(); "
+ ver-script-part2: "d = j['dpnp'][0]; print('='.join((d[s] for s in ('version', 'build'))))"
+ fetch-depth: 1
+ python-ver-test-all-dtypes: '3.14'
+ test-env-name: 'test'
+ rerun-tests-on-failure: 'true'
+ rerun-tests-max-attempts: 2
+ rerun-tests-timeout: 45
+
+jobs:
+ build:
+ name: Build
+
+ strategy:
+ fail-fast: false
+ matrix:
+ python: ['3.10', '3.11', '3.12', '3.13']
+ os: [ubuntu-22.04, windows-2022]
+ include:
+ - python: '3.14'
+ os: ubuntu-22.04
+ python_spec: '3.14.* *_cp314'
+ - python: '3.14'
+ os: windows-2022
+ python_spec: '3.14.* *_cp314'
+ # TODO: add free-threaded builds ('3.14.* *_cp314t') once a
+ # free-threaded dpctl is available on conda-forge
+
+ permissions:
+ # Needed to cancel any previous runs that are not completed for a given workflow
+ actions: write
+
+ runs-on: ${{ matrix.os }}
+ timeout-minutes: 90
+
+ defaults:
+ run:
+ shell: ${{ matrix.os == 'windows-2022' && 'cmd /C CALL {0}' || 'bash -el {0}' }}
+
+ env:
+ build-conda-pkg-env: 'environments/build_conda_pkg.yml'
+ build-env-name: 'build'
+ python-label: ${{ endsWith(matrix.python_spec, 't') && format('{0}t', matrix.python) || matrix.python }}
+ python-conda-spec: ${{ matrix.python_spec || matrix.python }}
+
+ steps:
+ - name: Cancel Previous Runs
+ uses: styfle/cancel-workflow-action@d07a454dad7609a92316b57b23c9ccfd4f59af66 # 0.13.1
+ with:
+ access_token: ${{ github.token }}
+
+ - name: Checkout DPNP repo
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ with:
+ fetch-depth: 0
+
+ - name: Setup miniconda
+ id: setup_miniconda
+ continue-on-error: true
+ uses: conda-incubator/setup-miniconda@8ee1f361103df19b6f8c8655fd3967a8ecb162d5 # v4.0.1
+ with:
+ miniforge-version: latest
+ use-mamba: 'true'
+ conda-remove-defaults: 'true'
+ environment-file: ${{ env.build-conda-pkg-env }}
+ activate-environment: ${{ env.build-env-name }}
+
+ - name: ReSetup miniconda
+ if: steps.setup_miniconda.outcome == 'failure'
+ uses: conda-incubator/setup-miniconda@8ee1f361103df19b6f8c8655fd3967a8ecb162d5 # v4.0.1
+ with:
+ miniforge-version: latest
+ use-mamba: 'true'
+ conda-remove-defaults: 'true'
+ environment-file: ${{ env.build-conda-pkg-env }}
+ activate-environment: ${{ env.build-env-name }}
+
+ - name: List installed packages
+ run: mamba list
+
+ - name: Store conda paths as envs
+ shell: bash -el {0}
+ run: |
+ echo "CONDA_BLD=$CONDA_PREFIX/conda-bld/${{ runner.os == 'Linux' && 'linux' || 'win' }}-64/" | tr "\\\\" '/' >> "$GITHUB_ENV"
+
+ - name: Build conda package
+ id: build_conda_pkg
+ continue-on-error: true
+ run: conda-build --no-test --python "${{ env.python-conda-spec }}" --numpy 2.0 ${{ env.channels-list }} ${{ env.recipe-dir }}
+
+ - name: ReBuild conda package
+ if: steps.build_conda_pkg.outcome == 'failure'
+ run: conda-build --no-test --python "${{ env.python-conda-spec }}" --numpy 2.0 ${{ env.channels-list }} ${{ env.recipe-dir }}
+
+ - name: Upload artifact
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
+ with:
+ name: ${{ env.package-name }} ${{ runner.os }} Python ${{ env.python-label }}
+ path: ${{ env.CONDA_BLD }}${{ env.package-name }}-*.conda
+
+ test_linux:
+ name: Test
+
+ needs: build
+
+ runs-on: ${{ matrix.os }}
+ timeout-minutes: 100
+
+ defaults:
+ run:
+ shell: bash -el {0}
+
+ strategy:
+ fail-fast: false
+ matrix:
+ python: ['3.10', '3.11', '3.12', '3.13']
+ os: [ubuntu-latest]
+ include:
+ - python: '3.14'
+ os: ubuntu-latest
+ python_spec: '3.14.* *_cp314'
+ # TODO: add free-threaded builds ('3.14.* *_cp314t') once a
+ # free-threaded dpctl is available on conda-forge
+
+ env:
+ dpnp-repo-path: '${{ github.workspace }}/source/'
+ create-conda-channel-env: 'source/environments/create_conda_channel.yml'
+ channel-path: '${{ github.workspace }}/channel/'
+ pkg-path-in-channel: '${{ github.workspace }}/channel/linux-64/'
+ ver-json-path: '${{ github.workspace }}/version.json'
+ python-label: ${{ endsWith(matrix.python_spec, 't') && format('{0}t', matrix.python) || matrix.python }}
+ python-install-spec: "python ${{ matrix.python_spec || format('{0}.*', matrix.python) }}"
+
+ steps:
+ - name: Set Swap Space
+ uses: pierotofy/set-swap-space@49819abfb41bd9b44fb781159c033dba90353a7c # v1.0
+ with:
+ swap-size-gb: 8
+
+ - name: Checkout DPNP repo
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ with:
+ fetch-depth: ${{ env.fetch-depth }}
+ path: ${{ env.dpnp-repo-path }}
+
+ - name: Download artifact
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
+ with:
+ name: ${{ env.package-name }} ${{ runner.os }} Python ${{ env.python-label }}
+ path: ${{ env.pkg-path-in-channel }}
+
+ - name: Setup miniconda
+ id: setup_miniconda
+ continue-on-error: true
+ uses: conda-incubator/setup-miniconda@8ee1f361103df19b6f8c8655fd3967a8ecb162d5 # v4.0.1
+ with:
+ miniforge-version: latest
+ use-mamba: 'true'
+ conda-remove-defaults: 'true'
+ environment-file: ${{ env.create-conda-channel-env }}
+ activate-environment: ${{ env.test-env-name }}
+
+ - name: ReSetup miniconda
+ if: steps.setup_miniconda.outcome == 'failure'
+ uses: conda-incubator/setup-miniconda@8ee1f361103df19b6f8c8655fd3967a8ecb162d5 # v4.0.1
+ with:
+ miniforge-version: latest
+ use-mamba: 'true'
+ conda-remove-defaults: 'true'
+ environment-file: ${{ env.create-conda-channel-env }}
+ activate-environment: ${{ env.test-env-name }}
+
+ - name: Create conda channel
+ run: |
+ python -m conda_index ${{ env.channel-path }}
+
+ - name: Test conda channel
+ run: |
+ conda search ${{ env.package-name }} -c ${{ env.channel-path }} --override-channels --info --json > ${{ env.ver-json-path }}
+ cat ${{ env.ver-json-path }}
+
+ - name: Get package version
+ run: |
+ PACKAGE_VERSION=$(python -c "${{ env.ver-script-part1 }} ${{ env.ver-script-part2 }}")
+ export PACKAGE_VERSION
+
+ echo "PACKAGE_VERSION=${PACKAGE_VERSION}"
+ echo "PACKAGE_VERSION=$PACKAGE_VERSION" >> "$GITHUB_ENV"
+
+ - name: Install dpnp
+ id: install_dpnp
+ continue-on-error: true
+ run: |
+ mamba install ${{ env.package-name }}=${{ env.PACKAGE_VERSION }} pytest pytest-xdist "${{ env.python-install-spec }}" ${{ env.TEST_CHANNELS }}
+ env:
+ TEST_CHANNELS: '-c ${{ env.channel-path }} ${{ env.channels-list }}'
+
+ - name: ReInstall dpnp
+ if: steps.install_dpnp.outcome == 'failure'
+ run: |
+ mamba install ${{ env.package-name }}=${{ env.PACKAGE_VERSION }} pytest pytest-xdist "${{ env.python-install-spec }}" ${{ env.TEST_CHANNELS }}
+ env:
+ TEST_CHANNELS: '-c ${{ env.channel-path }} ${{ env.channels-list }}'
+
+ - name: List installed packages
+ run: mamba list
+
+ - name: Smoke test
+ run: |
+ python -c "import dpctl; dpctl.lsplatform()"
+ python -c "import dpnp; print(dpnp.__version__)"
+
+ - name: Run tests
+ if: env.rerun-tests-on-failure != 'true'
+ run: |
+ export SKIP_TENSOR_TESTS=1
+ if [[ "${{ env.python-label }}" == "${{ env.python-ver-test-all-dtypes }}" ]]; then
+ export DPNP_TEST_ALL_INT_TYPES=1
+ python -m pytest -ra --pyargs ${{ env.package-name }}.tests
+ else
+ python -m pytest -n auto -ra --pyargs ${{ env.package-name }}.tests
+ fi
+
+ - name: Run tests
+ if: env.rerun-tests-on-failure == 'true'
+ id: run_tests_linux
+ uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0
+ with:
+ timeout_minutes: ${{ env.rerun-tests-timeout }}
+ max_attempts: ${{ env.rerun-tests-max-attempts }}
+ retry_on: any
+ command: |
+ . $CONDA/etc/profile.d/conda.sh
+ . $CONDA/etc/profile.d/mamba.sh
+ mamba activate ${{ env.test-env-name }}
+ export SKIP_TENSOR_TESTS=1
+
+ if [[ "${{ env.python-label }}" == "${{ env.python-ver-test-all-dtypes }}" ]]; then
+ export DPNP_TEST_ALL_INT_TYPES=1
+ python -m pytest -ra --pyargs ${{ env.package-name }}.tests
+ else
+ python -m pytest -n auto -ra --pyargs ${{ env.package-name }}.tests
+ fi
+
+ - name: Run tensor tests
+ if: env.rerun-tests-on-failure != 'true'
+ run: |
+ python -m pytest -n auto -ra --pyargs dpnp.tests.tensor
+
+ - name: Run tensor tests
+ if: env.rerun-tests-on-failure == 'true'
+ id: run_tests_tensor_linux
+ uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0
+ with:
+ timeout_minutes: ${{ env.rerun-tests-timeout }}
+ max_attempts: ${{ env.rerun-tests-max-attempts }}
+ retry_on: any
+ command: |
+ . $CONDA/etc/profile.d/conda.sh
+ . $CONDA/etc/profile.d/mamba.sh
+ mamba activate ${{ env.test-env-name }}
+
+ python -m pytest -n auto -ra --pyargs dpnp.tests.tensor
+
+ test_windows:
+ name: Test
+
+ needs: build
+
+ runs-on: ${{ matrix.os }}
+ timeout-minutes: 120
+
+ defaults:
+ run:
+ shell: cmd /C CALL {0}
+
+ strategy:
+ fail-fast: false
+ matrix:
+ python: ['3.10', '3.11', '3.12', '3.13']
+ os: [windows-2022]
+ include:
+ - python: '3.14'
+ os: windows-2022
+ python_spec: '3.14.* *_cp314'
+ # TODO: add free-threaded builds ('3.14.* *_cp314t') once a
+ # free-threaded dpctl is available on conda-forge
+
+ env:
+ dpnp-repo-path: '${{ github.workspace }}\source'
+ create-conda-channel-env: 'source\environments\create_conda_channel.yml'
+ channel-path: '${{ github.workspace }}\channel\'
+ pkg-path-in-channel: '${{ github.workspace }}\channel\win-64\'
+ ver-json-path: '${{ github.workspace }}\version.json'
+ python-label: ${{ endsWith(matrix.python_spec, 't') && format('{0}t', matrix.python) || matrix.python }}
+ python-install-spec: "python ${{ matrix.python_spec || format('{0}.*', matrix.python) }}"
+
+ steps:
+ - name: Checkout DPNP repo
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+ with:
+ fetch-depth: ${{ env.fetch-depth }}
+ path: ${{ env.dpnp-repo-path }}
+
+ - name: Download artifact
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
+ with:
+ name: ${{ env.package-name }} ${{ runner.os }} Python ${{ env.python-label }}
+ path: ${{ env.pkg-path-in-channel }}
+
+ - name: Store a path to package archive
+ run: |
+ @echo on
+
+ set SEARCH_SCRIPT="DIR ${{ env.pkg-path-in-channel }} /s/b | FINDSTR /r "dpnp-.*\.conda""
+ FOR /F "tokens=* USEBACKQ" %%F IN (`%SEARCH_SCRIPT%`) DO (
+ SET FULL_PACKAGE_PATH=%%F
+ )
+ echo FULL_PACKAGE_PATH: %FULL_PACKAGE_PATH%
+ (echo FULL_PACKAGE_PATH=%FULL_PACKAGE_PATH%) >> %GITHUB_ENV%
+
+ - name: Setup miniconda
+ id: setup_miniconda
+ continue-on-error: true
+ uses: conda-incubator/setup-miniconda@8ee1f361103df19b6f8c8655fd3967a8ecb162d5 # v4.0.1
+ with:
+ miniforge-version: latest
+ use-mamba: 'true'
+ conda-remove-defaults: 'true'
+ environment-file: ${{ env.create-conda-channel-env }}
+ activate-environment: ${{ env.test-env-name }}
+
+ - name: ReSetup miniconda
+ if: steps.setup_miniconda.outcome == 'failure'
+ uses: conda-incubator/setup-miniconda@8ee1f361103df19b6f8c8655fd3967a8ecb162d5 # v4.0.1
+ with:
+ miniforge-version: latest
+ use-mamba: 'true'
+ conda-remove-defaults: 'true'
+ environment-file: ${{ env.create-conda-channel-env }}
+ activate-environment: ${{ env.test-env-name }}
+
+ - name: Store conda paths as envs
+ run: |
+ @echo on
+ (echo CONDA_LIB_PATH=%CONDA_PREFIX%\Library\lib\) >> %GITHUB_ENV%
+ (echo CONDA_LIB_BIN_PATH=%CONDA_PREFIX%\Library\bin\) >> %GITHUB_ENV%
+
+ - name: Create conda channel
+ run: |
+ @echo on
+ python -m conda_index ${{ env.channel-path }}
+
+ - name: Test conda channel
+ run: |
+ @echo on
+ conda search ${{ env.package-name }} -c ${{ env.channel-path }} --override-channels --info --json > ${{ env.ver-json-path }}
+
+ - name: Dump version.json
+ run: more ${{ env.ver-json-path }}
+
+ - name: Get package version
+ run: |
+ @echo on
+ set "SCRIPT=${{ env.ver-script-part1 }} ${{ env.ver-script-part2 }}"
+ FOR /F "tokens=* USEBACKQ" %%F IN (`python -c "%SCRIPT%"`) DO (
+ set PACKAGE_VERSION=%%F
+ )
+ echo PACKAGE_VERSION: %PACKAGE_VERSION%
+ (echo PACKAGE_VERSION=%PACKAGE_VERSION%) >> %GITHUB_ENV%
+
+ - name: Install dpnp
+ run: |
+ @echo on
+ mamba install ${{ env.package-name }}=${{ env.PACKAGE_VERSION }} pytest pytest-xdist "${{ env.python-install-spec }}" ${{ env.TEST_CHANNELS }}
+ env:
+ TEST_CHANNELS: '-c ${{ env.channel-path }} ${{ env.channels-list }}'
+ MAMBA_NO_LOW_SPEED_LIMIT: 1
+
+ - name: List installed packages
+ run: mamba list
+
+ - name: Register the OpenCL CPU driver with the ICD loader
+ shell: pwsh
+ run: |
+ # conda-forge intel-opencl-rt does not ship a registration helper,
+ # so register the OpenCL CPU driver (intelocl64.dll) with the ICD loader manually
+ $vendors = "HKLM:\SOFTWARE\Khronos\OpenCL\Vendors"
+ $drivers = @(Get-ChildItem -Recurse -ErrorAction SilentlyContinue -Filter intelocl64.dll -Path "$env:CONDA_PREFIX\Library\bin")
+ if ($drivers.Count -eq 0) { throw "No OpenCL CPU driver (intelocl64.dll) found under $env:CONDA_PREFIX" }
+ if (-not (Test-Path $vendors)) { New-Item -Path $vendors -Force | Out-Null }
+ foreach ($driver in $drivers) {
+ New-ItemProperty -Path $vendors -Name $driver.FullName -Value 0 -PropertyType DWord -Force | Out-Null
+ }
+ Get-ItemProperty -Path $vendors
+
+ - name: Smoke test
+ run: |
+ python -c "import dpctl; dpctl.lsplatform()"
+ python -c "import dpnp; print(dpnp.__version__)"
+
+ - name: Run tests
+ if: env.rerun-tests-on-failure != 'true'
+ shell: pwsh
+ run: |
+ $env:SKIP_TENSOR_TESTS=1
+ if ("${{ env.python-label }}" -eq "${{ env.python-ver-test-all-dtypes }}") {
+ $env:DPNP_TEST_ALL_INT_TYPES=1
+ python -m pytest -ra --pyargs ${{ env.package-name }}.tests
+ } else {
+ python -m pytest -n auto -ra --pyargs ${{ env.package-name }}.tests
+ }
+
+ - name: Run tests
+ if: env.rerun-tests-on-failure == 'true'
+ id: run_tests_win
+ uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0
+ with:
+ timeout_minutes: ${{ env.rerun-tests-timeout }}
+ max_attempts: ${{ env.rerun-tests-max-attempts }}
+ retry_on: any
+ shell: pwsh
+ command: |
+ $env:SKIP_TENSOR_TESTS=1
+ if ( "${{ env.python-label }}" -eq "${{ env.python-ver-test-all-dtypes }}" ) {
+ $env:DPNP_TEST_ALL_INT_TYPES=1
+ python -m pytest -ra --pyargs ${{ env.package-name }}.tests
+ } else {
+ python -m pytest -n auto -ra --pyargs ${{ env.package-name }}.tests
+ }
+
+ - name: Run tensor tests
+ if: env.rerun-tests-on-failure != 'true'
+ shell: pwsh
+ run: |
+ python -m pytest -n auto -ra --pyargs dpnp.tests.tensor
+
+ - name: Run tensor tests
+ if: env.rerun-tests-on-failure == 'true'
+ id: run_tests_tensor_win
+ uses: nick-fields/retry@ad984534de44a9489a53aefd81eb77f87c70dc60 # v4.0.0
+ with:
+ timeout_minutes: ${{ env.rerun-tests-timeout }}
+ max_attempts: ${{ env.rerun-tests-max-attempts }}
+ retry_on: any
+ shell: pwsh
+ command: |
+ python -m pytest -n auto -ra --pyargs dpnp.tests.tensor
diff --git a/conda-recipe-cf/bld.bat b/conda-recipe-cf/bld.bat
new file mode 100644
index 00000000000..23024759aff
--- /dev/null
+++ b/conda-recipe-cf/bld.bat
@@ -0,0 +1,50 @@
+:: conda-forge folds the Intel compiler runtime libs (libircmt.lib, ...) into the
+:: build-only dpcpp_impl package (not visible from the host env), so they live
+:: in the build prefix and are off the linker's default LIB
+set "LIB=%BUILD_PREFIX%\Library\lib;%LIB%"
+
+"%PYTHON%" setup.py clean --all
+
+set "MKLROOT=%PREFIX%/Library"
+set "TBB_ROOT_HINT=%PREFIX%/Library"
+set "DPL_ROOT_HINT=%PREFIX%/Library"
+:: useful for building in resources constrained VMs (public CI)
+set "CMAKE_ARGS=%CMAKE_ARGS% -DCMAKE_INTERPROCEDURAL_OPTIMIZATION:BOOL=FALSE"
+
+:: try to detect SYCL resource/include dir from icpx
+for /f "usebackq delims=" %%R in (`icpx --print-resource-dir 2^>NUL`) do (
+ set "SYCL_RESOURCE_DIR=%%R"
+)
+
+if defined SYCL_RESOURCE_DIR (
+ if exist "%SYCL_RESOURCE_DIR%\include" (
+ set "SYCL_INCLUDE_DIR_HINT=%SYCL_RESOURCE_DIR%"
+ )
+)
+
+
+set "CC=icx"
+set "CXX=icx"
+
+set "CMAKE_GENERATOR=Ninja"
+:: make CMake verbose
+set "VERBOSE=1"
+
+:: set CMAKE to use less threads to avoid OOM
+set CMAKE_BUILD_PARALLEL_LEVEL=%CPU_COUNT%
+
+:: flags mean: --wheel --no-isolation --skip-dependency-check
+%PYTHON% -m build -w -n -x
+if %errorlevel% neq 0 exit 1
+
+:: wheel file was renamed
+for /f %%f in ('dir /b /S .\dist') do (
+ %PYTHON% -m pip install %%f ^
+ --no-build-isolation ^
+ --no-deps ^
+ --only-binary :all: ^
+ --no-index ^
+ --prefix %PREFIX% ^
+ -vv
+ if errorlevel 1 exit 1
+)
diff --git a/conda-recipe-cf/build.sh b/conda-recipe-cf/build.sh
new file mode 100755
index 00000000000..f5c4935f725
--- /dev/null
+++ b/conda-recipe-cf/build.sh
@@ -0,0 +1,49 @@
+#!/bin/bash
+
+# conda-forge folds the Intel compiler runtime libs (libircmt.lib, ...) into the
+# build-only dpcpp_impl package (not visible from the host env), so they live
+# in the build prefix and are off the linker's default LIBRARY_PATH
+export LIBRARY_PATH="$LIBRARY_PATH:${BUILD_PREFIX}/lib"
+
+# Intel LLVM must cooperate with compiler and sysroot from conda
+echo "--gcc-toolchain=${BUILD_PREFIX} --sysroot=${BUILD_PREFIX}/${HOST}/sysroot -target ${HOST}" > icpx_for_conda.cfg
+
+ICPXCFG="$(pwd)/icpx_for_conda.cfg"
+export ICPXCFG
+
+ICXCFG="$(pwd)/icpx_for_conda.cfg"
+export ICXCFG
+
+if [ -e "_skbuild" ]; then
+ ${PYTHON} setup.py clean --all
+fi
+
+export CC=icx
+export CXX=icpx
+
+# conda-forge's gcc/g++ activation injects -fno-merge-constants into CFLAGS/CXXFLAGS
+# when CONDA_BUILD==1, while icx/icpx doesn't support it and emit the warning.
+# See CMPLRLLVM-19167 / CMPLRLLVM-28729 for more context and PR which added the flag:
+# https://github.com/conda-forge/ctng-compiler-activation-feedstock/pull/193
+export CFLAGS="${CFLAGS//-fno-merge-constants/}"
+export CXXFLAGS="${CXXFLAGS//-fno-merge-constants/}"
+
+export CMAKE_GENERATOR=Ninja
+# Make CMake verbose
+export VERBOSE=1
+
+# set CMAKE to use less threads to avoid OOM
+export CMAKE_BUILD_PARALLEL_LEVEL=${CPU_COUNT}
+
+CMAKE_ARGS="${CMAKE_ARGS} -DDPNP_WITH_REDIST:BOOL=ON"
+
+# -wnx flags mean: --wheel --no-isolation --skip-dependency-check
+${PYTHON} -m build -w -n -x
+
+${PYTHON} -m pip install dist/dpnp*.whl \
+ --no-build-isolation \
+ --no-deps \
+ --only-binary :all: \
+ --no-index \
+ --prefix "${PREFIX}" \
+ -vv
diff --git a/conda-recipe-cf/conda_build_config.yaml b/conda-recipe-cf/conda_build_config.yaml
new file mode 100644
index 00000000000..408d05b438a
--- /dev/null
+++ b/conda-recipe-cf/conda_build_config.yaml
@@ -0,0 +1,18 @@
+numpy:
+ - '2'
+c_compiler: # [linux]
+ - gcc # [linux]
+cxx_compiler: # [linux]
+ - gxx # [linux]
+cxx_compiler_version: # [linux]
+ - '15' # [linux]
+c_stdlib: # [linux]
+ - sysroot # [linux]
+c_stdlib_version: # [linux]
+ - '2.28' # [linux]
+c_stdlib: # [win]
+ - vs # [win]
+cxx_compiler: # [win]
+ - vs2022 # [win]
+c_compiler: # [win]
+ - vs2022 # [win]
diff --git a/conda-recipe-cf/meta.yaml b/conda-recipe-cf/meta.yaml
new file mode 100644
index 00000000000..e98144ad7cd
--- /dev/null
+++ b/conda-recipe-cf/meta.yaml
@@ -0,0 +1,98 @@
+{% set required_compiler_and_mkl_version = "2026.0.0" %}
+{% set required_dpctl_version = "0.22.1" %}
+
+{% set pyproject = load_file_data('pyproject.toml') %}
+{% set py_build_deps = pyproject.get('build-system', {}).get('requires', []) %}
+
+package:
+ name: dpnp
+ version: {{ GIT_DESCRIBE_TAG }}
+
+source:
+ path: ..
+
+build:
+ number: {{ GIT_DESCRIBE_NUMBER }}
+ ignore_run_exports:
+ - dpctl
+ - numpy
+ - python
+ # building with Intel DPC++ and do not import the MSVC runtime DLLs
+ - vc14_runtime # [win]
+ - ucrt # [win]
+ missing_dso_whitelist:
+ - '*DPCTLSyclInterface*'
+ - '*/dpnp_backend_c.dll' # [win]
+ skip: true # [osx or py<39]
+
+requirements:
+ build:
+ - {{ compiler('cxx') }}
+ - {{ stdlib('c') }}
+ - {{ compiler('dpcpp') }} >={{ required_compiler_and_mkl_version }}
+ - ninja >=1.11.1 # [linux]
+ - cmake >=3.29.0
+ host:
+ - python
+ - pip >=25.0
+ - pybind11 >=3.0.2
+ - setuptools >=79.0.1
+ - wheel >=0.45.1
+ - python-build >=1.1
+ - scikit-build >=0.18.1
+ - cython >=3.1.0
+ - numpy >=1.26.0
+ - versioneer ==0.29
+ # versioneer dependency
+ - tomli # [py<311]
+ - dpctl >={{ required_dpctl_version }}
+ - mkl-devel-dpcpp >={{ required_compiler_and_mkl_version }}
+ - onedpl-devel
+ - tbb-devel
+ run:
+ - python
+ - {{ pin_compatible('dpctl', min_pin='x.x.x', max_pin=None) }}
+ - {{ pin_compatible('dpcpp-cpp-rt', min_pin='x.x', max_pin='x') }}
+ - {{ pin_compatible('intel-sycl-rt', min_pin='x.x', max_pin='x') }}
+ - {{ pin_compatible('intel-cmplr-lib-rt', min_pin='x.x', max_pin='x') }}
+ - {{ pin_compatible('mkl', min_pin='x.x', max_pin='x') }}
+ - {{ pin_compatible('onemkl-sycl-blas', min_pin='x.x', max_pin='x') }}
+ - {{ pin_compatible('onemkl-sycl-dft', min_pin='x.x', max_pin='x') }}
+ - {{ pin_compatible('onemkl-sycl-lapack', min_pin='x.x', max_pin='x') }}
+ - {{ pin_compatible('onemkl-sycl-rng', min_pin='x.x', max_pin='x') }}
+ - {{ pin_compatible('onemkl-sycl-vm', min_pin='x.x', max_pin='x') }}
+ - numpy
+ - ocl-icd-system # [linux]
+ - khronos-opencl-icd-loader # [win]
+
+test:
+ requires:
+ - pip
+ - pytest
+ - setuptools
+ - scipy # [py<314]
+ commands:
+ - pip check
+ - python -c "import dpnp; print(dpnp.__version__)"
+ - python -m dpctl -f
+
+about:
+ home: https://github.com/IntelPython/dpnp
+ license: BSD-3-Clause
+ license_file: LICENSE.txt
+ summary: 'Data Parallel Extension for NumPy'
+ description: |
+ LEGAL NOTICE: Use of this software package is subject to the
+ software license agreement (as set forth above, in the license section of
+ the installed Conda package and/or the README file) and all notices,
+ disclaimers or license terms for third party or open source software
+ included in or with the software.
+
+ EULA: BSD-3-Clause
+
+
+extra:
+ recipe-maintainers:
+ - antonwolfy
+ - vlad-perevezentsev
+ - ndgrigorian
diff --git a/conda-recipe-cf/run_test.bat b/conda-recipe-cf/run_test.bat
new file mode 100644
index 00000000000..ee2e40b1607
--- /dev/null
+++ b/conda-recipe-cf/run_test.bat
@@ -0,0 +1,16 @@
+@echo on
+
+:: Skip tensor tests by default to avoid OOM in conda builds.
+:: Set SKIP_TENSOR_TESTS=0 to run them on machines with enough memory.
+if not defined SKIP_TENSOR_TESTS (
+ set "SKIP_TENSOR_TESTS=1"
+)
+
+"%PYTHON%" -c "import dpnp; print(dpnp.__version__)"
+if %errorlevel% neq 0 exit 1
+
+"%PYTHON%" -m dpctl -f
+if %errorlevel% neq 0 exit 1
+
+"%PYTHON%" -m pytest -ra --pyargs dpnp
+if %errorlevel% neq 0 exit 1
diff --git a/conda-recipe-cf/run_test.sh b/conda-recipe-cf/run_test.sh
new file mode 100755
index 00000000000..7493ee5ea25
--- /dev/null
+++ b/conda-recipe-cf/run_test.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# Skip tensor tests by default to avoid OOM in conda builds.
+# Set SKIP_TENSOR_TESTS=0 to run them on machines with enough memory.
+if [ -z "${SKIP_TENSOR_TESTS}" ]; then
+ export SKIP_TENSOR_TESTS=1
+fi
+
+set -e
+
+$PYTHON -c "import dpnp; print(dpnp.__version__)"
+$PYTHON -m dpctl -f
+$PYTHON -m pytest -ra --pyargs dpnp
diff --git a/dpnp/tests/tensor/test_tensor_array_api_inspection.py b/dpnp/tests/tensor/test_tensor_array_api_inspection.py
index a04bccaf5db..8608878d932 100644
--- a/dpnp/tests/tensor/test_tensor_array_api_inspection.py
+++ b/dpnp/tests/tensor/test_tensor_array_api_inspection.py
@@ -36,6 +36,7 @@
default_device_index_type,
default_device_int_type,
)
+from dpnp.tests.third_party.cupy.testing import with_requires
_dtypes_no_fp16_fp64 = {
"bool": dpt.bool,
@@ -72,6 +73,7 @@ def test_array_api_inspection_default_device():
assert dpt.__array_namespace_info__().default_device().sycl_device == dev
+@with_requires("dpctl>=0.23.0dev0")
def test_array_api_inspection_devices():
try:
devices2 = dpctl.get_devices()
diff --git a/dpnp/tests/tensor/test_usm_ndarray_dlpack.py b/dpnp/tests/tensor/test_usm_ndarray_dlpack.py
index 7d374199562..f9c3f811a55 100644
--- a/dpnp/tests/tensor/test_usm_ndarray_dlpack.py
+++ b/dpnp/tests/tensor/test_usm_ndarray_dlpack.py
@@ -36,6 +36,7 @@
import dpnp.tensor as dpt
import dpnp.tensor._dlpack as _dlp
import dpnp.tensor._usmarray as dpt_arr
+from dpnp.tests.third_party.cupy.testing import with_requires
from .helper import (
get_queue_or_skip,
@@ -232,6 +233,7 @@ def test_from_dlpack_fortran_contig_array_roundtripping():
assert dpt.all(dpt.equal(ar2d_c, ar2d_r))
+@with_requires("dpctl>=0.23.0dev0")
def test_dlpack_from_subdevice():
"""
This test checks that array allocated on a sub-device,
@@ -584,6 +586,7 @@ def test_from_dlpack_to_kdlcpu_strides(mod, typestr):
assert V.strides == W.strides
+@with_requires("dpctl>=0.23.0dev0")
def test_dlpack_from_subdevice_to_kdlcpu():
"""
Check that array allocated on a sub-device can be
diff --git a/dpnp/tests/test_array_api_info.py b/dpnp/tests/test_array_api_info.py
index 60f81c0eddd..65a272038f4 100644
--- a/dpnp/tests/test_array_api_info.py
+++ b/dpnp/tests/test_array_api_info.py
@@ -9,6 +9,7 @@
is_win_platform,
numpy_version,
)
+from dpnp.tests.third_party.cupy.testing import with_requires
info = dpnp.__array_namespace_info__()
default_device = select_default_device()
@@ -129,6 +130,7 @@ def test_dtypes_invalid_device():
info.dtypes(device="str")
+@with_requires("dpctl>=0.23.0dev0")
def test_devices():
devices = info.devices()
assert isinstance(devices, tuple)