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

guan404ming pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm.git


The following commit(s) were added to refs/heads/main by this push:
     new bbfdab79d9 [CI] Repair Python test cleanup regressions (#19955)
bbfdab79d9 is described below

commit bbfdab79d998cfc6af22b0be510c543501d447b7
Author: Tianqi Chen <[email protected]>
AuthorDate: Mon Jul 6 16:29:52 2026 +0800

    [CI] Repair Python test cleanup regressions (#19955)
    
    ## Summary
    
    - Keep the Python test launcher close to plain `pytest -n auto`, move
    nightly tests under `tests/nightly/python`, remove obsolete launchers
    and collection bookkeeping, and partition CPU/GPU jobs with explicit
    `gpu` marker expressions.
    - Repair exact-pointer regressions at their owning boundaries: packed
    raw-string ABI values, CUDA/Metal matrix intrinsic pointers, internal TE
    extern offsets, MetaSchedule scalar annotations, localized
    auto-tensorization scope matching, and typed DLTensor fixture fields.
    - Preserve typed workspace calls in TIR and cast pointer-returning
    external calls in CodeGenC, covered by a plain-TIRx 1024-byte global
    workspace that is compiled as C++.
    - Finish phasing out value-bearing Relax `R.Prim` annotations by
    requiring an explicit dtype, removing obsolete value-based contracts,
    and expressing the DISCO rank-dependent slices as explicit scalar
    `call_tir` inputs.
    - Gate the distributed callback on the optional DISCO runtime, NCCL, and
    at least two GPUs so capability-limited jobs skip instead of failing.
    - Remove the non-demonstrating pointer probe, use direct TVMScript
    comparison for packed strings, and remove the four designated legacy
    testing modules.
    
    The seven repaired CPU categories cover packed raw strings (7 failures),
    CUDA/Metal matrix access-pointer types (7), internal TE extern offsets
    (1), a typed DLTensor fixture (1), MetaSchedule scalar annotations (1),
    CodeGenC workspace return casts (12), and localized auto-tensorization
    storage-scope matching (19).
    
    ## Validation
    
    - Base: `ded6ad8dd212869c881efb5590f8a33fc972728e`
    - Head: `a7277e86dbcfe0638c8c252d36760859c4ab4297`
    - All 35 locally available original failing node IDs pass across the
    focused runs.
    - The full focused TE, TIR builtin-lowering, and CodeGenC files pass: 61
    tests.
    - The complete touched Relax/TVMScript set plus
    PlanAndUpdateBufferAllocationLocation passes with 784 passed, 20
    skipped, and 1 expected failure.
    - The DISCO callback collects and skips when its runtime or two-GPU
    environment is unavailable.
    - Six direct mapping tests, twelve tensor-core sketches, and the dp4a
    sketch pass unchanged.
    - The compiler rebuild, branch-wide pre-commit hooks, and full-range
    whitespace checks pass.
    - The 13 broad CBLAS/TFLite nodes remain dependency-gated; their owning
    TE and generated-C regressions compile.
    
    No merge is included in this change.
---
 ci/jenkins/generated/gpu_jenkinsfile.groovy        |   4 -
 ci/jenkins/templates/gpu_jenkinsfile.groovy.j2     |   4 -
 conftest.py                                        |  32 ---
 docs/conf.py                                       |   2 +-
 docs/contribute/code_guide.rst                     |   5 +-
 docs/contribute/pull_request.rst                   |   2 +-
 docs/contribute/testing.rst                        |   4 +-
 pyproject.toml                                     |   5 +-
 python/tvm/relax/script/parser/entry.py            |  22 +-
 python/tvm/s_tir/tensor_intrin/cuda.py             |   4 +-
 python/tvm/s_tir/tensor_intrin/metal.py            |   4 +-
 python/tvm/testing/plugin.py                       | 104 ----------
 python/tvm/testing/utils.py                        | 124 +++--------
 src/s_tir/meta_schedule/mutator/mutate_parallel.cc |   2 +-
 src/s_tir/schedule/ir_comparator.cc                |  18 +-
 src/target/source/codegen_c.cc                     |   9 +
 src/te/operation/create_primfunc.cc                |  11 +-
 src/tirx/op/op.cc                                  |   6 +
 src/tirx/transform/lower_tvm_builtin.cc            |   1 +
 .../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/codegen/test_target_codegen_c_host.py |  18 ++
 tests/python/conftest.py                           |  21 +-
 tests/python/disco/test_callback.py                |  69 +++++--
 tests/python/disco/test_ccl.py                     |   3 +
 tests/python/disco/test_custom_allreduce.py        |   6 +-
 tests/python/relax/test_analysis_type_analysis.py  |  50 +----
 .../relax/test_backend_transform_shape_lower.py    |  81 --------
 tests/python/relax/test_bind_params.py             |  22 +-
 tests/python/relax/test_bind_symbolic_vars.py      |  67 ------
 tests/python/relax/test_blockbuilder_core.py       |   8 +-
 tests/python/relax/test_dataflow_rewriter.py       | 149 --------------
 tests/python/relax/test_op_binary.py               |  32 ---
 .../relax/test_transform_compute_prim_value.py     |  31 ---
 .../relax/test_transform_lazy_transform_params.py  | 145 -------------
 .../relax/test_transform_lift_transform_params.py  |   4 +-
 .../test_transform_remove_unused_parameters.py     |  21 +-
 tests/python/relax/test_tvmscript_parser.py        |   8 +
 tests/python/relax/test_utils.py                   |  62 +++---
 tests/python/relax/test_vm_build.py                |  94 ---------
 .../request_hook => python}/request_hook.py        |   4 +-
 ...sform_plan_update_buffer_allocation_location.py |   8 +-
 tests/python/te/test_te_create_primfunc.py         |  37 ++++
 tests/python/testing/test_testing.py               | 116 -----------
 .../testing/test_tvm_testing_before_after.py       | 147 -------------
 tests/python/testing/test_tvm_testing_features.py  | 192 -----------------
 .../python/testing/test_type_annotation_checker.py | 227 ---------------------
 .../test_tir_transform_lower_tvm_builtin.py        |  30 +++
 tests/python/tirx/conftest.py                      |  13 +-
 tests/python/tvmscript/test_tvmscript_roundtrip.py |  10 +-
 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              |  50 +----
 tests/scripts/task_python_unittest_gpuonly.sh      |  11 +-
 60 files changed, 339 insertions(+), 1846 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/conf.py b/docs/conf.py
index 24f43e1eb6..c226de1c40 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -215,7 +215,7 @@ def rst2md(text, gallery_conf, target_dir, heading_levels, 
real_func):
 
 
 def install_request_hook(gallery_conf, fname):
-    testing.utils.install_request_hook(depth=3)
+    testing.utils.install_request_hook(tvm_path.resolve() / "tests" / "python" 
/ "request_hook.py")
 
 
 INSTALL_TVM_DEV = """\
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..9150838e76 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 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/pyproject.toml b/pyproject.toml
index 2c38d1f9d8..a4f80182cf 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -167,10 +167,7 @@ addopts = "-v --tb=short"
 python_files = ["test_*.py", "*_test.py"]
 python_classes = ["Test*"]
 python_functions = ["test_*"]
-markers = [
-  "gpu: Mark a test as requiring a GPU",
-  "xdist_group(name): Run related tests in one pytest-xdist load group",
-]
+markers = ["gpu: Mark a test as requiring a GPU"]
 
 [tool.ruff]
 include = [
diff --git a/python/tvm/relax/script/parser/entry.py 
b/python/tvm/relax/script/parser/entry.py
index 1812a1102e..20605840f6 100644
--- a/python/tvm/relax/script/parser/entry.py
+++ b/python/tvm/relax/script/parser/entry.py
@@ -449,32 +449,21 @@ def Shape(values: list[Expr] | None = None, ndim: int = 
-1) -> ShapeProxy:
 
 
 class PrimProxy(TypeProxy):
-    dtype: str | None
+    dtype: str
 
     """The type of TIR-representable values.
 
     Parameters
     ----------
-    dtype : Optional[str]
+    dtype : str
        The data type.
 
     """
 
     def __init__(
         self,
-        dtype: str | None = None,
-        value: int | float | str | Expr | None = None,
+        dtype: str,
     ) -> None:
-        if dtype is None:
-            if tvm.ir.is_prim_expr(value):
-                dtype = str(value.ty)
-            elif isinstance(value, float):
-                dtype = "float32"
-            elif value is not None:
-                dtype = "int64"
-            else:
-                raise TypeError("R.Prim missing required argument 'dtype'")
-
         self.dtype = dtype
 
     def get_symbolic_vars(self) -> set[str]:
@@ -485,10 +474,9 @@ class PrimProxy(TypeProxy):
 
 
 def Prim(
-    dtype: str | None = None,
-    value: int | float | str | Expr | None = None,
+    dtype: str,
 ) -> PrimProxy:
-    return PrimProxy(dtype, value)
+    return PrimProxy(dtype)
 
 
 ############################ R.match_cast #############################
diff --git a/python/tvm/s_tir/tensor_intrin/cuda.py 
b/python/tvm/s_tir/tensor_intrin/cuda.py
index 8c28fd7ddf..701ac5e4a3 100644
--- a/python/tvm/s_tir/tensor_intrin/cuda.py
+++ b/python/tvm/s_tir/tensor_intrin/cuda.py
@@ -889,7 +889,7 @@ def get_wmma_load_intrin(
                     n_dim,
                     k_dim,
                     get_wmma_fragment_index(C, d1, frag_m, frag_n),
-                    A.access_ptr("r"),
+                    A.access_ptr("r", ptr_type=dtype),
                     s1,
                     layout,
                     dtype="void",
@@ -1016,7 +1016,7 @@ def get_wmma_store_intrin(
                     n_dim,
                     k_dim,
                     get_wmma_fragment_index(A, d1, m_dim, n_dim),
-                    C.access_ptr("w"),
+                    C.access_ptr("w", ptr_type=dtype),
                     s1,
                     "row_major",
                     dtype="void",
diff --git a/python/tvm/s_tir/tensor_intrin/metal.py 
b/python/tvm/s_tir/tensor_intrin/metal.py
index 132906b67d..5b19793ddf 100644
--- a/python/tvm/s_tir/tensor_intrin/metal.py
+++ b/python/tvm/s_tir/tensor_intrin/metal.py
@@ -125,7 +125,7 @@ def get_simdgroup_load_intrin(
             T.metal.simdgroup_load(
                 C.data,
                 index=get_simdgroup_index(C, d1, col, row),
-                ptr=A.access_ptr("r"),
+                ptr=A.access_ptr("r", ptr_type=dtype),
                 stride=s1,
                 col=col,
                 row=row,
@@ -182,7 +182,7 @@ def get_simdgroup_store_intrin(
             T.metal.simdgroup_store(
                 A.data,
                 index=get_simdgroup_index(A, s1, col, row),
-                ptr=C.access_ptr("w"),
+                ptr=C.access_ptr("w", ptr_type=dtype),
                 stride=d1,
                 col=col,
                 row=row,
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..f41f06dc07 100644
--- a/python/tvm/testing/utils.py
+++ b/python/tvm/testing/utils.py
@@ -24,7 +24,7 @@ Organization
 
 This file contains functions expected to be called directly by a user
 while writing unit tests.  Integrations with the pytest framework
-are in plugin.py.
+for TVM's own test suite are in ``tests/python/conftest.py``.
 
 Testing Markers
 ***************
@@ -73,6 +73,7 @@ import logging
 import os
 import pickle
 import platform
+import runpy
 import sys
 import time
 from pathlib import Path
@@ -91,6 +92,7 @@ from tvm.support import nvcc
 
 SKIP_SLOW_TESTS = os.getenv("SKIP_SLOW_TESTS", "").lower() in {"true", "1", 
"yes"}
 IS_IN_CI = os.getenv("CI", "") == "true"
+_REQUEST_HOOK_INITIALIZERS = {}
 
 skip_if_wheel_test = pytest.mark.skipif(
     os.getenv("WHEEL_TEST", "").lower() in {"true", "1", "yes"},
@@ -679,10 +681,11 @@ def fixture(func=None, *, cache_return_value=False):
     If the setup is expensive to perform, then the
     cache_return_value=True argument can be passed to cache the setup.
     The fixture function will be run only once (or once per parameter,
-    if used with tvm.testing.parameter), and the same return value
-    will be passed to all tests that use it.  If the environment
-    variable TVM_TEST_DISABLE_CACHE is set to a non-zero value, it
-    will disable this feature and no caching will be performed.
+    if used with tvm.testing.parameter).  The cached setup value is
+    retained for the lifetime of the test process, and each test receives
+    an independent copy.  If the environment variable TVM_TEST_DISABLE_CACHE
+    is set to a non-zero value, it will disable this feature and no caching
+    will be performed.
 
     Example
     -------
@@ -719,15 +722,10 @@ def fixture(func=None, *, cache_return_value=False):
     force_disable_cache = bool(int(os.environ.get("TVM_TEST_DISABLE_CACHE", 
"0")))
     cache_return_value = cache_return_value and not force_disable_cache
 
-    # Deliberately at function scope, so that caching can track how
-    # many times the fixture has been used.  If used, the cache gets
-    # cleared after the fixture is no longer needed.
-    scope = "function"
-
     def wraps(func):
         if cache_return_value:
             func = _fixture_cache(func)
-        func = pytest.fixture(func, scope=scope)
+        func = pytest.fixture(func, scope="function")
         return func
 
     if func is None:
@@ -791,13 +789,6 @@ class _DeepCopyAllowedClasses(dict):
 def _fixture_cache(func):
     cache = {}
 
-    # Can't use += on a bound method's property.  Therefore, this is a
-    # list rather than a variable so that it can be accessed from the
-    # pytest_collection_modifyitems().
-    num_tests_use_this_fixture = [0]
-
-    num_times_fixture_used = 0
-
     # Using functools.lru_cache would require the function arguments
     # to be hashable, which wouldn't allow caching fixtures that
     # depend on numpy arrays.  For example, a fixture that takes a
@@ -821,41 +812,21 @@ def _fixture_cache(func):
 
     @functools.wraps(func)
     def wrapper(*args, **kwargs):
-        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"
-            )
+        cache_key = get_cache_key(*args, **kwargs)
 
         try:
-            cache_key = get_cache_key(*args, **kwargs)
-
-            try:
-                cached_value = cache[cache_key]
-            except KeyError:
-                cached_value = cache[cache_key] = func(*args, **kwargs)
-
-            yield copy.deepcopy(
-                cached_value,
-                # allowed_class_list should be a list of classes that
-                # are safe to copy using copy.deepcopy, but do not
-                # implement __deepcopy__, __reduce__, or
-                # __reduce_ex__.
-                _DeepCopyAllowedClasses(allowed_class_list=[]),
-            )
-
-        finally:
-            # Clear the cache once all tests that use a particular fixture
-            # have completed.
-            nonlocal num_times_fixture_used
-            num_times_fixture_used += 1
-            if num_times_fixture_used >= num_tests_use_this_fixture[0]:
-                cache.clear()
-
-    # Set in the pytest_collection_modifyitems(), by _count_num_fixture_uses
-    wrapper.num_tests_use_this_fixture = num_tests_use_this_fixture
+            cached_value = cache[cache_key]
+        except KeyError:
+            cached_value = cache[cache_key] = func(*args, **kwargs)
+
+        return copy.deepcopy(
+            cached_value,
+            # allowed_class_list should be a list of classes that
+            # are safe to copy using copy.deepcopy, but do not
+            # implement __deepcopy__, __reduce__, or
+            # __reduce_ex__.
+            _DeepCopyAllowedClasses(allowed_class_list=[]),
+        )
 
     return wrapper
 
@@ -893,49 +864,22 @@ def is_ampere_or_newer():
     return major >= 8 and minor != 9
 
 
-def install_request_hook(depth: int) -> None:
-    """Add a wrapper around urllib.request for CI tests"""
+def install_request_hook(hook_script: Path) -> None:
+    """Add a wrapper around urllib.request for CI tests."""
     if not IS_IN_CI:
         return
 
-    # 
https://sphinx-gallery.github.io/stable/faq.html#why-is-file-not-defined-what-can-i-use
-    base = None
-    msg = ""
+    hook_script = Path(hook_script).resolve()
+    if not hook_script.is_file():
+        raise RuntimeError(f"Request hook {hook_script} does not exist")
+
+    # Load the exact hook file without exposing the test root as an import 
path.
+    # Cache its initializer because Sphinx invokes this once per gallery 
example.
     try:
-        base = __file__
-        msg += f"found file {__file__}\n"
-    except NameError:
-        msg += "no file\n"
-
-    if base is None:
-        hook_script_dir = Path.cwd().resolve()
-        msg += "used path.cwd()\n"
-    else:
-        hook_script_dir = Path(base).resolve().parent
-        msg += "used base()\n"
-
-    msg += f"using depth {depth}\n"
-    if depth <= 0:
-        raise ValueError(f"depth less than 1 not supported, found: {depth}")
-
-    # Go up the parent directories
-    while depth > 0:
-        msg += f"[depth={depth}] dir={hook_script_dir}\n"
-        hook_script_dir = hook_script_dir.parent
-        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}")
-
-    # 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
-    sys.path.append(str(hook_script_dir))
-    # This import is intentionally delayed since it should only happen in CI
-    import request_hook  # pylint: disable=import-outside-toplevel
-
-    request_hook.init()
+        init = _REQUEST_HOOK_INITIALIZERS[hook_script]
+    except KeyError:
+        init = _REQUEST_HOOK_INITIALIZERS[hook_script] = 
runpy.run_path(str(hook_script))["init"]
+    init()
 
 
 def strtobool(val):
diff --git a/src/s_tir/meta_schedule/mutator/mutate_parallel.cc 
b/src/s_tir/meta_schedule/mutator/mutate_parallel.cc
index a0e3639ff9..29fcc72bfd 100644
--- a/src/s_tir/meta_schedule/mutator/mutate_parallel.cc
+++ b/src/s_tir/meta_schedule/mutator/mutate_parallel.cc
@@ -248,7 +248,7 @@ bool FindParallelDecision(const Trace& trace, TRandState* 
rand_state,
       
get_sblock_insts.at(ann_inst->inputs[0].as_or_throw<s_tir::SBlockRV>().get());
   TVM_FFI_ICHECK_EQ(get_sblock_inst->attrs.size(), 2);
   candidate->inst = ffi::GetRef<Instruction>(ann_inst);
-  candidate->parallel_extent = 
ann_inst->inputs[1].as_or_throw<IntImm>()->value;
+  candidate->parallel_extent = ann_inst->inputs[1].cast<IntImm>()->value;
   candidate->block_name = get_sblock_inst->attrs[0].as_or_throw<ffi::String>();
   candidate->func_name = get_sblock_inst->attrs[1].as_or_throw<ffi::String>();
   return true;
diff --git a/src/s_tir/schedule/ir_comparator.cc 
b/src/s_tir/schedule/ir_comparator.cc
index 399fa1721d..e20bfcbf21 100644
--- a/src/s_tir/schedule/ir_comparator.cc
+++ b/src/s_tir/schedule/ir_comparator.cc
@@ -739,8 +739,22 @@ bool AutoTensorizeComparator::CompareBuffer(const Buffer& 
lhs, const Buffer& rhs
   if (it != rhs_buffer_map_.end()) {
     equal = (*it).second.same_as(lhs);
   } else {
-    // Remap both buffer itself and buffer data, skip buffer shape and scope
-    equal = DefEqual(lhs->data, rhs->data) && lhs->dtype == rhs->dtype;
+    // Remap both buffer itself and buffer data, skipping buffer shape and 
storage scope.  Auto
+    // tensorization inserts the cache stages that move workload buffers into 
an intrinsic's
+    // required scope, while the pointer element type must still agree.
+    auto data_it = equal_map_.find(lhs->data);
+    if (data_it != equal_map_.end()) {
+      equal = data_it->second.same_as(rhs->data);
+    } else {
+      const auto* lhs_ptr = lhs->data->ty.as<PointerTypeNode>();
+      const auto* rhs_ptr = rhs->data->ty.as<PointerTypeNode>();
+      equal = lhs_ptr && rhs_ptr &&
+              ffi::StructuralEqual()(lhs_ptr->element_type, 
rhs_ptr->element_type);
+      if (equal) {
+        equal_map_[lhs->data] = rhs->data;
+      }
+    }
+    equal = equal && lhs->dtype == rhs->dtype;
     if (equal) {
       rhs_buffer_map_[rhs] = lhs;
       lhs_buffer_map_[lhs] = rhs;
diff --git a/src/target/source/codegen_c.cc b/src/target/source/codegen_c.cc
index 8bf390a508..f80a95469e 100644
--- a/src/target/source/codegen_c.cc
+++ b/src/target/source/codegen_c.cc
@@ -650,6 +650,12 @@ void CodeGenC::VisitExpr_(const NotNode* op, std::ostream& 
os) {  // NOLINT(*)
 void CodeGenC::PrintCallExtern(Type ret_type, ffi::String global_symbol,
                                const ffi::Array<Expr>& args, bool 
skip_first_arg,
                                std::ostream& os) {  // NOLINT(*)
+  bool cast_pointer_return = ret_type.as<PointerTypeNode>();
+  if (cast_pointer_return) {
+    os << "((";
+    PrintType(ret_type, os);
+    os << ")";
+  }
   os << global_symbol << "(";
   for (size_t i = static_cast<size_t>(skip_first_arg); i < args.size(); ++i) {
     this->PrintExpr(args[i], os);
@@ -658,6 +664,9 @@ void CodeGenC::PrintCallExtern(Type ret_type, ffi::String 
global_symbol,
     }
   }
   os << ")";
+  if (cast_pointer_return) {
+    os << ")";
+  }
 }
 
 void CodeGenC::VisitExpr_(const CallNode* op, std::ostream& os) {  // NOLINT(*)
diff --git a/src/te/operation/create_primfunc.cc 
b/src/te/operation/create_primfunc.cc
index 3d1b0fa0d3..d64b768e0e 100644
--- a/src/te/operation/create_primfunc.cc
+++ b/src/te/operation/create_primfunc.cc
@@ -641,10 +641,17 @@ Stmt GenerateStmtFromExternOp(const te::ExternOp& 
extern_op, CreateFuncInfo* inf
   for (int i = 0; i < extern_op->num_outputs(); ++i) {
     const Buffer& placeholder = extern_op->output_placeholders[i];
     const te::Tensor& output_tensor = extern_op.output(i);
-    info->tensor2buffers[output_tensor] = placeholder;
+    Buffer output_buffer = placeholder;
     if (!info->IsArg(output_tensor)) {
-      info->root_alloc.push_back(placeholder);
+      PrimExpr zero_offset = IntImm(placeholder->elem_offset.ty(), 0);
+      if (const auto* offset_var = placeholder->elem_offset.as<VarNode>()) {
+        var_map[offset_var] = zero_offset;
+      }
+      output_buffer.CopyOnWrite()->elem_offset = zero_offset;
+      input_buffer_map[placeholder.get()] = output_buffer;
+      info->root_alloc.push_back(output_buffer);
     }
+    info->tensor2buffers[output_tensor] = output_buffer;
   }
 
   // The access region does not need to be collected here, as it will
diff --git a/src/tirx/op/op.cc b/src/tirx/op/op.cc
index 363121933f..2344ba6137 100644
--- a/src/tirx/op/op.cc
+++ b/src/tirx/op/op.cc
@@ -562,6 +562,12 @@ PrimExpr reinterpret(PrimType t, PrimExpr value, Span 
span) {
 }
 
 Expr reinterpret(Type target_ty, Expr value, Span span) {
+  if (value.as<StringImmNode>()) {
+    TVM_FFI_CHECK(target_ty.as<PointerTypeNode>(), TypeError)
+        << "String reinterpret requires a pointer target, but got " << 
target_ty;
+    return Call(std::move(target_ty), tirx::builtin::reinterpret(), 
{std::move(value)}, {}, {},
+                std::move(span));
+  }
   if (auto target_dtype = target_ty.as<PrimType>()) {
     if (auto prim_value = value.as<PrimExpr>()) {
       return reinterpret(target_dtype.value(), prim_value.value(), 
std::move(span));
diff --git a/src/tirx/transform/lower_tvm_builtin.cc 
b/src/tirx/transform/lower_tvm_builtin.cc
index 49ee7d306e..55790e51a4 100644
--- a/src/tirx/transform/lower_tvm_builtin.cc
+++ b/src/tirx/transform/lower_tvm_builtin.cc
@@ -553,6 +553,7 @@ class BuiltinLower : public StmtExprMutator {
       int arg_type_index;
       if (arg.as<StringImmNode>()) {
         arg_type_index = ffi::TypeIndex::kTVMFFIRawStr;
+        arg = reinterpret(PointerType::VoidPointerTy(), std::move(arg));
       } else if (arg->ty.as<PointerTypeNode>()) {
         arg_type_index = IsArrayHandle(arg) ? 
ffi::TypeIndex::kTVMFFIDLTensorPtr
                                             : ffi::TypeIndex::kTVMFFIOpaquePtr;
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/codegen/test_target_codegen_c_host.py 
b/tests/python/codegen/test_target_codegen_c_host.py
index 5dac50d48e..8af6be0b79 100644
--- a/tests/python/codegen/test_target_codegen_c_host.py
+++ b/tests/python/codegen/test_target_codegen_c_host.py
@@ -227,5 +227,23 @@ def test_subroutine_call():
     )
 
 
+def test_workspace_allocation_cast():
+    @I.ir_module
+    class Module:
+        @T.prim_func
+        def main(A: T.Buffer((256,), "float32")):
+            workspace = T.alloc_buffer((256,), "float32", scope="global")
+            for i in range(256):
+                workspace[i] = A[i]
+            for i in range(256):
+                A[i] = workspace[i]
+
+    built = tvm.tirx.build(Module, target="c")
+    assert "((float*)TVMBackendAllocWorkspace(" in built.inspect_source()
+
+    temp = utils.tempdir()
+    built.export_library(temp.relpath("workspace.so"))
+
+
 if __name__ == "__main__":
     tvm.testing.main()
diff --git a/tests/python/conftest.py b/tests/python/conftest.py
index 5d55ba5c6a..b3a7dc8378 100644
--- a/tests/python/conftest.py
+++ b/tests/python/conftest.py
@@ -14,17 +14,16 @@
 # 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
+from pathlib import Path
 
-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")
 
-    COLLECT_IGNORE.append("tir_base/test_tir_intrin.py")
+def pytest_sessionstart():
+    if os.getenv("CI", "") == "true":
+        from tvm.testing.utils import (
+            install_request_hook,  # pylint: disable=import-outside-toplevel
+        )
+
+        install_request_hook(Path(__file__).with_name("request_hook.py"))
diff --git a/tests/python/disco/test_callback.py 
b/tests/python/disco/test_callback.py
index 5d3d7f14b0..817e2289f6 100644
--- a/tests/python/disco/test_callback.py
+++ b/tests/python/disco/test_callback.py
@@ -25,13 +25,16 @@ import pytest
 
 import tvm
 import tvm.testing
+from tvm.script import ir as I
 from tvm.script import relax as R
 from tvm.script import tirx as T
 from tvm.testing import env
 
 
 @pytest.mark.gpu
[email protected](tvm.runtime.disco is None, reason="disco runtime is not 
available")
 @pytest.mark.skipif(not env.has_nccl(), reason="need nccl")
[email protected](not env.has_multi_gpu(), reason="need multiple gpus")
 def test_callback():
     """Simulate lazy loading of parameters in a callback
 
@@ -39,22 +42,54 @@ def test_callback():
     callback to load the parameters.
     """
 
-    @R.function
-    def transform_params(
-        rank_arg: R.Prim(value="rank"),
-        fget_item: R.Callable([R.Any, R.Prim("int64")], R.Any),
-    ):
-        rank = T.int64()
-
-        A = fget_item(R.str("A"), R.prim_value(0))
-        A = R.match_cast(A, R.Tensor([4, 4], "int32"))
-        A = R.strided_slice(A, axes=[0], begin=[rank * 2], end=[(rank + 1) * 
2])
-
-        B = fget_item(R.str("B"), R.prim_value(1))
-        B = R.match_cast(B, R.Tensor([2, 2], "float32"))
-        B = R.strided_slice(B, axes=[1], begin=[rank * 1], end=[(rank + 1) * 
1])
-
-        return (A, B)
+    @I.ir_module(s_tir=True)
+    class Module:
+        @T.prim_func(private=True, s_tir=True)
+        def slice_A(
+            A: T.Buffer((4, 4), "int32"),
+            rank: T.int64,
+            A_sharded: T.Buffer((2, 4), "int32"),
+        ):
+            for i, j in T.grid(2, 4):
+                with T.sblock("slice_A"):
+                    vi, vj = T.axis.remap("SS", [i, j])
+                    A_sharded[vi, vj] = A[rank * 2 + vi, vj]
+
+        @T.prim_func(private=True, s_tir=True)
+        def slice_B(
+            B: T.Buffer((2, 2), "float32"),
+            rank: T.int64,
+            B_sharded: T.Buffer((2, 1), "float32"),
+        ):
+            for i in range(2):
+                with T.sblock("slice_B"):
+                    vi = T.axis.spatial(2, i)
+                    B_sharded[vi, 0] = B[vi, rank]
+
+        @R.function
+        def transform_params(
+            rank_arg: R.Prim("int64"),
+            fget_item: R.Callable([R.Any, R.Prim("int64")], R.Any),
+        ):
+            cls = Module
+
+            A = fget_item(R.str("A"), R.prim_value(0))
+            A = R.match_cast(A, R.Tensor([4, 4], "int32"))
+            A = R.call_tir(
+                cls.slice_A,
+                (A, rank_arg),
+                out_ty=R.Tensor([2, 4], "int32"),
+            )
+
+            B = fget_item(R.str("B"), R.prim_value(1))
+            B = R.match_cast(B, R.Tensor([2, 2], "float32"))
+            B = R.call_tir(
+                cls.slice_B,
+                (B, rank_arg),
+                out_ty=R.Tensor([2, 1], "float32"),
+            )
+
+            return (A, B)
 
     pipeline = tvm.ir.transform.Sequential(
         [
@@ -65,7 +100,7 @@ def test_callback():
     )
 
     with tvm.target.Target("cuda"):
-        mod = tvm.IRModule.from_expr(transform_params)
+        mod = Module
         mod = pipeline(mod)
         built = tvm.compile(mod, "cuda")
 
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..db23257703 100644
--- a/tests/python/disco/test_custom_allreduce.py
+++ b/tests/python/disco/test_custom_allreduce.py
@@ -26,7 +26,9 @@ from tvm_ffi import Shape
 import tvm
 import tvm.testing
 from tvm.runtime import DataType, disco
-from tvm.runtime.disco import Session
+
+if disco is None:
+    pytest.skip("disco runtime is not available", allow_module_level=True)
 
 
 class AllReduceStrategyType(enum.IntEnum):
@@ -56,7 +58,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.ProcessSession(num_workers=len(devices))
     sess.init_ccl(ccl, *devices)
 
     num_elements = reduce(lambda x, y: x * y, shape)
diff --git a/tests/python/relax/test_analysis_type_analysis.py 
b/tests/python/relax/test_analysis_type_analysis.py
index c98f5bd9ca..a367de212f 100644
--- a/tests/python/relax/test_analysis_type_analysis.py
+++ b/tests/python/relax/test_analysis_type_analysis.py
@@ -636,57 +636,13 @@ def _generate_prim_test_cases():
         # LCA of a PrimType with itself yields itself
         yield (R.Prim(dtype), R.Prim(dtype), R.Prim(dtype))
 
-        # The LCA of two values, each statically known to be the same
-        # value, is known to have that value.
-        yield (
-            R.Prim(value=tirx.const(0, dtype)),
-            R.Prim(value=tirx.const(0, dtype)),
-            R.Prim(value=tirx.const(0, dtype)),
-        )
-
-        # The LCA of two values, each of which is statically known to
-        # have a different value, no longer knows the contained value.
-        yield (
-            R.Prim(value=tirx.const(0, dtype)),
-            R.Prim(value=tirx.const(1, dtype)),
-            R.Prim(dtype=dtype),
-        )
-
-        # LCA of a known variable with itself yields itself
-        var_N = tirx.Var("N", dtype)
-        yield (R.Prim(value=var_N), R.Prim(value=var_N), R.Prim(value=var_N))
-
-        # LCA of a known variable with a known static value is no
-        # longer known to have a specific value.
-        yield (R.Prim(value=var_N), R.Prim(value=tirx.const(0, dtype)), 
R.Prim(dtype=dtype))
-        yield (R.Prim(value=tirx.const(0, dtype)), R.Prim(value=var_N), 
R.Prim(dtype=dtype))
-
-        var_M = tirx.Var("M", dtype)
-        yield (R.Prim(value=var_N), R.Prim(value=var_M), R.Prim(dtype=dtype))
-
     for dtype_a in dtypes:
         for dtype_b in dtypes:
             if dtype_a != dtype_b:
-                # Unlike R.Tensor, R.Prim does not currently support a
-                # value with an unknown datatype.  If the dtype
-                # differs between the two annotations, the next wider
-                # category is R.Any.
+                # If the dtype differs between the two annotations,
+                # the next wider category is R.Any.
                 yield (R.Prim(dtype_a), R.Prim(dtype_b), R.Any)
 
-                # Because the dtypes are different, even `R.Prim` containing
-                # the same value in different representations (e.g.
-                # `T.float32(0)` vs `T.float16(0)`) fall back to `R.Any`.
-                yield (
-                    R.Prim(value=tirx.const(0, dtype_a)),
-                    R.Prim(value=tirx.const(0, dtype_b)),
-                    R.Any,
-                )
-
-                # And the same is true for known variable values
-                var_N = tirx.Var("N", dtype_a)
-                var_M = tirx.Var("M", dtype_b)
-                yield (R.Prim(value=var_N), R.Prim(value=var_M), R.Any)
-
 
 @pytest.mark.parametrize("test_case", list(_generate_prim_test_cases()))
 def test_prim_type_lca(test_case):
@@ -806,7 +762,7 @@ def test_collect_nonnegative_expressions():
         A: R.Tensor([1024, "M", "N-2"]),
         B: R.Tensor([128, "N", "M+2"]),
         C: R.Shape(["M", "N"]),
-        D: R.Prim(value="N"),
+        D: R.Prim("int64"),
     ):
         return R.tuple()
 
diff --git a/tests/python/relax/test_backend_transform_shape_lower.py 
b/tests/python/relax/test_backend_transform_shape_lower.py
index d38e5dc8ab..746edf9ace 100644
--- a/tests/python/relax/test_backend_transform_shape_lower.py
+++ b/tests/python/relax/test_backend_transform_shape_lower.py
@@ -16,8 +16,6 @@
 # under the License.
 # ruff: noqa: F841
 
-import pytest
-
 import tvm.script
 import tvm.testing
 from tvm import relax
@@ -817,84 +815,5 @@ def test_check_weights_with_dynamic_shape():
     assert_structural_equal(after, expected)
 
 
[email protected](reason="value-bearing R.Prim annotations were removed")
-def test_update_symbolic_vars_in_match_cast_rhs():
-    """Symbolic variables may be used on the RHS of match_cast"""
-
-    @I.ir_module
-    class Before:
-        @R.function
-        def main(
-            arg_prim_value: R.Prim(value="n"),
-        ):
-            R.func_attr({"relax.force_pure": True})
-            n = T.int64()
-            shape = R.shape([n])
-            m = T.int64()
-            _ = R.match_cast(shape, R.Shape([m]))
-            return R.prim_value(m)
-
-    @I.ir_module
-    class Expected:
-        @R.function
-        def main(arg_prim_value: R.Prim(value="n")) -> R.Prim("int64"):
-            R.func_attr({"relax.force_pure": True})
-            n = T.int64()
-
-            shape_heap = R.call_builtin_with_ctx(
-                "vm.builtin.alloc_shape_heap",
-                [2],
-                ty_args=(R.Tensor(dtype="int64", ndim=1),),
-            )
-            _ = R.call_packed(
-                "vm.builtin.check_prim_value_info",
-                arg_prim_value,
-                R.dtype("int64"),
-                "",
-                ty_args=[R.Tuple],
-            )
-            _ = R.call_packed(
-                "vm.builtin.match_prim_value",
-                arg_prim_value,
-                shape_heap,
-                MatchShapeCode.STORE_TO_HEAP,
-                0,
-                "",
-                ty_args=[R.Tuple],
-            )
-            shape = R.call_packed(
-                "vm.builtin.make_shape",
-                shape_heap,
-                1,
-                MakeShapeCode.LOAD_SHAPE,
-                0,
-                ty_args=[R.Shape(ndim=1)],
-            )
-            _ = R.call_packed(
-                "vm.builtin.match_shape",
-                shape,
-                shape_heap,
-                1,
-                MatchShapeCode.STORE_TO_HEAP,
-                1,
-                "",
-                ty_args=[R.Tuple],
-            )
-
-            m = T.int64()
-            _ = R.match_cast(shape, R.Shape([m]))
-            gv = R.call_packed(
-                "vm.builtin.make_prim_value",
-                shape_heap,
-                MakeShapeCode.LOAD_SHAPE,
-                1,
-                ty_args=[R.Prim(value=m)],
-            )
-            return gv
-
-    After = relax.transform.VMShapeLower(emit_err_ctx=False)(Before)
-    assert_structural_equal(Expected, After)
-
-
 if __name__ == "__main__":
     tvm.testing.main()
diff --git a/tests/python/relax/test_bind_params.py 
b/tests/python/relax/test_bind_params.py
index 14eddcb360..8d24e95d6c 100644
--- a/tests/python/relax/test_bind_params.py
+++ b/tests/python/relax/test_bind_params.py
@@ -112,26 +112,16 @@ prim_value_dtype = tvm.testing.parameter("int64", 
"int32", "float32")
 
 
 def test_bind_prim_value(prim_value_dtype):
-    if prim_value_dtype != "int64":
-        pytest.xfail(reason="Currently, only support int64 as known symbolic 
value")
-
-    N = tirx.Var("N", prim_value_dtype)
+    prim_type = tvm.ir.PrimType(prim_value_dtype)
+    param = relax.Var("A", prim_type)
+    before = relax.Function([param], param, 
prim_type).with_attr("global_symbol", "main")
     value = tirx.const(16, prim_value_dtype)
 
-    @R.function
-    def before(A: R.Prim(value=N)) -> R.Prim(value=N):
-        R.func_attr({"global_symbol": "main"})
-        B: R.Prim(value=N) = A
-        return B
-
-    @R.function
-    def expected() -> R.Prim(value=value):
-        R.func_attr({"global_symbol": "main"})
-        return value
-
     after = before.bind_params({"A": value})
 
-    tvm.ir.assert_structural_equal(expected, after)
+    assert not after.params
+    tvm.ir.assert_structural_equal(after.ret_ty, prim_type)
+    tvm.ir.assert_structural_equal(after.body.body, value)
 
 
 def test_error_on_unknown_var():
diff --git a/tests/python/relax/test_bind_symbolic_vars.py 
b/tests/python/relax/test_bind_symbolic_vars.py
index bb494747b1..1f80917860 100644
--- a/tests/python/relax/test_bind_symbolic_vars.py
+++ b/tests/python/relax/test_bind_symbolic_vars.py
@@ -204,73 +204,6 @@ def test_bind_symbolic_vars_in_shape_expr():
     tvm.ir.assert_structural_equal(expected, after)
 
 
[email protected](reason="value-bearing R.Prim annotations were removed")
-def test_bind_defining_of_symbolic_vars_in_prim_value():
-    """R.Prim may define symbolic variables
-
-    This case is a bit odd, because it always results in a
-    fully-constrained parameter at the relax level.  After binding in
-    this test case, we have a function that accepts three parameters,
-    and the third parameter must always be the number 16.
-
-    However, this provides the most consistent behavior with other
-    uses of `relax.Function.bind_symbolic_vars`, which restricts the
-    allowed values for each parameter, but does not alter the number
-    of parameters.  This is in contrast to the `BindParams` pass,
-    which provides a known value for relax parameters, removing them
-    from the function signature.
-
-    This convention also prevents surprise changes to the function
-    signature, such as shown in
-    `test_bind_symbolic_vars_with_expr_in_prim_value`.
-    """
-
-    @R.function(private=True)
-    def before(A: R.Tensor(["M * N"]), x: R.Prim(value="M"), y: 
R.Prim(value="N")):
-        M = T.int64()
-        N = T.int64()
-        B = R.call_dps_packed("dummy_func", [A], out_ty=R.Tensor([2 * M * N]))
-        return B
-
-    @R.function(private=True)
-    def expected(A: R.Tensor(["M * 16"]), x: R.Prim(value="M"), y: 
R.Prim(value=16)):
-        B = R.call_dps_packed("dummy_func", [A], out_ty=R.Tensor([M * 32]))
-        return B
-
-    after = before.bind_symbolic_vars({"N": 16})
-    tvm.ir.assert_structural_equal(expected, after)
-
-
-def test_bind_usage_of_symbolic_vars_in_prim_value():
-    """R.Prim may use symbolic variables defined by other parameters
-
-    Like test_bind_defining_of_symbolic_vars_in_prim_value, but with
-    R.Prim using a symbolic variable rather than defining it.
-
-    This also demonstrates why we should not remove fully-constrained
-    R.Prim function parameters.  In this case, we have a function that
-    accepts two parameters, and we have specialized the shape of the
-    first parameter.  It would be unexpected for specialization of the
-    first parameter to result in removal of a different parameter
-    altogether.
-    """
-
-    @R.function(private=True)
-    def before(A: R.Tensor(["M", "N"]), x: R.Prim(value="M*N")):
-        M = T.int64()
-        N = T.int64()
-        B = R.call_dps_packed("dummy_func", [A], out_ty=R.Tensor([2 * M * N]))
-        return B
-
-    @R.function(private=True)
-    def expected(A: R.Tensor([16, 16]), x: R.Prim(value=256)):
-        B = R.call_dps_packed("dummy_func", [A], out_ty=R.Tensor([512]))
-        return B
-
-    after = before.bind_symbolic_vars({"M": 16, "N": 16})
-    tvm.ir.assert_structural_equal(expected, after)
-
-
 def test_bind_strided_slice():
     """relax.op.strided_slice stores Expr attributes"""
 
diff --git a/tests/python/relax/test_blockbuilder_core.py 
b/tests/python/relax/test_blockbuilder_core.py
index 725ebd8219..dceadc3af5 100644
--- a/tests/python/relax/test_blockbuilder_core.py
+++ b/tests/python/relax/test_blockbuilder_core.py
@@ -662,8 +662,8 @@ def test_emit_nested_tuple(emit_nested_tuple):
 
             @R.function
             def func(
-                n_1: R.Prim(value="n"),
-                m_1: R.Prim(value="m"),
+                n_1: R.Prim("int64"),
+                m_1: R.Prim("int64"),
                 x: R.Tensor(("n", "m"), dtype="float32"),
                 y: R.Tensor(("m", "n"), dtype="float32"),
             ):
@@ -673,8 +673,8 @@ def test_emit_nested_tuple(emit_nested_tuple):
 
             @R.function
             def func(
-                n_1: R.Prim(value="n"),
-                m_1: R.Prim(value="m"),
+                n_1: R.Prim("int64"),
+                m_1: R.Prim("int64"),
                 x: R.Tensor(("n", "m"), dtype="float32"),
                 y: R.Tensor(("m", "n"), dtype="float32"),
             ):
diff --git a/tests/python/relax/test_dataflow_rewriter.py 
b/tests/python/relax/test_dataflow_rewriter.py
index c7a9ae2cbb..8446f770ac 100644
--- a/tests/python/relax/test_dataflow_rewriter.py
+++ b/tests/python/relax/test_dataflow_rewriter.py
@@ -14,23 +14,16 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
-# ruff: noqa: F841
 
 
 import pytest
 
 import tvm.testing
-from tvm import relax
-from tvm.ir import Op
 from tvm.script import ir as I
 from tvm.script import relax as R
 from tvm.script import tirx as T
 
 
-def inspect_tensor_field(op_name, *args):
-    return relax.Call(Op.get(f"relax.inspect.{op_name}"), args)
-
-
 def test_rewrite_defined_by_ir_module():
     @R.rewriter
     class Rewriter:
@@ -372,148 +365,6 @@ def test_recursive_rewrite_rules():
     tvm.ir.assert_structural_equal(expected, after)
 
 
[email protected](reason="value-bearing R.Prim match-cast semantics were 
removed")
-def test_rewrite_of_arbitrary_dtype():
-    """A pattern-match may apply to a tensor with unknown dtype
-
-    In this test case, a pattern identifies `R.strided_slice` usage
-    which returns the last slice of an array, and replaces it with a
-    view into the input array.
-
-    """
-
-    @R.rewriter
-    class Rewriter:
-        @R.function
-        def pattern(A: R.Tensor(["M", "N"])) -> R.Tensor(["N"]):
-            M = T.int64()
-            N = T.int64()
-            last_slice_2d: R.Tensor([1, N]) = R.strided_slice(A, axes=[0], 
begin=[M - 1], end=[M])
-            last_slice_1d: R.Tensor([N]) = R.squeeze(last_slice_2d, axis=0)
-            return last_slice_1d
-
-        @R.function
-        def replacement(A: R.Tensor(["M", "N"])) -> R.Tensor(["N"]):
-            M = T.int64()
-            N = T.int64()
-
-            # A primitive-valued Relax inspect Call can be used in a
-            # Relax context that accepts an Expr.  Currently,
-            # this requires `R.match_cast` to produce a TIR symbolic
-            # variable from the Relax Expr.
-            bits_per_element = T.uint8()
-            _ = R.match_cast(
-                inspect_tensor_field("tensor_dtype_bits", A),
-                R.Prim(value=bits_per_element),
-            )
-            lanes_per_element = T.uint16()
-            _ = R.match_cast(
-                inspect_tensor_field("tensor_dtype_lanes", A),
-                R.Prim(value=lanes_per_element),
-            )
-
-            last_slice = R.memory.view(
-                A,
-                [N],
-                relative_byte_offset=(M - 1)
-                * N
-                * T.ceildiv(
-                    bits_per_element.astype("int64") * 
lanes_per_element.astype("int64"), 8
-                ),
-            )
-            return last_slice
-
-    @I.ir_module
-    class Before:
-        @R.function
-        def main(
-            A: R.Tensor([32, 16], "float16"),
-            B: R.Tensor(["P", "Q"], "int4x8"),
-            C: R.Tensor([16, 32]),
-        ):
-            P = T.int64()
-            Q = T.int64()
-
-            A_slice_2d = R.strided_slice(A, axes=[0], begin=[31], end=[32])
-            A_slice_1d = R.squeeze(A_slice_2d, axis=0)
-
-            B_slice_2d = R.strided_slice(B, axes=[0], begin=[P - 1], end=[P])
-            B_slice_1d = R.squeeze(B_slice_2d, axis=0)
-
-            C_slice_2d = R.strided_slice(C, axes=[0], begin=[15], end=[16])
-            C_slice_1d = R.squeeze(C_slice_2d, axis=0)
-
-            return (A_slice_1d, B_slice_1d, C_slice_1d)
-
-    @I.ir_module
-    class Expected:
-        @R.function
-        def main(
-            A: R.Tensor([32, 16], "float16"),
-            B: R.Tensor(["P", "Q"], "int4x8"),
-            C: R.Tensor([16, 32]),
-        ):
-            P = T.int64()
-            Q = T.int64()
-
-            # The pattern matches any 2-d tensor, with any data type.
-            # When the match's shape and dtype are both known,
-            # normalization and canonicalization produces a statically
-            # known value for `relative_byte_offset`.
-            #
-            # Relative offset is `(31 rows) *
-            #                     (16 elements/row) *
-            #                     (2 bytes/element)`
-            A_slice_1d = R.memory.view(A, shape=[16], relative_byte_offset=992)
-
-            # The pattern can also match a 2-d tensor with dynamic
-            # shape.  The `relative_byte_offset` uses the known
-            # datatype (4 bytes for each int4x8), but with dynamic
-            # shape variables substituted in where required.
-            #
-            # Relative offset is `((P-1) rows) *
-            #                     (Q elements/row) *
-            #                     (4 bytes/element)`
-            B_slice_1d = R.memory.view(B, shape=[Q], relative_byte_offset=(P - 
1) * Q * 4)
-
-            # The pattern can also match a 2-d tensor with static
-            # shape, but unknown data type.  The
-            # `relative_byte_offset` is determined based on the known
-            # number of elements, and the dynamic size of each
-            # element.
-            #
-            # Relative offset is `(15 rows) *
-            #                     (32 elements/row) *
-            #                     (ceildiv(bits*lanes,8) bytes/element)`
-            C_bits_per_element = T.uint8()
-            C_bits_prim_value = inspect_tensor_field("tensor_dtype_bits", C)
-            _ = R.match_cast(
-                C_bits_prim_value,
-                R.Prim(value=C_bits_per_element),
-            )
-            C_lanes_per_element = T.uint16()
-            C_lanes_prim_value = inspect_tensor_field("tensor_dtype_lanes", C)
-            _ = R.match_cast(
-                C_lanes_prim_value,
-                R.Prim(value=C_lanes_per_element),
-            )
-
-            C_slice_1d = R.memory.view(
-                C,
-                shape=[32],
-                relative_byte_offset=(
-                    (C_bits_per_element.astype("int64") * 
C_lanes_per_element.astype("int64") + 7)
-                    // 8
-                )
-                * 480,
-            )
-
-            return (A_slice_1d, B_slice_1d, C_slice_1d)
-
-    after = Rewriter(Before)
-    tvm.ir.assert_structural_equal(Expected, after)
-
-
 def test_rewrite_may_introduce_private_relax_subroutines():
     """The replacement may contain subroutines"""
 
diff --git a/tests/python/relax/test_op_binary.py 
b/tests/python/relax/test_op_binary.py
index f5d12bbe67..e3befa2a97 100644
--- a/tests/python/relax/test_op_binary.py
+++ b/tests/python/relax/test_op_binary.py
@@ -144,23 +144,6 @@ def 
test_infer_ty_binary_arith_prim_value_with_prim_value(binary_arith_op: Calla
     _check_inference(bb, binary_arith_op(x, y), tvm.ir.PrimType("float32"))
 
 
[email protected]("binary_arith_op,tir_arith_op", binary_arith_ops)
[email protected](reason="Not yet implemented")
-def test_infer_ty_binary_arith_known_prim_value_with_prim_value(
-    binary_arith_op: Callable, tir_arith_op
-):
-    bb = relax.BlockBuilder()
-
-    tir_x = tirx.Var("tir_x", "float32")
-    tir_y = tirx.Var("tir_y", "float32")
-
-    x = relax.Var("x", R.Prim(value=tir_x))
-    y = relax.Var("y", R.Prim(value=tir_y))
-
-    _check_inference(bb, binary_arith_op(x, y), tvm.ir.PrimType("float32"))
-    _check_inference(bb, binary_arith_op(y, x), tvm.ir.PrimType("float32"))
-
-
 binary_cmp_ops = [
     (relax.op.equal, tirx.EQ),
     (relax.op.greater, tirx.GT),
@@ -206,21 +189,6 @@ def 
test_infer_ty_binary_cmp_prim_value_to_prim_value(binary_cmp_op: Callable):
     _check_inference(bb, binary_cmp_op(y, x), tvm.ir.PrimType("bool"))
 
 
[email protected]("binary_cmp_op,tir_cmp_op", binary_cmp_ops)
[email protected](reason="Not yet implemented")
-def test_infer_ty_binary_cmp_known_prim_value_to_prim_value(binary_cmp_op: 
Callable, tir_cmp_op):
-    bb = relax.BlockBuilder()
-
-    tir_x = tirx.Var("tir_x", "float32")
-    tir_y = tirx.Var("tir_y", "float32")
-
-    x = relax.Var("x", R.Prim(value=tir_x))
-    y = relax.Var("y", R.Prim(value=tir_y))
-
-    _check_inference(bb, binary_cmp_op(x, y), tvm.ir.PrimType("bool"))
-    _check_inference(bb, binary_cmp_op(y, x), tvm.ir.PrimType("bool"))
-
-
 @pytest.mark.parametrize("binary_arith_op", [row[0] for row in 
binary_arith_ops])
 def test_binary_infer_ty_shape_symbolic(binary_arith_op: Callable):
     bb = relax.BlockBuilder()
diff --git a/tests/python/relax/test_transform_compute_prim_value.py 
b/tests/python/relax/test_transform_compute_prim_value.py
index a7b89f0654..37a4fafcb1 100644
--- a/tests/python/relax/test_transform_compute_prim_value.py
+++ b/tests/python/relax/test_transform_compute_prim_value.py
@@ -15,8 +15,6 @@
 # specific language governing permissions and limitations
 # under the License.
 
-import pytest
-
 import tvm
 import tvm.testing
 from tvm.script import ir as I
@@ -84,34 +82,5 @@ def test_prim_value_in_branch_condition():
     tvm.ir.assert_structural_equal(After, Expected)
 
 
[email protected](reason="value-bearing R.Prim annotations were removed")
-def test_prim_value_in_pure_function():
-    @I.ir_module
-    class Before:
-        @R.function
-        def main(_N: R.Prim(value="N"), _M: R.Prim(value="M")) -> 
R.Prim(value="N*M"):
-            N = T.int64()
-            M = T.int64()
-            out = R.prim_value(N * M)
-            return out
-
-    @I.ir_module
-    class Expected:
-        @R.function
-        def main(_N: R.Prim(value="N"), _M: R.Prim(value="M")) -> 
R.Prim(value="N*M"):
-            N = T.int64()
-            M = T.int64()
-            out = Expected.compute_symbolic_expr(R.prim_value(N), 
R.prim_value(M))
-            return out
-
-        @T.prim_func(private=True, s_tir=True)
-        def compute_symbolic_expr(N: T.int64, M: T.int64) -> T.int64:
-            T.func_attr({"tirx.is_host_func": True})
-            T.ret(N * M)
-
-    After = tvm.relax.transform.ComputePrimValue()(Before)
-    tvm.ir.assert_structural_equal(After, Expected)
-
-
 if __name__ == "__main__":
     tvm.testing.main()
diff --git a/tests/python/relax/test_transform_lazy_transform_params.py 
b/tests/python/relax/test_transform_lazy_transform_params.py
index 3d6a3ea88e..23b5d61c70 100644
--- a/tests/python/relax/test_transform_lazy_transform_params.py
+++ b/tests/python/relax/test_transform_lazy_transform_params.py
@@ -16,7 +16,6 @@
 # under the License.
 # ruff: noqa: F841
 import numpy as np
-import pytest
 
 import tvm
 import tvm.testing
@@ -744,53 +743,6 @@ def test_params_without_tuple():
     tvm.ir.assert_structural_equal(After, Expected)
 
 
[email protected](reason="value-bearing R.Prim annotations were removed")
-def test_retain_before_num_input():
-    """Only lazily load parameters after num_input"""
-
-    @I.ir_module(s_tir=True)
-    class Before:
-        @R.function
-        def transform_params(
-            relax_rank: R.Prim(value="rank"),
-            A: R.Tensor([16, 16], "float32"),
-            B: R.Tensor([16, 16], "float32"),
-        ):
-            R.func_attr({"num_input": 1})
-            rank = T.int64()
-            A_sharded = R.strided_slice(
-                A, axes=[0], begin=[rank * 8], end=[(rank + 1) * 8], 
assume_inbound=True
-            )
-            B_sharded = R.strided_slice(
-                B, axes=[1], begin=[rank * 8], end=[(rank + 1) * 8], 
assume_inbound=True
-            )
-            return (A_sharded, B_sharded)
-
-    @I.ir_module(s_tir=True)
-    class Expected:
-        @R.function(pure=False)
-        def transform_params(relax_rank: R.Prim(value="rank")):
-            R.func_attr({"num_input": 1})
-            rank = T.int64()
-
-            A = R.call_packed("get_item", R.prim_value(0), ty_args=[R.Any])
-            A = R.match_cast(A, R.Tensor([16, 16], "float32"))
-            A_sharded = R.strided_slice(
-                A, axes=[0], begin=[rank * 8], end=[(rank + 1) * 8], 
assume_inbound=True
-            )
-
-            B = R.call_packed("get_item", R.prim_value(1), ty_args=[R.Any])
-            B = R.match_cast(B, R.Tensor([16, 16], "float32"))
-            B_sharded = R.strided_slice(
-                B, axes=[1], begin=[rank * 8], end=[(rank + 1) * 8], 
assume_inbound=True
-            )
-
-            return (A_sharded, B_sharded)
-
-    After = LazyTransformParams(fset_item=None)(Before)
-    tvm.ir.assert_structural_equal(After, Expected)
-
-
 def test_params_without_tuple_with_symbolic_var():
     @I.ir_module(s_tir=True)
     class Before:
@@ -838,103 +790,6 @@ def test_get_item_callback():
     tvm.ir.assert_structural_equal(After, Expected)
 
 
[email protected](reason="value-bearing R.Prim annotations were removed")
-def test_get_item_callback_num_attrs():
-    @I.ir_module(s_tir=True)
-    class Before:
-        @R.function(pure=False)
-        def transform_params(
-            rank_arg: R.Prim(value="rank"),
-            world_size_arg: R.Prim(value="world_size"),
-            weight_A: R.Tensor([16, 64], "float32"),
-            weight_B: R.Tensor([1024, 2048], "float32"),
-        ):
-            R.func_attr({"num_input": 2})
-
-            rank = T.int64()
-            world_size = T.int64()
-
-            _ = R.assert_op(
-                R.prim_value(16 % world_size == 0),
-                [R.prim_value(16), R.prim_value(world_size)],
-                format=(
-                    "World size must evenly divide A.shape[0] ({}), but 
received world size of {}."
-                ),
-            )
-            weight_A = R.strided_slice(
-                weight_A,
-                axes=[0],
-                begin=[rank * 16 // world_size],
-                end=[(rank + 1) * 16 // world_size],
-            )
-
-            _ = R.assert_op(
-                R.prim_value(2048 % world_size == 0),
-                [R.prim_value(2048), R.prim_value(world_size)],
-                format=(
-                    "World size must evenly divide B.shape[1] ({}), but 
received world size of {}."
-                ),
-            )
-            weight_B = R.strided_slice(
-                weight_B,
-                axes=[1],
-                begin=[rank * 2048 // world_size],
-                end=[(rank + 1) * 2048 // world_size],
-            )
-
-            return (weight_A, weight_B)
-
-    @I.ir_module(s_tir=True)
-    class Expected:
-        @R.function(pure=False)
-        def transform_params(
-            rank_arg: R.Prim(value="rank"),
-            world_size_arg: R.Prim(value="world_size"),
-            fget_item: R.Callable([R.Prim("int64"), R.Any], R.Any),
-        ):
-            R.func_attr({"num_input": 3})
-
-            rank = T.int64()
-            world_size = T.int64()
-
-            _ = R.assert_op(
-                R.prim_value(16 % world_size == 0),
-                [R.prim_value(16), R.prim_value(world_size)],
-                format=(
-                    "World size must evenly divide A.shape[0] ({}), but 
received world size of {}."
-                ),
-            )
-            weight_A = fget_item(R.prim_value(0), R.str("weight_A"))
-            weight_A = R.match_cast(weight_A, R.Tensor([16, 64], "float32"))
-            weight_A = R.strided_slice(
-                weight_A,
-                axes=[0],
-                begin=[rank * 16 // world_size],
-                end=[(rank + 1) * 16 // world_size],
-            )
-
-            _ = R.assert_op(
-                R.prim_value(2048 % world_size == 0),
-                [R.prim_value(2048), R.prim_value(world_size)],
-                format=(
-                    "World size must evenly divide B.shape[1] ({}), but 
received world size of {}."
-                ),
-            )
-            weight_B = fget_item(R.prim_value(1), R.str("weight_B"))
-            weight_B = R.match_cast(weight_B, R.Tensor([1024, 2048], 
"float32"))
-            weight_B = R.strided_slice(
-                weight_B,
-                axes=[1],
-                begin=[rank * 2048 // world_size],
-                end=[(rank + 1) * 2048 // world_size],
-            )
-
-            return (weight_A, weight_B)
-
-    After = relax.transform.LazyGetInput()(Before)
-    tvm.ir.assert_structural_equal(After, Expected)
-
-
 def test_get_item_callback_dynamic_shape():
     @I.ir_module(s_tir=True)
     class Before:
diff --git a/tests/python/relax/test_transform_lift_transform_params.py 
b/tests/python/relax/test_transform_lift_transform_params.py
index 9bc032b831..9cb73c79e1 100644
--- a/tests/python/relax/test_transform_lift_transform_params.py
+++ b/tests/python/relax/test_transform_lift_transform_params.py
@@ -1684,8 +1684,8 @@ def 
test_symbolic_var_defined_in_params_but_used_in_weights():
 
     In order to be a source of definition, a symbolic variable in the
     parameters must occur as a distinct parameter, as a tensor shape
-    `R.Tensor(["var"])`, an explicit `R.Shape(["var"])`, or as a
-    `R.Prim(value="var")`.  A variable that is part of a larger
+    `R.Tensor(["var"])` or an explicit `R.Shape(["var"])`.  A variable
+    that is part of a larger
     expression, such as `R.Tensor(["m * n"])`, are variable usages,
     not variable definitions.
     """
diff --git a/tests/python/relax/test_transform_remove_unused_parameters.py 
b/tests/python/relax/test_transform_remove_unused_parameters.py
index 3eaf8270bd..7e500c5204 100644
--- a/tests/python/relax/test_transform_remove_unused_parameters.py
+++ b/tests/python/relax/test_transform_remove_unused_parameters.py
@@ -63,11 +63,9 @@ def test_replace_symbolic_variables():
     removing the `R.Tensor` argument, we may need to provide
     additional parameters to define the symbolic variables.
 
-    Value-bearing `R.Prim(value=...)` annotations were removed in the tirx
-    refactor (a `PrimType` carries only a dtype and defines no TIR var, which
-    leaves the var undefined under the strict tirx well-formedness verifier).
-    The replacement is to promote each free symbolic variable through a 1-D
-    `R.Shape` parameter, which actually *defines* the variable.
+    A `PrimType` carries only a dtype and defines no TIR var.  Each free
+    symbolic variable is therefore promoted through a 1-D `R.Shape`
+    parameter, which actually *defines* the variable.
     """
 
     @I.ir_module
@@ -131,12 +129,11 @@ def test_no_extra_symbolic_variables():
     tvm.ir.assert_structural_equal(After, Expected)
 
 
-def test_remove_extra_prim_variables():
-    """Remove parameters that only serve to define existing symbolic variables
+def test_remove_extra_prim_parameters():
+    """Remove unused scalar parameters.
 
-    If a `R.Prim` parameter provies a definition of a symbolic
-    variable, but that symbolic variable can be determined from a
-    different parameter, then the `R.Prim` parameter can be removed.
+    The tensor parameter already defines the symbolic dimensions, while the
+    dtype-only scalar parameters are unused by the private function.
     """
 
     @I.ir_module
@@ -149,7 +146,9 @@ def test_remove_extra_prim_variables():
 
         @R.function(private=True)
         def func(
-            A: R.Tensor(["m", "n"], "float32"), _m: R.Prim(value="m"), _n: 
R.Prim(value="n")
+            A: R.Tensor(["m", "n"], "float32"),
+            _m: R.Prim("int64"),
+            _n: R.Prim("int64"),
         ) -> R.Tensor(["m", "n"], "float32"):
             m = T.int64()
             n = T.int64()
diff --git a/tests/python/relax/test_tvmscript_parser.py 
b/tests/python/relax/test_tvmscript_parser.py
index 7f7311ba60..1ca64a44ad 100644
--- a/tests/python/relax/test_tvmscript_parser.py
+++ b/tests/python/relax/test_tvmscript_parser.py
@@ -1313,6 +1313,14 @@ def test_scalar_tensor_as_branch_condition():
     tvm.ir.assert_structural_equal(if_else.cond.ty, R.Tensor([], "bool"))
 
 
+def test_prim_annotation_requires_dtype():
+    with pytest.raises(TypeError, match="missing 1 required positional 
argument: 'dtype'"):
+        R.Prim()
+
+    with pytest.raises(TypeError, match="unexpected keyword argument 'value'"):
+        R.Prim(value="n")
+
+
 def test_prim_value_as_branch_condition():
     """In addition to scalar tensor, can use R.Prim condition"""
 
diff --git a/tests/python/relax/test_utils.py b/tests/python/relax/test_utils.py
index b654edfc31..d87b1a761b 100644
--- a/tests/python/relax/test_utils.py
+++ b/tests/python/relax/test_utils.py
@@ -24,7 +24,6 @@ import tvm
 from tvm import relax
 from tvm.ir.base import assert_structural_equal
 from tvm.script.parser import relax as R
-from tvm.script.parser import tirx as T
 
 
 def test_copy_with_new_vars():
@@ -171,7 +170,6 @@ def test_structural_equal_of_call_nodes():
     tvm.ir.assert_structural_equal(uses_same_object_twice, 
uses_two_different_objects)
 
 
[email protected](reason="value-bearing R.Prim annotations were removed")
 def test_structural_equal_with_recursive_lambda_function():
     """A recursive lambda function may be checked for structural equality
 
@@ -188,15 +186,14 @@ def 
test_structural_equal_with_recursive_lambda_function():
         @R.function
         def func(n: R.Prim("int64")):
             @R.function
-            def recursive_lambda(i_arg: R.Prim(value="i")) -> R.Prim("int64"):
-                i = T.int64()
-                if R.prim_value(i == 0):
-                    output = R.prim_value(T.int64(0))
+            def recursive_lambda(i_arg: R.Prim("int64")) -> R.Prim("int64"):
+                condition = R.equal(i_arg, R.prim_value(0))
+                if condition:
+                    output = R.prim_value(0)
                 else:
-                    remainder_relax = recursive_lambda(R.prim_value(i - 1))
-                    remainder_tir = T.int64()
-                    _ = R.match_cast(remainder_relax, 
R.Prim(value=remainder_tir))
-                    output = R.prim_value(i + remainder_tir)
+                    next_i = R.subtract(i_arg, R.prim_value(1))
+                    remainder = recursive_lambda(next_i)
+                    output = R.add(i_arg, remainder)
                 return output
 
             return recursive_lambda(n)
@@ -219,17 +216,16 @@ def 
test_structural_equal_with_distinct_recursive_lambda_function():
     @R.function(private=True)
     def func_a(n: R.Prim("int64")):
         @R.function
-        def recursive_lambda(i_arg: R.Prim(value="i")) -> R.Prim("int64"):
-            i = T.int64()
-            if R.prim_value(i == 0):
-                output = R.prim_value(T.int64(0))
-                #                             ^
-                # The first mismatch is here  ^
+        def recursive_lambda(i_arg: R.Prim("int64")) -> R.Prim("int64"):
+            condition = R.equal(i_arg, R.prim_value(0))
+            if condition:
+                output = R.prim_value(0)
+                #                          ^
+                # The first mismatch is here
             else:
-                remainder_relax = recursive_lambda(R.prim_value(i - 1))
-                remainder_tir = T.int64()
-                _ = R.match_cast(remainder_relax, R.Prim(value=remainder_tir))
-                output = R.prim_value(i + remainder_tir)
+                next_i = R.subtract(i_arg, R.prim_value(1))
+                remainder = recursive_lambda(next_i)
+                output = R.add(i_arg, remainder)
             return output
 
         return recursive_lambda(n)
@@ -237,17 +233,16 @@ def 
test_structural_equal_with_distinct_recursive_lambda_function():
     @R.function(private=True)
     def func_b(n: R.Prim("int64")):
         @R.function
-        def recursive_lambda(i_arg: R.Prim(value="i")) -> R.Prim("int64"):
-            i = T.int64()
-            if R.prim_value(i == 0):
-                output = R.prim_value(T.int64(1))
-                #                             ^
-                # The first mismatch is here  ^
+        def recursive_lambda(i_arg: R.Prim("int64")) -> R.Prim("int64"):
+            condition = R.equal(i_arg, R.prim_value(0))
+            if condition:
+                output = R.prim_value(1)
+                #                          ^
+                # The first mismatch is here
             else:
-                remainder_relax = recursive_lambda(R.prim_value(i - 1))
-                remainder_tir = T.int64()
-                _ = R.match_cast(remainder_relax, R.Prim(value=remainder_tir))
-                output = R.prim_value(i * remainder_tir)
+                next_i = R.subtract(i_arg, R.prim_value(1))
+                remainder = recursive_lambda(next_i)
+                output = R.multiply(i_arg, remainder)
             return output
 
         return recursive_lambda(n)
@@ -262,10 +257,11 @@ def 
test_structural_equal_with_distinct_recursive_lambda_function():
         "value",
         "body",
         "blocks[0]",
-        "bindings[0]",
+        "bindings[1]",
+        "value",
+        "true_branch",
+        "body",
         "value",
-        "cond",
-        "a",
     ]
 
     with pytest.raises(ValueError, match=re.escape(".".join(mismatch_path))):
diff --git a/tests/python/relax/test_vm_build.py 
b/tests/python/relax/test_vm_build.py
index 304ae33d77..5156202726 100644
--- a/tests/python/relax/test_vm_build.py
+++ b/tests/python/relax/test_vm_build.py
@@ -559,100 +559,6 @@ def test_vm_relax_symbolic_shape_tuple(exec_mode):
         func(R.prim_value(2))
 
 
[email protected](reason="value-bearing R.Prim annotations are erased to 
dtype-only PrimType")
-def test_vm_relax_symbolic_prim_value(exec_mode):
-    @I.ir_module(s_tir=True)
-    class mod:
-        @R.function
-        def main(shape: R.Prim(value="n")):
-            n = T.int64()
-            return R.prim_value(n * n)
-
-    target = tvm.target.Target("llvm", host="llvm")
-    ex = relax.build(mod, target, exec_mode=exec_mode)
-    vm = relax.VirtualMachine(ex, tvm.cpu())
-
-    func = vm["main"]
-
-    assert func(2) == 4
-
-    with pytest.raises(TypeError):
-        func(Shape([2]))
-
-
[email protected](reason="value-bearing R.Prim annotations are erased to 
dtype-only PrimType")
-def test_vm_relax_multiple_symbolic_prim_value(exec_mode):
-    """Like test_vm_relax_symbolic_prim_value, but with multiple variables"""
-
-    @I.ir_module(s_tir=True)
-    class mod:
-        @R.function
-        def main(
-            # Provides definition of "n"
-            _n: R.Prim(value="n"),
-            # Requires definitions of both "n" and "m", but cannot
-            # provide either.
-            _shape: R.Shape(["n*2", "m*2"]),
-            # Provides definition of "m"
-            _m: R.Prim(value="m"),
-        ):
-            n = T.int64()
-            m = T.int64()
-            return R.shape([n * n, m + 1])
-
-    target = tvm.target.Target("llvm", host="llvm")
-    ex = relax.build(mod, target, exec_mode=exec_mode)
-    vm = relax.VirtualMachine(ex, tvm.cpu())
-
-    func = vm["main"]
-
-    assert func(2, Shape([4, 12]), 6) == (4, 7)
-
-    with pytest.raises(RuntimeError):
-        func(2, Shape([4, 12]), 1)
-
-    with pytest.raises(RuntimeError):
-        func(Shape([2]))
-
-
[email protected](reason="Current support for R.Prim with known value is 
primarily for int64")
[email protected]("exec_mode", EXEC_MODE)
-def test_vm_relax_prim_value_fp32(exec_mode):
-    """A Expr may be R.prim('float32')
-
-    Unlike shape tuples, which must contain int64, a Expr may be
-    any type that can be represented as a single primitive value.
-    """
-
-    @I.ir_module(s_tir=True)
-    class mod:
-        @R.function
-        def main(
-            # First failure occurs during parsing.  The syntactic
-            # sugar for symbolic variables assumes that all symbolic
-            # variables are int64, rather than using the type that is
-            # later declared.
-            _x: R.Prim(value="half_fill_value"),
-        ):
-            half_fill_value = T.float32()
-            # Second failure occurs when calling `relax.op.full`.  The
-            # `fill_value` is expected to be a scalar constant
-            # (R.Tensor with 0-dim shape), not a primitive value, even
-            # though these are semantically the same.
-            return R.full(shape=[16, 16], fill_value=R.prim_value(2 * 
half_fill_value))
-
-    target = tvm.target.Target("llvm", host="llvm")
-    # Third failure occurs here.  The current codegen assumes that all
-    # symbolic variables are int64.
-    ex = relax.build(mod, target, exec_mode=exec_mode)
-    vm = relax.VirtualMachine(ex, tvm.cpu())
-
-    func = vm["main"]
-
-    res = func(16.0).numpy()
-    assert np.all(res == 32.0)
-
-
 def test_vm_relax_dyn_tir_shape(exec_mode):
     # case where TIR variables are unbound in generated PrimFunc
     bb = relax.BlockBuilder()
diff --git a/tests/scripts/request_hook/request_hook.py 
b/tests/python/request_hook.py
similarity index 92%
rename from tests/scripts/request_hook/request_hook.py
rename to tests/python/request_hook.py
index 48ac5e2a30..f3faf77a19 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)
 
@@ -46,6 +46,8 @@ class TvmRequestHook(urllib.request.Request):
 
 def init():
     global LOGGER
+    if urllib.request.Request is TvmRequestHook:
+        return
     urllib.request.Request = TvmRequestHook
     LOGGER = logging.getLogger("tvm_request_hook")
     LOGGER.setLevel(logging.DEBUG)
diff --git 
a/tests/python/s_tir/transform/test_s_tir_transform_plan_update_buffer_allocation_location.py
 
b/tests/python/s_tir/transform/test_s_tir_transform_plan_update_buffer_allocation_location.py
index d5173bcc13..9c59c321be 100644
--- 
a/tests/python/s_tir/transform/test_s_tir_transform_plan_update_buffer_allocation_location.py
+++ 
b/tests/python/s_tir/transform/test_s_tir_transform_plan_update_buffer_allocation_location.py
@@ -384,9 +384,13 @@ def test_dltensor_buffer_is_unlowered():
     @T.prim_func(s_tir=True)
     def before(dlpack_handle: T.handle, axis: T.int64) -> T.int64:
         ndim: T.int32 = T.tvm_struct_get(dlpack_handle, 0, 5, "int32")
-        stride_ptr: T.let[T.handle("int64")] = T.tvm_struct_get(dlpack_handle, 
0, 4, "handle")
+        stride_ptr: T.let[T.handle("int64")] = T.tvm_struct_get(
+            dlpack_handle, 0, 4, dtype=T.handle("int64").ty
+        )
         if T.isnullptr(stride_ptr):
-            shape_ptr: T.let[T.handle("int64")] = 
T.tvm_struct_get(dlpack_handle, 0, 3, "handle")
+            shape_ptr: T.let[T.handle("int64")] = T.tvm_struct_get(
+                dlpack_handle, 0, 3, dtype=T.handle("int64").ty
+            )
             shape = T.decl_buffer(ndim, "int64", data=shape_ptr)
             product = T.decl_buffer([], "int64")
             product[()] = 1
diff --git a/tests/python/te/test_te_create_primfunc.py 
b/tests/python/te/test_te_create_primfunc.py
index 90d7b69a55..48f9c1bf7b 100644
--- a/tests/python/te/test_te_create_primfunc.py
+++ b/tests/python/te/test_te_create_primfunc.py
@@ -293,6 +293,43 @@ def test_extern():
     _check_workload(te_extern, tir_extern)
 
 
+def te_extern_epilogue():
+    A = te.placeholder((4, 3), name="A")
+    B = te.placeholder((3, 2), name="B")
+    C = te.extern(
+        (4, 2),
+        [A, B],
+        lambda ins, outs: tvm.tirx.call_packed("testing.echo", ins[0], ins[1], 
outs[0]),
+        name="C",
+    )
+    D = te.compute(C.shape, lambda i, j: C[i, j] + 1.0, name="D")
+    return [A, B, D]
+
+
[email protected]_func(s_tir=True)
+def tir_extern_epilogue(var_A: T.handle, var_B: T.handle, D: T.Buffer((4, 2), 
"float32")):
+    T.func_attr({"global_symbol": "main", "tirx.noalias": True})
+    A = T.match_buffer(var_A, (4, 3), offset_factor=1)
+    B = T.match_buffer(var_B, (3, 2), offset_factor=1)
+    C = T.sblock_alloc_buffer((4, 2), elem_offset=0, offset_factor=1)
+    with T.sblock("C"):
+        T.reads()
+        T.writes()
+        T.call_packed("testing.echo", A, B, C)
+    for i, j in T.grid(4, 2):
+        with T.sblock("D"):
+            vi, vj = T.axis.remap("SS", [i, j])
+            T.reads(C[vi, vj])
+            T.writes(D[vi, vj])
+            D[vi, vj] = C[vi, vj] + T.float32(1)
+
+
+def test_extern_epilogue():
+    _check_workload(te_extern_epilogue, tir_extern_epilogue)
+    func = 
te.create_prim_func(te_extern_epilogue()).with_attr("global_symbol", 
"extern_epilogue")
+    tvm.compile(func, target="llvm")
+
+
 def te_reordered_matmul():
     k = te.reduce_axis((0, 128), "k")
     A = te.placeholder((128, 128), name="A")
diff --git a/tests/python/testing/test_testing.py 
b/tests/python/testing/test_testing.py
deleted file mode 100644
index 373e78845b..0000000000
--- a/tests/python/testing/test_testing.py
+++ /dev/null
@@ -1,116 +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.
-# ruff: noqa: E731, F821, F841
-import numpy as np
-
-import tvm
-import tvm.testing
-
-
-def test_check_numerical_grads():
-    # Functions and their derivatives
-    functions = [
-        lambda x: (x * x * x, 3 * x * x),
-        lambda x: (x * x, 2 * x),
-        lambda x: (np.abs(x), np.sign(x)),
-        lambda x: (np.log(np.abs(x)), 1 / x),
-        lambda x: (np.sqrt(np.abs(x)), np.sign(x) / (2 * np.sqrt(np.abs(x)))),
-        lambda x: (1 / x, -1 / (x * x)),
-        lambda x: (np.sign(np.sin(1 / x)), np.zeros_like(x)),
-        lambda x: (x * np.sin(1 / x), np.sin(1 / x) - np.cos(1 / x) / x),
-        lambda x: (np.sin(1 / x), -np.cos(1 / x) / (x * x)),
-        lambda x: (np.tan(x), 1.0 / (np.cos(x) * np.cos(x))),
-    ]
-
-    np.random.seed(0)
-
-    # Avoid values too close to 0 since singularities of our functions are 
there
-    min_x = 0.5
-
-    for func in functions:
-        x_input = np.random.uniform(min_x, 10, size=(3, 4))
-
-        # We need a function returning a scalar, so sum the results
-        func_forw = lambda x: np.sum(func(x)[0])
-        grads = [func(x_input)[1]]
-
-        tvm.testing.check_numerical_grads(func_forw, [x_input], grads)
-
-    # Check functions with multiple arguments
-    for f1 in functions:
-        for f2 in functions:
-            x_input = np.random.uniform(min_x, 10, size=(3, 4))
-            y_input = np.random.uniform(min_x, 10, size=(3, 4))
-
-            func_forw = lambda x, y: np.sum(f1(x)[0] + f2(y)[0])
-            grads = [f1(x_input)[1], f2(y_input)[1]]
-
-            tvm.testing.check_numerical_grads(func_forw, [x_input, y_input], 
grads)
-
-            # Same thing but with keyword arguments
-            func_forw = lambda x, y: np.sum(f1(x)[0] + f2(y)[0])
-            grads = {"x": f1(x_input)[1], "y": f2(y_input)[1]}
-
-            tvm.testing.check_numerical_grads(func_forw, {"x": x_input, "y": 
y_input}, grads)
-
-    def _noise1(x, atol=1e-2, rtol=0.1):
-        # We go in random direction using twice the original tolerance to be 
sure this
-        # results in an error
-        sqrt_n = np.sqrt(float(np.prod(x.shape)))
-        tol = 2 * (np.linalg.norm(x) * rtol + atol * sqrt_n)
-        noise = np.random.normal(size=x.shape)
-        noise = tol * noise / np.linalg.norm(noise)
-        return x + noise
-
-    def _noise2(x, atol=1e-2, rtol=0.1):
-        # This noise affects just a single component
-        sqrt_n = np.sqrt(float(np.prod(x.shape)))
-        tol = 2 * (np.linalg.norm(x) * rtol + atol * sqrt_n)
-        n = np.random.randint(np.prod(x.shape))
-        noise = np.zeros_like(x)
-        noise.reshape(-1)[n] = tol
-        return x + noise
-
-    # Add noise to gradients and check that the function throws
-    for f1 in functions:
-        for f2 in functions:
-            x_input = np.random.uniform(min_x, 10, size=(3, 4))
-            y_input = np.random.uniform(min_x, 10, size=(3, 4))
-
-            func_forw = lambda x, y: np.sum(f1(x)[0] + f2(y)[0])
-            grads = [_noise1(f1(x_input)[1]), _noise1(f2(y_input)[1])]
-
-            try:
-                tvm.testing.check_numerical_grads(func_forw, [x_input, 
y_input], grads)
-            except AssertionError as e:
-                pass
-            else:
-                raise AssertionError("tvm.testing.check_numerical_grads didn't 
raise an exception")
-
-            func_forw = lambda x, y: np.sum(f1(x)[0] + f2(y)[0])
-            grads = {"x": _noise2(f1(x_input)[1]), "y": 
_noise2(f2(y_input)[1])}
-
-            try:
-                tvm.testing.check_numerical_grads(func_forw, {"x": x_input, 
"y": y_input}, grads)
-            except AssertionError as e:
-                pass
-            else:
-                raise AssertionError("tvm.testing.check_numerical_grads didn't 
raise an exception")
-
-
-if __name__ == "__main__":
-    test_tvm.testing.check_numerical_grads()
diff --git a/tests/python/testing/test_tvm_testing_before_after.py 
b/tests/python/testing/test_tvm_testing_before_after.py
deleted file mode 100644
index 7fb7cbbff0..0000000000
--- a/tests/python/testing/test_tvm_testing_before_after.py
+++ /dev/null
@@ -1,147 +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 tvm
-import tvm.testing
-from tvm.script import ir_module
-from tvm.script import tirx as T
-
-
-def test_before_after_prim_func():
-    @T.prim_func(private=True, s_tir=True)
-    def before():
-        T.evaluate(0)
-
-    expected = before
-
-    mod = tvm.IRModule.from_expr(before)
-    # Identity transform (no-op)
-    mod = (lambda x: x)(mod)
-    tvm.ir.assert_structural_equal(mod["main"], expected)
-
-
-def test_before_after_method():
-    @T.prim_func(private=True, s_tir=True)
-    def before():
-        T.evaluate(0)
-
-    expected = before
-
-    mod = tvm.IRModule.from_expr(before)
-    # Identity transform (no-op)
-    mod = (lambda x: x)(mod)
-    tvm.ir.assert_structural_equal(mod["main"], expected)
-
-
-def test_before_after_fixture():
-    @T.prim_func(private=True, s_tir=True)
-    def before():
-        T.evaluate(0)
-
-    expected = before
-
-    mod = tvm.IRModule.from_expr(before)
-    # Identity transform (no-op)
-    mod = (lambda x: x)(mod)
-    tvm.ir.assert_structural_equal(mod["main"], expected)
-
-
-def test_before_after_delayed_prim_func():
-    @T.prim_func(private=True, s_tir=True)
-    def before():
-        T.evaluate(0)
-
-    expected = before
-
-    mod = tvm.IRModule.from_expr(before)
-    # Identity transform (no-op)
-    mod = (lambda x: x)(mod)
-    tvm.ir.assert_structural_equal(mod["main"], expected)
-
-
-def test_before_after_parametrized_fixture():
-    """Test with different buffer sizes"""
-    for n in [1, 8, 16]:
-
-        @T.prim_func(private=True, s_tir=True)
-        def before(A: T.Buffer(n, "float32")):
-            for i in T.serial(n):
-                A[i] = 0.0
-
-        expected = before
-
-        mod = tvm.IRModule.from_expr(before)
-        # Identity transform (no-op)
-        mod = (lambda x: x)(mod)
-        tvm.ir.assert_structural_equal(mod["main"], expected)
-
-
-def test_before_after_ir_module():
-    """The preferred form for writing TIR unit tests
-
-    All evaluation is done at test-time, with the minimal amount of
-    additional lines.
-    """
-
-    @ir_module
-    class before:
-        @T.prim_func(private=True, s_tir=True)
-        def func_A(A: T.Buffer(16, "float32")):
-            for i in T.serial(16):
-                A[i] = 0.0
-
-        @T.prim_func(private=True, s_tir=True)
-        def func_B(A: T.Buffer(16, "int32")):
-            for i in T.serial(16):
-                A[i] = 42
-
-    expected = before
-
-    # Identity transform (no-op)
-    mod = (lambda x: x)(before)
-    tvm.ir.assert_structural_equal(mod, expected)
-
-
-def test_before_after_ir_module_explicit_fixture():
-    """Like test_before_after_ir_module, but with an explicit fixture
-
-    If the IRModule depends on additional fixtures, this form can be
-    used.
-    """
-
-    @ir_module
-    class before:
-        @T.prim_func(private=True, s_tir=True)
-        def func_A(A: T.Buffer(16, "float32")):
-            for i in T.serial(16):
-                A[i] = 0.0
-
-        @T.prim_func(private=True, s_tir=True)
-        def func_B(A: T.Buffer(16, "int32")):
-            for i in T.serial(16):
-                A[i] = 42
-
-    expected = before
-
-    # Identity transform (no-op)
-    mod = (lambda x: x)(before)
-    tvm.ir.assert_structural_equal(mod, expected)
-
-
-if __name__ == "__main__":
-    tvm.testing.main()
diff --git a/tests/python/testing/test_tvm_testing_features.py 
b/tests/python/testing/test_tvm_testing_features.py
deleted file mode 100644
index 2f4c798947..0000000000
--- a/tests/python/testing/test_tvm_testing_features.py
+++ /dev/null
@@ -1,192 +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.
-# ruff: noqa: RUF012
-
-import os
-
-import pytest
-
-import tvm.testing
-
-pytestmark = pytest.mark.xdist_group(name="tvm-testing-features")
-
-# This file tests features in tvm.testing, such as verifying that
-# cached fixtures are run an appropriate number of times.  As a
-# result, the order of the tests is important.  Use of --last-failed
-# or --failed-first while debugging this file is not advised.  If
-# these tests are distributed/parallelized using pytest-xdist or
-# similar, all tests in this file should run sequentially on the same
-# node.  (See https://stackoverflow.com/a/59504228)
-
-
-class TestParameter:
-    param1_vals = [1, 2, 3]
-    param2_vals = ["a", "b", "c"]
-
-    independent_usages = 0
-    param1 = tvm.testing.parameter(*param1_vals)
-    param2 = tvm.testing.parameter(*param2_vals)
-
-    def test_using_independent(self, param1, param2):
-        type(self).independent_usages += 1
-
-    def test_independent(self):
-        assert self.independent_usages == len(self.param1_vals) * 
len(self.param2_vals)
-
-
-class TestFixtureCaching:
-    param1_vals = [1, 2, 3]
-    param2_vals = ["a", "b", "c"]
-
-    param1 = tvm.testing.parameter(*param1_vals)
-    param2 = tvm.testing.parameter(*param2_vals)
-
-    uncached_calls = 0
-    cached_calls = 0
-
-    @tvm.testing.fixture
-    def uncached_fixture(self, param1):
-        type(self).uncached_calls += 1
-        return 2 * param1
-
-    def test_use_uncached(self, param1, param2, uncached_fixture):
-        assert 2 * param1 == uncached_fixture
-
-    def test_uncached_count(self):
-        assert self.uncached_calls == len(self.param1_vals) * 
len(self.param2_vals)
-
-    @tvm.testing.fixture(cache_return_value=True)
-    def cached_fixture(self, param1):
-        type(self).cached_calls += 1
-        return 3 * param1
-
-    def test_use_cached(self, param1, param2, cached_fixture):
-        assert 3 * param1 == cached_fixture
-
-    def test_cached_count(self):
-        cache_disabled = bool(int(os.environ.get("TVM_TEST_DISABLE_CACHE", 
"0")))
-        if cache_disabled:
-            assert self.cached_calls == len(self.param1_vals) * 
len(self.param2_vals)
-        else:
-            assert self.cached_calls == len(self.param1_vals)
-
-
-class TestCachedFixtureIsCopy:
-    param = tvm.testing.parameter(1, 2, 3, 4)
-
-    @tvm.testing.fixture(cache_return_value=True)
-    def cached_mutable_fixture(self):
-        return {"val": 0}
-
-    def test_modifies_fixture(self, param, cached_mutable_fixture):
-        assert cached_mutable_fixture["val"] == 0
-
-        # The tests should receive a copy of the fixture value.  If
-        # the test receives the original and not a copy, then this
-        # will cause the next parametrization to fail.
-        cached_mutable_fixture["val"] = param
-
-
-class TestBrokenFixture:
-    # Tests that use a fixture that throws an exception fail, and are
-    # marked as setup failures.  The tests themselves are never run.
-    # This behavior should be the same whether or not the fixture
-    # results are cached.
-
-    num_uses_broken_uncached_fixture = 0
-    num_uses_broken_cached_fixture = 0
-
-    @tvm.testing.fixture
-    def broken_uncached_fixture(self):
-        raise RuntimeError("Intentionally broken fixture")
-
-    @pytest.mark.xfail(True, reason="Broken fixtures should result in a 
failing setup", strict=True)
-    def test_uses_broken_uncached_fixture(self, broken_uncached_fixture):
-        type(self).num_uses_broken_fixture += 1
-
-    def test_num_uses_uncached(self):
-        assert self.num_uses_broken_uncached_fixture == 0
-
-    @tvm.testing.fixture(cache_return_value=True)
-    def broken_cached_fixture(self):
-        raise RuntimeError("Intentionally broken fixture")
-
-    @pytest.mark.xfail(True, reason="Broken fixtures should result in a 
failing setup", strict=True)
-    def test_uses_broken_cached_fixture(self, broken_cached_fixture):
-        type(self).num_uses_broken_cached_fixture += 1
-
-    def test_num_uses_cached(self):
-        assert self.num_uses_broken_cached_fixture == 0
-
-
[email protected](
-    bool(int(os.environ.get("TVM_TEST_DISABLE_CACHE", "0"))),
-    reason="Cannot test cache behavior while caching is disabled",
-)
-class TestCacheableTypes:
-    class EmptyClass:
-        pass
-
-    @tvm.testing.fixture(cache_return_value=True)
-    def uncacheable_fixture(self):
-        return self.EmptyClass()
-
-    def test_uses_uncacheable(self, request):
-        # Normally the num_tests_use_this_fixture would be set before
-        # anything runs.  For this test case only, because we are
-        # delaying the use of the fixture, we need to manually
-        # increment it.
-        self.uncacheable_fixture.num_tests_use_this_fixture[0] += 1
-        with pytest.raises(TypeError):
-            request.getfixturevalue("uncacheable_fixture")
-
-    class ImplementsReduce:
-        def __reduce__(self):
-            return super().__reduce__()
-
-    @tvm.testing.fixture(cache_return_value=True)
-    def fixture_with_reduce(self):
-        return self.ImplementsReduce()
-
-    def test_uses_reduce(self, fixture_with_reduce):
-        pass
-
-    class ImplementsDeepcopy:
-        def __deepcopy__(self, memo):
-            return type(self)()
-
-    @tvm.testing.fixture(cache_return_value=True)
-    def fixture_with_deepcopy(self):
-        return self.ImplementsDeepcopy()
-
-    def test_uses_deepcopy(self, fixture_with_deepcopy):
-        pass
-
-
-class TestPytestCache:
-    param = tvm.testing.parameter(1, 2, 3)
-
-    @pytest.fixture(scope="class")
-    def cached_fixture(self, param):
-        return param * param
-
-    def test_uses_cached_fixture(self, param, cached_fixture):
-        assert cached_fixture == param * param
-
-
-if __name__ == "__main__":
-    tvm.testing.main()
diff --git a/tests/python/testing/test_type_annotation_checker.py 
b/tests/python/testing/test_type_annotation_checker.py
deleted file mode 100644
index b5d2afcb92..0000000000
--- a/tests/python/testing/test_type_annotation_checker.py
+++ /dev/null
@@ -1,227 +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.
-# ruff: noqa: F401
-"""Test type checker based on python's type annotations"""
-
-import sys
-from collections.abc import Callable
-from typing import Union
-
-import _pytest
-import pytest
-
-import tvm
-from tvm.s_tir.schedule._type_checker import type_checked
-
-
-def int_func(x: int) -> int:
-    return 2 * x
-
-
-def str_func(x: str) -> str:
-    return 2 * x
-
-
-test_cases = [
-    {
-        "type_annotation": int,
-        "positive_cases": [5],
-        "negative_cases": ["5"],
-    },
-    {
-        "type_annotation": list[int],
-        "positive_cases": [
-            [5],
-            [],
-            # Tuples are allowed to be used as lists, because both are
-            # represented in FFI as tvm::Array.
-            (1, 2, 3),
-        ],
-        "negative_cases": [
-            None,
-            5,
-            ["5"],
-        ],
-    },
-    {
-        "type_annotation": dict[str, int],
-        "positive_cases": [
-            {"key1": 0, "key2": 1, "key3": -1},
-        ],
-        "negative_cases": [None, [1], {1: "1"}],
-    },
-    {
-        "type_annotation": tuple[int],
-        "positive_cases": [
-            (5,),
-        ],
-        "negative_cases": [
-            None,
-            (1, 2, 3),
-            [1],
-            5,
-            ["5"],
-        ],
-    },
-    {
-        "type_annotation": tuple[str, int],
-        "positive_cases": [
-            ("x", 5),
-        ],
-        "negative_cases": [
-            42,
-            ("x", 5, 6),
-            ("x", 5, "y"),
-            ("x", 5.0),
-            (None, 5),
-        ],
-    },
-    {
-        "type_annotation": str | int,
-        "positive_cases": [
-            "x",
-            5,
-        ],
-        "negative_cases": [
-            5.0,
-            ("x", 5, 6),
-            None,
-        ],
-    },
-    {
-        "type_annotation": Callable,
-        "positive_cases": [str_func, int_func],
-        "negative_cases": [
-            None,
-            "x",
-            42,
-        ],
-    },
-    {
-        "type_annotation": Callable[[int], int],
-        "positive_cases": [int_func],
-        "negative_cases": [
-            None,
-            "x",
-            42,
-            pytest.param(
-                str_func,
-                marks=pytest.mark.xfail(
-                    reason="Signature of Callable arguments not currently 
checked"
-                ),
-            ),
-        ],
-    },
-]
-
-
-def make_parametrization(type_annotation, case):
-    if isinstance(case, _pytest.mark.structures.ParameterSet):
-        marks = case.marks
-        (case,) = case.values
-    else:
-        marks = []
-
-    try:
-        annotation_name = type_annotation.__name__
-    except AttributeError:
-        annotation_name = str(type_annotation).replace("typing.", "")
-
-    if hasattr(case, "__name__"):
-        case_name = case.__name__
-    else:
-        case_name = str(case)
-
-    name = f"{annotation_name}, {case_name}"
-
-    return pytest.param(type_annotation, case, marks=marks, id=name)
-
-
-positive_cases = [
-    make_parametrization(config["type_annotation"], case)
-    for config in test_cases
-    for case in config["positive_cases"]
-]
-
-negative_cases = [
-    make_parametrization(config["type_annotation"], case)
-    for config in test_cases
-    for case in config["negative_cases"]
-]
-
-
[email protected](
-    ["type_annotation", "case"],
-    positive_cases,
-)
-def test_matches_type(type_annotation, case):
-    @type_checked
-    def func(_: type_annotation):
-        pass
-
-    func(case)
-
-
[email protected](
-    ["type_annotation", "case"],
-    negative_cases,
-)
-def test_not_matches(type_annotation, case):
-    @type_checked
-    def func(_: type_annotation):
-        pass
-
-    with pytest.raises(TypeError):
-        func(case)
-
-
[email protected](
-    ["type_annotation", "expected_key", "expected_subtypes"],
-    [
-        pytest.param(str | int, "union", [str, int], id="str | int"),
-        pytest.param(list[str], "list", [str], id="List[str]"),
-        pytest.param(dict[str, int], "dict", [str, int], id="Dict[str, int]"),
-        pytest.param(tuple[str, int], "tuple", (str, int), id="Tuple[str, 
int]"),
-        pytest.param(
-            list[str] | dict[str, int],
-            "union",
-            [list[str], dict[str, int]],
-            id="Union[List[str], Dict[str, int]]",
-        ),
-    ],
-)
-def test_subscripted_generics(type_annotation, expected_key, 
expected_subtypes):
-    """Test that _dispatcher correctly handles subscripted generics in Python 
3.14+.
-
-    In Python 3.14, Union and other generic types have a different internal 
representation.
-    This test ensures that the dispatcher correctly identifies these types.
-    """
-    from tvm.s_tir.schedule._type_checker import _dispatcher
-
-    key, subtypes = _dispatcher(type_annotation)
-    assert key == expected_key, f"Expected '{expected_key}' but got '{key}'"
-
-    if isinstance(expected_subtypes, tuple):
-        assert tuple(subtypes) == expected_subtypes, (
-            f"Expected {expected_subtypes} but got {subtypes}"
-        )
-    else:
-        assert subtypes == expected_subtypes, f"Expected {expected_subtypes} 
but got {subtypes}"
-
-
-if __name__ == "__main__":
-    tvm.testing.main()
diff --git 
a/tests/python/tirx-transform/test_tir_transform_lower_tvm_builtin.py 
b/tests/python/tirx-transform/test_tir_transform_lower_tvm_builtin.py
index df3e8d529c..d58d993d2a 100644
--- a/tests/python/tirx-transform/test_tir_transform_lower_tvm_builtin.py
+++ b/tests/python/tirx-transform/test_tir_transform_lower_tvm_builtin.py
@@ -113,6 +113,36 @@ def test_lower_call_packed():
     tvm.ir.assert_structural_equal(After, Expected)
 
 
[email protected](not env.has_llvm(), reason="need llvm")
+def test_lower_call_packed_raw_string():
+    @I.ir_module
+    class Before:
+        @T.prim_func(s_tir=True)
+        def main():
+            T.func_attr({"target": tvm.target.Target("llvm")})
+            T.call_packed("testing.echo", "payload")
+
+    @I.ir_module
+    class Expected:
+        @T.prim_func(s_tir=True)
+        def main():
+            T.func_attr({"target": tvm.target.Target("llvm")})
+            stack_ffi_any: T.let[T.handle] = T.tvm_stack_alloca("tvm_ffi_any", 
2)
+            T.tvm_struct_set(stack_ffi_any, 0, 13, 8)
+            T.tvm_struct_set(stack_ffi_any, 0, 14, 0)
+            T.tvm_struct_set(stack_ffi_any, 0, 15, 
T.reinterpret(T.handle().ty, "payload"))
+            T.tvm_struct_set(stack_ffi_any, 1, 13, 0)
+            T.tvm_struct_set(stack_ffi_any, 1, 14, 0)
+            T.tvm_struct_set(stack_ffi_any, 1, 15, T.int64(0))
+            T.call_packed_lowered("testing.echo", stack_ffi_any, 0, 1)
+
+    After = tvm.tirx.transform.LowerTVMBuiltin()(Before)
+    tvm.ir.assert_structural_equal(After, Expected)
+
+    # The typed pointer is required by the LLVM TVMFFIAny lowering.
+    tvm.compile(Before, target="llvm")
+
+
 @pytest.mark.skipif(not env.has_llvm(), reason="need llvm")
 def test_call_packed_return_non_i32():
     # This call packed that return non i32 types
diff --git a/tests/python/tirx/conftest.py b/tests/python/tirx/conftest.py
index fb8ba62f4f..2653a1f05a 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,17 @@ from tvm.testing import env
 def pytest_collection_modifyitems(config, items):
     if env.has_cuda_compute(10):
         return
+    suite_root = Path(__file__).resolve().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)
+        path = getattr(item, "path", None)
+        if path is None:
+            continue
+        try:
+            path = Path(path).resolve()
+        except TypeError:
+            continue
+        if path.is_relative_to(suite_root):
+            item.add_marker(skip)
diff --git a/tests/python/tvmscript/test_tvmscript_roundtrip.py 
b/tests/python/tvmscript/test_tvmscript_roundtrip.py
index 10828ddf25..08bf42decf 100644
--- a/tests/python/tvmscript/test_tvmscript_roundtrip.py
+++ b/tests/python/tvmscript/test_tvmscript_roundtrip.py
@@ -3292,15 +3292,11 @@ def relax_symbolic_var():
 
 
 def relax_float_symbolic_var():
-    """Relax symbolic variables may hold any dtype"""
+    """Relax scalar variables may use any dtype."""
 
     @R.function
-    def func(A: R.Tensor(["N"], "float16"), _: R.Prim(value="threshold")):
-        N = T.int64()
-        threshold = T.float16()
-
-        B = A >= R.prim_value(threshold / T.cast(N, "float16"))
-        return B
+    def func(value: R.Prim("float16")):
+        return value
 
     return func
 
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..524a9f2a2e 100755
--- a/tests/scripts/task_python_unittest.sh
+++ b/tests/scripts/task_python_unittest.sh
@@ -19,55 +19,9 @@
 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[@]}"
+python3 -m pytest -vvs -n auto -m "${TVM_TEST_MARKER:-not gpu}" tests/python
diff --git a/tests/scripts/task_python_unittest_gpuonly.sh 
b/tests/scripts/task_python_unittest_gpuonly.sh
index 8194b23ac4..ca1ae86f73 100755
--- a/tests/scripts/task_python_unittest_gpuonly.sh
+++ b/tests/scripts/task_python_unittest_gpuonly.sh
@@ -19,7 +19,7 @@
 set -euxo pipefail
 
 # Every GPU test carries the `gpu` marker; the specific backend is gated by 
skipif.
-export PYTEST_ADDOPTS="-m gpu ${PYTEST_ADDOPTS:-}"
+export TVM_TEST_MARKER="gpu"
 
 # Test most of the enabled runtimes here.
 # TODO: disabled opencl tests due to segmentation fault.
@@ -32,10 +32,7 @@ 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 -m "${TVM_TEST_MARKER}" \
+    tests/python/codegen/test_target_codegen_vulkan.py

Reply via email to