This is an automated email from the ASF dual-hosted git repository.
tqchen 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 4fd6cfab15 [TVMScript] Render invisible paths in structural
diagnostics (#19916)
4fd6cfab15 is described below
commit 4fd6cfab157cdd7e77399bb419f43193c050043d
Author: Tianqi Chen <[email protected]>
AuthorDate: Wed Jul 1 02:37:06 2026 +0800
[TVMScript] Render invisible paths in structural diagnostics (#19916)
Structural diagnostics can identify a field below an object that
TVMScript renders without exposing that field. An underline alone then
points at the nearest visible parent and hides the full internal
location. This change keeps Script string-returning while making the
diagnostic context self-contained.
When the requested path is <root>.dtype, Script now returns this string
by default:
```text
Access path: <root>.dtype
Note: The underlined object is the nearest visible parent of this path.
T.int32
^^^^^^^
```
render_invisible_path_info defaults to true. Calls without target paths
are unchanged, and callers can set it to false to retain the legacy
underline-only string.
The implementation reuses the printer span-selection logic to capture
the deepest visible path and assembles the minimal
access-path/note/script block in C++. Pass-error enrichment uses the
same Script path. Production Python remains unchanged; focused Python
tests assert the complete strings for default-on, explicit-false,
hidden, exact-visible, unavailable-visible, pass-error, and
structural-equality cases.
---
include/tvm/script/printer/config.h | 4 +
src/ir/transform.cc | 1 +
src/script/printer/doc_printer/base_doc_printer.cc | 8 +-
src/script/printer/doc_printer/base_doc_printer.h | 9 +++
.../printer/doc_printer/python_doc_printer.cc | 45 +++++++++--
src/script/printer/script_printer.cc | 32 +++++++-
.../relax/test_transform_error_enrichment.py | 24 +++---
.../test_tvmscript_printer_invisible_path_info.py | 68 ++++++++++++++++
.../test_tvmscript_printer_python_doc_printer.py | 4 +
.../test_tvmscript_printer_structural_equal.py | 18 +++++
.../test_tvmscript_printer_underlining.py | 90 ++++++++++++++--------
11 files changed, 255 insertions(+), 48 deletions(-)
diff --git a/include/tvm/script/printer/config.h
b/include/tvm/script/printer/config.h
index e0ed32d380..f8cb7cba8a 100644
--- a/include/tvm/script/printer/config.h
+++ b/include/tvm/script/printer/config.h
@@ -76,6 +76,9 @@ class PrinterConfigNode : public ffi::Object {
/*! \brief Whether variable names should include the object's address */
bool show_object_address = false;
+ /*! \brief Whether to render access-path context for invisible underlined
paths. Defaults true. */
+ bool render_invisible_path_info = true;
+
/* \brief ffi::Object path to be underlined */
ffi::Array<ffi::reflection::AccessPath> path_to_underline;
/*! \brief ffi::Object path to be annotated. */
@@ -126,6 +129,7 @@ class PrinterConfigNode : public ffi::Object {
.def_ro("num_context_lines", &PrinterConfigNode::num_context_lines)
.def_ro("syntax_sugar", &PrinterConfigNode::syntax_sugar)
.def_ro("show_object_address", &PrinterConfigNode::show_object_address)
+ .def_ro("render_invisible_path_info",
&PrinterConfigNode::render_invisible_path_info)
.def_ro("path_to_underline", &PrinterConfigNode::path_to_underline)
.def_ro("path_to_annotate", &PrinterConfigNode::path_to_annotate)
.def_ro("obj_to_underline", &PrinterConfigNode::obj_to_underline)
diff --git a/src/ir/transform.cc b/src/ir/transform.cc
index af387c3b19..5b49f2b26a 100644
--- a/src/ir/transform.cc
+++ b/src/ir/transform.cc
@@ -320,6 +320,7 @@ std::optional<std::string> RenderScriptWithUnderline(const
ffi::ObjectRef& node,
// module. A small TIR/Relax function is ~8-15 lines; 10 lines of context
// on each side of the underline covers it end-to-end.
config_dict.Set("num_context_lines", static_cast<int>(10));
+ config_dict.Set("render_invisible_path_info", true);
ffi::Any cfg = (*config_fn)(config_dict);
ffi::Any rendered = (*script_fn)(node, cfg);
return rendered.cast<ffi::String>().operator std::string();
diff --git a/src/script/printer/doc_printer/base_doc_printer.cc
b/src/script/printer/doc_printer/base_doc_printer.cc
index a6019a94d1..93e0233d38 100644
--- a/src/script/printer/doc_printer/base_doc_printer.cc
+++ b/src/script/printer/doc_printer/base_doc_printer.cc
@@ -267,6 +267,7 @@ void DocPrinter::Append(const Doc& doc, const
PrinterConfig& cfg) {
for (const AccessPath& p : cfg->path_to_underline) {
path_to_underline_.push_back(p);
current_max_path_depth_.push_back(0);
+ current_visible_paths_.push_back(std::nullopt);
current_underline_candidates_.push_back(std::vector<ByteSpan>());
}
PrintDoc(doc);
@@ -291,6 +292,10 @@ ffi::String DocPrinter::GetString() const {
MergeAndExemptSpans(underlines_, underlines_exempted_));
}
+ffi::Array<ffi::Optional<AccessPath>> DocPrinter::GetVisiblePaths() const {
+ return ffi::Array<ffi::Optional<AccessPath>>(current_visible_paths_);
+}
+
void DocPrinter::PrintDoc(const Doc& doc) {
size_t start_pos = output_.tellp();
@@ -364,8 +369,9 @@ void DocPrinter::MarkSpan(const ByteSpan& span, const
AccessPath& path) {
for (int i = 0; i < n; ++i) {
AccessPath p = path_to_underline_[i];
if (path->depth >= current_max_path_depth_[i] && path->IsPrefixOf(p)) {
- if (path->depth > current_max_path_depth_[i]) {
+ if (path->depth > current_max_path_depth_[i] ||
!current_visible_paths_[i].defined()) {
current_max_path_depth_[i] = path->depth;
+ current_visible_paths_[i] = path;
current_underline_candidates_[i].clear();
}
current_underline_candidates_[i].push_back(span);
diff --git a/src/script/printer/doc_printer/base_doc_printer.h
b/src/script/printer/doc_printer/base_doc_printer.h
index 8c2c330370..1dee2322f3 100644
--- a/src/script/printer/doc_printer/base_doc_printer.h
+++ b/src/script/printer/doc_printer/base_doc_printer.h
@@ -83,6 +83,12 @@ class DocPrinter {
*/
ffi::String GetString() const;
+ /*!
+ * \brief Return the visible source path selected for each requested
+ * underline path.
+ */
+ ffi::Array<ffi::Optional<AccessPath>> GetVisiblePaths() const;
+
protected:
/*!
* \brief Get the printed string
@@ -293,6 +299,9 @@ class DocPrinter {
/*! \brief Path length of the objects that are current candidates for
underlining. */
std::vector<int> current_max_path_depth_;
+ /*! \brief Visible path selected by the current best underline candidate. */
+ std::vector<ffi::Optional<AccessPath>> current_visible_paths_;
+
/*! \brief Spans that we have already committed to underline. */
std::vector<ByteSpan> underlines_;
};
diff --git a/src/script/printer/doc_printer/python_doc_printer.cc
b/src/script/printer/doc_printer/python_doc_printer.cc
index 55da056f40..1b1673abf8 100644
--- a/src/script/printer/doc_printer/python_doc_printer.cc
+++ b/src/script/printer/doc_printer/python_doc_printer.cc
@@ -25,6 +25,8 @@
#include <algorithm>
#include <cmath>
#include <map>
+#include <optional>
+#include <sstream>
#include <string>
#include "../../../support/str_escape.h"
@@ -34,6 +36,33 @@
namespace tvm {
namespace script {
namespace printer {
+namespace {
+
+ffi::String RenderInvisiblePathInfo(const ffi::String& script,
+ const ffi::Array<AccessPath>&
requested_paths,
+ const
ffi::Array<ffi::Optional<AccessPath>>& visible_paths) {
+ if (requested_paths.empty()) return script;
+
+ std::ostringstream os;
+ for (size_t i = 0; i < requested_paths.size(); ++i) {
+ if (i != 0) os << "\n";
+ const AccessPath& requested_path = requested_paths[i];
+ os << "Access path: " << requested_path;
+
+ ffi::Optional<AccessPath> visible_path = std::nullopt;
+ if (i < visible_paths.size()) visible_path = visible_paths[i];
+ if (!visible_path.defined()) {
+ os << "\nNote: No visible object for this path is rendered in
TVMScript.";
+ } else if (!visible_path.value()->PathEqual(requested_path) &&
+ visible_path.value()->IsPrefixOf(requested_path)) {
+ os << "\nNote: The underlined object is the nearest visible parent of
this path.";
+ }
+ }
+ os << "\n\n" << script;
+ return ffi::String(os.str());
+}
+
+} // namespace
/*!
* \brief Operator precedence
@@ -798,12 +827,18 @@ ffi::String DocToPythonScript(Doc doc, const
PrinterConfig& cfg) {
}
PythonDocPrinter printer(cfg);
printer.Append(doc, cfg);
- std::string result = printer.GetString();
- int last_space = result.size();
- while (last_space > 0 && std::isspace(result[last_space - 1])) {
- last_space--;
+ std::string script = printer.GetString();
+
+ // GetString terminates non-empty output with one newline. Preserve the
+ // established DocToPythonScript result without normalizing any other
+ // trailing whitespace.
+ if (!script.empty()) {
+ TVM_FFI_ICHECK_EQ(script.back(), '\n');
+ script.pop_back();
}
- return result.substr(0, last_space);
+
+ if (!cfg->render_invisible_path_info) return script;
+ return RenderInvisiblePathInfo(script, cfg->path_to_underline,
printer.GetVisiblePaths());
}
TVM_FFI_STATIC_INIT_BLOCK() {
diff --git a/src/script/printer/script_printer.cc
b/src/script/printer/script_printer.cc
index d46b061401..983cfd2a82 100644
--- a/src/script/printer/script_printer.cc
+++ b/src/script/printer/script_printer.cc
@@ -23,9 +23,30 @@
#include <tvm/script/printer/printer.h>
#include <algorithm>
+#include <sstream>
namespace tvm {
+namespace {
+
+std::string RenderFallbackWithInvisiblePathInfo(const ffi::String& script,
+ const PrinterConfig& config) {
+ if (!config->render_invisible_path_info ||
config->path_to_underline.empty()) {
+ return std::string(script);
+ }
+
+ std::ostringstream os;
+ for (size_t i = 0; i < config->path_to_underline.size(); ++i) {
+ if (i != 0) os << "\n";
+ os << "Access path: " << config->path_to_underline[i]
+ << "\nNote: No visible object for this path is rendered in TVMScript.";
+ }
+ os << "\n\n" << script;
+ return os.str();
+}
+
+} // namespace
+
TVM_FFI_STATIC_INIT_BLOCK() { PrinterConfigNode::RegisterReflection(); }
TVMScriptPrinter::FType& TVMScriptPrinter::vtable() {
@@ -34,11 +55,12 @@ TVMScriptPrinter::FType& TVMScriptPrinter::vtable() {
}
std::string Script(const ffi::ObjectRef& node, const
ffi::Optional<PrinterConfig>& cfg) {
+ PrinterConfig config = cfg.value_or(PrinterConfig());
if (!TVMScriptPrinter::vtable().can_dispatch(node)) {
// Fall back to ffi::ReprPrint for types not registered with
TVMScriptPrinter.
- return std::string(ffi::ReprPrint(ffi::Any(node)));
+ return RenderFallbackWithInvisiblePathInfo(ffi::ReprPrint(ffi::Any(node)),
config);
}
- return TVMScriptPrinter::vtable()(node, cfg.value_or(PrinterConfig()));
+ return TVMScriptPrinter::vtable()(node, config);
}
bool IsIdentifier(const std::string& name) {
@@ -117,6 +139,9 @@ PrinterConfig::PrinterConfig(ffi::Map<ffi::String, Any>
config_dict) {
if (auto v = config_dict.Get("show_object_address")) {
n->show_object_address = v.value().cast<bool>();
}
+ if (auto v = config_dict.Get("render_invisible_path_info")) {
+ n->render_invisible_path_info = v.value().cast<bool>();
+ }
// Dialect-specific keys are stored in extra_config with dotted-name keys.
// String-typed dialect keys passed through directly.
for (const char* key : {"tirx.prefix", "relax.prefix"}) {
@@ -133,6 +158,9 @@ PrinterConfig::PrinterConfig(ffi::Map<ffi::String, Any>
config_dict) {
for (auto kv : extra) {
n->extra_config.Set(kv.first, kv.second);
}
+ if (auto render = extra.Get("render_invisible_path_info")) {
+ n->render_invisible_path_info = render.value().cast<bool>();
+ }
}
// Checking prefixes if they are valid Python identifiers.
diff --git a/tests/python/relax/test_transform_error_enrichment.py
b/tests/python/relax/test_transform_error_enrichment.py
index 4ec1936823..93e44d6096 100644
--- a/tests/python/relax/test_transform_error_enrichment.py
+++ b/tests/python/relax/test_transform_error_enrichment.py
@@ -51,15 +51,21 @@ def test_pass_error_renders_underlined_tvmscript():
mod = _bad_matmul_module()
with pytest.raises(ValueError) as excinfo:
relax.transform.Normalize()(mod)
- msg = str(excinfo.value)
- # The original validator message is preserved.
- assert "Matmul requires the reduction length" in msg
- # The failing pass is named.
- assert "Error in pass: Normalize" in msg
- # The location is rendered as TVMScript with the offending expr underlined.
- assert "Location (TVMScript):" in msg
- assert "R.matmul(x, y" in msg
- assert "^^^" in msg
+ assert str(excinfo.value) == (
+ "Matmul requires the reduction length of the operands to be equal.
However, the LHS x "
+ "has shape R.shape([3, 4]), while the RHS y has shape R.shape([5, 6]).
The reduction "
+ "dimensions of T.int64(4) and T.int64(5) are not equal.\n\n"
+ "Error in pass: Normalize\n"
+ "Location (TVMScript):\n"
+ "Access path: <root>.body.blocks[0].bindings[0].value\n\n"
+ "# from tvm.script import relax as R\n\n"
+ "@R.function\n"
+ 'def main(x: R.Tensor((3, 4), dtype="float32"), '
+ 'y: R.Tensor((5, 6), dtype="float32")) -> R.Tensor((3, 6),
dtype="float32"):\n'
+ " lv = R.matmul(x, y, out_dtype=None)\n"
+ " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"
+ " return lv"
+ )
@pytest.mark.skip_well_formed_check_before_transform
diff --git
a/tests/python/tvmscript/test_tvmscript_printer_invisible_path_info.py
b/tests/python/tvmscript/test_tvmscript_printer_invisible_path_info.py
new file mode 100644
index 0000000000..b110be0923
--- /dev/null
+++ b/tests/python/tvmscript/test_tvmscript_printer_invisible_path_info.py
@@ -0,0 +1,68 @@
+# 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.
+
+from tvm_ffi.access_path import AccessPath
+
+import tvm
+import tvm.testing
+from tvm.runtime.script_printer import PrinterConfig, _script
+
+
+def test_render_invisible_path_info_defaults_to_true():
+ config = PrinterConfig()
+ assert config.render_invisible_path_info is True
+
+ result =
tvm.ir.PrimType("int32").script(path_to_underline=[AccessPath.root().attr("dtype")])
+ assert result == (
+ "Access path: <root>.dtype\n"
+ "Note: The underlined object is the nearest visible parent of this
path.\n\n"
+ "T.int32\n"
+ "^^^^^^^"
+ )
+
+
+def test_render_invisible_path_info_without_target_path_is_unchanged():
+ assert tvm.ir.PrimType("int32").script() == "T.int32"
+
+
+def test_render_invisible_path_info_explicit_false_uses_legacy_output():
+ result = tvm.ir.PrimType("int32").script(
+ path_to_underline=[AccessPath.root().attr("dtype")],
+ extra_config={"render_invisible_path_info": False},
+ )
+ assert result == "T.int32\n^^^^^^^"
+
+
+def test_render_invisible_path_info_exact_visible_path_omits_note():
+ result =
tvm.ir.PrimType("int32").script(path_to_underline=[AccessPath.root()])
+ assert result == "Access path: <root>\n\nT.int32\n^^^^^^^"
+
+
+def test_render_invisible_path_info_without_visible_path():
+ result = _script(
+ tvm.runtime.ShapeTuple([1, 2]),
+ PrinterConfig(path_to_underline=[AccessPath.root().attr("missing")]),
+ )
+ assert result == (
+ "Access path: <root>.missing\n"
+ "Note: No visible object for this path is rendered in TVMScript.\n\n"
+ "Shape(1, 2)"
+ )
+
+
+if __name__ == "__main__":
+ tvm.testing.main()
diff --git
a/tests/python/tvmscript/test_tvmscript_printer_python_doc_printer.py
b/tests/python/tvmscript/test_tvmscript_printer_python_doc_printer.py
index 9aaf5e1b22..9cf7baa302 100644
--- a/tests/python/tvmscript/test_tvmscript_printer_python_doc_printer.py
+++ b/tests/python/tvmscript/test_tvmscript_printer_python_doc_printer.py
@@ -911,6 +911,10 @@ def test_print_comment_doc(comment, expected):
assert to_python_script(doc) == format_script(expected)
+def test_print_comment_doc_preserves_trailing_tab():
+ assert to_python_script(CommentDoc("test comment\t")) == "# test comment\t"
+
+
@pytest.mark.parametrize(
"comment, expected",
[
diff --git a/tests/python/tvmscript/test_tvmscript_printer_structural_equal.py
b/tests/python/tvmscript/test_tvmscript_printer_structural_equal.py
index b9d17cd886..6441cd6745 100644
--- a/tests/python/tvmscript/test_tvmscript_printer_structural_equal.py
+++ b/tests/python/tvmscript/test_tvmscript_printer_structural_equal.py
@@ -36,6 +36,24 @@ and rhs at {objpath2}:
{func2.script(path_to_underline=[objpath2], syntax_sugar=False)}"""
+def test_prim_type_hidden_path_exact_message():
+ with pytest.raises(ValueError) as exc_info:
+ assert_structural_equal(tvm.ir.PrimType("int32"),
tvm.ir.PrimType("float32"))
+
+ assert str(exc_info.value) == (
+ "StructuralEqual check failed, caused by lhs at <root>.dtype:\n"
+ "Access path: <root>.dtype\n"
+ "Note: The underlined object is the nearest visible parent of this
path.\n\n"
+ "T.int32\n"
+ "^^^^^^^\n"
+ "and rhs at <root>.dtype:\n"
+ "Access path: <root>.dtype\n"
+ "Note: The underlined object is the nearest visible parent of this
path.\n\n"
+ "T.float32\n"
+ "^^^^^^^^^"
+ )
+
+
def test_prim_func_buffer_map():
@T.prim_func(s_tir=True)
def func1(a: T.handle, b: T.handle):
diff --git a/tests/python/tvmscript/test_tvmscript_printer_underlining.py
b/tests/python/tvmscript/test_tvmscript_printer_underlining.py
index d475939d84..e3fa2f42eb 100644
--- a/tests/python/tvmscript/test_tvmscript_printer_underlining.py
+++ b/tests/python/tvmscript/test_tvmscript_printer_underlining.py
@@ -63,6 +63,10 @@ def format_script(s: str) -> str:
return cleaned_lines.strip()
+def format_script_with_path_info(s: str, *path_info: str) -> str:
+ return "\n".join(path_info) + "\n\n" + format_script(s)
+
+
def test_underline_basic():
doc = StmtBlockDoc(
[
@@ -71,13 +75,16 @@ def test_underline_basic():
ExprStmtDoc(make_id_doc("qux")),
]
)
- assert to_python_script(doc, path_to_underline=[make_path("baz")]) ==
format_script(
+ assert to_python_script(
+ doc, path_to_underline=[make_path("baz")]
+ ) == format_script_with_path_info(
"""
foo
bar + baz
^^^
qux
- """
+ """,
+ "Access path: <root>.baz",
)
@@ -89,14 +96,17 @@ def test_underline_multiple_spans():
ExprStmtDoc(OperationDoc(OperationKind.Add, [make_id_doc("foo"),
make_id_doc("foo")])),
]
)
- assert to_python_script(doc, path_to_underline=[make_path("foo")]) ==
format_script(
+ assert to_python_script(
+ doc, path_to_underline=[make_path("foo")]
+ ) == format_script_with_path_info(
"""
foo
^^^
bar
foo + foo
^^^ ^^^
- """
+ """,
+ "Access path: <root>.foo",
)
@@ -110,14 +120,15 @@ def test_underline_multiple_spans_with_line_numbers():
)
assert to_python_script(
doc, print_line_numbers=True, path_to_underline=[make_path("foo")]
- ) == format_script(
+ ) == format_script_with_path_info(
"""
1 foo
^^^
2 bar
3 foo + foo
^^^ ^^^
- """
+ """,
+ "Access path: <root>.foo",
)
@@ -130,13 +141,16 @@ def test_underline_multiline():
)
doc.source_paths = [make_path("whole_doc")]
- assert to_python_script(doc, path_to_underline=[make_path("whole_doc")])
== format_script(
+ assert to_python_script(
+ doc, path_to_underline=[make_path("whole_doc")]
+ ) == format_script_with_path_info(
"""
foo
^^^
bar
^^^
- """
+ """,
+ "Access path: <root>.whole_doc",
)
@@ -285,16 +299,17 @@ def test_print_two_context_lines(to_underline,
expected_text):
[ExprStmtDoc(make_id_doc(f"x{i}", "yes" if i in to_underline else
"no")) for i in range(10)]
)
result = to_python_script(doc, num_context_lines=2,
path_to_underline=[make_path("yes")])
- assert result == format_script(expected_text)
+ path_info = ["Access path: <root>.yes"]
+ if to_underline == [33]:
+ path_info.append("Note: No visible object for this path is rendered in
TVMScript.")
+ assert result == format_script_with_path_info(expected_text, *path_info)
def test_underline_and_print_line_numbers():
doc = StmtBlockDoc([ExprStmtDoc(make_id_doc(f"line{i + 1}")) for i in
range(12)])
result = to_python_script(doc, print_line_numbers=True,
path_to_underline=[make_path("line6")])
- assert (
- result.strip()
- == format_script(
- """
+ assert result == "Access path: <root>.line6\n\n " + format_script(
+ """
1 line1
2 line2
3 line3
@@ -309,7 +324,6 @@ def test_underline_and_print_line_numbers():
11 line11
12 line12
"""
- ).strip()
)
@@ -325,10 +339,8 @@ def test_underline_multi_access_paths():
make_path("line9"),
],
)
- assert (
- result.strip()
- == format_script(
- """
+ assert result == format_script_with_path_info(
+ """
line1
^^^^^
line2
@@ -344,8 +356,12 @@ def test_underline_multi_access_paths():
line9
^^^^^
line10
- """
- ).strip()
+ """,
+ "Access path: <root>.line1",
+ "Access path: <root>.line3",
+ "Access path: <root>.line5",
+ "Access path: <root>.line7",
+ "Access path: <root>.line9",
)
@@ -354,7 +370,7 @@ def test_underline_and_print_line_numbers_with_context():
result = to_python_script(
doc, print_line_numbers=True, num_context_lines=2,
path_to_underline=[make_path("line8")]
)
- assert result == format_script(
+ assert result == format_script_with_path_info(
"""
(... 5 lines skipped ...)
6 line6
@@ -364,7 +380,8 @@ def test_underline_and_print_line_numbers_with_context():
9 line9
10 line10
(... 2 lines skipped ...)
- """
+ """,
+ "Access path: <root>.line8",
)
@@ -373,12 +390,14 @@ def test_underline_based_on_path_prefix():
result = to_python_script(doc,
path_to_underline=[make_path("foo").attr("x").attr("y")])
# There is no document that matches the desired path exactly,
# but path of "foo" is a prefix of the desired path, and thus should be
underlined.
- assert result == format_script(
+ assert result == format_script_with_path_info(
"""
foo
^^^
bar
- """
+ """,
+ "Access path: <root>.foo.x.y",
+ "Note: The underlined object is the nearest visible parent of this
path.",
)
@@ -391,13 +410,15 @@ def test_longer_prefix_must_win():
)
result = to_python_script(doc,
path_to_underline=[make_path("foo").attr("x").attr("y")])
# "foo" should not be underlined because there is a document with a more
specific path prefix
- assert result == format_script(
+ assert result == format_script_with_path_info(
"""
foo
bar
foo_x
^^^^^
- """
+ """,
+ "Access path: <root>.foo.x.y",
+ "Note: The underlined object is the nearest visible parent of this
path.",
)
@@ -411,7 +432,10 @@ def test_underline_from_obj():
T.evaluate(a)
T.evaluate(b)
- result = func.with_attr("global_symbol",
"main").script(obj_to_underline=[func.params[0]])
+ result = func.with_attr("global_symbol", "main").script(
+ obj_to_underline=[func.params[0]],
+ extra_config={"render_invisible_path_info": False},
+ )
assert result == format_script(
"""
# from tvm.script import tirx as T
@@ -450,7 +474,8 @@ def test_underline_from_multi_obj():
func.body.seq[3],
func.body.seq[5],
func.body.seq[7],
- ]
+ ],
+ extra_config={"render_invisible_path_info": False},
)
assert result == format_script(
"""
@@ -483,7 +508,8 @@ def test_underline_func():
result = func.with_attr("global_symbol", "main").script(
path_to_underline=[
AccessPath.root(),
- ]
+ ],
+ extra_config={"render_invisible_path_info": False},
)
assert result == format_script(
"""
@@ -510,7 +536,8 @@ def test_underline_func_in_irmodule():
result = irmodule.script(
path_to_underline=[
AccessPath.root().attr("functions").map_item(irmodule.get_global_var("func")),
- ]
+ ],
+ extra_config={"render_invisible_path_info": False},
)
assert result == format_script(
"""
@@ -540,7 +567,8 @@ def test_underline_irmodule():
result = irmodule.script(
path_to_underline=[
AccessPath.root(),
- ]
+ ],
+ extra_config={"render_invisible_path_info": False},
)
assert result == format_script(
"""