chore: migrate build system from pip/setup.py to uv workspaces (#12686)#12770
chore: migrate build system from pip/setup.py to uv workspaces (#12686)#12770sh4shv4t wants to merge 8 commits intokubeflow:masterfrom
Conversation
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
🎉 Welcome to the Kubeflow Pipelines repo! 🎉 Thanks for opening your first PR! We're excited to have you onboard 🚀 Next steps:
Feel free to ask questions in the comments. |
|
Hi @sh4shv4t. Thanks for your PR. I'm waiting for a kubeflow member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
…low#12686) This commit performs a complete migration of the Kubeflow Pipelines SDK and related packages from pip-based installation (setup.py, requirements.txt) to uv workspaces with modern pyproject.toml configuration. ## Motivation Addresses issue kubeflow#12686 by adopting uv for faster, more reliable dependency management and build processes. The uv workspace architecture provides: - 10-100x faster dependency resolution and installation - Deterministic builds via uv.lock - Unified tooling for development, testing, and CI - Better integration with modern Python packaging standards (PEP 517/518/621) ## Major Changes ### Package Structure - Created root pyproject.toml with workspace configuration for 4 packages: - kfp (sdk/python) - kfp-pipeline-spec (api/v2alpha1/python) - kfp-kubernetes (kubernetes_platform/python) - kfp-server-api (backend/api/v2beta1/python_http_client) - Created individual pyproject.toml files for each package with: - Package metadata and dependencies - Build system configuration (hatchling) - Optional dependency groups (lint, test, dev, ci, docs) - Tool configurations (mypy, pytest, coverage, isort, etc.) ### Removed Files - All setup.py files (4 packages) - All requirements.txt, requirements.in, requirements-dev.txt files - All MANIFEST.in files - hack/update-all-requirements.sh (no longer needed) - hack/update-requirements.sh (no longer needed) ### Generated Files - uv.lock: Lockfile with 196 resolved packages and exact versions - .github/actions/setup-python/action.yml: Composite action for CI setup - .github/workflows/check-uv-lock.yml: Workflow to validate lockfile ### CI/CD Updates **Test Scripts (8 files updated):** - presubmit-yapf-sdk.sh: Uses `uv run yapf` and `uv run python -m pre_commit_hooks.string_fixer` - presubmit-isort-sdk.sh: Uses `uv run pycln` and `uv run isort` - presubmit-docformatter-sdk.sh: Uses `uv run docformatter` - presubmit-tests-sdk-unit.sh: Uses `uv sync --extra ci` and `uv run pytest` - presubmit-tests-sdk-client.sh: Uses uv for package installation and pytest - presubmit-tests-sdk.sh: Uses uv for full SDK tests - presubmit-test-sdk-upgrade.sh: Uses `uv build --package` instead of `python -m build` - presubmit-component-yaml.sh: Uses uv sync and uv pip install **Workflows (6 files updated):** - kfp-kubernetes-library-test.yml: Replaced custom action with setup-python - kfp-sdk-tests.yml: Replaced custom action with setup-python - sdk-docformatter.yml: Uses .github/actions/setup-python - sdk-isort.yml: Uses .github/actions/setup-python - sdk-upgrade.yml: Uses .github/actions/setup-python - sdk-component-yaml.yml: Replaced custom action with setup-python **Other CI Changes:** - .github/dependabot.yml: Added pip ecosystem monitoring for uv requirements - gcpc-modules-tests.yml: Updated to use uv for package installation - Updated pre-commit config to use uv ### Documentation Updates - developer_guide.md: Updated installation instructions to use uv - sdk/python/README.md: Updated development setup instructions - Various workflow README files updated ### Proto Generation - Updated Makefiles to work without requirements.in files - Fixed uv PATH issues in Docker containers by using ~/.local/bin/uv - Removed README.md requirement from auto-generated packages ### Dependencies - Added pre-commit-hooks to lint dependencies (required for string_fixer) - All dependencies now managed through pyproject.toml dependency groups - Version pins preserved from original requirements files ## Testing - All 4 packages build successfully with `uv build --package <name>` - Proto generation works via updated Makefiles - Local tests pass with `uv run pytest` - CI test scripts updated to use uv instead of pip ## Breaking Changes **For developers:** - Must install uv: `curl -LsSf https://astral.sh/uv/install.sh | sh` - Replace `pip install -e .` with `uv sync` or `uv pip install -e .` - Replace `pip install -r requirements.txt` with `uv sync` - Replace `python -m tool` with `uv run tool` **For CI/automation:** - requirements.txt files no longer exist - Must use uv for package installation - Use composite action `.github/actions/setup-python` for workflow setup ## Migration Path Users can continue using pip to install published packages from PyPI. This change only affects development workflows, not end-user installation. Signed-off-by: Shashvat <sh4shv4t@gmail.com> Signed-off-by: sh4shv4t <shashvat.k.singh.16@gmail.com>
…ion steps Several CI workflows were failing because they were missing required setup steps: 1. kfp-sdk-unit-tests.yml: Added proto generation and workspace package installation steps before running tests. The workflow was setting SETUP_ENV=false but wasn't providing the required dependencies. 2. sdk-upgrade.yml: Added workspace package installation step. The workflow had proto generation but was missing the editable package installations. 3. readthedocs-builds.yml: Added workspace package installation after proto generation. sphinx-build requires the packages to be installed to build documentation. All workflows now follow the same pattern: - Setup Python with uv - Generate proto files (via protobuf action or make commands) - Install workspace packages in editable mode with uv pip install -e - Run tests with SETUP_ENV=false This ensures tests run in the uv-managed virtual environment with all dependencies correctly installed. Signed-off-by: sh4shv4t <shashvat.k.singh.16@gmail.com>
The CI workflows were failing because 'uv pip install -e' was trying to resolve and install dependencies for workspace packages, which conflicts with the dependencies already installed by 'uv sync --extra ci'. Changes made: - Added --no-deps flag to all 'uv pip install -e' commands in workflows - This prevents uv from reinstalling/resolving dependencies that are already satisfied by the uv.lock file - Applies to: kfp-sdk-tests, kfp-sdk-unit-tests, kfp-kubernetes-library-test, sdk-component-yaml, sdk-upgrade, and readthedocs-builds workflows The --no-deps flag ensures workspace packages are installed in editable mode without touching the already-installed dependency tree, avoiding version conflicts and installation errors. This follows the pattern: 1. uv sync --extra ci (installs all deps from lockfile) 2. Generate proto files 3. uv pip install --no-deps -e packages (install workspace packages only) 4. Run tests in the uv-managed environment Signed-off-by: sh4shv4t <shashvat.k.singh.16@gmail.com>
The composite actions were failing with error:
'The wheel filename "*.whl" is invalid: Must have a version'
This occurred because shell glob patterns (*.whl) were not being expanded
before being passed to uv pip install. The literal string '*.whl' was
treated as a filename instead of a wildcard pattern.
Fixed by:
- Using bash array expansion to properly handle wheel file globs
- Added nullglob option to handle cases where no files match
- Added error checking to detect missing wheel files
- Quote array expansion to handle filenames with spaces
Changes in:
- .github/actions/protobuf/action.yml: Fixed kfp-pipeline-spec wheel install
- .github/actions/kfp-k8s/action.yml: Fixed kfp-server-api and kfp wheel installs
This pattern now correctly expands globs:
shopt -s nullglob
wheels=(dist/*.whl)
uv pip install --system "${wheels[@]}"
Signed-off-by: sh4shv4t <shashvat.k.singh.16@gmail.com>
The previous glob expansion using bash arrays was causing failures across multiple CI workflows. Simplified the approach to use ls with error checking. Changes: - Replace bash array glob expansion with $(ls dist/*.whl | head -n1) - This approach is more portable and reliable across different shell contexts - Maintains error checking to ensure wheel files exist before installation - Uses head -n1 to select the first wheel file (there should only be one) This fixes the 55 failing tests by using a simpler, more reliable approach to wheel file discovery that works consistently in GitHub Actions workflows. Applies to: - .github/actions/protobuf/action.yml - .github/actions/kfp-k8s/action.yml Signed-off-by: sh4shv4t <shashvat.k.singh.16@gmail.com>
The --system flag causes uv to install packages into the system Python instead of the virtual environment created by 'uv sync'. This was causing CI failures because: 1. setup-python action runs 'uv sync' creating .venv/ 2. protobuf/kfp-k8s actions used 'uv pip install --system' installing to system Python, not the venv 3. 'uv run pytest' runs in .venv/ which lacked those packages Changes: - Remove redundant uv setup from protobuf and kfp-k8s actions (now provided by setup-python action) - Remove --system flag from all uv pip install commands - Update kfp-kubernetes-native-migration-tests workflow to use our setup-python action and uv commands Signed-off-by: sh4shv4t <shashvat.k.singh.16@gmail.com>
Several workflows were missing required setup steps: 1. kfp-sdk-client-tests.yml: Added protobuf action and workspace packages installation before running tests 2. gcpc-modules-tests.yml: Replaced manual protobuf-compiler installation with protobuf action, added workspace packages installation 3. readthedocs-builds.yml: Added protobuf action instead of manual make command 4. components/test_load_all_components.sh: Changed python3 to uv run python to use the correct virtual environment 5. setup-python/action.yml: Updated to actions/setup-python@v6 for consistency with other workflows Signed-off-by: sh4shv4t <shashvat.k.singh.16@gmail.com>
0e93491 to
d29c44c
Compare
There was a problem hiding this comment.
Pull request overview
This PR migrates the KFP repository from fragmented pip-based dependency management to a unified uv workspace, replacing 7 setup.py files, 18 requirements.txt files, and 46+ scattered pip install commands with a single uv.lock file containing 195 resolved packages.
Changes:
- Created root pyproject.toml defining a workspace with 4 member packages (kfp, kfp-kubernetes, kfp-pipeline-spec, kfp-server-api)
- Migrated all packages from setup.py to PEP 621-compliant pyproject.toml files with hatchling build backend
- Updated CI/CD workflows and test scripts to use uv commands (uv sync, uv run, uv build)
- Added new composite action .github/actions/setup-python for consistent Python/uv setup
- Updated documentation (AGENTS.md, sdk/CONTRIBUTING.md, .readthedocs.yml) for uv-based workflows
- Removed all legacy setup.py, requirements.txt, requirements.in, and MANIFEST.in files
Reviewed changes
Copilot reviewed 58 out of 59 changed files in this pull request and generated 17 comments.
Show a summary per file
| File | Description |
|---|---|
| pyproject.toml | Root workspace configuration with constraint-dependencies and optional extras groups (lint, test, dev, docs, ci) |
| sdk/python/pyproject.toml | KFP SDK package configuration with dynamic versioning from kfp/version.py |
| kubernetes_platform/python/pyproject.toml | kfp-kubernetes package with workspace source links to kfp |
| api/v2alpha1/python/pyproject.toml | kfp-pipeline-spec proto-generated package |
| backend/api/v2beta1/python_http_client/pyproject.toml | kfp-server-api swagger-generated client |
| .github/actions/setup-python/action.yml | New composite action for Python + uv setup with dependency installation |
| .github/workflows/*.yml | Updated 10+ workflows to use new setup-python action and uv commands |
| test/presubmit-*.sh | Updated test scripts to use uv sync and uv run commands |
| api/Makefile, sdk/Makefile, kubernetes_platform/Makefile | Updated to use uv build commands in Docker containers |
| .pre-commit-config.yaml | Converted Python linting hooks to use uv run with local repo |
| .readthedocs.yml | Configured to use uv for documentation builds |
| .github/dependabot.yml | Added dependency update configuration for pip ecosystem and GitHub Actions |
| .github/workflows/check-uv-lock.yml | New workflow to verify uv.lock stays in sync with pyproject.toml files |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| rm -rf dist | ||
| python setup.py --quiet sdist | ||
| uv build --package kfp-server-api | ||
| twine check dist/* |
There was a problem hiding this comment.
The twine check dist/* command should be executed as uv run twine check dist/* for consistency with the rest of the codebase and to ensure the correct environment is used.
| make python | ||
| cd python | ||
| uv build --package kfp | ||
| twine check dist/* |
There was a problem hiding this comment.
The twine check dist/* command should be executed as uv run twine check dist/* for consistency with the rest of the codebase and to ensure the correct environment is used.
| make python | ||
| cd python | ||
| uv build --package kfp-kubernetes | ||
| twine check dist/* |
There was a problem hiding this comment.
The twine check dist/* command should be executed as uv run twine check dist/* for consistency with the rest of the codebase and to ensure the correct environment is used.
| twine check dist/* | |
| uv run twine check dist/* |
sdk/Makefile
Outdated
| sh -c 'cd /go/src/github.com/kubeflow/pipelines && \ | ||
| pip install --user --break-system-packages uv && \ | ||
| cd sdk/python && \ | ||
| uv build --package kfp' |
There was a problem hiding this comment.
The uv build --package kfp command is executed from within the sdk/python directory, but --package expects to be run from the workspace root. Since the command changes to sdk/python first, it should use uv build without the --package flag, or stay at the workspace root and use the full package name. This will likely fail at build time.
kubernetes_platform/Makefile
Outdated
| sh -c 'cd /go/src/github.com/kubeflow/pipelines && \ | ||
| pip install --user --break-system-packages uv && \ | ||
| cd kubernetes_platform/python && \ | ||
| python3 generate_proto.py && \ | ||
| python3 setup.py sdist && pip wheel --no-deps dist/*.tar.gz -w dist' | ||
| ~/.local/bin/uv build --package kfp-kubernetes' |
There was a problem hiding this comment.
The same issue exists here: uv build --package kfp-kubernetes is executed from within the kubernetes_platform/python directory. The --package flag expects to be run from the workspace root. This should either use uv build without the --package flag, or execute from the workspace root with the package name.
| python3 -m pip install --upgrade pip | ||
|
|
||
| python3 -m pip install kfp | ||
| LATEST_KFP_SDK_RELEASE=$(python3 -m pip show kfp | grep "Version:" | awk '{print $2}' | awk '{$1=$1};1') | ||
| echo "Installed latest KFP SDK version: $LATEST_KFP_SDK_RELEASE" | ||
|
|
||
| # Before installing KFP we need to install our kfp dependencies from source since | ||
| # these packages are patch version aligned, and during releases they may be | ||
| # unreleased in PyPi. | ||
|
|
||
| # Build (to generate proto code) and install kfp-pipeline-spec | ||
| # Build and install workspace packages from source using uv | ||
| # Generate proto files (requires Docker) | ||
| pushd api | ||
| make python | ||
| python3 -m pip install v2alpha1/python | ||
| popd | ||
|
|
||
| # Install kfp-server-api | ||
| python3 -m pip install backend/api/v2beta1/python_http_client | ||
| # Build all workspace packages | ||
| uv build --package kfp-pipeline-spec | ||
| uv build --package kfp-server-api | ||
| uv build --package kfp | ||
|
|
||
| # Install the built packages (simulates upgrade from PyPI to HEAD) | ||
| python3 -m pip install dist/kfp_pipeline_spec-*.whl --force-reinstall | ||
| python3 -m pip install dist/kfp_server_api-*.whl --force-reinstall | ||
| python3 -m pip install dist/kfp-*.whl --force-reinstall |
There was a problem hiding this comment.
This script is using a mix of pip and uv commands. Lines 19-20 use pip to install kfp from PyPI, but lines 31-33 use uv build. Lines 36-38 then use pip to install the built wheels. While this might be intentional for testing upgrade scenarios, it creates an inconsistent environment. Consider whether uv should be used for all package installations, or document why this mixing is necessary for the upgrade test scenario.
| - name: Build kfp | ||
| run: | | ||
| cd sdk | ||
| make python | ||
| cd python | ||
| uv build --package kfp |
There was a problem hiding this comment.
The uv build --package kfp command is executed from within the sdk/python directory. The --package flag expects to be run from the workspace root. This should either use uv build without the --package flag, or stay at the workspace root and use the full package name.
sdk/Makefile
Outdated
| sh -c 'cd /go/src/github.com/kubeflow/pipelines/sdk/python && \ | ||
| python3 setup.py sdist && pip wheel --no-deps dist/*.tar.gz -w dist' | ||
| sh -c 'cd /go/src/github.com/kubeflow/pipelines && \ | ||
| pip install --user --break-system-packages uv && \ |
There was a problem hiding this comment.
This build target installs the uv build tool via pip install --user --break-system-packages uv without any version pinning or integrity verification, then uses it to produce release artifacts with uv build --package kfp. If the uv package on PyPI or the network path to it is compromised, an attacker could execute arbitrary code in the build container and tamper with the generated kfp distributions. To reduce supply-chain risk, pin uv to a specific trusted version (or vendor it locally) and, where feasible, add an integrity check for the downloaded artifact before using it in the release pipeline.
kubernetes_platform/Makefile
Outdated
| sh -c 'cd /go/src/github.com/kubeflow/pipelines/kubernetes_platform/python && \ | ||
| python3 -m pip install --user --break-system-packages -r requirements.txt && \ | ||
| sh -c 'cd /go/src/github.com/kubeflow/pipelines && \ | ||
| pip install --user --break-system-packages uv && \ |
There was a problem hiding this comment.
This build rule installs the uv build tool from PyPI with pip install --user --break-system-packages uv and immediately uses it to build the kfp-kubernetes wheel, but the dependency is not pinned or integrity-checked. A malicious or compromised uv release could execute in this container and alter the generated wheel or otherwise tamper with build outputs. Pin uv to a known-good version (or vendor it) and prefer an installation method that supports integrity verification for the tool used in your packaging pipeline.
api/Makefile
Outdated
| sh -c 'cd /go/src/github.com/kubeflow/pipelines/api/v2alpha1/python && \ | ||
| python3 -m pip install --user --break-system-packages -r requirements.txt && \ | ||
| sh -c 'cd /go/src/github.com/kubeflow/pipelines && \ | ||
| pip install --user --break-system-packages uv && \ |
There was a problem hiding this comment.
This Docker-based build path installs uv via pip install --user --break-system-packages uv without a version pin or integrity verification and then uses it to build the kfp-pipeline-spec package. Because uv directly controls how the wheel is constructed, a compromised or malicious uv package from PyPI could tamper with the generated artifacts or run arbitrary code in the build environment. Mitigate this supply-chain risk by pinning uv to a specific trusted version (or vendoring it) and, where possible, validating the downloaded tool before using it in the release process.
- Use 'uv run twine check' for consistency in publish-packages.yml - Run 'uv build' from workspace root in all Makefiles - Pin uv version to 0.6.6 for supply-chain security - Add comment explaining pip/uv mixing in upgrade test Signed-off-by: sh4shv4t <shashvat.k.singh.16@gmail.com>
|
/ok-to-test |
Description
This PR implements a complete migration from fragmented pip-based dependency management to a unified uv workspace, addressing The migration modernizes the build system while maintaining full backward compatibility with existing workflows.
What does this PR do?
Replaces 7 setup.py files, 18 requirements.txt files, and 46+ scattered pip install commands across the repository with a single unified uv workspace containing one lockfile (uv.lock) with 195 resolved packages.
Key Changes
Build System Migration:
Created root pyproject.toml defining workspace with 4 member packages
Generated single uv.lock (634KB, 195 packages) replacing all requirements files
Centralized constraint-dependencies (protobuf>=6.31.1,<7.0, kubernetes>=8.0.0,<31, google-auth>=1.6.1,<3, etc.)
Configured workspace member resolution via [tool.uv.sources] for local development
Package Conversions (PEP 621 + hatchling):
kfp (sdk/python): Dynamic versioning from kfp/version.py, 20+ dependencies with optional extras
kfp-kubernetes (kubernetes_platform/python): Dynamic versioning from init.py, workspace source links
kfp-pipeline-spec (api/v2alpha1/python): Proto-generated package with hardcoded version
kfp-server-api (backend/api/v2beta1/python_http_client): Swagger-generated client with inline readme
CI/CD Infrastructure:
Added .github/actions/setup-python/action.yml composite action using astral-sh/setup-uv
Updated 6 workflows: sdk-yapf, kfp-sdk-unit-tests, kfp-sdk-client-tests, publish-packages, readthedocs-builds, gcpc-modules-tests
Replaced 46+ scattered pip install commands with standardized uv sync/uv run
Added .github/workflows/check-uv-lock.yml for automated lockfile sync verification
Configured .github/dependabot.yml for pip ecosystem dependency updates
Development Tooling:
Updated .pre-commit-config.yaml: Python linting hooks converted to use uv run (yapf, isort, pycln, docformatter)
Updated Makefiles in api/, kubernetes_platform/, sdk/ to use uv build --package
Proto generation Makefiles install uv in Docker container, use ~/.local/bin/uv build
Documentation:
Updated AGENTS.md: Modernized local testing, linting, and quick reference sections
Updated sdk/CONTRIBUTING.md: Complete rewrite with uv-based setup instructions
Updated .readthedocs.yml: Configured to use uv for Sphinx documentation builds
Cleanup:
Removed 7 setup.py files from all workspace packages
Removed 18 requirements.txt/requirements.in/requirements-dev.txt files
Removed 4 MANIFEST.in files
Removed hack/update-all-requirements.sh and hack/update-requirements.sh
Verification
✅ All 4 packages build successfully:
uv build --package kfp-pipeline-spec # → 2.15.2 (.tar.gz + .whl)
uv build --package kfp-server-api # → 2.15.2 (.tar.gz + .whl)
uv build --package kfp # → 2.15.2 (.tar.gz + .whl)
uv build --package kfp-kubernetes # → 2.15.2 (.tar.gz + .whl)
✅ Proto generation working:
make -C api python # Generates pipeline_spec_pb2.py
make -C kubernetes_platform python # Generates kubernetes_executor_config_pb2.py
✅ Dependency resolution:
uv lock → Resolved 195 packages in <10s
uv lock --check → Lockfile in sync
All constraint-dependencies applied correctly across workspace
✅ Test suite:
uv run pytest sdk/python/kfp/dsl/types/ → 263 tests collected and passing
uv run pytest sdk/python/kfp/compiler/ --co → 256 tests collected successfully
✅ Package imports:
import kfp # ✓ KFP 2.15.2
from kfp.pipeline_spec import pipeline_spec_pb2 # ✓ Proto imports working
from kfp.dsl import component, pipeline # ✓ All main modules import
✅ CLI tools:
uv run kfp --version → kfp 2.15.2
uv run yapf --version → yapf 0.43.0
uv run isort --version → isort 5.10.1
Benefits
Single source of truth: One uv.lock replaces 18 fragmented requirements files
Reproducible builds: Constraint-dependencies enforce version bounds across all packages
Faster CI: uv resolves dependencies 10-100x faster than pip
Simplified workflow: uv sync/uv run/uv build replaces complex pip/virtualenv/build commands
Atomic operations: All packages resolved together, eliminates version conflicts between workspace members
Migration Path for Contributors
Existing workflows remain compatible:
Before (still works in legacy areas):
pip install -r requirements.txt
Fixes #12686
After (new workspace):
uv sync # Install all dependencies
uv sync --extra dev # Install with dev dependencies
uv run pytest sdk/python/kfp # Run tests
uv build --package kfp # Build package
Checklist:
Signed off commits with git commit --signoff
PR title follows convention: chore: migrate build system from pip/setup.py to uv workspaces (#12686)
All packages buildable and tests passing
CI workflows updated and validated
Documentation updated for new workflow
No breaking changes to published package APIs