From 5f60a7f4addb42229c44ac4888e82a769dfaeed9 Mon Sep 17 00:00:00 2001 From: Jie Li Date: Fri, 12 Dec 2025 14:36:18 +0800 Subject: [PATCH 1/5] Add Python builds tests to CI pre-merge pipeline Signed-off-by: Jie Li --- tests/unittest/test_pip_install.py | 100 +++++++++++++++++++++++------ 1 file changed, 81 insertions(+), 19 deletions(-) diff --git a/tests/unittest/test_pip_install.py b/tests/unittest/test_pip_install.py index 346b5051ac..d292c99589 100644 --- a/tests/unittest/test_pip_install.py +++ b/tests/unittest/test_pip_install.py @@ -77,12 +77,17 @@ def get_cpython_version(): return "cp{}{}".format(python_version[0], python_version[1]) -def download_wheel(args): - if not args.wheel_path.startswith(("http://", "https://")): - args.wheel_path = "https://" + args.wheel_path - res = requests.get(args.wheel_path) +def get_wheel_url(wheel_path): + """Get direct wheel URL from wheel_path (directory listing or direct URL).""" + if not wheel_path.startswith(("http://", "https://")): + wheel_path = "https://" + wheel_path + + if wheel_path.endswith(".whl"): + return wheel_path + + res = requests.get(wheel_path) if res.status_code != 200: - print(f"Fail to get the result of {args.wheel_path}") + print(f"Fail to get the result of {wheel_path}") exit(1) wheel_name = None for line in res.text.split("\n"): @@ -96,11 +101,15 @@ def download_wheel(args): wheel_name = name break if not wheel_name: - print(f"Fail to get the wheel name of {args.wheel_path}") + print(f"Fail to get the wheel name of {wheel_path}") exit(1) - if args.wheel_path[-1] == "/": - args.wheel_path = args.wheel_path[:-1] - wheel_url = f"{args.wheel_path}/{wheel_name}" + if wheel_path[-1] == "/": + wheel_path = wheel_path[:-1] + return f"{wheel_path}/{wheel_name}" + + +def download_wheel(args): + wheel_url = get_wheel_url(args.wheel_path) subprocess.check_call("rm *.whl || true", shell=True) subprocess.check_call(f"apt-get install -y wget && wget -q {wheel_url}", shell=True) @@ -168,15 +177,7 @@ def create_link_for_models(): os.symlink(src, dst, target_is_directory=True) -def test_pip_install(): - parser = argparse.ArgumentParser(description="Check Pip Install") - parser.add_argument("--wheel_path", - type=str, - required=False, - default="Default", - help="The wheel path") - args = parser.parse_args() - +def test_pip_install(args): print("########## Install required system libs ##########") if not os.path.exists("/usr/local/mpi/bin/mpicc"): subprocess.check_call("apt-get -y install libopenmpi-dev", shell=True) @@ -205,5 +206,66 @@ def test_pip_install(): "python3 ../../examples/llm-api/quickstart_example.py", shell=True) +def test_python_builds(args): + """Test Python builds using precompiled wheel. + + This test verifies the TRTLLM_PRECOMPILED_LOCATION workflow: + 1. Use precompiled wheel URL to extract C++ bindings + 2. Build Python-only wheel (editable install) + 3. Verify installation works correctly + 4. Run quickstart example + """ + print("########## Python Builds Test ##########") + + wheel_url = get_wheel_url(args.wheel_path) + print(f"Using precompiled wheel: {wheel_url}") + + repo_root = os.path.abspath( + os.path.join(os.path.dirname(__file__), "..", "..")) + print(f"Repository root: {repo_root}") + + # Uninstall existing tensorrt_llm to test fresh editable install + subprocess.run("pip3 uninstall -y tensorrt_llm || true", + shell=True, + check=False) + + print("########## Install with TRTLLM_PRECOMPILED_LOCATION ##########") + env = os.environ.copy() + env["TRTLLM_PRECOMPILED_LOCATION"] = wheel_url + + subprocess.check_call(["pip3", "install", "-e", ".", "-v"], + cwd=repo_root, + env=env) + + print("########## Verify installation ##########") + subprocess.check_call( + 'python3 -c "import tensorrt_llm; print(tensorrt_llm.__version__)"', + shell=True) + + print("########## Verify C++ extension files ##########") + subprocess.check_call([ + "python3", "-m", "pytest", "-v", + "tests/unittest/utils/test_prebuilt_whl_cpp_extensions.py" + ], + cwd=repo_root) + + print("########## Create link for models ##########") + create_link_for_models() + + print("########## Test quickstart example ##########") + subprocess.check_call( + f"python3 {repo_root}/examples/llm-api/quickstart_example.py", + shell=True) + + if __name__ == "__main__": - test_pip_install() + parser = argparse.ArgumentParser(description="Check Pip Install") + parser.add_argument("--wheel_path", + type=str, + required=False, + default="Default", + help="The wheel path") + args = parser.parse_args() + + test_pip_install(args) + test_python_builds(args) From ce77c5276a494f2949bcf97d12e6266281a103dc Mon Sep 17 00:00:00 2001 From: Jie Li Date: Wed, 24 Dec 2025 12:40:08 +0800 Subject: [PATCH 2/5] update sanity check in python builds Signed-off-by: Jie Li --- tests/unittest/test_pip_install.py | 55 +++++++++++------------------- 1 file changed, 20 insertions(+), 35 deletions(-) diff --git a/tests/unittest/test_pip_install.py b/tests/unittest/test_pip_install.py index d292c99589..f343c0b385 100644 --- a/tests/unittest/test_pip_install.py +++ b/tests/unittest/test_pip_install.py @@ -177,6 +177,23 @@ def create_link_for_models(): os.symlink(src, dst, target_is_directory=True) +def run_sanity_check(examples_path="../../examples"): + """Run sanity checks after installation.""" + print("########## Test import tensorrt_llm ##########") + subprocess.check_call( + 'python3 -c "import tensorrt_llm; print(tensorrt_llm.__version__)"', + shell=True) + print("########## Verify license files ##########") + verify_license_files() + + print("########## Create link for models ##########") + create_link_for_models() + + print("########## Test quickstart example ##########") + subprocess.check_call( + f"python3 {examples_path}/llm-api/quickstart_example.py", shell=True) + + def test_pip_install(args): print("########## Install required system libs ##########") if not os.path.exists("/usr/local/mpi/bin/mpicc"): @@ -191,19 +208,7 @@ def test_pip_install(args): download_wheel(args) install_tensorrt_llm() - print("########## Test import tensorrt_llm ##########") - subprocess.check_call( - 'python3 -c "import tensorrt_llm; print(tensorrt_llm.__version__)"', - shell=True) - print("########## Verify license files ##########") - verify_license_files() - - print("########## Create link for models ##########") - create_link_for_models() - - print("########## Test quickstart example ##########") - subprocess.check_call( - "python3 ../../examples/llm-api/quickstart_example.py", shell=True) + run_sanity_check() def test_python_builds(args): @@ -236,34 +241,14 @@ def test_python_builds(args): subprocess.check_call(["pip3", "install", "-e", ".", "-v"], cwd=repo_root, env=env) - - print("########## Verify installation ##########") - subprocess.check_call( - 'python3 -c "import tensorrt_llm; print(tensorrt_llm.__version__)"', - shell=True) - - print("########## Verify C++ extension files ##########") - subprocess.check_call([ - "python3", "-m", "pytest", "-v", - "tests/unittest/utils/test_prebuilt_whl_cpp_extensions.py" - ], - cwd=repo_root) - - print("########## Create link for models ##########") - create_link_for_models() - - print("########## Test quickstart example ##########") - subprocess.check_call( - f"python3 {repo_root}/examples/llm-api/quickstart_example.py", - shell=True) + run_sanity_check(examples_path=f"{repo_root}/examples") if __name__ == "__main__": parser = argparse.ArgumentParser(description="Check Pip Install") parser.add_argument("--wheel_path", type=str, - required=False, - default="Default", + required=True, help="The wheel path") args = parser.parse_args() From 3d43be8161cf59631e5e2c55584ddeb76f02681a Mon Sep 17 00:00:00 2001 From: Jie Li Date: Thu, 25 Dec 2025 12:07:15 +0800 Subject: [PATCH 3/5] Fix: swap test order to preserve wheel installation for CI Signed-off-by: Jie Li --- tests/unittest/test_pip_install.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/unittest/test_pip_install.py b/tests/unittest/test_pip_install.py index f343c0b385..327aec92c5 100644 --- a/tests/unittest/test_pip_install.py +++ b/tests/unittest/test_pip_install.py @@ -252,5 +252,6 @@ if __name__ == "__main__": help="The wheel path") args = parser.parse_args() - test_pip_install(args) + # Run python_builds first (sanity check), then pip_install last test_python_builds(args) + test_pip_install(args) From d57d525d7c7aad87d4913dc45167ca4a976bc2d9 Mon Sep 17 00:00:00 2001 From: Jie Li Date: Thu, 25 Dec 2025 13:47:12 +0800 Subject: [PATCH 4/5] keep python builds as sanity check Signed-off-by: Jie Li --- tests/unittest/test_pip_install.py | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/tests/unittest/test_pip_install.py b/tests/unittest/test_pip_install.py index 327aec92c5..9394f0bf00 100644 --- a/tests/unittest/test_pip_install.py +++ b/tests/unittest/test_pip_install.py @@ -194,7 +194,8 @@ def run_sanity_check(examples_path="../../examples"): f"python3 {examples_path}/llm-api/quickstart_example.py", shell=True) -def test_pip_install(args): +def install_system_libs(): + """Install required system libraries for tensorrt_llm.""" print("########## Install required system libs ##########") if not os.path.exists("/usr/local/mpi/bin/mpicc"): subprocess.check_call("apt-get -y install libopenmpi-dev", shell=True) @@ -205,6 +206,10 @@ def test_pip_install(args): subprocess.check_call("pip3 install --upgrade setuptools || true", shell=True) + +def test_pip_install(args): + install_system_libs() + download_wheel(args) install_tensorrt_llm() @@ -212,16 +217,20 @@ def test_pip_install(args): def test_python_builds(args): - """Test Python builds using precompiled wheel. + """Test Python builds using precompiled wheel (sanity check only). This test verifies the TRTLLM_PRECOMPILED_LOCATION workflow: - 1. Use precompiled wheel URL to extract C++ bindings - 2. Build Python-only wheel (editable install) - 3. Verify installation works correctly - 4. Run quickstart example + 1. Install required system libs + 2. Use precompiled wheel URL to extract C++ bindings + 3. Build Python-only wheel (editable install) + 4. Verify installation works correctly + 5. Run quickstart example + 6. Clean up editable install to leave env in clean state """ print("########## Python Builds Test ##########") + install_system_libs() + wheel_url = get_wheel_url(args.wheel_path) print(f"Using precompiled wheel: {wheel_url}") @@ -243,6 +252,12 @@ def test_python_builds(args): env=env) run_sanity_check(examples_path=f"{repo_root}/examples") + # Clean up: uninstall editable install to leave env in clean state + print("########## Clean up editable install ##########") + subprocess.run("pip3 uninstall -y tensorrt_llm || true", + shell=True, + check=False) + if __name__ == "__main__": parser = argparse.ArgumentParser(description="Check Pip Install") @@ -251,7 +266,5 @@ if __name__ == "__main__": required=True, help="The wheel path") args = parser.parse_args() - - # Run python_builds first (sanity check), then pip_install last test_python_builds(args) test_pip_install(args) From 467cdc3e7ed99903a9b8bc581c272e40cca4f00e Mon Sep 17 00:00:00 2001 From: Jie Li Date: Thu, 25 Dec 2025 15:51:43 +0800 Subject: [PATCH 5/5] update python builds with --no-deps Signed-off-by: Jie Li --- tests/unittest/test_pip_install.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/unittest/test_pip_install.py b/tests/unittest/test_pip_install.py index 9394f0bf00..e0e2599eb0 100644 --- a/tests/unittest/test_pip_install.py +++ b/tests/unittest/test_pip_install.py @@ -222,7 +222,7 @@ def test_python_builds(args): This test verifies the TRTLLM_PRECOMPILED_LOCATION workflow: 1. Install required system libs 2. Use precompiled wheel URL to extract C++ bindings - 3. Build Python-only wheel (editable install) + 3. Build Python-only wheel (editable install with --no-deps) 4. Verify installation works correctly 5. Run quickstart example 6. Clean up editable install to leave env in clean state @@ -247,7 +247,8 @@ def test_python_builds(args): env = os.environ.copy() env["TRTLLM_PRECOMPILED_LOCATION"] = wheel_url - subprocess.check_call(["pip3", "install", "-e", ".", "-v"], + # Use --no-deps to avoid changing torch/torchvision versions. + subprocess.check_call(["pip3", "install", "-e", ".", "--no-deps", "-v"], cwd=repo_root, env=env) run_sanity_check(examples_path=f"{repo_root}/examples")