This is an automated email from the ASF dual-hosted git repository. tqchen pushed a commit to branch tvm-further-cleanup-python-tests-followup in repository https://gitbox.apache.org/repos/asf/tvm.git
commit 847a618c9d7e7e359157faebdd5ef05b85dc8e6e Author: Tianqi Chen <[email protected]> AuthorDate: Sun Jul 5 15:17:37 2026 +0000 [CI] Simplify Python test execution Run the regular Python suite from its canonical test root while preserving load-group scheduling for fixture ordering. Keep test-only pytest hooks local, move NNAPI tests under the nightly tree, and remove inert launchers and stale platform exclusions. --- ci/jenkins/generated/gpu_jenkinsfile.groovy | 4 - ci/jenkins/templates/gpu_jenkinsfile.groovy.j2 | 4 - conftest.py | 32 ------- docs/contribute/code_guide.rst | 5 +- docs/contribute/pull_request.rst | 2 +- docs/contribute/testing.rst | 4 +- python/tvm/testing/plugin.py | 104 --------------------- python/tvm/testing/utils.py | 12 +-- .../python}/test_nnapi/__init__.py | 0 .../python}/test_nnapi/conftest.py | 0 .../python}/test_nnapi/infrastructure.py | 0 .../test_nnapi/test_from_exported_to_cuda.py | 0 .../python}/test_nnapi/test_network.py | 0 .../python}/test_nnapi/test_ops.py | 0 tests/python/conftest.py | 60 +++++++++--- tests/python/disco/test_ccl.py | 3 + tests/python/disco/test_custom_allreduce.py | 3 +- .../request_hook => python}/request_hook.py | 2 +- tests/python/tirx/conftest.py | 6 +- tests/scripts/ci.py | 5 - tests/scripts/task_clear_pytest.sh | 22 ----- tests/scripts/task_python_integration.sh | 32 ------- tests/scripts/task_python_integration_gpuonly.sh | 27 ------ tests/scripts/task_python_unittest.sh | 51 +--------- tests/scripts/task_python_unittest_gpuonly.sh | 8 +- 25 files changed, 76 insertions(+), 310 deletions(-) diff --git a/ci/jenkins/generated/gpu_jenkinsfile.groovy b/ci/jenkins/generated/gpu_jenkinsfile.groovy index 8624efbea8..e7ce14c4ba 100644 --- a/ci/jenkins/generated/gpu_jenkinsfile.groovy +++ b/ci/jenkins/generated/gpu_jenkinsfile.groovy @@ -530,10 +530,6 @@ def run_unittest_GPU(node_type) { script: "${docker_run} ${ci_gpu} ./tests/scripts/task_python_unittest_gpuonly.sh", label: 'Run Python GPU unit tests', ) - sh ( - script: "${docker_run} ${ci_gpu} ./tests/scripts/task_python_integration_gpuonly.sh", - label: 'Run Python GPU integration tests', - ) }) } } diff --git a/ci/jenkins/templates/gpu_jenkinsfile.groovy.j2 b/ci/jenkins/templates/gpu_jenkinsfile.groovy.j2 index b05e84c7e7..4553fbefa2 100644 --- a/ci/jenkins/templates/gpu_jenkinsfile.groovy.j2 +++ b/ci/jenkins/templates/gpu_jenkinsfile.groovy.j2 @@ -53,10 +53,6 @@ script: "${docker_run} ${ci_gpu} ./tests/scripts/task_python_unittest_gpuonly.sh", label: 'Run Python GPU unit tests', ) - sh ( - script: "${docker_run} ${ci_gpu} ./tests/scripts/task_python_integration_gpuonly.sh", - label: 'Run Python GPU integration tests', - ) {% endcall %} diff --git a/conftest.py b/conftest.py deleted file mode 100644 index dd294ea548..0000000000 --- a/conftest.py +++ /dev/null @@ -1,32 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -import os -import sys -from pathlib import Path - -pytest_plugins = ["tvm.testing.plugin"] -IS_IN_CI = os.getenv("CI", "") == "true" -REPO_ROOT = Path(__file__).resolve().parent - - -def pytest_sessionstart(): - if IS_IN_CI: - hook_script_dir = REPO_ROOT / "tests" / "scripts" / "request_hook" - sys.path.append(str(hook_script_dir)) - import request_hook # pylint: disable=import-outside-toplevel - - request_hook.init() diff --git a/docs/contribute/code_guide.rst b/docs/contribute/code_guide.rst index 1622af120c..5136b9d4d6 100644 --- a/docs/contribute/code_guide.rst +++ b/docs/contribute/code_guide.rst @@ -127,7 +127,8 @@ Python Code Styles Writing Python Tests -------------------- -We use `pytest <https://docs.pytest.org/en/stable/>`_ for all python testing. ``tests/python`` contains all the tests. +We use `pytest <https://docs.pytest.org/en/stable/>`_ for all Python testing. Regular tests live +under ``tests/python``, while environment-specific nightly tests live under ``tests/nightly/python``. See :doc:`testing` for details on running tests, target parametrization, and the target-specific marks used by CI. @@ -162,7 +163,7 @@ server can go down or be slow), so try to avoid using the network at all during this isn't a reasonable proposition (e.g. the docs tutorials which need to download models). New network downloads are rejected by the CI `request hook -<https://github.com/apache/tvm/blob/main/tests/scripts/request_hook/request_hook.py>`_. Prefer +<https://github.com/apache/tvm/blob/main/tests/python/request_hook.py>`_. Prefer checked-in fixtures or generated data. If a download is unavoidable, arrange a stable project-managed mirror with the maintainers and add an explicit ``URL_MAP`` entry. diff --git a/docs/contribute/pull_request.rst b/docs/contribute/pull_request.rst index a6c41b755f..969bb6f7d8 100644 --- a/docs/contribute/pull_request.rst +++ b/docs/contribute/pull_request.rst @@ -251,7 +251,7 @@ If you want to run all tests: # build tvm (see install-from-source for CMake build instructions) cd build && cmake .. && cmake --build . --parallel $(nproc) && cd .. - ./tests/scripts/task_python_unittest.sh + python -m pytest -vvs -n auto --dist=loadgroup tests/python If you want to run a single test: diff --git a/docs/contribute/testing.rst b/docs/contribute/testing.rst index 74a308945a..f30fd7d03b 100644 --- a/docs/contribute/testing.rst +++ b/docs/contribute/testing.rst @@ -299,8 +299,8 @@ in which stages. - Which tests run - The ``Unit Test`` and ``Integration Test`` stages of the Jenkinsfile - determine how ``pytest`` is called. Each task starts by unpacking a + The ``Unit Test`` stage of the Jenkinsfile determines how ``pytest`` + is called. Each task starts by unpacking a compiled library that was previous compiled in the ``BUILD`` stage, then runs a test script (e.g. ``tests/scripts/task_python_unittest.sh``). These scripts set diff --git a/python/tvm/testing/plugin.py b/python/tvm/testing/plugin.py deleted file mode 100644 index 2869664842..0000000000 --- a/python/tvm/testing/plugin.py +++ /dev/null @@ -1,104 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# pylint: disable=unused-argument - -"""Pytest plugin for using tvm testing extensions. - -TVM provides utilities for testing across all supported targets, and -to more easily parametrize across many inputs. For more information -on usage of these features, see documentation in the tvm.testing -module. - -These are enabled by default in all pytests provided by tvm, but may -be useful externally for one-off testing. To enable, add the -following line to the test script, or to the conftest.py in the same -directory as the test scripts. - - pytest_plugins = ['tvm.testing.plugin'] - -""" - -import _pytest - - -def pytest_collection_modifyitems(config, items): - """Called after all tests are chosen, currently used for bookkeeping.""" - # pylint: disable=unused-argument - _count_num_fixture_uses(items) - _remove_global_fixture_definitions(items) - _sort_tests(items) - - -def _count_num_fixture_uses(items): - # Helper function, counts the number of tests that use each cached - # fixture. Should be called from pytest_collection_modifyitems(). - for item in items: - is_skipped = item.get_closest_marker("skip") or any( - mark.args[0] for mark in item.iter_markers("skipif") - ) - if is_skipped: - continue - - for fixturedefs in item._fixtureinfo.name2fixturedefs.values(): - # Only increment the active fixturedef, in a name has been overridden. - fixturedef = fixturedefs[-1] - if hasattr(fixturedef.func, "num_tests_use_this_fixture"): - fixturedef.func.num_tests_use_this_fixture[0] += 1 - - -def _remove_global_fixture_definitions(items): - # Helper function, removes fixture definitions from the global - # variables of the modules they were defined in. This is intended - # to improve readability of error messages by giving a NameError - # if a test function accesses a pytest fixture but doesn't include - # it as an argument. Should be called from - # pytest_collection_modifyitems(). - - modules = set(item.module for item in items) - - for module in modules: - for name in dir(module): - obj = getattr(module, name) - if hasattr(obj, "_pytestfixturefunction") and isinstance( - obj._pytestfixturefunction, _pytest.fixtures.FixtureFunctionMarker - ): - delattr(module, name) - - -def _sort_tests(items): - """Sort tests by file/function. - - By default, pytest will sort tests to maximize the re-use of - fixtures. However, this assumes that all fixtures have an equal - cost to generate, and no caches outside of those managed by - pytest. A tvm.testing.parameter is effectively free, while - reference data for testing may be quite large. Since most of the - TVM fixtures are specific to a python function, sort the test - ordering by python function, so that - tvm.testing.utils._fixture_cache can be cleared sooner rather than - later. - - Should be called from pytest_collection_modifyitems. - - """ - - def sort_key(item): - filename, lineno, test_name = item.location - test_name = test_name.split("[")[0] - return filename, lineno, test_name - - items.sort(key=sort_key) diff --git a/python/tvm/testing/utils.py b/python/tvm/testing/utils.py index 6b1c02b01e..2e1e04a7f0 100644 --- a/python/tvm/testing/utils.py +++ b/python/tvm/testing/utils.py @@ -824,9 +824,8 @@ def _fixture_cache(func): if num_tests_use_this_fixture[0] == 0: raise RuntimeError( "Fixture use count is 0. " - "This can occur if tvm.testing.plugin isn't registered. " - "If using outside of the TVM test directory, " - "please add `pytest_plugins = ['tvm.testing.plugin']` to your conftest.py" + "Cached tvm.testing fixtures must be collected from tests/python " + "so its conftest can count fixture uses." ) try: @@ -925,9 +924,10 @@ def install_request_hook(depth: int) -> None: depth -= 1 # Ensure the specified dir is valid - hook_script_dir = hook_script_dir / "tests" / "scripts" / "request_hook" - if not hook_script_dir.exists(): - raise RuntimeError(f"Directory {hook_script_dir} does not exist:\n{msg}") + hook_script_dir = hook_script_dir / "tests" / "python" + hook_script = hook_script_dir / "request_hook.py" + if not hook_script.is_file(): + raise RuntimeError(f"File {hook_script} does not exist:\n{msg}") # Import the hook and start it up (it's not included here directly to avoid # keeping a database of URLs inside the tvm Python package diff --git a/tests/python/nightly/test_nnapi/__init__.py b/tests/nightly/python/test_nnapi/__init__.py similarity index 100% rename from tests/python/nightly/test_nnapi/__init__.py rename to tests/nightly/python/test_nnapi/__init__.py diff --git a/tests/python/nightly/test_nnapi/conftest.py b/tests/nightly/python/test_nnapi/conftest.py similarity index 100% rename from tests/python/nightly/test_nnapi/conftest.py rename to tests/nightly/python/test_nnapi/conftest.py diff --git a/tests/python/nightly/test_nnapi/infrastructure.py b/tests/nightly/python/test_nnapi/infrastructure.py similarity index 100% rename from tests/python/nightly/test_nnapi/infrastructure.py rename to tests/nightly/python/test_nnapi/infrastructure.py diff --git a/tests/python/nightly/test_nnapi/test_from_exported_to_cuda.py b/tests/nightly/python/test_nnapi/test_from_exported_to_cuda.py similarity index 100% rename from tests/python/nightly/test_nnapi/test_from_exported_to_cuda.py rename to tests/nightly/python/test_nnapi/test_from_exported_to_cuda.py diff --git a/tests/python/nightly/test_nnapi/test_network.py b/tests/nightly/python/test_nnapi/test_network.py similarity index 100% rename from tests/python/nightly/test_nnapi/test_network.py rename to tests/nightly/python/test_nnapi/test_network.py diff --git a/tests/python/nightly/test_nnapi/test_ops.py b/tests/nightly/python/test_nnapi/test_ops.py similarity index 100% rename from tests/python/nightly/test_nnapi/test_ops.py rename to tests/nightly/python/test_nnapi/test_ops.py diff --git a/tests/python/conftest.py b/tests/python/conftest.py index 5d55ba5c6a..bf105ae97c 100644 --- a/tests/python/conftest.py +++ b/tests/python/conftest.py @@ -14,17 +14,55 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -"""Configure pytest""" +"""Configure pytest for TVM's Python test suite.""" -import sys +import os -COLLECT_IGNORE = [] -if sys.platform.startswith("win"): - COLLECT_IGNORE.append("frontend/coreml") - COLLECT_IGNORE.append("frontend/keras") - COLLECT_IGNORE.append("frontend/pytorch") - COLLECT_IGNORE.append("frontend/tensorflow") - COLLECT_IGNORE.append("frontend/tflite") - COLLECT_IGNORE.append("frontend/onnx") +import _pytest - COLLECT_IGNORE.append("tir_base/test_tir_intrin.py") + +def pytest_collection_modifyitems(items): + """Maintain the ordering and cache bookkeeping required by TVM fixtures.""" + _count_num_fixture_uses(items) + _remove_global_fixture_definitions(items) + _sort_tests(items) + + +def _count_num_fixture_uses(items): + for item in items: + is_skipped = item.get_closest_marker("skip") or any( + mark.args[0] for mark in item.iter_markers("skipif") + ) + if is_skipped: + continue + + for fixturedefs in item._fixtureinfo.name2fixturedefs.values(): + fixturedef = fixturedefs[-1] + if hasattr(fixturedef.func, "num_tests_use_this_fixture"): + fixturedef.func.num_tests_use_this_fixture[0] += 1 + + +def _remove_global_fixture_definitions(items): + modules = {item.module for item in items} + for module in modules: + for name in dir(module): + obj = getattr(module, name) + if hasattr(obj, "_pytestfixturefunction") and isinstance( + obj._pytestfixturefunction, _pytest.fixtures.FixtureFunctionMarker + ): + delattr(module, name) + + +def _sort_tests(items): + def sort_key(item): + filename, lineno, test_name = item.location + return filename, lineno, test_name.split("[")[0] + + items.sort(key=sort_key) + + +def pytest_sessionstart(): + if os.getenv("CI", "") == "true": + from request_hook import init # pylint: disable=import-outside-toplevel + + init() diff --git a/tests/python/disco/test_ccl.py b/tests/python/disco/test_ccl.py index 29d46d4ec1..82dbc27ab7 100644 --- a/tests/python/disco/test_ccl.py +++ b/tests/python/disco/test_ccl.py @@ -31,6 +31,9 @@ from tvm.runtime.vm import VirtualMachine from tvm.s_tir import dlight as dl from tvm.script import relax as R +if di is None: + pytest.skip("disco runtime is not available", allow_module_level=True) + _all_session_kinds = [di.ThreadedSession, di.ProcessSession] _compiled_ccl = get_global_func("runtime.disco.compiled_ccl", allow_missing=True) if _compiled_ccl is None: diff --git a/tests/python/disco/test_custom_allreduce.py b/tests/python/disco/test_custom_allreduce.py index f49da02836..6728e3115d 100644 --- a/tests/python/disco/test_custom_allreduce.py +++ b/tests/python/disco/test_custom_allreduce.py @@ -26,7 +26,6 @@ from tvm_ffi import Shape import tvm import tvm.testing from tvm.runtime import DataType, disco -from tvm.runtime.disco import Session class AllReduceStrategyType(enum.IntEnum): @@ -56,7 +55,7 @@ _ccl = [ccl for ccl in _compiled_ccl() if ccl == "nccl"] @pytest.mark.parametrize("strategy", _strategies) def test_allreduce(shape, ccl, strategy): devices = [0, 1] - sess: Session = disco.ProcessSession(num_workers=len(devices)) + sess: disco.Session = disco.ProcessSession(num_workers=len(devices)) sess.init_ccl(ccl, *devices) num_elements = reduce(lambda x, y: x * y, shape) diff --git a/tests/scripts/request_hook/request_hook.py b/tests/python/request_hook.py similarity index 95% rename from tests/scripts/request_hook/request_hook.py rename to tests/python/request_hook.py index 48ac5e2a30..5a00a11cdd 100644 --- a/tests/scripts/request_hook/request_hook.py +++ b/tests/python/request_hook.py @@ -35,7 +35,7 @@ class TvmRequestHook(urllib.request.Request): msg = ( f"Uncaught URL found in CI: {url}. " "Avoid network access or arrange a stable project-managed mirror, " - "then add it to URL_MAP in tests/scripts/request_hook/request_hook.py." + "then add it to URL_MAP in tests/python/request_hook.py." ) raise RuntimeError(msg) diff --git a/tests/python/tirx/conftest.py b/tests/python/tirx/conftest.py index fb8ba62f4f..c2a7a28d28 100644 --- a/tests/python/tirx/conftest.py +++ b/tests/python/tirx/conftest.py @@ -25,6 +25,8 @@ real sm_100a device so it skips cleanly where the hardware is absent and runs in full where it is present. """ +from pathlib import Path + import pytest from tvm.testing import env @@ -33,8 +35,10 @@ from tvm.testing import env def pytest_collection_modifyitems(config, items): if env.has_cuda_compute(10): return + suite_root = Path(__file__).parent skip = pytest.mark.skip( reason="tirx suite requires a CUDA compute capability 10.0 (sm_100a) device" ) for item in items: - item.add_marker(skip) + if item.path.is_relative_to(suite_root): + item.add_marker(skip) diff --git a/tests/scripts/ci.py b/tests/scripts/ci.py index bea70e0b52..fa027c150a 100755 --- a/tests/scripts/ci.py +++ b/tests/scripts/ci.py @@ -591,7 +591,6 @@ generated = [ [ "./tests/scripts/task_java_unittest.sh", "./tests/scripts/task_python_unittest_gpuonly.sh", - "./tests/scripts/task_python_integration_gpuonly.sh", ], ), }, @@ -601,10 +600,6 @@ generated = [ help="Run CPU build and test(s)", options={ "cpp": CPP_UNITTEST, - "integration": ( - "run integration tests", - ["./tests/scripts/task_python_integration.sh"], - ), "unittest": ( "run unit tests", [ diff --git a/tests/scripts/task_clear_pytest.sh b/tests/scripts/task_clear_pytest.sh deleted file mode 100755 index 430425791c..0000000000 --- a/tests/scripts/task_clear_pytest.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -set -euo pipefail - -# PR jobs evaluate their Jenkinsfile from the trusted base branch. Keep this -# inert entry point until the Jenkinsfile update has landed on the base branch. diff --git a/tests/scripts/task_python_integration.sh b/tests/scripts/task_python_integration.sh deleted file mode 100755 index 7dd3c9b578..0000000000 --- a/tests/scripts/task_python_integration.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env bash -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -set -euxo pipefail - -export PYTHONPATH="$(pwd)/python" -export LD_LIBRARY_PATH="build:${LD_LIBRARY_PATH:-}" - -# to avoid CI CPU thread throttling. -export TVM_BIND_THREADS=0 -export TVM_NUM_THREADS=2 - -# cleanup pycache -find . -type f -path "*.pyc" | xargs rm -f - -# setup tvm-ffi into python folder -uv pip install -v --target=python ./3rdparty/tvm-ffi/ diff --git a/tests/scripts/task_python_integration_gpuonly.sh b/tests/scripts/task_python_integration_gpuonly.sh deleted file mode 100755 index 9b825b9182..0000000000 --- a/tests/scripts/task_python_integration_gpuonly.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -set -exo pipefail - -export TVM_TEST_TARGETS='cuda;opencl;metal;rocm;nvptx;{"kind":"opencl","device":"mali,adreno"}' -# Every GPU test carries the `gpu` marker; the specific backend is gated by skipif. -export PYTEST_ADDOPTS="-m gpu $PYTEST_ADDOPTS" -export TVM_RELAY_TEST_TARGETS="cuda" -export TVM_INTEGRATION_GPU_ONLY=1 - -./tests/scripts/task_python_integration.sh diff --git a/tests/scripts/task_python_unittest.sh b/tests/scripts/task_python_unittest.sh index 0728743fb5..1cf297fc28 100755 --- a/tests/scripts/task_python_unittest.sh +++ b/tests/scripts/task_python_unittest.sh @@ -19,55 +19,10 @@ set -euxo pipefail export PYTHONPATH="$(pwd)/python" -export PYTEST_ADDOPTS="-s -vv ${CI_PYTEST_ADD_OPTIONS:-} ${PYTEST_ADDOPTS:-}" - -# cleanup pycache -find . -type f -path "*.pyc" | xargs rm -f +export PYTEST_ADDOPTS="${CI_PYTEST_ADD_OPTIONS:-} ${PYTEST_ADDOPTS:-}" # setup tvm-ffi into python folder uv pip install -v --target=python ./3rdparty/tvm-ffi/ -# First run the minimal platform test. A GPU-only run can select no tests here. -if [ ! -d tests/python/all-platform-minimal-test ]; then - echo "Missing pytest target: tests/python/all-platform-minimal-test" >&2 - exit 1 -fi -python3 -m pytest -n auto tests/python/all-platform-minimal-test || [ "$?" -eq 5 ] - -# Then run all unit tests. -TEST_FILES=( - "arith" - "ci" - "codegen" - "driver" - "ir" - "runtime" - "target" - "te" - "testing" - "s_tir/base" - "s_tir/schedule" - "s_tir/dlight" - "s_tir/analysis" - "s_tir/meta_schedule" - "s_tir/transform" - "tirx-analysis" - "tirx-base" - "tirx-transform" - "tirx" - "tvmscript" - "relax" -) - -PYTEST_TARGETS=() -for TEST_FILE in "${TEST_FILES[@]}"; do - TEST_PATH="tests/python/${TEST_FILE}" - if [ ! -e "${TEST_PATH}" ]; then - echo "Missing pytest target: ${TEST_PATH}" >&2 - exit 1 - fi - PYTEST_TARGETS+=("${TEST_PATH}") -done - -# Do not mask pytest's exit 5: an unexpectedly empty broad suite must fail CI. -python3 -m pytest -n auto --dist=loadgroup "${PYTEST_TARGETS[@]}" +# Load-group distribution keeps the order-dependent fixture tests on one worker. +python3 -m pytest -vvs -n auto --dist=loadgroup tests/python diff --git a/tests/scripts/task_python_unittest_gpuonly.sh b/tests/scripts/task_python_unittest_gpuonly.sh index 8194b23ac4..e6ac397c45 100755 --- a/tests/scripts/task_python_unittest_gpuonly.sh +++ b/tests/scripts/task_python_unittest_gpuonly.sh @@ -32,10 +32,6 @@ export TVM_TEST_TARGETS='cuda;metal;rocm;nvptx' export TVM_TEST_TARGETS='{"kind":"vulkan","from_device":0}' export PYTHONPATH="$(pwd)/python" -export PYTEST_ADDOPTS="-s -vv ${CI_PYTEST_ADD_OPTIONS:-} ${PYTEST_ADDOPTS:-}" +export PYTEST_ADDOPTS="${CI_PYTEST_ADD_OPTIONS:-} ${PYTEST_ADDOPTS:-}" -if [ ! -f tests/python/codegen/test_target_codegen_vulkan.py ]; then - echo "Missing pytest target: tests/python/codegen/test_target_codegen_vulkan.py" >&2 - exit 1 -fi -python3 -m pytest -n auto tests/python/codegen/test_target_codegen_vulkan.py +python3 -m pytest -vvs -n auto tests/python/codegen/test_target_codegen_vulkan.py
