diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 21958a3..85c89c2 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -30,6 +30,51 @@ jobs: name: cibw-sdist path: dist/*.tar.gz + test_sdist: + name: Test SDist with python ${{ matrix.python }} + needs: [make_sdist] + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python: ["3.8", "3.9", "3.10", "3.11"] + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + name: Install Python ${{ matrix.python }} + with: + python-version: ${{ matrix.python }} + + - name: Install dependencies + run: | + pip install pytest pytest-cov + + - uses: actions/download-artifact@v4 + with: + name: cibw-sdist + path: dist + + - name: Install SDist + run: | + pip -V + pip install dist/*.tar.gz + rm -rf dist + + - name: Test installed SDist + run: pytest ./tests + + check_dist: + name: Check dist + needs: [build_wheels, make_sdist, test_sdist] + runs-on: ubuntu-latest + steps: + - uses: actions/download-artifact@v4 + with: + path: all + + - run: pipx run twine check --strict all/*/* + build_wheels: name: Wheel on ${{ matrix.os }} runs-on: ${{ matrix.os }} @@ -37,6 +82,11 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] + arch: ["auto"] + + include: + - os: macos-14 + arch: "arm64" steps: - uses: actions/checkout@v4 @@ -44,6 +94,10 @@ jobs: fetch-depth: 0 - uses: pypa/cibuildwheel@v2.17 + env: + CIBW_BUILD: "cp38-* cp39-* cp310-* cp311-*" + CIBW_ARCHS: "${{ matrix.arch }}" + CIBW_REPAIR_WHEEL_COMMAND: "" - name: Upload wheels uses: actions/upload-artifact@v4 @@ -52,7 +106,7 @@ jobs: path: wheelhouse/*.whl upload_all: - needs: [build_wheels, make_sdist] + needs: [check_dist] environment: pypi permissions: id-token: write @@ -67,7 +121,3 @@ jobs: merge-multiple: true - uses: pypa/gh-action-pypi-publish@release/v1 - with: - # Remember to tell (test-)pypi about this repo before publishing - # Remove this line to publish to PyPI - repository-url: https://test.pypi.org/legacy/ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5a3d7a8..534b1c4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,13 +40,9 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.8", "3.12"] + python-version: ["3.8", "3.9", "3.10", "3.11"] runs-on: [ubuntu-latest, macos-latest, windows-latest] - include: - - python-version: pypy-3.10 - runs-on: ubuntu-latest - steps: - uses: actions/checkout@v4 with: @@ -69,3 +65,34 @@ jobs: uses: codecov/codecov-action@v4.1.0 with: token: ${{ secrets.CODECOV_TOKEN }} + + checks-cibw: + name: > + Check Python ${{ matrix.python-version }} on ${{ matrix.runs-on }} (${{ + matrix.arch }}) + runs-on: ${{ matrix.runs-on }} + needs: [pre-commit] + strategy: + fail-fast: false + matrix: + include: + - runs-on: macos-14 + python-version: cp39 + arch: "arm64" + - runs-on: macos-14 + python-version: cp310 + arch: "arm64" + - runs-on: macos-14 + python-version: cp311 + arch: "arm64" + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: pypa/cibuildwheel@v2.17 + env: + CIBW_BUILD: "${{ matrix.python-version }}-*" + CIBW_ARCHS: "${{ matrix.arch }}" + CIBW_REPAIR_WHEEL_COMMAND: "" diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0f277c4..d2d36c4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -60,6 +60,7 @@ repos: args: [] additional_dependencies: - pytest + - virtualenv - repo: https://github.com/codespell-project/codespell rev: "v2.2.6" diff --git a/CMakeLists.txt b/CMakeLists.txt index 791b1e4..a82ef05 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,62 @@ -cmake_minimum_required(VERSION 3.15...3.26) -project(${SKBUILD_PROJECT_NAME} LANGUAGES CXX) +cmake_minimum_required(VERSION 3.21) -set(PYBIND11_FINDPYTHON ON) -find_package(pybind11 CONFIG REQUIRED) +set(VTK_VERSION "9.2.5") -pybind11_add_module(_core MODULE src/main.cpp) -install(TARGETS _core DESTINATION ${SKBUILD_PROJECT_NAME}) +project( + vtk-sdk + VERSION ${VTK_VERSION} + DESCRIPTION "VTK SDK python distributions" + HOMEPAGE_URL "https://github.com/Kitware/vtk-sdk-python-distributions" + LANGUAGES NONE) + +find_package( + Python + COMPONENTS Interpreter Development.Module + REQUIRED) + +# ---------------------------------------------------------------------------- +# Download and extract vtk-wheel-sdk archive + +include(cmake/download-vtk-sdk.cmake) + +# ---------------------------------------------------------------------------- +# Install content of the vtk-wheel-sdk archive + +set(VTK_SDK_INSTALL_DIR "content") + +# Append "/" after ${extract_dir} to ensure folder content is copied to the +# destination, instead of the folder itself. +install( + DIRECTORY ${extract_dir}/ + DESTINATION vtk_sdk/${VTK_SDK_INSTALL_DIR} + PATTERN "bin/*" EXCLUDE) + +install( + DIRECTORY ${extract_dir}/bin/ + DESTINATION vtk_sdk/${VTK_SDK_INSTALL_DIR}/bin + PATTERN + "*" + PERMISSIONS + OWNER_READ + OWNER_WRITE + OWNER_EXECUTE + GROUP_READ + GROUP_EXECUTE + WORLD_READ + WORLD_EXECUTE) + +# ---------------------------------------------------------------------------- +# Configure and install "cmake.prefix" entry point files + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/vtk-config.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/vtk_sdk/cmake/vtk-config.cmake @ONLY) + +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/vtk-config-version.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/vtk_sdk/cmake/vtk-config-version.cmake @ONLY) + +install( + FILES ${CMAKE_CURRENT_SOURCE_DIR}/src/vtk_sdk/cmake/__init__.py + ${CMAKE_CURRENT_BINARY_DIR}/vtk_sdk/cmake/vtk-config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/vtk_sdk/cmake/vtk-config-version.cmake + DESTINATION vtk_sdk/cmake) diff --git a/README.md b/README.md index bca51b2..5fa6fdd 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ distributed-memory parallel processing for scalability and better performance. This project is intended to distribute the content of the existing VTK wheel SDKs as first-class `vtk-sdk` wheels. -Each `vtk-sdk` Python wheel is equipped with a scikit-build-core `cmake-module` +Each `vtk-sdk` Python wheel is equipped with a scikit-build-core `cmake.prefix` [entrypoint][scikit-build-core-entrypoint], housing the official VTK SDK sourced from the corresponding [archive][wheel-sdks-link]. diff --git a/cmake/download-vtk-sdk.cmake b/cmake/download-vtk-sdk.cmake new file mode 100644 index 0000000..d93e276 --- /dev/null +++ b/cmake/download-vtk-sdk.cmake @@ -0,0 +1,57 @@ +message(STATUS "Setting VTK_SDK_BINARY_URL") + +# Python and ABI tags +set(python_abi_name "cp${Python_VERSION_MAJOR}${Python_VERSION_MINOR}") +set(PYTHON_ABI_TAG "${python_abi_name}-${python_abi_name}") +include(${CMAKE_CURRENT_LIST_DIR}/vtk-sdk-urls.cmake) + +# Platform tag +if(LINUX) + if(Python_SOABI MATCHES "x86_64") + set(plaform_name "linux_x86_64") + elseif(Python_SOABI MATCHES "arm64") + set(plaform_name "linux_arm64") + else() + message(FATAL_ERROR "Unsupported SOABI [${Python_SOABI}]") + endif() +elseif(APPLE) + set(plaform_name "macosx_x86_64") + if(Python_SOABI MATCHES "arm64") + set(plaform_name "macosx_arm64") + endif() +elseif(WIN32) + set(plaform_name "win_x86_64") + if(Python_SOABI MATCHES "arm64") + set(plaform_name "win_arm64") + endif() +else() + message( + FATAL_ERROR + "Failed to set plaform_tag based of Python_SOABI [${Python_SOABI}]") +endif() + +# URL and SHA256 +set(VTK_SDK_BINARY_URL ${${plaform_name}_url}) +message(STATUS "Setting VTK_SDK_BINARY_URL: ${VTK_SDK_BINARY_URL}") + +set(VTK_SDK_EXPECTED_SHA256 ${${plaform_name}_sha256}) +message(STATUS "Setting VTK_SDK_EXPECTED_SHA256: ${VTK_SDK_EXPECTED_SHA256}") + +if(NOT DEFINED VTK_SDK_BINARY_URL OR NOT DEFINED VTK_SDK_EXPECTED_SHA256) + message(FATAL_ERROR "Unsupported platform ${plaform_name}") +endif() + +if(${VTK_SDK_BINARY_URL} STREQUAL "NOTFOUND" OR ${VTK_SDK_EXPECTED_SHA256} STREQUAL "NOTFOUND") + message(FATAL_ERROR "Unsupported platform ${plaform_name}") +endif() + +set(download_dir ${PROJECT_BINARY_DIR}) +set(extract_dir ${PROJECT_BINARY_DIR}/vtk-wheel-sdk) + +include(FetchContent) +FetchContent_Populate( + vtkwheelsdk + URL ${VTK_SDK_BINARY_URL} + URL_HASH SHA256=${VTK_SDK_EXPECTED_SHA256} + DOWNLOAD_DIR ${download_dir} + SOURCE_DIR ${extract_dir}) diff --git a/cmake/vtk-config-version.cmake.in b/cmake/vtk-config-version.cmake.in new file mode 100644 index 0000000..05fd041 --- /dev/null +++ b/cmake/vtk-config-version.cmake.in @@ -0,0 +1 @@ +include(${CMAKE_CURRENT_LIST_DIR}/../@VTK_SDK_INSTALL_DIR@/vtk-@VTK_VERSION@.data/headers/cmake/vtk-config-version.cmake) diff --git a/cmake/vtk-config.cmake.in b/cmake/vtk-config.cmake.in new file mode 100644 index 0000000..d3daf73 --- /dev/null +++ b/cmake/vtk-config.cmake.in @@ -0,0 +1 @@ +include(${CMAKE_CURRENT_LIST_DIR}/../@VTK_SDK_INSTALL_DIR@/vtk-@VTK_VERSION@.data/headers/cmake/vtk-config.cmake) diff --git a/cmake/vtk-sdk-urls.cmake b/cmake/vtk-sdk-urls.cmake new file mode 100644 index 0000000..db348da --- /dev/null +++ b/cmake/vtk-sdk-urls.cmake @@ -0,0 +1,56 @@ + +if(${PYTHON_ABI_TAG} STREQUAL "cp38-cp38") + set(linux_x86_64_url "https://vtk.org/files/wheel-sdks/vtk-wheel-sdk-9.2.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.tar.xz") + set(linux_x86_64_sha256 "f67ab5114eeccda490bd5a7ab8e6921e0b59d51489e7f47eb0ebc7f18e7cbd93") + + set(macosx_x86_64_url "https://vtk.org/files/wheel-sdks/vtk-wheel-sdk-9.2.5-cp38-cp38-macosx_10_10_x86_64.tar.xz") + set(macosx_x86_64_sha256 "a97438851a029fc3e9a630261a101001f5fc2edae45710f1cb0cde2dd2899334") + + set(macosx_arm64_url "NOTFOUND") + set(macosx_arm64_sha256 "NOTFOUND") + + set(win_x86_64_url "https://vtk.org/files/wheel-sdks/vtk-wheel-sdk-9.2.5-cp38-cp38-win_amd64.tar.xz") + set(win_x86_64_sha256 "306360396efa3cffb03ecda75c4df84a89ededf05d0adfda4894d80adf2542ec") +endif() + +if(${PYTHON_ABI_TAG} STREQUAL "cp39-cp39") + set(linux_x86_64_url "https://vtk.org/files/wheel-sdks/vtk-wheel-sdk-9.2.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.tar.xz") + set(linux_x86_64_sha256 "8199f0cff9a43831eadeba0e4d89421c947002c53c030c50edb50312bb0726cd") + + set(macosx_x86_64_url "https://vtk.org/files/wheel-sdks/vtk-wheel-sdk-9.2.5-cp39-cp39-macosx_10_10_x86_64.tar.xz") + set(macosx_x86_64_sha256 "6a63d28a726188194fa7858d33645f43ea9ef21e696b8da91cc0536cf4c9131a") + + set(macosx_arm64_url "https://vtk.org/files/wheel-sdks/vtk-wheel-sdk-9.2.5-cp39-cp39-macosx_11_0_arm64.tar.xz") + set(macosx_arm64_sha256 "3747b3448b1ae0f511a389f82398a1ec5a883189ed01ed35c870ef746096ec6d") + + set(win_x86_64_url "https://vtk.org/files/wheel-sdks/vtk-wheel-sdk-9.2.5-cp39-cp39-win_amd64.tar.xz") + set(win_x86_64_sha256 "befbbea3bfc8584c5dd3b2c04b5ce7273eeb4581a5586adf10cb35b859609026") +endif() + +if(${PYTHON_ABI_TAG} STREQUAL "cp310-cp310") + set(linux_x86_64_url "https://vtk.org/files/wheel-sdks/vtk-wheel-sdk-9.2.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.tar.xz") + set(linux_x86_64_sha256 "79f8a8c6caf9d98aef29426637ea9eb9228682072dfa5b69bb97dc3baa2e93d7") + + set(macosx_x86_64_url "https://vtk.org/files/wheel-sdks/vtk-wheel-sdk-9.2.5-cp310-cp310-macosx_10_10_x86_64.tar.xz") + set(macosx_x86_64_sha256 "a0d37d8f93521753cb3bed8da3548f9f6c1f45cee493070b5dcc3801f62b33e5") + + set(macosx_arm64_url "https://vtk.org/files/wheel-sdks/vtk-wheel-sdk-9.2.5-cp310-cp310-macosx_11_0_arm64.tar.xz") + set(macosx_arm64_sha256 "99120ac6448907865b1feb95be4111992d2d511954d2c381bd5299ec87c6f76c") + + set(win_x86_64_url "https://vtk.org/files/wheel-sdks/vtk-wheel-sdk-9.2.5-cp310-cp310-win_amd64.tar.xz") + set(win_x86_64_sha256 "b85c5d48e6c36082c590276dd34458e5238cea7ae37156b5b30a2ca3e133d2b9") +endif() + +if(${PYTHON_ABI_TAG} STREQUAL "cp311-cp311") + set(linux_x86_64_url "https://vtk.org/files/wheel-sdks/vtk-wheel-sdk-9.2.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.tar.xz") + set(linux_x86_64_sha256 "dcd452e018b3a5a7a0b5dfab8e38af2ddbd0e0e387b1a8488b4516354c4a30fb") + + set(macosx_x86_64_url "https://vtk.org/files/wheel-sdks/vtk-wheel-sdk-9.2.5-cp311-cp311-macosx_10_10_x86_64.tar.xz") + set(macosx_x86_64_sha256 "f0bf60a0c740b9c92bb0f35cadb1f0c38d23b3994bdf24295ac986761dc6e59c") + + set(macosx_arm64_url "https://vtk.org/files/wheel-sdks/vtk-wheel-sdk-9.2.5-cp311-cp311-macosx_11_0_arm64.tar.xz") + set(macosx_arm64_sha256 "d2948347e7c803d8e691b48d58dd057ddb2265baf603eb0d7036a71a538e037d") + + set(win_x86_64_url "https://vtk.org/files/wheel-sdks/vtk-wheel-sdk-9.2.5-cp311-cp311-win_amd64.tar.xz") + set(win_x86_64_sha256 "f70dca96484ba357fad52ce4d998b6480e5717e7e1d0f707f20c494c41d7a00e") +endif() diff --git a/pyproject.toml b/pyproject.toml index 0002726..851b361 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -37,6 +37,7 @@ dependencies = [] test = [ "pytest >=6", "pytest-cov >=3", + "virtualenv", ] dev = [ "pytest >=6", @@ -56,12 +57,15 @@ Homepage = "https://github.com/Kitware/vtk-sdk-python-distributions" Discussions = "https://github.com/Kitware/vtk-sdk-python-distributions/discussions" Changelog = "https://github.com/Kitware/vtk-sdk-python-distributions/releases" +[project.entry-points."cmake.prefix"] +any = "vtk_sdk.cmake" [tool.scikit-build] minimum-version = "0.8.2" build-dir = "build/{wheel_tag}" metadata.version.provider = "scikit_build_core.metadata.setuptools_scm" sdist.include = ["src/vtk_sdk/_version.py"] +wheel.packages = ["src/vtk_sdk"] [tool.setuptools_scm] diff --git a/scripts/update_vtk_sdk_version.py b/scripts/update_vtk_sdk_version.py new file mode 100644 index 0000000..14597a8 --- /dev/null +++ b/scripts/update_vtk_sdk_version.py @@ -0,0 +1,90 @@ +from __future__ import annotations + +import os +import textwrap +import urllib.request + +VTK_VERSION = "9.2.5" +ABI_TAGS = ["cp38-cp38", "cp39-cp39", "cp310-cp310", "cp311-cp311"] +PLATFORMS = { + "macosx_x86_64": "macosx_10_10_x86_64", + "macosx_arm64": "macosx_11_0_arm64", + "linux_x86_64": "manylinux_2_17_x86_64.manylinux2014_x86_64", + "win_x86_64": "win_amd64", +} + + +def download_file(url: str, filename: str): + if not os.path.exists(filename) or os.stat(filename).st_size == 0: + print(f"Requesting download {filename} from {url} ...") + try: + urllib.request.urlretrieve(url, filename) + print("Download finished") + except OSError as exc: + msg = f"Failed to download {url} to {filename}: {exc}" + raise ValueError(msg) + + +def generate_cmake_variables(urls_and_sha256s: dict, abi: str): + template_inputs = {"abi": abi} + + # Get SHA256s and URLs + for var_prefix, urls_and_sha256s_values in urls_and_sha256s.items(): + template_inputs[f"{var_prefix}_url"] = urls_and_sha256s_values[0] + template_inputs[f"{var_prefix}_sha256"] = urls_and_sha256s_values[1] + + return textwrap.dedent(""" + if(${{PYTHON_ABI_TAG}} STREQUAL "{abi}") + set(linux_x86_64_url "{linux_x86_64_url}") + set(linux_x86_64_sha256 "{linux_x86_64_sha256}") + + set(macosx_x86_64_url "{macosx_x86_64_url}") + set(macosx_x86_64_sha256 "{macosx_x86_64_sha256}") + + set(macosx_arm64_url "{macosx_arm64_url}") + set(macosx_arm64_sha256 "{macosx_arm64_sha256}") + + set(win_x86_64_url "{win_x86_64_url}") + set(win_x86_64_sha256 "{win_x86_64_sha256}") + endif() + """).format(**template_inputs) + + +def get_expected_shas() -> dict: + filename = f"vtk-wheel-sdk-{VTK_VERSION}-SHA-256.txt" + url = f"https://vtk.org/files/wheel-sdks/{filename}" + download_file(url, filename) + + shas = {} + with open(filename, "rb") as content: + for line in content.readlines(): + sha256 = line.split()[0].strip().decode() + file = line.split()[1].strip().decode() + shas[file] = sha256 + + return shas + + +def main(): + shas = get_expected_shas() + cmake_code = "" + for abi in ABI_TAGS: + archives = {} + for platform_name, platform_abi in PLATFORMS.items(): + filename = f"vtk-wheel-sdk-{VTK_VERSION}-{abi}-{platform_abi}.tar.xz" + # check availability + if filename not in shas: + archives[platform_name] = ("NOTFOUND", "NOTFOUND") + continue + + url = f"https://vtk.org/files/wheel-sdks/{filename}" + archives[platform_name] = (url, shas[filename]) + + cmake_code += generate_cmake_variables(archives, abi) + + with open(f"{__file__}/../cmake/vtk-sdk-urls.cmake", "wb") as file: + file.write(cmake_code.encode()) + + +if __name__ == "__main__": + main() diff --git a/src/main.cpp b/src/main.cpp deleted file mode 100644 index d570cd0..0000000 --- a/src/main.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include - -int add(int i, int j) { return i + j; } - -namespace py = pybind11; - -PYBIND11_MODULE(_core, m) { - m.doc() = R"pbdoc( - Pybind11 example plugin - ----------------------- - .. currentmodule:: python_example - .. autosummary:: - :toctree: _generate - add - subtract - )pbdoc"; - - m.def("add", &add, R"pbdoc( - Add two numbers - Some other explanation about the add function. - )pbdoc"); - - m.def("subtract", [](int i, int j) { return i - j; }, R"pbdoc( - Subtract two numbers - Some other explanation about the subtract function. - )pbdoc"); -} diff --git a/src/vtk_sdk/__init__.py b/src/vtk_sdk/__init__.py index d081a1d..d7e1c59 100644 --- a/src/vtk_sdk/__init__.py +++ b/src/vtk_sdk/__init__.py @@ -1,7 +1,7 @@ """ Copyright (c) 2024 Jean-Christophe Fillion-Robin. All rights reserved. -vtk-sdk: Distribution of the VTK wheel SDK with a convenient "cmake-module" scikit-build-core entrypoint +vtk-sdk: Distribution of the VTK wheel SDK with a convenient "cmake.prefix" scikit-build-core entrypoint """ from __future__ import annotations diff --git a/src/vtk_sdk/_core.pyi b/src/vtk_sdk/_core.pyi deleted file mode 100644 index 537c611..0000000 --- a/src/vtk_sdk/_core.pyi +++ /dev/null @@ -1,4 +0,0 @@ -from __future__ import annotations - -def add(_x: int, _y: int) -> int: ... -def subtract(_x: int, _y: int) -> int: ... diff --git a/src/vtk_sdk/cmake/__init__.py b/src/vtk_sdk/cmake/__init__.py new file mode 100644 index 0000000..e0de3db --- /dev/null +++ b/src/vtk_sdk/cmake/__init__.py @@ -0,0 +1,3 @@ +"""This module serves as `cmake.prefix` scikit-build-core entrypoint to +lookup the location of the `vtk-config.cmake` and `vtk-config-version.cmake` files. +""" diff --git a/tests/packages/find_package/CMakeLists.txt b/tests/packages/find_package/CMakeLists.txt new file mode 100644 index 0000000..cfff955 --- /dev/null +++ b/tests/packages/find_package/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.15...3.26) + +project(${SKBUILD_PROJECT_NAME} VERSION ${SKBUILD_PROJECT_VERSION}) + +find_package(Python COMPONENTS Interpreter Development.Module) + +set(expected_version "9.2.5") +find_package(VTK ${expected_version} REQUIRED) diff --git a/tests/packages/find_package/pyproject.toml b/tests/packages/find_package/pyproject.toml new file mode 100644 index 0000000..32a838c --- /dev/null +++ b/tests/packages/find_package/pyproject.toml @@ -0,0 +1,12 @@ +[build-system] +requires = ["scikit-build-core", "vtk-sdk"] +build-backend = "scikit_build_core.build" + +[project] +name = "vtk-sdk-test" +version = "1.0.0" +authors = [ + { name = "Alexy Pellegrini", email = "alexy.pellegrini@kitware.com" }, + { name = "Jean-Christophe Fillion-Robin", email = "jchris.fillionr@kitware.com" }, +] +dependencies = [] diff --git a/tests/packages/src/vtk_simple/__init__.py b/tests/packages/src/vtk_simple/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_compiled.py b/tests/test_compiled.py deleted file mode 100644 index d0342ca..0000000 --- a/tests/test_compiled.py +++ /dev/null @@ -1,11 +0,0 @@ -from __future__ import annotations - -import vtk_sdk._core as m - - -def test_add(): - assert m.add(2, 3) == 5 - - -def test_subtract(): - assert m.subtract(7, 5) == 2 diff --git a/tests/test_find_package.py b/tests/test_find_package.py new file mode 100644 index 0000000..6e07334 --- /dev/null +++ b/tests/test_find_package.py @@ -0,0 +1,104 @@ +from __future__ import annotations + +import os +import subprocess +import sys +from pathlib import Path +from typing import Literal, overload + +import pytest +import virtualenv as _virtualenv # type: ignore[import-untyped] + +DIR = Path(__file__).parent.resolve() +BASE = DIR / "packages" / "find_package" + + +class VEnv: + def __init__(self, env_dir: Path, *, wheelhouse: Path | None = None) -> None: + cmd = [str(env_dir), "--no-setuptools", "--no-wheel", "--activators", ""] + result = _virtualenv.cli_run(cmd, setup_logging=False) + self.wheelhouse = wheelhouse + self.executable = Path(result.creator.exe) + self.env_dir = env_dir.resolve() + self.platlib = Path( + self.execute("import sysconfig; print(sysconfig.get_path('platlib'))") + ) + self.purelib = Path( + self.execute("import sysconfig; print(sysconfig.get_path('purelib'))") + ) + + @overload + def run(self, *args: str, capture: Literal[True]) -> str: ... + + @overload + def run(self, *args: str, capture: Literal[False] = ...) -> None: ... + + def run(self, *args: str, capture: bool = False) -> str | None: + __tracebackhide__ = True + env = os.environ.copy() + paths = {str(self.executable.parent)} + env["PATH"] = os.pathsep.join([*paths, env["PATH"]]) + env["VIRTUAL_ENV"] = str(self.env_dir) + env["PIP_DISABLE_PIP_VERSION_CHECK"] = "ON" + if self.wheelhouse is not None: + env["PIP_NO_INDEX"] = "ON" + env["PIP_FIND_LINKS"] = str(self.wheelhouse) + + str_args = [os.fspath(a) for a in args] + + # Windows does not make a python shortcut in venv + if str_args[0] in {"python", "python3"}: + str_args[0] = str(self.executable) + + if capture: + result = subprocess.run( + str_args, + check=False, + capture_output=True, + text=True, + env=env, + ) + if result.returncode != 0: + print(result.stdout, file=sys.stdout) + print(result.stderr, file=sys.stderr) + print("FAILED RUN:", *str_args, file=sys.stderr) + raise SystemExit(result.returncode) + return result.stdout.strip() + + result_bytes = subprocess.run( + str_args, + check=False, + env=env, + ) + if result_bytes.returncode != 0: + print("FAILED RUN:", *str_args, file=sys.stderr) + raise SystemExit(result_bytes.returncode) + return None + + def execute(self, command: str) -> str: + return self.run(str(self.executable), "-c", command, capture=True) + + def module(self, *args: str) -> None: + return self.run(str(self.executable), "-m", *args) + + def install(self, *args: str, isolated: bool = True) -> None: + isolated_flags = "" if isolated else ["--no-build-isolation"] + self.module("pip", "install", *isolated_flags, *args) + + +@pytest.fixture() +def virtualenv(tmp_path: Path) -> VEnv: + path = tmp_path / "venv" + return VEnv(path) + + +ROOT = DIR.parent + + +def test_find_package(virtualenv: VEnv, tmp_path: Path): + virtualenv.run( + "python", "-m", "pip", "wheel", str(ROOT), "--wheel-dir", str(tmp_path) + ) + virtualenv.run( + "python", "-m", "pip", "install", "--find-links", str(tmp_path), str(BASE) + )