# 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: F841 """ In this test file, we want to make sure the Python code can construct Doc objects, then access and modify their attributes correctly. """ import pytest from tvm_ffi.access_path import AccessPath import tvm from tvm.script.printer.doc import ( AssertDoc, AssignDoc, AttrAccessDoc, CallDoc, ClassDoc, CommentDoc, DictDoc, DocStringDoc, ExprStmtDoc, ForDoc, FunctionDoc, IdDoc, IfDoc, IndexDoc, LambdaDoc, ListDoc, LiteralDoc, OperationDoc, OperationKind, ReturnDoc, ScopeDoc, SliceDoc, StmtBlockDoc, TupleDoc, WhileDoc, ) @pytest.mark.parametrize( "value", [None, "test", 0, 1, -2, 0.0, 1.5, -1.3, True, False], ) def test_literal_doc_construction(value): doc = LiteralDoc(value) if isinstance(value, float): # FloatImm cannot be compared with Python's float directly assert float(doc.value) == pytest.approx(value) else: assert doc.value == value def test_id_doc(): doc = IdDoc("name") assert doc.name == "name" def test_attr_access_doc(): target = IdDoc("x") doc = AttrAccessDoc(target, "attribute") assert doc.value == target assert doc.name == "attribute" @pytest.mark.parametrize( "indices", [ [], [LiteralDoc(1)], [LiteralDoc(2), IdDoc("x")], [SliceDoc(LiteralDoc(1), LiteralDoc(2))], [SliceDoc(LiteralDoc(1)), IdDoc("y")], ], ) def test_index_doc(indices): target = IdDoc("x") doc = IndexDoc(target, indices) assert doc.value == target assert list(doc.indices) == indices @pytest.mark.parametrize( "args, kwargs", [ ([], {}), ([LiteralDoc("arg")], {}), ([LiteralDoc("arg"), IdDoc("x")], {}), ([], {"x": LiteralDoc("x")}), ([], {"x": LiteralDoc("x"), "y": LiteralDoc("y")}), ([LiteralDoc("arg")], {"x": LiteralDoc("x"), "y": LiteralDoc("y")}), ([LiteralDoc("arg"), IdDoc("x")], {"x": LiteralDoc("x"), "y": LiteralDoc("y")}), ], ) def test_call_doc(args, kwargs): target = IdDoc("x") doc = CallDoc(target, *args, **kwargs) assert doc.callee == target assert list(doc.args) == args assert dict(zip(doc.kwargs_keys, doc.kwargs_values)) == kwargs @pytest.mark.parametrize( "operands", [ [], [LiteralDoc(1)], [LiteralDoc(2), IdDoc("x")], [LiteralDoc(2), IdDoc("x"), LiteralDoc("y")], ], ) def test_operation_doc(operands): # Here we just test the contructor and attr visitor of OperationDoc # so the choice of OperationKind doesn't matter operator = OperationKind.Add doc = OperationDoc(OperationKind.Add, operands) assert doc.kind == operator assert list(doc.operands) == operands @pytest.mark.parametrize( "args", [ [], [IdDoc("x")], [IdDoc("x"), IdDoc("y")], ], ) def test_lambda_doc(args): body = LiteralDoc(1) doc = LambdaDoc(args, body) assert doc.body == body assert list(doc.args) == args @pytest.mark.parametrize( "elements", [ [], [IdDoc("x")], [IdDoc("x"), IdDoc("y")], ], ) def test_tuple_doc(elements): doc = TupleDoc(elements) assert list(doc.elements) == elements @pytest.mark.parametrize( "elements", [ [], [IdDoc("x")], [IdDoc("x"), IdDoc("y")], ], ) def test_list_doc(elements): doc = ListDoc(elements) assert list(doc.elements) == elements @pytest.mark.parametrize( "content", [ {}, {LiteralDoc("k"): IdDoc("v")}, {LiteralDoc("k"): IdDoc("v"), LiteralDoc("k2"): IdDoc("v2")}, ], ) def test_dict_doc(content): doc = DictDoc(content) assert dict(zip(doc.keys, doc.values)) == content @pytest.mark.parametrize("start", [LiteralDoc(1), None]) @pytest.mark.parametrize("stop", [LiteralDoc(2), None]) @pytest.mark.parametrize("step", [LiteralDoc(3), None]) def test_slice_doc(start, stop, step): doc = SliceDoc(start, stop) assert doc.start == start assert doc.stop == stop def test_expr_doc_attr_access(): target = IdDoc("x") attr = "test" doc = target.attr(attr) assert doc.value == target assert doc.name == attr @pytest.mark.parametrize( "indices", [ (), LiteralDoc(1), SliceDoc(LiteralDoc(1), LiteralDoc(2)), (LiteralDoc(1),), (LiteralDoc(2), IdDoc("x")), (SliceDoc(LiteralDoc(1), LiteralDoc(2)),), (SliceDoc(LiteralDoc(1)), IdDoc("y")), ], ) def test_expr_doc_get_item(indices): target = IdDoc("x") doc = target[indices] assert doc.value == target if not isinstance(indices, tuple): indices = (indices,) assert tuple(doc.indices) == indices @pytest.mark.parametrize( "args, kwargs", [ ([], {}), ([LiteralDoc("arg")], {}), ([LiteralDoc("arg"), IdDoc("x")], {}), ([], {"x": LiteralDoc("x")}), ([], {"x": LiteralDoc("x"), "y": LiteralDoc("y")}), ([LiteralDoc("arg")], {"x": LiteralDoc("x"), "y": LiteralDoc("y")}), ([LiteralDoc("arg"), IdDoc("x")], {"x": LiteralDoc("x"), "y": LiteralDoc("y")}), ], ) def test_expr_doc_call_with(args, kwargs): target = IdDoc("x") doc = target.call(*args, **kwargs) assert doc.callee == target assert list(doc.args) == args assert dict(zip(doc.kwargs_keys, doc.kwargs_values)) == kwargs @pytest.mark.parametrize( "stmts", [ [], [ExprStmtDoc(IdDoc("x"))], [ExprStmtDoc(IdDoc("x")), ExprStmtDoc(IdDoc("y"))], ], ) def test_stmt_block_doc(stmts): doc = StmtBlockDoc(stmts) assert list(doc.stmts) == stmts @pytest.mark.parametrize( "lhs, rhs, annotation", [ (IdDoc("x"), IdDoc("y"), None), (IdDoc("x"), None, IdDoc("int")), (IdDoc("x"), IdDoc("y"), IdDoc("int")), ], ) def test_assign_doc(lhs, rhs, annotation): doc = AssignDoc(lhs, rhs, annotation) assert doc.lhs == lhs assert doc.rhs == rhs assert doc.annotation == annotation @pytest.mark.parametrize( "lhs, rhs, annotation", [ (IdDoc("x"), None, None), (TupleDoc([IdDoc("x"), IdDoc("y")]), None, IdDoc("int")), (TupleDoc([IdDoc("x"), IdDoc("y")]), IdDoc("u"), IdDoc("int")), ], ) def test_invalid_assign_doc(lhs, rhs, annotation): with pytest.raises(ValueError) as e: AssignDoc(lhs, rhs, annotation) @pytest.mark.parametrize( "else_branch", [ [], [ExprStmtDoc(IdDoc("x"))], [ExprStmtDoc(IdDoc("x")), ExprStmtDoc(IdDoc("y"))], ], ) @pytest.mark.parametrize( "then_branch", [ [], [ExprStmtDoc(IdDoc("x"))], [ExprStmtDoc(IdDoc("x")), ExprStmtDoc(IdDoc("y"))], ], ) def test_if_doc(then_branch, else_branch): predicate = IdDoc("x") if not then_branch and not else_branch: with pytest.raises(ValueError) as e: IfDoc(predicate, then_branch, else_branch) return else: doc = IfDoc(predicate, then_branch, else_branch) assert doc.predicate == predicate assert list(doc.then_branch) == then_branch assert list(doc.else_branch) == else_branch @pytest.mark.parametrize( "body", [ [], [ExprStmtDoc(IdDoc("x"))], [ExprStmtDoc(IdDoc("x")), ExprStmtDoc(IdDoc("y"))], ], ) def test_while_doc(body): predicate = IdDoc("x") doc = WhileDoc(predicate, body) assert doc.predicate == predicate assert list(doc.body) == body @pytest.mark.parametrize( "body", [ [], [ExprStmtDoc(IdDoc("x"))], [ExprStmtDoc(IdDoc("x")), ExprStmtDoc(IdDoc("y"))], ], ) def test_for_doc(body): lhs = IdDoc("x") rhs = IdDoc("y") doc = ForDoc(lhs, rhs, body) assert doc.lhs == lhs assert doc.rhs == rhs assert list(doc.body) == body @pytest.mark.parametrize( "lhs", [ None, IdDoc("x"), ], ) @pytest.mark.parametrize( "body", [ [], [ExprStmtDoc(IdDoc("x"))], [ExprStmtDoc(IdDoc("x")), ExprStmtDoc(IdDoc("y"))], ], ) def test_scope_doc(lhs, body): rhs = IdDoc("y") doc = ScopeDoc(lhs, rhs, body) assert doc.lhs == lhs assert doc.rhs == rhs assert list(doc.body) == body def test_expr_stmt_doc(): expr = IdDoc("x") doc = ExprStmtDoc(expr) assert doc.expr == expr @pytest.mark.parametrize( "msg", [ None, LiteralDoc("msg"), ], ) def test_assert_doc(msg): test = IdDoc("x") doc = AssertDoc(test, msg) assert doc.test == test assert doc.msg == msg def test_return_doc(): value = IdDoc("x") doc = ReturnDoc(value) assert doc.value == value @pytest.mark.parametrize( "args", [ [], [AssignDoc(IdDoc("x"), None, IdDoc("int"))], [ AssignDoc(IdDoc("x"), None, IdDoc("int")), AssignDoc(IdDoc("y"), LiteralDoc(1), IdDoc("int")), ], ], ) @pytest.mark.parametrize( "decorators", [ [], [IdDoc("test")], [IdDoc("test"), IdDoc("test2")], ], ) @pytest.mark.parametrize( "return_type", [ None, LiteralDoc(None), ], ) @pytest.mark.parametrize( "body", [ [], [ExprStmtDoc(IdDoc("x"))], [ExprStmtDoc(IdDoc("x")), ExprStmtDoc(IdDoc("y"))], ], ) def test_function_doc(args, decorators, return_type, body): name = IdDoc("name") doc = FunctionDoc(name, args, decorators, return_type, body) assert doc.name == name assert list(doc.args) == args assert list(doc.decorators) == decorators assert doc.return_type == return_type assert list(doc.body) == body @pytest.mark.parametrize( "decorators", [ [], [IdDoc("test")], [IdDoc("test"), IdDoc("test2")], ], ) @pytest.mark.parametrize( "body", [ [], [ExprStmtDoc(IdDoc("x"))], [ExprStmtDoc(IdDoc("x")), ExprStmtDoc(IdDoc("y"))], ], ) def test_class_doc(decorators, body): name = IdDoc("name") doc = ClassDoc(name, decorators, body) assert doc.name == name assert list(doc.decorators) == decorators assert list(doc.body) == body @pytest.mark.parametrize( "comment", [ "", "test comment 1", "test comment 1\ntest comment 1", ], ) def test_comment_doc(comment): doc = CommentDoc(comment) assert doc.comment == comment @pytest.mark.parametrize( "comment", [ "", "test comment 1", "test comment 1\ntest comment 1", ], ) def test_doc_string_doc(comment): doc = DocStringDoc(comment) assert doc.comment == comment def test_stmt_doc_comment(): doc = ExprStmtDoc(IdDoc("x")) assert doc.comment is None comment = "test comment" doc.comment = comment # Make sure the previous statement doesn't set attribute # as if it's an ordinary Python object (__slots__ enforces this). assert not hasattr(doc, "__dict__") or "comment" not in doc.__dict__ assert doc.comment == comment def test_doc_source_paths(): doc = IdDoc("x") assert len(doc.source_paths) == 0 source_paths = [AccessPath.root(), AccessPath.root().attr("x")] doc.source_paths = source_paths # This should triggers the __getattr__ and gets a tvm_ffi.Array assert not isinstance(doc.source_paths, list) assert list(doc.source_paths) == source_paths doc.source_paths = [] assert len(doc.source_paths) == 0 if __name__ == "__main__": tvm.testing.main()