This is an automated email from the ASF dual-hosted git repository.

tqchen pushed a commit to branch jenkins-wheel-test-artifacts
in repository https://gitbox.apache.org/repos/asf/tvm.git


The following commit(s) were added to refs/heads/jenkins-wheel-test-artifacts 
by this push:
     new d0b4f744e5 [CI] Install wheel consumers into the checkout Python target
d0b4f744e5 is described below

commit d0b4f744e50cf5b65e60355bd07dd37260df1ba2
Author: Tianqi Chen <[email protected]>
AuthorDate: Thu Oct 15 15:58:14 2026 +0000

    [CI] Install wheel consumers into the checkout Python target
---
 ci/jenkins/README.md                        | 26 +++++----
 tests/scripts/task_python_install_wheels.sh | 91 +++++------------------------
 2 files changed, 30 insertions(+), 87 deletions(-)

diff --git a/ci/jenkins/README.md b/ci/jenkins/README.md
index dbb68032b7..081650703f 100644
--- a/ci/jenkins/README.md
+++ b/ci/jenkins/README.md
@@ -132,8 +132,8 @@ existing platform CMake configuration. `uv build` does not 
resolve runtime depen
 requirements. CPU, ARM and Wasm host builds request `all;cpptest`
 and run C++ tests in that same native tree before uploading anything. Python
 consumers install the exact TVM and FFI wheels with `--no-deps --offline`, 
clear
-checkout path overrides, and verify artifact hashes and package/native-library
-paths. Only `build/wheels/*.whl` is uploaded. GPU Java consumers discover 
headers,
+checkout path overrides, and verify package/native-library paths. Only
+`build/wheels/*.whl` is uploaded. GPU Java consumers discover headers,
 linker paths and packaged native libraries through `tvm.config` and
 `tvm_ffi.config`; no separate native files are transferred. The configuration
 commands avoid loading TVM's Python compiler, backends or native libraries.
@@ -149,16 +149,18 @@ modifying the image environment or exposing the build 
overlay to test consumers.
 `uv build` then runs offline without isolation.
 
 The selected images must already provide compatible runtime and test 
dependencies,
-apart from core FFI and its ORCJIT addon. Consumers install the explicit
-`apache-tvm-ffi-orcjit==0.1.2 --no-deps` prerequisite used by legacy Python 
tests,
-then install exactly one transferred wheel for each of TVM and FFI with
-`--no-deps --offline`. Consumers do not compile FFI.
-The checkout remains available for tests and resources through `TVM_HOME`, 
including
-Wasm assets under `web/dist`, without adding its Python package ahead of the
-wheel. Provenance checks bind installed distributions to the transferred wheel
-filenames and the loaded files' SHA-256 hashes from each wheel RECORD, and 
verify
-TVM/FFI Python and native libraries load
-from the test environment. Other missing runtime dependencies remain errors.
+apart from core FFI and its ORCJIT addon. Consumers use the image's existing 
Python
+and install into the checkout-local `.local/python` directory with `uv pip 
--target`.
+They install the explicit `apache-tvm-ffi-orcjit==0.1.2 --no-deps` 
prerequisite,
+then exactly one transferred TVM wheel and one FFI wheel with `--no-deps 
--offline`
+and `--reinstall`. Repeated setup replaces these packages in the same writable 
target.
+No additional virtualenv or consumer-side FFI compilation is needed.
+
+`PYTHONPATH` points to the absolute target directory, keeping image 
dependencies
+available while preventing checkout imports from shadowing the wheels. A short
+smoke check verifies that the loaded TVM/FFI Python and native libraries come 
from
+that target. `TVM_HOME` retains checkout resources, including Wasm assets under
+`web/dist`. The generated `.local` directory is ignored by Git.
 
 `CMAKE_BUILD_PARALLEL_LEVEL` is passed through Docker as an environment 
variable.
 An explicit value wins; otherwise builds use at least one CPU and divide the
diff --git a/tests/scripts/task_python_install_wheels.sh 
b/tests/scripts/task_python_install_wheels.sh
index 6791f36780..b0ff9e9851 100644
--- a/tests/scripts/task_python_install_wheels.sh
+++ b/tests/scripts/task_python_install_wheels.sh
@@ -16,25 +16,14 @@
 # specific language governing permissions and limitations
 # under the License.
 
-# Source this file so subsequent Python invocations use the wheel environment.
-# Docker defaults PYTHONPATH to the checkout; never let it shadow the 
artifacts.
+# Source this file so subsequent Python invocations use the installed wheels.
+# Docker defaults PYTHONPATH to the checkout; replace it with the explicit 
target.
 unset PYTHONPATH TVM_LIBRARY_PATH TVM_FFI_LIBRARY_PATH
 export PYTHONNOUSERSITE=1
-# Installed TVM still needs checkout resources such as web/dist for Wasm 
linking.
 export TVM_HOME="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
-export TVM_WHEEL_DIR="$(realpath "${TVM_WHEEL_DIR:-$(pwd)/build/wheels}")"
-# Preserve the image's active environment (often itself a venv), including when
-# local ci.py sources this setup again for a named test suite.
-export TVM_IMAGE_PYTHON="${TVM_IMAGE_PYTHON:-$(command -v python3)}"
-export 
TVM_IMAGE_SITE_PACKAGES="${TVM_IMAGE_SITE_PACKAGES:-$("$TVM_IMAGE_PYTHON" -I -c 
'import site; print("\n".join(site.getsitepackages()))')}"
-export VIRTUAL_ENV="${TVM_WHEEL_DIR%/}/../wheel-venv"
-uv venv --offline --python "$TVM_IMAGE_PYTHON" --clear "$VIRTUAL_ENV"
-# Append the image dependencies after our wheels without executing its .pth 
files:
-# system-site-packages can install editable-import hooks ahead of the wheel.
-TVM_WHEEL_SITE="$("$VIRTUAL_ENV/bin/python3" -c 'import sysconfig; 
print(sysconfig.get_path("purelib"))')"
-printf '%s\n' "$TVM_IMAGE_SITE_PACKAGES" > 
"$TVM_WHEEL_SITE/image-dependencies.pth"
-export PATH="$VIRTUAL_ENV/bin:$PATH"
-# Require one artifact for each distribution before creating an installation.
+TVM_WHEEL_DIR="$(realpath "${TVM_WHEEL_DIR:-$TVM_HOME/build/wheels}")"
+TVM_PYTHON_TARGET="$TVM_HOME/.local/python"
+
 shopt -s nullglob
 tvm_wheels=("$TVM_WHEEL_DIR"/apache_tvm-*.whl)
 ffi_wheels=("$TVM_WHEEL_DIR"/apache_tvm_ffi-*.whl)
@@ -44,72 +33,24 @@ if [ "${#tvm_wheels[@]}" -ne 1 ] || [ "${#ffi_wheels[@]}" 
-ne 1 ]; then
     return 1
 fi
 # Match the explicit prerequisite in the legacy Python test setup.
-uv pip install --python "$VIRTUAL_ENV/bin/python3" --no-deps 
apache-tvm-ffi-orcjit==0.1.2
-uv pip install --python "$VIRTUAL_ENV/bin/python3" --no-deps --offline 
--reinstall \
+uv pip install --python python3 --target "$TVM_PYTHON_TARGET" --no-deps 
apache-tvm-ffi-orcjit==0.1.2
+uv pip install --python python3 --target "$TVM_PYTHON_TARGET" --no-deps 
--offline --reinstall \
     "${tvm_wheels[0]}" "${ffi_wheels[0]}"
+export PYTHONPATH="$TVM_PYTHON_TARGET"
 
-# Fail before pytest if a source/editable install or native override leaked in.
+# Keep source resources through TVM_HOME, but load Python and native code from 
the target.
 python3 - <<'PYTHON'
-import base64
-import csv
-import hashlib
-import io
-import json
 import os
-import sys
-from importlib.metadata import distribution, requires, version
 from pathlib import Path
-from urllib.parse import unquote, urlparse
-from zipfile import ZipFile
-from packaging.requirements import Requirement
-
-# Core FFI comes from the build-stage wheel and ORCJIT is pinned explicitly.
-# Check the wheel requirements without invoking a resolver or hardcoding a 
floor.
-for text in requires("apache-tvm") or []:
-    requirement = Requirement(text)
-    if requirement.marker and not requirement.marker.evaluate({"extra": ""}):
-        continue
-    installed = version(requirement.name)
-    assert requirement.specifier.contains(installed, prereleases=True), (text, 
installed)
-
 import tvm
 import tvm_ffi
 
-prefix = Path(sys.prefix).resolve()
-path = Path(tvm.__file__).resolve()
-assert path.is_relative_to(prefix), path
-print(f"Installed tvm: {path}")
-# Bind each distribution and its loaded Python/native files to the exact wheel.
-def verify_wheel(name, pattern, paths):
-    wheel, = Path(os.environ["TVM_WHEEL_DIR"]).glob(pattern)
-    dist = distribution(name)
-    source = json.loads(dist.read_text("direct_url.json"))
-    assert Path(unquote(urlparse(source["url"]).path)).resolve() == 
wheel.resolve(), source
-    assert "archive_info" in source and "dir_info" not in source, source
-    with ZipFile(wheel) as archive:
-        record, = (name for name in archive.namelist() if 
name.endswith(".dist-info/RECORD"))
-        hashes = {row[0]: row[1] for row in 
csv.reader(io.StringIO(archive.read(record).decode()))}
-    for path in paths:
-        path = Path(path).resolve()
-        relative = 
path.relative_to(Path(dist.locate_file("")).resolve()).as_posix()
-        digest = hashlib.sha256()
-        with path.open("rb") as stream:
-            for chunk in iter(lambda: stream.read(1024 * 1024), b""):
-                digest.update(chunk)
-        actual = "sha256=" + 
base64.urlsafe_b64encode(digest.digest()).decode().rstrip("=")
-        assert actual == hashes[relative], (name, path)
-    print(f"Installed {name} wheel: {wheel.name}")
-
-verify_wheel("apache-tvm", "apache_tvm-*.whl",
-             [tvm.__file__, *(lib._name for lib in 
tvm.base._LOADED_LIBS.values())])
-verify_wheel("apache-tvm-ffi", "apache_tvm_ffi-*.whl",
-             [tvm_ffi.__file__, tvm_ffi.core.__file__, tvm_ffi.LIB._name])
-for path in (Path(tvm_ffi.__file__).resolve(), 
Path(tvm_ffi.LIB._name).resolve()):
-    assert path.is_relative_to(prefix), path
-    print(f"Installed FFI: {path}")
+target = Path(os.environ["PYTHONPATH"]).resolve()
+paths = [tvm.__file__, tvm_ffi.__file__, tvm_ffi.core.__file__, 
tvm_ffi.LIB._name]
 assert {"tvm_runtime", "tvm_compiler"} <= tvm.base._LOADED_LIBS.keys()
-for name, library in tvm.base._LOADED_LIBS.items():
-    path = Path(library._name).resolve()
-    assert path.is_relative_to(prefix), (name, path)
-    print(f"Installed {name}: {path}")
+paths.extend(library._name for library in tvm.base._LOADED_LIBS.values())
+for filename in paths:
+    path = Path(filename).resolve()
+    assert path.is_relative_to(target), path
+    print(f"Installed wheel artifact: {path}")
 PYTHON

Reply via email to