diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..ac1f319 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,74 @@ +name: Lint and Test + +on: + pull_request: + paths: + - .github/workflows/ci.yml + - pyproject.toml + - src/** + - tests/** + +defaults: + run: + shell: bash + +jobs: + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: astral-sh/setup-uv@v6 + with: + enable-cache: true + + - name: Install dev dependencies + run: uv sync --group dev + + - name: Run pre-commit hooks + run: uv run pre-commit run --all-files + + get-python-versions: + name: Get Python versions + runs-on: ubuntu-latest + outputs: + python-versions: ${{ steps.versions.outputs.python-versions }} + steps: + - uses: actions/checkout@v4 + + - uses: astral-sh/setup-uv@v6 + + - name: Discover available Python versions + id: versions + run: | + min_ver=$(python3 -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['requires-python'])") + versions=$( + uv python list --all-versions "$min_ver" \ + | grep -oP 'cpython-\K\d+\.\d+(?=\.\d+-)' \ + | sort -uV \ + | python3 -c "import sys, json; print(json.dumps(sys.stdin.read().split()))" + ) + echo "python-versions=$versions" >> $GITHUB_OUTPUT + + test: + name: Test (Python ${{ matrix.python-version }}) + needs: get-python-versions + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: ${{ fromJson(needs.get-python-versions.outputs.python-versions) }} + steps: + - uses: actions/checkout@v4 + + - uses: astral-sh/setup-uv@v6 + with: + enable-cache: true + python-version: ${{ matrix.python-version }} + + - name: Install dev dependencies + run: uv sync --group dev --extra all + + - name: Run tests + run: uv run pytest diff --git a/.github/workflows/pack-pip.yml b/.github/workflows/pack-pip.yml index 0902080..45234b4 100644 --- a/.github/workflows/pack-pip.yml +++ b/.github/workflows/pack-pip.yml @@ -1,5 +1,6 @@ name: pip packaging -on: + +on: workflow_dispatch: inputs: python_repository: @@ -14,7 +15,11 @@ on: - .github/workflows/pack-pip.yml - pyproject.toml - CMakeLists.txt - + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + defaults: run: shell: bash @@ -39,15 +44,21 @@ jobs: - name: Build wheels uses: pypa/cibuildwheel@v3.3.1 - - name: install Python + - name: Set up Python uses: actions/setup-python@v5 - + + - name: Set up UV + uses: astral-sh/setup-uv@v6 + with: + enable-cache: true + - name: Test built wheel run: | - pip install --find-links=wheelhouse khisto - pip install pytest>=8.3 pytest-cov>=6 pytest-xdist>=3.6 pytest-sugar>=1.0 - pytest tests/ - + uv venv .test-env + uv pip install --python .test-env --find-links=wheelhouse "khisto[all]" + VIRTUAL_ENV=.test-env uv sync --group dev --no-install-project + VIRTUAL_ENV=.test-env uv run pytest tests/ --no-cov + - uses: actions/upload-artifact@v6 with: name: pkg-wheel-${{ matrix.os }} @@ -65,7 +76,7 @@ jobs: environment: name: testpypi steps: - - uses: actions/download-artifact@v5 + - uses: actions/download-artifact@v6 with: pattern: pkg-* path: dist @@ -74,9 +85,9 @@ jobs: with: verbose: true repository-url: https://test.pypi.org/legacy/ - + release-pypi: - # Publish only on tag pushes in the KhiopsML repository + # Publish only on tag pushes in the KhiopsML repository name: Publish to PyPI.org if: github.ref_type == 'tag' && github.repository_owner == 'KhiopsML' && inputs.python_repository == 'pypi' needs: [build-wheel] @@ -86,7 +97,7 @@ jobs: environment: name: pypi steps: - - uses: actions/download-artifact@v5 + - uses: actions/download-artifact@v6 with: pattern: pkg-* path: dist diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..c3f506e --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,9 @@ +# Copyright (c) 2025-2026 Orange. All rights reserved. +# This software is distributed under the BSD 3-Clause-clear License, the text of which is available +# at https://spdx.org/licenses/BSD-3-Clause-Clear.html or see the "LICENSE" file for more details. + +"""Root conftest: force a non-interactive matplotlib backend for all tests.""" + +import os + +os.environ.setdefault("MPLBACKEND", "Agg")