From 1f356d962bc701d0c772e5b39ff6d5bf53578386 Mon Sep 17 00:00:00 2001 From: Thierry RAMORASOAVINA Date: Tue, 26 May 2026 10:06:58 +0200 Subject: [PATCH 1/2] Use "khiops-core" and "khiops-driver-*" PyPI packages containing binaries only - these packages become mandatory ("khiops-core") or optional ("khiops-driver-*") dependencies dragged during the installation process - these packages must be installed in the Conda environments used to simulate multiple environs (the Conda packages MUST not be used) - in order to avoid distorting usage statistics the test workflows will always use khiops packages from TestPypi --- .../instructions/ci-workflows.instructions.md | 3 +- .../docker-changes.instructions.md | 42 +++---- .github/workflows/api-docs.yml | 10 ++ .github/workflows/dev-docker.yml | 42 +++---- .github/workflows/pip.yml | 19 ++- .github/workflows/quick-checks.yml | 14 ++- .github/workflows/tests.yml | 57 +++++---- CHANGELOG.md | 4 + khiops/core/internals/filesystems.py | 66 ++++++++++- khiops/core/internals/runner.py | 86 +++++++++----- .../docker/khiopspydev/Dockerfile.debian | 108 ------------------ packaging/docker/khiopspydev/Dockerfile.rocky | 27 +---- ...erfile.ubuntu => Dockerfile.ubuntu-debian} | 31 +---- pyproject.toml | 7 +- ...xtract_dependencies_from_pyproject_toml.py | 33 +++++- tests/test_khiops_integrations.py | 10 -- 16 files changed, 268 insertions(+), 291 deletions(-) delete mode 100644 packaging/docker/khiopspydev/Dockerfile.debian rename packaging/docker/khiopspydev/{Dockerfile.ubuntu => Dockerfile.ubuntu-debian} (68%) diff --git a/.github/instructions/ci-workflows.instructions.md b/.github/instructions/ci-workflows.instructions.md index a49539dc..0b3d0d21 100644 --- a/.github/instructions/ci-workflows.instructions.md +++ b/.github/instructions/ci-workflows.instructions.md @@ -40,8 +40,7 @@ Three job groups: JUnit XML via `unittest-xml-reporting`. - **`check-khiops-integration-on-linux`**: Runs integration tests on multiple Linux containers (ubuntu22.04, rocky8, rocky9, debian13). Validates Khiops - status, runs samples, tests major-version mismatch detection with a - `py3_khiops10_conda` environment, and runs the integration test suite. + status, runs samples and the integration tests suite. - **`check-khiops-integration-on-windows`**: Installs Khiops Desktop via NSIS installer on Windows 2022 with Python 3.12. Runs integration tests and samples outside a Python virtual environment, then installs khiops-python diff --git a/.github/instructions/docker-changes.instructions.md b/.github/instructions/docker-changes.instructions.md index da5625b6..67660953 100644 --- a/.github/instructions/docker-changes.instructions.md +++ b/.github/instructions/docker-changes.instructions.md @@ -17,23 +17,22 @@ by the `dev-docker.yml` workflow. ## Image Variants -There are three Dockerfiles, one per OS family: +There are two Dockerfiles: -| Dockerfile | OS targets | Package manager | Remote file drivers | -|---|---|---|---| -| `Dockerfile.ubuntu` | Ubuntu 22.04 | apt | System-wide `.deb` (GCS, S3, Azure) + fakeS3 | -| `Dockerfile.debian` | Debian 13 | apt | System-wide bookworm `.deb` (GCS, S3, Azure) + fakeS3 | -| `Dockerfile.rocky` | Rocky 8, Rocky 9 | dnf | None | +| Dockerfile | OS targets | Package manager | Remote file drivers | +|----------------------------|------------------|---|---| +| `Dockerfile.ubuntu-debian` | Ubuntu 22.04 or Debian 13 | apt | System-wide `.deb` (GCS, S3, Azure) + fakeS3 | +| `Dockerfile.rocky` | Rocky 8, Rocky 9 | dnf | None | All images are published to `ghcr.io/khiopsml/khiops-python/khiopspydev-`. ### Debian and Ubuntu -`Dockerfile.debian` and `Dockerfile.ubuntu` are nearly identical. They diverge -because Debian 13 remote file driver packages are not available, so Debian -forces the Debian 12 (bookworm) builds for the GCS, S3, and Azure driver `.deb` -packages. Any shared change should be applied to both files. There is an open -TODO to unify them (see the comment at the top of `Dockerfile.debian`). +`Dockerfile.ubuntu-debian` is a unique Dockerfile to build either a Ubuntu or a Debian target image +because there is no difference except for the base image used. + +The only reason why the system-wide native Khiops binary (from a `.deb` package) is still installed in the target image +is to allow the automated integration tests (located in the `tests/test_remote_access.py` test file) run against a `KhiopsDockerRunner`. ### Rocky @@ -52,18 +51,14 @@ All Dockerfiles accept these `ARG` values, supplied by `dev-docker.yml`: | `KHIOPS_REVISION` | Khiops native release tag to install | `11.0.0` | | `SERVER_REVISION` | Git ref for the `khiops-server` image (copied into the final stage) | `main` | | `PYTHON_VERSIONS` | Space-separated Python versions for Conda environments | `3.10 3.11 3.12 3.13 3.14` | -| `KHIOPS_GCS_DRIVER_REVISION` | GCS remote file driver version (Debian/Ubuntu only) | `0.0.16` | -| `KHIOPS_S3_DRIVER_REVISION` | S3 remote file driver version (Debian/Ubuntu only) | `0.0.15` | -| `KHIOPS_AZURE_DRIVER_REVISION` | Azure remote file driver version (Debian/Ubuntu only) | `0.0.6` | ## Multi-Stage Build Structure Each Dockerfile uses a multi-stage build: 1. **`khiopsdev`** — Based on `ghcr.io/khiopsml/khiops/khiopsdev-:latest`. - Installs dev tools (git, pip, pandoc, wget), the Khiops native binary, and - Miniforge for Conda. On Debian/Ubuntu, also installs system-wide remote file - drivers (GCS, S3, Azure `.deb` packages) and `ruby-dev` (needed for fakeS3). + Installs dev tools (git, pip, pandoc, wget, zip, unzip), the Khiops native binary, and + Miniforge for Conda. On Debian/Ubuntu, also installs `ruby-dev` (needed for fakeS3). 2. **`server`** — Pulls the `khiops-server` binary from `ghcr.io/khiopsml/khiops-server:`. 3. **`base`** (final) — Copies the server binary into the `khiopsdev` stage. On @@ -75,10 +70,6 @@ For each Python version in `PYTHON_VERSIONS`, a Conda environment is created: - **`py`** — Bare Python (for pip-based test installs). -A special **`py3_khiops10_conda`** environment is always created with -`khiops-core==10.3.2` to test backward compatibility with Khiops major -version 10. - ## Helper Scripts | Script | Purpose | @@ -100,8 +91,7 @@ version 10. optionally also `latest`. - **Build context**: `./packaging/docker/khiopspydev/`. - **Build args**: Passes `KHIOPS_REVISION`, `KHIOPSDEV_OS`, `SERVER_REVISION`, - `PYTHON_VERSIONS`, `KHIOPS_GCS_DRIVER_REVISION`, `KHIOPS_S3_DRIVER_REVISION`, - and `KHIOPS_AZURE_DRIVER_REVISION`. + `PYTHON_VERSIONS`. - **Important**: The `add-hosts: s3-bucket.localhost:127.0.0.1` input is required because buildx mounts `/etc/hosts` read-only, so the fakeS3 hostname cannot be added inside the Dockerfile. @@ -133,12 +123,6 @@ Builds the Sphinx documentation inside the `khiopspydev-ubuntu22.04` container. in consumer workflows (`tests.yml`, etc.). - **Adding system dependencies**: Install them in the appropriate `RUN` block (apt for Debian/Ubuntu, dnf for Rocky). -- **Remote file drivers**: Version bumps go in the - `DEFAULT_KHIOPS_GCS_DRIVER_REVISION` / `DEFAULT_KHIOPS_S3_DRIVER_REVISION` / - `DEFAULT_KHIOPS_AZURE_DRIVER_REVISION` env vars in `dev-docker.yml`. Note: - there is a known workaround in the Ubuntu and Debian Dockerfiles for a release - tag typo in the Azure driver repository (the download URL hard-codes tag - `0.0.7` regardless of the revision ARG — see the `XXX` comment). - **fakeS3**: Pinned to version `1.2.1` because `>= 1.3` requires a license key. If fakeS3 becomes incompatible, consider alternatives (the Dockerfile comments mention `s3rver` as a candidate). diff --git a/.github/workflows/api-docs.yml b/.github/workflows/api-docs.yml index 3314c31d..8603f171 100644 --- a/.github/workflows/api-docs.yml +++ b/.github/workflows/api-docs.yml @@ -60,6 +60,16 @@ jobs: run: | # Install package itself to install the samples datasets python -m pip install --upgrade pip + # Add homogeneous TOML support (Python >= 3.12 has standard tomllib) + python -m pip install tomli + # First, install all dependencies except khiops-core and khiops-drivers-* + python scripts/extract_dependencies_from_pyproject_toml.py -f "pyproject.toml" --exclude-khiops-family > requires-no-khiops.txt + python -m pip install --user `cat requires-no-khiops.txt` + # khiops-core and khiops-drivers-* must always be installed from TestPyPI in order to avoid distorting usage statistics + python scripts/extract_dependencies_from_pyproject_toml.py -f "pyproject.toml" --khiops-family-only > requires-khiops.txt + python -m pip install --user --index-url https://test.pypi.org/simple `cat requires-khiops.txt` + rm -f requires-khiops.txt requires-no-khiops.txt + # Lastly, install khiops-python python -m pip install --user . kh-download-datasets --force-overwrite --version ${{ inputs.khiops-samples-revision || env.DEFAULT_KHIOPS_SAMPLES_REVISION }} kh-status diff --git a/.github/workflows/dev-docker.yml b/.github/workflows/dev-docker.yml index b5d2f796..010616e2 100644 --- a/.github/workflows/dev-docker.yml +++ b/.github/workflows/dev-docker.yml @@ -5,9 +5,6 @@ env: DEFAULT_IMAGE_INCREMENT: 0 DEFAULT_SERVER_REVISION: main DEFAULT_PYTHON_VERSIONS: 3.10 3.11 3.12 3.13 3.14 - DEFAULT_KHIOPS_GCS_DRIVER_REVISION: 0.0.16 - DEFAULT_KHIOPS_S3_DRIVER_REVISION: 0.0.15 - DEFAULT_KHIOPS_AZURE_DRIVER_REVISION: 0.0.6 # XXX : to modify soon on: pull_request: paths: [packaging/docker/khiopspydev/Dockerfile.*, .github/workflows/dev-docker.yml] @@ -16,7 +13,7 @@ on: khiops-revision: type: string default: 11.0.0 - description: Khiops Revision + description: Khiops Revision (for tests against KhiopsDockerRunner) image-increment: type: number default: 0 @@ -37,18 +34,6 @@ on: type: string default: main description: Khiops Server Revision - khiops-gcs-driver-revision: - type: string - default: 0.0.16 - description: Driver version for Google Cloud Storage remote files - khiops-s3-driver-revision: - type: string - default: 0.0.15 - description: Driver version for AWS-S3 remote files - khiops-azure-driver-revision: - type: string - default: 0.0.6 # XXX : to modify soon - description: Driver version for Azure remote files and blobs concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true @@ -63,16 +48,28 @@ jobs: packages: write # to write in the Github package registry steps: - name: Set input parameters as env or output + shell: bash run: | set -x echo "KHIOPS_REVISION=${{ inputs.khiops-revision || env.DEFAULT_KHIOPS_REVISION }}" >> "$GITHUB_ENV" echo "IMAGE_INCREMENT=${{ inputs.image-increment || env.DEFAULT_IMAGE_INCREMENT }}" >> "$GITHUB_ENV" - echo "KHIOPSDEV_OS_CODENAME=$(echo '${{ matrix.khiopsdev-os }}' | tr -d '0-9.')" >> "$GITHUB_ENV" + KHIOPSDEV_OS_CODENAME=$(echo '${{ matrix.khiopsdev-os }}' | tr -d '0-9.') + echo "KHIOPSDEV_OS_CODENAME=${KHIOPSDEV_OS_CODENAME}" >> "$GITHUB_ENV" + case ${KHIOPSDEV_OS_CODENAME} in + ubuntu | debian) + # same Dockerfile for the whole family + echo "DOCKER_FILE_NAME=Dockerfile.ubuntu-debian" >> "$GITHUB_ENV" + ;; + rocky) + echo "DOCKER_FILE_NAME=Dockerfile.rocky" >> "$GITHUB_ENV" + ;; + *) + echo "::error::Status error: '${KHIOPSDEV_OS_CODENAME}' is an unexpected OS codename." + exit 1 + ;; + esac echo "SERVER_REVISION=${{ inputs.server-revision || env.DEFAULT_SERVER_REVISION }}" >> "$GITHUB_ENV" echo "IMAGE_URL=ghcr.io/khiopsml/khiops-python/khiopspydev-${{ matrix.khiopsdev-os }}" >> "$GITHUB_ENV" - echo "KHIOPS_GCS_DRIVER_REVISION=${{ inputs.khiops-gcs-driver-revision || env.DEFAULT_KHIOPS_GCS_DRIVER_REVISION }}" >> "$GITHUB_ENV" - echo "KHIOPS_S3_DRIVER_REVISION=${{ inputs.khiops-s3-driver-revision || env.DEFAULT_KHIOPS_S3_DRIVER_REVISION }}" >> "$GITHUB_ENV" - echo "KHIOPS_AZURE_DRIVER_REVISION=${{ inputs.khiops-azure-driver-revision || env.DEFAULT_KHIOPS_AZURE_DRIVER_REVISION }}" >> "$GITHUB_ENV" - name: Checkout khiops-python sources uses: actions/checkout@v4 - name: Set up Docker Buildx @@ -103,15 +100,12 @@ jobs: # added using inputs because /etc/hosts is read-only for alternate builders (buildx via moby buildkit) add-hosts: s3-bucket.localhost:127.0.0.1 context: ./packaging/docker/khiopspydev/ - file: ./packaging/docker/khiopspydev/Dockerfile.${{ env.KHIOPSDEV_OS_CODENAME }} + file: ./packaging/docker/khiopspydev/${{ env.DOCKER_FILE_NAME }} build-args: | "KHIOPS_REVISION=${{ env.KHIOPS_REVISION }}" "KHIOPSDEV_OS=${{ matrix.khiopsdev-os }}" "SERVER_REVISION=${{ env.SERVER_REVISION }}" "PYTHON_VERSIONS=${{ inputs.python-versions || env.DEFAULT_PYTHON_VERSIONS }}" - "KHIOPS_GCS_DRIVER_REVISION=${{ env.KHIOPS_GCS_DRIVER_REVISION }}" - "KHIOPS_S3_DRIVER_REVISION=${{ env.KHIOPS_S3_DRIVER_REVISION }}" - "KHIOPS_AZURE_DRIVER_REVISION=${{ env.KHIOPS_AZURE_DRIVER_REVISION }}" tags: ${{ env.DOCKER_IMAGE_TAGS }} # Push only on manual request push: ${{ inputs.push || false }} diff --git a/.github/workflows/pip.yml b/.github/workflows/pip.yml index a76758f6..eaa585b1 100644 --- a/.github/workflows/pip.yml +++ b/.github/workflows/pip.yml @@ -77,6 +77,12 @@ jobs: run: | SAMPLES_REVISION=${{ inputs.samples-revision || env.DEFAULT_SAMPLES_REVISION }} echo "SAMPLES_REVISION=$SAMPLES_REVISION" >> "$GITHUB_ENV" + - name: Checkout sources # Checkout the sources to be able to extract the dependencies list + uses: actions/checkout@v4 + with: + # Get Git tags so that versioneer can function correctly + # See issue https://github.com/actions/checkout/issues/701 + fetch-depth: 0 - name: Checkout Khiops samples uses: actions/checkout@v4 with: @@ -88,12 +94,13 @@ jobs: uses: actions/download-artifact@v4 with: name: pip-package - - name: Install package + - name: Install the package shell: bash run: | # Allow Pip to write to its cache mkdir -p /github/home/.cache/pip chown -R $(whoami) /github/home/.cache/pip + # Install the Khiops Python library # A virtual env is mandatory under debian @@ -102,6 +109,16 @@ jobs: source khiops-debian-venv/bin/activate fi pip install --upgrade pip + # Add homogeneous TOML support (Python >= 3.12 has standard tomllib) + pip install tomli + # First, install all dependencies except khiops-core and khiops-drivers-* + python scripts/extract_dependencies_from_pyproject_toml.py -f "pyproject.toml" --exclude-khiops-family > requires-no-khiops.txt + pip install `cat requires-no-khiops.txt` + # khiops-core and khiops-drivers-* must always be installed from TestPyPI in order to avoid distorting usage statistics + python scripts/extract_dependencies_from_pyproject_toml.py -f "pyproject.toml" --khiops-family-only > requires-khiops.txt + pip install --index-url https://test.pypi.org/simple `cat requires-khiops.txt` + rm -f requires-khiops.txt requires-no-khiops.txt + # Lastly, install khiops-python pip install $(ls khiops*.tar.gz) if [[ "${{ matrix.container }}" == "debian13" ]]; then deactivate diff --git a/.github/workflows/quick-checks.yml b/.github/workflows/quick-checks.yml index 9d3c9485..80b0e3c8 100644 --- a/.github/workflows/quick-checks.yml +++ b/.github/workflows/quick-checks.yml @@ -19,11 +19,15 @@ jobs: - name: Install khiops-python dev dependencies run: | # Extract and install package dependency requirements from metadata - pip install pip-tools - python -m piptools compile -o requirements.txt - - # Install dev dependencies - pip install -r requirements.txt + # Add homogeneous TOML support (Python >= 3.12 has standard tomllib) + pip install tomli + # First, install all dependencies except khiops-core and khiops-drivers-* + python scripts/extract_dependencies_from_pyproject_toml.py -f "pyproject.toml" --exclude-khiops-family > requires-no-khiops.txt + pip install `cat requires-no-khiops.txt` + # khiops-core and khiops-drivers-* must always be installed from TestPyPI in order to avoid distorting usage statistics + python scripts/extract_dependencies_from_pyproject_toml.py -f "pyproject.toml" --khiops-family-only > requires-khiops.txt + pip install --index-url https://test.pypi.org/simple `cat requires-khiops.txt` + rm -f requires-khiops.txt requires-no-khiops.txt # Install black for the samples-generation script pip install black diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index bee58ee6..52a9e848 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -96,9 +96,16 @@ jobs: # Add homogeneous TOML support (Python >= 3.12 has standard tomllib) $CONDA install -y -n "$CONDA_ENV" tomli - $CONDA run --no-capture-output -n "$CONDA_ENV" python scripts/extract_dependencies_from_pyproject_toml.py -f "pyproject.toml" > requires.txt - $CONDA install -y -n "$CONDA_ENV" `cat requires.txt` - rm -f requires.txt + # Conda environments are only used to support multiple Python versions, hence install Pip packages inside + # Install Pip inside the Conda env to use it instead of the system-wide Pip + $CONDA install -y -n "$CONDA_ENV" pip + # First, install all dependencies except khiops-core and khiops-drivers-* + $CONDA run --no-capture-output -n "$CONDA_ENV" python scripts/extract_dependencies_from_pyproject_toml.py -f "pyproject.toml" --exclude-khiops-family > requires-no-khiops.txt + $CONDA run -n "$CONDA_ENV" pip install `cat requires-no-khiops.txt` + # khiops-core and khiops-drivers-* must always be installed from TestPyPI in order to avoid distorting usage statistics + $CONDA run --no-capture-output -n "$CONDA_ENV" python scripts/extract_dependencies_from_pyproject_toml.py -f "pyproject.toml" --khiops-family-only > requires-khiops.txt + $CONDA run -n "$CONDA_ENV" pip install --index-url https://test.pypi.org/simple `cat requires-khiops.txt` + rm -f requires-khiops.txt requires-no-khiops.txt - name: Configure Expensive Tests Setting # Skip expensive tests by default, unless on the `main-v10` or `main` branches if: github.ref != 'main-v10' && github.ref != 'main' && ! inputs.run-expensive-tests @@ -264,11 +271,17 @@ jobs: # Python versioneer fails to compute the current version correctly otherwise git config --global --add safe.directory $(Resolve-Path '.' | % {$_.toString()}) python -m pip install setuptools - python scripts/extract_dependencies_from_pyproject_toml.py -f "pyproject.toml" -s "\n" > requires.txt # Install the Python requirements outside a python venv - Get-Content .\requires.txt ` + # First, install all dependencies except khiops-core and khiops-drivers-* + python scripts/extract_dependencies_from_pyproject_toml.py -f "pyproject.toml" -s "\n" --exclude-khiops-family > requires-no-khiops.txt + Get-Content .\requires-no-khiops.txt ` | ForEach-Object {python -m pip install $_.toString()} + # khiops-core and khiops-drivers-* must always be installed from TestPyPI in order to avoid distorting usage statistics + python scripts/extract_dependencies_from_pyproject_toml.py -f "pyproject.toml" -s "\n" --khiops-family-only > requires-khiops.txt + # the official PyPI index is also needed for transitive dependencies (for example `impi-rt` on Windows) + Get-Content .\requires-khiops.txt ` + | ForEach-Object {python -m pip install --index-url https://test.pypi.org/simple --extra-index-url https://pypi.org/simple $_.toString()} # Create and activate a python venv python -m venv khiops-windows-venv @@ -276,12 +289,16 @@ jobs: # Install the Python requirements inside a venv # The venv python executable is used here - Get-Content .\requires.txt ` - | ForEach-Object {khiops-windows-venv\Scripts\python -m pip install $_.toString()} + # Same Pip indexes prioritization rules as above + Get-Content .\requires-no-khiops.txt ` + | ForEach-Object {python -m pip install $_.toString()} + Get-Content .\requires-khiops.txt ` + | ForEach-Object {python -m pip install --index-url https://test.pypi.org/simple --extra-index-url https://pypi.org/simple $_.toString()} # Deactivate the python venv deactivate - Remove-Item -force requires.txt + Remove-Item -force requires-no-khiops.txt + Remove-Item -force requires-khiops.txt - name: Setup and Install Test Requirements run: python -m pip install -r test-requirements.txt - name: Test Khiops Integration @@ -391,9 +408,13 @@ jobs: # Install tomli for Python < 3.11 pip install tomli - python scripts/extract_dependencies_from_pyproject_toml.py -f "pyproject.toml" > requires.txt - pip install `cat requires.txt` - rm -f requires.txt + # First, install all dependencies except khiops-core and khiops-drivers-* + python scripts/extract_dependencies_from_pyproject_toml.py -f "pyproject.toml" --exclude-khiops-family > requires-no-khiops.txt + pip install `cat requires-no-khiops.txt` + # khiops-core and khiops-drivers-* must always be installed from TestPyPI in order to avoid distorting usage statistics + python scripts/extract_dependencies_from_pyproject_toml.py -f "pyproject.toml" --khiops-family-only > requires-khiops.txt + pip install --index-url https://test.pypi.org/simple `cat requires-khiops.txt` + rm -f requires-khiops.txt requires-no-khiops.txt if [[ "${{ matrix.container }}" == "debian13" ]]; then deactivate fi @@ -447,20 +468,6 @@ jobs: echo "::error::Status error: improper setup, as expected: khiops-python has been cloned, not installed from a package" fi - # Run the library against an incompatible Khiops (with a different major version) - # This instance of Khiops is isolated in a dedicated conda environment - CONDA="/root/miniforge3/bin/conda" - # Check an error is raised because of the major version mismatch - # The khiops-python library from the cloned sources is used here - PATTERN=$($CONDA run -n py3_khiops10_conda python -c "import khiops.core as kh; print(kh.get_runner().khiops_version)" 2> >(grep -Ei 'major version.*?does not match')) - if [ -z "$PATTERN" ]; then - echo "::error::Status error: khiops-python should fail because of the major version mismatch" - if [[ "${{ matrix.container }}" == "debian13" ]]; then - deactivate - fi - exit 1; - fi - # Run the remaining integration tests python -m unittest -v tests.test_khiops_integrations diff --git a/CHANGELOG.md b/CHANGELOG.md index fa18a324..d5bc9efd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,8 +13,12 @@ - (General) Support for Azure storage ### Changed +- (General) Full-Pip installation support: `khiops` now depends on the `khiops-core` and optionally on the remote storage driver packages - (`core`) Rename `variable_part_dimensions` to `inner_variable_dimensions` in Coclustering results. +### Removed +- (General) Support of the installation type combining "OS Native Khiops Core" and "Pip Khiops Python library" + ## 11.0.0.3 - 2026-03-06 ### Added diff --git a/khiops/core/internals/filesystems.py b/khiops/core/internals/filesystems.py index f63d20ab..e338b6dd 100644 --- a/khiops/core/internals/filesystems.py +++ b/khiops/core/internals/filesystems.py @@ -7,6 +7,7 @@ """Classes to interact with local and remote filesystems""" import json import os +import platform import shutil import warnings from abc import ABC, abstractmethod @@ -116,8 +117,8 @@ def _child_uri_info(uri_info, child_name): uri_info : `urllib.parse.ParseResult` URI info structure (output of `urllib.parse.urlparse`) - child_name : str - Name of the new childe node + child_name : `str` + Name of the new child node Returns ------- @@ -127,6 +128,45 @@ def _child_uri_info(uri_info, child_name): return uri_info._replace(path=_child_path(uri_info.path, child_name)) +def _check_khiops_driver_library(remote_storage_type, khiops_drivers_path): + """Ensures the dynamic library for the Khiops driver exists + + Parameters + ---------- + remote_storage_type : `str` + Type of the supported storage type + + khiops_drivers_path : `str` + Absolute path to the folder containing all the drivers libraries. + If a relative path (without the leading '/') is passed, + an absolute path is inferred using the current folder which will probably + cause an error eventually. + + this method raises a `RuntimeError` if the dynamic library is not found + """ + assert type(remote_storage_type) == str and len(remote_storage_type) > 0 + assert remote_storage_type in ("s3", "gcs", "azure") + assert type(khiops_drivers_path) == str and len(khiops_drivers_path) > 0 + + match platform.system(): + case "Windows": + extension = ".dll" + case "Darwin": # MacOS + extension = ".dylib" + case _: # any Linux platform + extension = ".so" + absolute_path = os.path.join( + os.path.abspath(khiops_drivers_path), + f"libkhiopsdriver_file_{remote_storage_type}{extension}", + ) + if not os.path.exists(absolute_path): + raise RuntimeError( + f"Khiops driver for '{remote_storage_type}' " + f"is missing (expected in {absolute_path}). " + "Make sure you installed it." + ) + + ###################### ## Helper Functions ## ###################### @@ -538,6 +578,13 @@ class GoogleCloudStorageResource(FilesystemResource): """ def __init__(self, uri): + + khiops_drivers_path = os.environ.get("KHIOPS_DRIVERS_PATH") + if khiops_drivers_path: + _check_khiops_driver_library( + remote_storage_type="gcs", khiops_drivers_path=khiops_drivers_path + ) + # Stop initialization if google.cloud module is not available if gcs_import_error is not None: warnings.warn( @@ -635,11 +682,18 @@ class AmazonS3Resource(FilesystemResource): """ def __init__(self, uri): + + khiops_drivers_path = os.environ.get("KHIOPS_DRIVERS_PATH") + if khiops_drivers_path: + _check_khiops_driver_library( + remote_storage_type="s3", khiops_drivers_path=khiops_drivers_path + ) + # Stop initialization if boto3 could not be imported if boto3_import_error is not None: warnings.warn( "Could not import boto3 python library, " - "make sure you it installed to access S3 files." + "make sure you installed it to access S3 files." ) raise boto3_import_error @@ -778,6 +832,12 @@ def __init__(self, uri): Azure Storage Resource initializer common to Files and Blobs """ + khiops_drivers_path = os.environ.get("KHIOPS_DRIVERS_PATH") + if khiops_drivers_path: + _check_khiops_driver_library( + remote_storage_type="azure", khiops_drivers_path=khiops_drivers_path + ) + # Stop initialization if Azure modules are not available if azure_import_error is not None: warnings.warn( diff --git a/khiops/core/internals/runner.py b/khiops/core/internals/runner.py index 46f1fb69..4054bdd2 100644 --- a/khiops/core/internals/runner.py +++ b/khiops/core/internals/runner.py @@ -24,7 +24,7 @@ import uuid import warnings from abc import ABC, abstractmethod -from importlib.metadata import PackageNotFoundError, files +from importlib.metadata import PackageNotFoundError, distribution, files from pathlib import Path import khiops @@ -243,11 +243,11 @@ def _infer_khiops_installation_method(trace=False): it was not activated previously nor during the execution and thus the CONDA_PREFIX environment variable is undefined and the path to the `bin` directory inside the conda environment is not in PATH - - 'binary+pip' installs the binaries and the shared libraries system-wide - but will keep the python libraries - in the python system folder - or in the Python folder inside the home directory of the user, - or in a virtual environment (if one is used) + - 'pip' environment containing binaries, shared libraries and the python libraries + can either be : + - system-wide (strongly discouraged) + - or in the Python folder inside the home directory of the user (aka "User site"), + - or in a classical virtual environment (highly encouraged) """ # We are in a Conda environment if @@ -277,10 +277,10 @@ def _infer_khiops_installation_method(trace=False): ): installation_method = "conda-based" else: - installation_method = "binary+pip" + installation_method = "pip" if trace: print(f"Installation method: '{installation_method}'") - assert installation_method in ("conda", "conda-based", "binary+pip") + assert installation_method in ("conda", "conda-based", "pip") return installation_method @@ -953,24 +953,24 @@ def __init__(self): self._initialize_khiops_environment() def _initialize_khiops_environment(self): - # Check the `khiops_env` script - # On Windows native installations, rely on the `KHIOPS_HOME` environment - # variable set by the Khiops Desktop Application installer + # Search for the `khiops_env` script location installation_method = _infer_khiops_installation_method() - if platform.system() == "Windows" and installation_method == "binary+pip": - # KHIOPS_HOME variable by default - if "KHIOPS_HOME" in os.environ: - khiops_env_path = os.path.join( - os.environ["KHIOPS_HOME"], "bin", "khiops_env.cmd" - ) - # Raise error if KHIOPS_HOME is not set + if platform.system() == "Windows" and installation_method == "pip": + sys_executable_direct_parent = Path(sys.executable).parents[0] + probable_khiops_env = os.path.join( + sys_executable_direct_parent, "khiops_env.cmd" + ) + # The script is found in the current environment + if os.path.exists(probable_khiops_env): + khiops_env_path = probable_khiops_env + # Raise error otherwise else: raise KhiopsEnvironmentError( - "No environment variable named 'KHIOPS_HOME' found. " - "Make sure you have installed Khiops >= 10.2.3. " + "No 'khiops_env.cmd' found in the current environment. " + "Make sure you have installed properly the Khiops Python library " + "and Khiops (if this latter was not installed automatically). " "Go to https://khiops.org for more information." ) - # In Conda-based environments, `khiops_env` might not be in the PATH, # hence its path must be inferred elif installation_method == "conda-based": @@ -987,7 +987,8 @@ def _initialize_khiops_environment(self): raise KhiopsEnvironmentError( "The 'khiops_env' script not found for the current " f"'{installation_method}' installation method. Make sure " - "you have installed khiops >= 10.2.3. " + "you have installed properly the Khiops Python library " + "and Khiops (if this latter was not installed automatically). " "Go to https://khiops.org for more information." ) @@ -1029,6 +1030,13 @@ def _initialize_khiops_environment(self): elif var_name == "KHIOPS_MPI_COMMAND": self._mpi_command_args = shlex.split(var_value) os.environ["KHIOPS_MPI_COMMAND"] = var_value + # On Windows "KHIOPS_MPI_DLL_PATH" (containing the Intel MPI Library) + # must be added to "PATH" otherwise Khiops wouldn't find it + # and fail immediately + elif var_name == "KHIOPS_MPI_DLL_PATH": + os.environ["PATH"] = os.pathsep.join( + [var_value, os.environ.get("PATH")] + ) # Propagate all the other environment variables to Khiops binaries else: os.environ[var_name] = var_value @@ -1088,6 +1096,8 @@ def _initialize_khiops_version(self): installation_method = _infer_khiops_installation_method() # Fail immediately if the major versions differ + # It can still occur if the installation method is 'conda' or 'conda-based', + # but never if the installation method is 'pip' (as a dependency is specified) # Note: the installation status will not show at all if self.khiops_version.major != compatible_khiops_version.major: raise KhiopsRuntimeError( @@ -1130,7 +1140,7 @@ def _initialize_khiops_version(self): def _detect_library_installation_incompatibilities(self, library_root_dir_path): """Detects known incompatible installations of this library in the 3 installation modes see `_infer_khiops_installation_method` - (binary+pip, conda, conda-based) + (pip, conda, conda-based) The error_list or warning_list collections are not empty if an issue is detected @@ -1199,7 +1209,7 @@ def _detect_library_installation_incompatibilities(self, library_root_dir_path): "Go to https://khiops.org for instructions.\n" ) error_list.append(error) - # 'binary+pip', 'conda-based' or borderline installations + # 'pip', 'conda-based' or borderline installations else: # ensure a known installer was used otherwise unexpected issues can occur @@ -1220,13 +1230,31 @@ def _detect_library_installation_incompatibilities(self, library_root_dir_path): ) warning_list.append(warning) - # we consider only the 'binary+pip' and 'conda-based' installations here + # we consider only the 'pip' and 'conda-based' installations here # - 'conda-based' installation (similar to a non-activated virtual env) - # - 'binary+pip' installation under a virtual env - # - User site 'binary+pip' installation (without virtual env) - # - system-wide 'binary+pip' installation (without virtual env)... + # - 'pip' installation under a virtual env + # - User site 'pip' installation (without virtual env) + # - system-wide 'pip' installation (without virtual env)... # (an empty string means a borderline installation was found, # no further check cannot be performed) + + # in a 'pip' installation method, + # the current Khiops Python library depends on the Khiops binary-only + # PyPI package. + # Let's check if this dependency has not disappeared. + # If it is the case an error must have occurred long before + # except for edge cases (for example when the Khiops binaries + # are installed system-wide despite all the recommendations) + try: + distribution("khiops-core") + except PackageNotFoundError as exc: + error = ( + f"The Khiops binaries are not installed properly: {exc}. " + "Re-install the Khiops Python library to automatically install " + "Khiops. Go to https://khiops.org for more information.\n" + ) + error_list.append(error) + base_dir = _infer_base_dir_for_conda_based_or_pip_installations() if len(base_dir) > 0: # Store in separate variable(s) to abstract over @@ -1252,7 +1280,7 @@ def _detect_library_installation_incompatibilities(self, library_root_dir_path): # for conda-based installations python is inside 'base_dir' sys_executable_direct_parent != base_dir_path and - # for 'binary+pip' installations (within a virtual env) + # for 'pip' installations (within a virtual env) # python is inside 'base_dir'/Scripts sys_executable_grand_parent != base_dir_path ) diff --git a/packaging/docker/khiopspydev/Dockerfile.debian b/packaging/docker/khiopspydev/Dockerfile.debian deleted file mode 100644 index f16a0142..00000000 --- a/packaging/docker/khiopspydev/Dockerfile.debian +++ /dev/null @@ -1,108 +0,0 @@ -# TODO : avoid duplication in trying to use the same docker file for debian and ubuntu -# 2 distinct files exist now because the releases for debian 12 are used for the remote drivers -# Arguments -ARG KHIOPSDEV_OS -ARG SERVER_REVISION -FROM ghcr.io/khiopsml/khiops/khiopsdev-${KHIOPSDEV_OS}:latest AS khiopsdev -LABEL maintainer="khiops.team@orange.com" -LABEL description="Container for the development of khiops-python" - -# Install dev tools and miniforge (for the unit tests); build and install Khiops -ARG KHIOPS_REVISION -RUN true \ - # Install git (for khiops-python version calculation) and pip \ - && apt-get -y update \ - && apt-get -y --no-install-recommends install git python3-pip \ - # On Debian/Ubuntu systems, python3-venv must be installed to provide ensurepip. - # It is still possible to create venvs using the --without-pip flag but any subsequent - # module installation with pip would be impossible - python3-venv \ - zip pandoc wget ruby-dev \ - # Get Linux distribution codename \ - && if [ -f /etc/os-release ]; then . /etc/os-release; fi \ - # Obtain the Khiops native package \ - && KHIOPS_PKG_FILE=$KHIOPS_REVISION/khiops-core-openmpi_$KHIOPS_REVISION-1-$VERSION_CODENAME.amd64.deb \ - && wget -O KHIOPS_CORE.deb "https://github.com/KhiopsML/khiops/releases/download/${KHIOPS_PKG_FILE}" \ - # Install the Khiops native package : make it always succeed. \ - # If dpkg fails it is due to missing dependencies which will be installed by apt in the next line \ - && (dpkg -i --force-all KHIOPS_CORE.deb || true) \ - && apt-get -f -y install \ - && rm -f KHIOPS_CORE.deb \ - # Set python to python3 \ - && update-alternatives --install /usr/bin/python python /usr/bin/python3 1 \ - # Install miniforge to have multiple Python versions via Conda \ - && mkdir -p /root/miniforge3 && cd /root/miniforge3 \ - && wget https://github.com/conda-forge/miniforge/releases/download/25.9.1-0/Miniforge3-25.9.1-0-Linux-x86_64.sh -O ./Miniforge3_25.9.1-0-Linux-x86_64.sh \ - && echo "07f64c1d908ae036e9f6a81f97704899311c0ae677d83980d664b9781d4cc5fc Miniforge3_25.9.1-0-Linux-x86_64.sh" | sha256sum --check \ - && bash ./Miniforge3_25.9.1-0-Linux-x86_64.sh -b -u -p /root/miniforge3 \ - && rm -rf /root/miniforge3/Miniforge3_25.9.1-0-Linux-x86_64.sh \ - # Make sure that MPI is openmpi \ - && update-alternatives --set mpirun /usr/bin/mpirun.openmpi \ - # Clean build files \ - && rm -fr /var/lib/apt/lists/* \ - && apt-get clean \ - && rm -rf ./khiops \ - && true - -# set up all the supported Python environments under Conda (for the unit tests) -# relying on a variable containing all the versions -ARG PYTHON_VERSIONS -ARG KHIOPS_GCS_DRIVER_REVISION -ARG KHIOPS_S3_DRIVER_REVISION -ARG KHIOPS_AZURE_DRIVER_REVISION - -# Initialize all the Conda environments -RUN true \ - && export CONDA="/root/miniforge3/bin/conda" \ - && /bin/bash -c ' \ - # Update conda to the latest version \ - $CONDA update -n base conda; \ - for version in ${PYTHON_VERSIONS}; \ - do \ - $CONDA create -y -n py${version} python=${version}; \ - done; \ - # Install Khiops from a different major version in a dedicated conda environment \ - # for a specific test regarding compatibility test \ - # The python interpreter version of the base environment is used as no specific version is given \ - $CONDA create -y -n py3_khiops10_conda; \ - $CONDA install -y -n py3_khiops10_conda khiops-core==10.3.2; \ - ' \ - && true - -RUN mkdir -p /scripts -COPY ./run_service.sh ./run_fake_remote_file_servers.sh /scripts/ -RUN chmod +x /scripts/run_service.sh /scripts/run_fake_remote_file_servers.sh && \ - useradd -rm -d /home/ubuntu -s /bin/bash -g root -u 1000 ubuntu - -# remote files drivers installed system-wide -RUN true \ - # Get Linux distribution codename \ - && if [ -f /etc/os-release ]; then . /etc/os-release; fi \ - # Force the installation of the debian 12 versions (bookworm) - && wget -O khiops-gcs.deb https://github.com/KhiopsML/khiopsdriver-gcs/releases/download/${KHIOPS_GCS_DRIVER_REVISION}/khiops-driver-gcs_${KHIOPS_GCS_DRIVER_REVISION}-1-bookworm.amd64.deb \ - && wget -O khiops-s3.deb https://github.com/KhiopsML/khiopsdriver-s3/releases/download/${KHIOPS_S3_DRIVER_REVISION}/khiops-driver-s3_${KHIOPS_S3_DRIVER_REVISION}-1-bookworm.amd64.deb \ - # XXX There is a typo in the latest release tag. Until it is fixed, we need to use the hardcoded folder name - && wget -O khiops-azure.deb https://github.com/KhiopsML/khiopsdriver-azure/releases/download/0.0.7/khiops-driver-azure_${KHIOPS_AZURE_DRIVER_REVISION}-1-bookworm.amd64.deb \ - && (dpkg -i --force-all khiops-gcs.deb khiops-s3.deb khiops-azure.deb || true) \ - && apt-get -f -y install \ - && rm -f khiops-gcs.deb khiops-s3.deb khiops-azure.deb \ - && true - -FROM ghcr.io/khiopsml/khiops-server:${SERVER_REVISION} AS server - -FROM khiopsdev AS base -COPY --from=server /service /usr/bin/service - -# S3 fake file server (only in the ubuntu container) -# Do not use the latest fakes3 version because starting from 1.3 a licence is required -# if fakes3 is no longer compatible think about switching to an alternative and fully compatible server -# (https://github.com/jamhall/s3rver:v3.7.1 is not yet for example) -RUN gem install fakes3:1.2.1 sorted_set -# Avoid resolving a fake s3-bucket.localhost hostname -# Alternate builders (buildx via moby buildkit) mount /etc/hosts read-only, the following command will fail -# echo "127.0.0.1 s3-bucket.localhost" >> /etc/hosts -# You will have to add the `add-hosts` input instead (https://github.com/docker/build-push-action/#inputs) - -# Port on which fakes3 is listening -EXPOSE 4569 - diff --git a/packaging/docker/khiopspydev/Dockerfile.rocky b/packaging/docker/khiopspydev/Dockerfile.rocky index b7994209..775c0733 100644 --- a/packaging/docker/khiopspydev/Dockerfile.rocky +++ b/packaging/docker/khiopspydev/Dockerfile.rocky @@ -7,10 +7,7 @@ LABEL description="Container for the development of khiops-python" # Reuse KHIOPSDEV_OS from previous stage ARG KHIOPSDEV_OS -ARG KHIOPS_REVISION # - Install dev tools and miniforge (for the unit tests) -# - Build and install Khiops -# - Set mpich as the default MPI RUN true \ && useradd -rm -d /home/rocky -s /bin/bash -g root -u 1000 rocky \ # Install git (for khiops-python version calculation), pandoc and pip \ @@ -28,21 +25,6 @@ RUN true \ python3.11-pip \ python3.11-setuptools ; \ fi \ - # Get Linux distribution codename \ - && if [ -f /etc/os-release ]; then . /etc/os-release; fi \ - && IFS='.' read -ra VERSION <<< "$VERSION_ID" \ - && ROCKY_VERSION=${VERSION[0]} \ - # Obtain the Khiops native package \ - && KHIOPS_PKG_FILE=$KHIOPS_REVISION/khiops-core-openmpi-$(echo ${KHIOPS_REVISION} | tr '-' '_')-1.el$ROCKY_VERSION.x86_64.rpm \ - && wget -O KHIOPS_CORE.rpm "https://github.com/KhiopsML/khiops/releases/download/${KHIOPS_PKG_FILE}" \ - # Install the Khiops native package \ - && dnf install KHIOPS_CORE.rpm -y \ - && rm -f KHIOPS_CORE.rpm \ - # Make sure that MPI is openmpi \ - && source /etc/profile.d/modules.sh \ - && module unload mpi \ - # Hard-code OpenMPI module name \ - && module load mpi/openmpi-x86_64 \ # Set python to python3.11 and pip to Pip 3.11 on Rocky 8 and 9 \ && if [ "$KHIOPSDEV_OS" = "rocky8" -o "$KHIOPSDEV_OS" = "rocky9" ]; then \ alternatives --install /usr/bin/python python /usr/bin/python3.11 2; \ @@ -58,7 +40,6 @@ RUN true \ && rm -rf /root/miniforge3/Miniforge3_25.9.1-0-Linux-x86_64.sh \ # Clean build files \ && dnf clean all \ - && rm -rf ./khiops \ && true # set up all the supported Python environments under Conda (for the unit tests) @@ -74,13 +55,7 @@ RUN true \ for version in ${PYTHON_VERSIONS}; \ do \ $CONDA create -y -n py${version} python=${version}; \ - done; \ - # Install Khiops from a different major version in a dedicated conda environment \ - # for a specific test regarding compatibility test \ - # The python interpreter version of the base environment is used as no specific version is given \ - $CONDA create -y -n py3_khiops10_conda; \ - $CONDA install -y -n py3_khiops10_conda khiops-core==10.3.2; \ - ' \ + done;' \ && true RUN mkdir -p /scripts diff --git a/packaging/docker/khiopspydev/Dockerfile.ubuntu b/packaging/docker/khiopspydev/Dockerfile.ubuntu-debian similarity index 68% rename from packaging/docker/khiopspydev/Dockerfile.ubuntu rename to packaging/docker/khiopspydev/Dockerfile.ubuntu-debian index b842a266..5bde832d 100644 --- a/packaging/docker/khiopspydev/Dockerfile.ubuntu +++ b/packaging/docker/khiopspydev/Dockerfile.ubuntu-debian @@ -5,12 +5,12 @@ FROM ghcr.io/khiopsml/khiops/khiopsdev-${KHIOPSDEV_OS}:latest AS khiopsdev LABEL maintainer="khiops.team@orange.com" LABEL description="Container for the development of khiops-python" -# Install dev tools and miniforge (for the unit tests); build and install Khiops +# Install dev tools and miniforge (for the unit tests); install Khiops (only for tests against KhiopsDockerRunner) ARG KHIOPS_REVISION RUN true \ - # Install git (for khiops-python version calculation) and pip \ + # Install git (for khiops-python version calculation), pip and unzip (used when deflating the samples) \ && apt-get -y update \ - && apt-get -y --no-install-recommends install git python3-pip \ + && apt-get -y --no-install-recommends install git python3-pip unzip \ # On Debian/Ubuntu systems, python3-venv must be installed to provide ensurepip. # It is still possible to create venvs using the --without-pip flag but any subsequent # module installation with pip would be impossible @@ -39,15 +39,11 @@ RUN true \ # Clean build files \ && rm -fr /var/lib/apt/lists/* \ && apt-get clean \ - && rm -rf ./khiops \ && true # set up all the supported Python environments under Conda (for the unit tests) # relying on a variable containing all the versions ARG PYTHON_VERSIONS -ARG KHIOPS_GCS_DRIVER_REVISION -ARG KHIOPS_S3_DRIVER_REVISION -ARG KHIOPS_AZURE_DRIVER_REVISION # Initialize all the Conda environments RUN true \ @@ -58,13 +54,7 @@ RUN true \ for version in ${PYTHON_VERSIONS}; \ do \ $CONDA create -y -n py${version} python=${version}; \ - done; \ - # Install Khiops from a different major version in a dedicated conda environment \ - # for a specific test regarding compatibility test \ - # The python interpreter version of the base environment is used as no specific version is given \ - $CONDA create -y -n py3_khiops10_conda; \ - $CONDA install -y -n py3_khiops10_conda khiops-core==10.3.2; \ - ' \ + done;' \ && true RUN mkdir -p /scripts @@ -72,19 +62,6 @@ COPY ./run_service.sh ./run_fake_remote_file_servers.sh /scripts/ RUN chmod +x /scripts/run_service.sh /scripts/run_fake_remote_file_servers.sh && \ useradd -rm -d /home/ubuntu -s /bin/bash -g root -u 1000 ubuntu -# remote files drivers installed system-wide -RUN true \ - # Get Linux distribution codename \ - && if [ -f /etc/os-release ]; then . /etc/os-release; fi \ - && wget -O khiops-gcs.deb https://github.com/KhiopsML/khiopsdriver-gcs/releases/download/${KHIOPS_GCS_DRIVER_REVISION}/khiops-driver-gcs_${KHIOPS_GCS_DRIVER_REVISION}-1-${VERSION_CODENAME}.amd64.deb \ - && wget -O khiops-s3.deb https://github.com/KhiopsML/khiopsdriver-s3/releases/download/${KHIOPS_S3_DRIVER_REVISION}/khiops-driver-s3_${KHIOPS_S3_DRIVER_REVISION}-1-${VERSION_CODENAME}.amd64.deb \ - # XXX There is a typo in the latest release tag. Until it is fixed, we need to use the hardcoded folder name - && wget -O khiops-azure.deb https://github.com/KhiopsML/khiopsdriver-azure/releases/download/0.0.7/khiops-driver-azure_${KHIOPS_AZURE_DRIVER_REVISION}-1-${VERSION_CODENAME}.amd64.deb \ - && (dpkg -i --force-all khiops-gcs.deb khiops-s3.deb khiops-azure.deb || true) \ - && apt-get -f -y install \ - && rm -f khiops-gcs.deb khiops-s3.deb khiops-azure.deb \ - && true - FROM ghcr.io/khiopsml/khiops-server:${SERVER_REVISION} AS server FROM khiopsdev AS base diff --git a/pyproject.toml b/pyproject.toml index c53c39de..11f8d40f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -102,8 +102,10 @@ classifiers = [ "Programming Language :: Python", "Topic :: Scientific/Engineering", ] -requires-python = ">=3.8" +requires-python = ">=3.10" dependencies = [ + # XXX : replace with the latest khiops-core 11.0.1 stable version + "khiops-core>=11.0.1a4,<12.0.0", # package containing khiops-core binaries # do not use the latest versions, to avoid undesired breaking changes "pandas>=2.3.3,<4.0.0", "scikit-learn>=1.7.2,<1.9.0", @@ -119,14 +121,17 @@ Homepage = "https://khiops.org" s3 = [ # do not use the latest version, to avoid undesired breaking changes "boto3>=1.17.39,<=1.35.69", + "khiops-driver-s3", # package containing the driver binary ] gcs = [ "google-cloud-storage>=1.37.0", + "khiops-driver-gcs", # package containing the driver binary ] azure = [ "azure-core>=1.39.0,<2.0.0", "azure-storage-blob>=12.28.0,<13.0.0", "azure-storage-file-share>=12.24.0,<13.0.0", + "khiops-driver-azure", # package containing the driver binary ] [tool.setuptools.packages.find] diff --git a/scripts/extract_dependencies_from_pyproject_toml.py b/scripts/extract_dependencies_from_pyproject_toml.py index 905efc15..02b3cbe5 100644 --- a/scripts/extract_dependencies_from_pyproject_toml.py +++ b/scripts/extract_dependencies_from_pyproject_toml.py @@ -24,7 +24,21 @@ def main(args): # Optional dependencies listed as per-group dependencies for dependency_group in project_metadata["optional-dependencies"].values(): dependencies += list(dependency_group) - print(args.dependency_separator.join(dependencies)) + + if args.khiops_family_only: + print( + args.dependency_separator.join( + [d for d in dependencies if d.startswith("khiops-")] + ) + ) + elif args.exclude_khiops_family: + print( + args.dependency_separator.join( + [d for d in dependencies if not d.startswith("khiops-")] + ) + ) + else: + print(args.dependency_separator.join(dependencies)) if __name__ == "__main__": @@ -47,4 +61,21 @@ def main(args): type=lambda s: codecs.decode(s, "unicode_escape") if s == "\\n" else s, help="Dependency separator (default: ' ')", ) + + exclusive_filtering_group = parser.add_mutually_exclusive_group() + + exclusive_filtering_group.add_argument( + "--khiops-family-only", + action="store_true", + help="Keep only the dependencies from the Khiops family", + required=False, + ) + + exclusive_filtering_group.add_argument( + "--exclude-khiops-family", + action="store_true", + help="Exclude the dependencies from the Khiops family", + required=False, + ) + main(parser.parse_args()) diff --git a/tests/test_khiops_integrations.py b/tests/test_khiops_integrations.py index 66a76a58..2b851420 100644 --- a/tests/test_khiops_integrations.py +++ b/tests/test_khiops_integrations.py @@ -227,10 +227,7 @@ def test_environment_error_on_bogus_khiops_env_script(self): # Create temporary khiops_env path temp_khiops_env_file_path = os.path.join(temp_khiops_env_dir, "khiops_env") - # On Windows, set KHIOPS_HOME to the temp dir - original_khiops_home_env_var = os.environ.get("KHIOPS_HOME") if platform.system() == "Windows": - os.environ["KHIOPS_HOME"] = temp_dir temp_khiops_env_file_path += ".cmd" # Replace the khiops_env with a script that fails showing an error message @@ -268,13 +265,6 @@ def test_environment_error_on_bogus_khiops_env_script(self): # Restore initial PATH os.environ["PATH"] = original_path_env_var - # On Windows, restore initial KHIOPS_HOME - if ( - platform.system() == "Windows" - and original_khiops_home_env_var is not None - ): - os.environ["KHIOPS_HOME"] = original_khiops_home_env_var - # Check that the script error message matches the expected one expected_msg = ( "Error initializing the environment for Khiops from the " From 47a0f74c952e296e3aa4085ad8da508c8d0d7f52 Mon Sep 17 00:00:00 2001 From: Thierry RAMORASOAVINA Date: Thu, 28 May 2026 11:46:30 +0200 Subject: [PATCH 2/2] Change code formatting to match 'black' linter suggestion --- khiops/tools.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/khiops/tools.py b/khiops/tools.py index 1359a35a..efcd9d7d 100644 --- a/khiops/tools.py +++ b/khiops/tools.py @@ -156,9 +156,10 @@ def download_datasets( # Download the sample zip file and extracted to the home dataset dir print(f"Downloading samples from {samples_zip_url}") - with tempfile.NamedTemporaryFile() as temp_zip_file, urllib.request.urlopen( - samples_zip_url - ) as zip_request: + with ( + tempfile.NamedTemporaryFile() as temp_zip_file, + urllib.request.urlopen(samples_zip_url) as zip_request, + ): temp_zip_file.write(zip_request.read()) temp_zip_file.seek(0) with zipfile.ZipFile(temp_zip_file) as temp_zip: