From 84f9c7000adb5f701354fe4064ca78b37d4c438d Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Tue, 1 Oct 2024 16:47:05 +0200 Subject: [PATCH 01/29] fix absolute relative paths --- tests/functional/syntax/test_import.py | 72 ++++++++++++++++++++++++++ vyper/semantics/analysis/module.py | 6 +-- 2 files changed, 73 insertions(+), 5 deletions(-) create mode 100644 tests/functional/syntax/test_import.py diff --git a/tests/functional/syntax/test_import.py b/tests/functional/syntax/test_import.py new file mode 100644 index 0000000000..7bad91021b --- /dev/null +++ b/tests/functional/syntax/test_import.py @@ -0,0 +1,72 @@ +import pytest + +from vyper import compiler +from vyper.exceptions import ( + ModuleNotFound +) + +def test_implicitly_relative_import_crashes(make_input_bundle): + top = """ +import subdir0.lib0 as lib0 + +@external +def foo(): + lib0.foo() + """ + + lib0 = """ +import subdir1.lib1 as lib1 + +def foo(): + lib1.foo() + """ + + lib1 = """ + +def foo(): + pass + """ + + input_bundle = make_input_bundle({"top.vy": top, "subdir0/lib0.vy": lib0, "subdir0/subdir1/lib1.vy": lib1}) + + with pytest.raises(ModuleNotFound): + compiler.compile_code(top, input_bundle=input_bundle) + + + lib0 = """ +from subdir1 import lib1 as lib1 + +def foo(): + lib1.foo() + """ + + input_bundle = make_input_bundle({"top.vy": top, "subdir0/lib0.vy": lib0, "subdir0/subdir1/lib1.vy": lib1}) + + with pytest.raises(ModuleNotFound): + compiler.compile_code(top, input_bundle=input_bundle) + + +def test_absolute_path_passes(make_input_bundle): + top = """ +import subdir0.lib0 as lib0 + +@external +def foo(): + lib0.foo() + """ + + lib0 = """ +import subdir0.subdir1.lib1 as lib1 + +def foo(): + lib1.foo() + """ + + lib1 = """ + +def foo(): + pass + """ + + input_bundle = make_input_bundle({"top.vy": top, "subdir0/lib0.vy": lib0, "subdir0/subdir1/lib1.vy": lib1}) + compiler.compile_code(top, input_bundle=input_bundle) diff --git a/vyper/semantics/analysis/module.py b/vyper/semantics/analysis/module.py index d05e494b80..24ae46b93f 100644 --- a/vyper/semantics/analysis/module.py +++ b/vyper/semantics/analysis/module.py @@ -789,11 +789,7 @@ def _add_import( # load an InterfaceT or ModuleInfo from an import. # raises FileNotFoundError def _load_import(self, node: vy_ast.VyperNode, level: int, module_str: str, alias: str) -> Any: - # the directory this (currently being analyzed) module is in - self_search_path = Path(self.ast.resolved_path).parent - - with self.input_bundle.poke_search_path(self_search_path): - return self._load_import_helper(node, level, module_str, alias) + return self._load_import_helper(node, level, module_str, alias) def _load_import_helper( self, node: vy_ast.VyperNode, level: int, module_str: str, alias: str From 0a69fca00b280c6e35490fac9e94f9d0e43a6e36 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Tue, 1 Oct 2024 17:20:38 +0200 Subject: [PATCH 02/29] lint --- tests/functional/syntax/test_import.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/tests/functional/syntax/test_import.py b/tests/functional/syntax/test_import.py index 7bad91021b..56f6fbf458 100644 --- a/tests/functional/syntax/test_import.py +++ b/tests/functional/syntax/test_import.py @@ -1,9 +1,8 @@ import pytest from vyper import compiler -from vyper.exceptions import ( - ModuleNotFound -) +from vyper.exceptions import ModuleNotFound + def test_implicitly_relative_import_crashes(make_input_bundle): top = """ @@ -27,20 +26,23 @@ def foo(): pass """ - input_bundle = make_input_bundle({"top.vy": top, "subdir0/lib0.vy": lib0, "subdir0/subdir1/lib1.vy": lib1}) + input_bundle = make_input_bundle( + {"top.vy": top, "subdir0/lib0.vy": lib0, "subdir0/subdir1/lib1.vy": lib1} + ) with pytest.raises(ModuleNotFound): compiler.compile_code(top, input_bundle=input_bundle) - lib0 = """ -from subdir1 import lib1 as lib1 +from subdir1 import lib1 as lib1 def foo(): lib1.foo() """ - input_bundle = make_input_bundle({"top.vy": top, "subdir0/lib0.vy": lib0, "subdir0/subdir1/lib1.vy": lib1}) + input_bundle = make_input_bundle( + {"top.vy": top, "subdir0/lib0.vy": lib0, "subdir0/subdir1/lib1.vy": lib1} + ) with pytest.raises(ModuleNotFound): compiler.compile_code(top, input_bundle=input_bundle) @@ -68,5 +70,7 @@ def foo(): pass """ - input_bundle = make_input_bundle({"top.vy": top, "subdir0/lib0.vy": lib0, "subdir0/subdir1/lib1.vy": lib1}) + input_bundle = make_input_bundle( + {"top.vy": top, "subdir0/lib0.vy": lib0, "subdir0/subdir1/lib1.vy": lib1} + ) compiler.compile_code(top, input_bundle=input_bundle) From 57f7abd6e431fd9cda69bcb2df372a1504fa0064 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Thu, 3 Oct 2024 21:02:53 +0200 Subject: [PATCH 03/29] fix path from absolute to relative --- tests/unit/cli/vyper_json/test_compile_json.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/cli/vyper_json/test_compile_json.py b/tests/unit/cli/vyper_json/test_compile_json.py index ef3284cd15..756e16ad73 100644 --- a/tests/unit/cli/vyper_json/test_compile_json.py +++ b/tests/unit/cli/vyper_json/test_compile_json.py @@ -293,5 +293,5 @@ def get(filename, contractname): def test_relative_import_paths(input_json): input_json["sources"]["contracts/potato/baz/baz.vy"] = {"content": "from ... import foo"} input_json["sources"]["contracts/potato/baz/potato.vy"] = {"content": "from . import baz"} - input_json["sources"]["contracts/potato/footato.vy"] = {"content": "from baz import baz"} + input_json["sources"]["contracts/potato/footato.vy"] = {"content": "from .baz import baz"} compile_from_input_dict(input_json) From 0db6330b7c83a76263673ccfa1b7f120344fcd4a Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Thu, 3 Oct 2024 21:06:01 +0200 Subject: [PATCH 04/29] add test case for correct relative path --- tests/functional/syntax/test_import.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/functional/syntax/test_import.py b/tests/functional/syntax/test_import.py index 56f6fbf458..fc07d8fab6 100644 --- a/tests/functional/syntax/test_import.py +++ b/tests/functional/syntax/test_import.py @@ -74,3 +74,15 @@ def foo(): {"top.vy": top, "subdir0/lib0.vy": lib0, "subdir0/subdir1/lib1.vy": lib1} ) compiler.compile_code(top, input_bundle=input_bundle) + + lib0 = """ +from .subdir1 import lib1 as lib1 + +def foo(): + lib1.foo() + """ + + input_bundle = make_input_bundle( + {"top.vy": top, "subdir0/lib0.vy": lib0, "subdir0/subdir1/lib1.vy": lib1} + ) + compiler.compile_code(top, input_bundle=input_bundle) From b1dee66de28628a8b63eb910a09fbaafbf2d3edb Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Thu, 3 Oct 2024 21:14:24 +0200 Subject: [PATCH 05/29] make relative paths work again --- vyper/semantics/analysis/module.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/vyper/semantics/analysis/module.py b/vyper/semantics/analysis/module.py index 24ae46b93f..54a2334a41 100644 --- a/vyper/semantics/analysis/module.py +++ b/vyper/semantics/analysis/module.py @@ -1,3 +1,4 @@ +import contextlib import os from pathlib import Path, PurePath from typing import Any, Optional @@ -789,7 +790,13 @@ def _add_import( # load an InterfaceT or ModuleInfo from an import. # raises FileNotFoundError def _load_import(self, node: vy_ast.VyperNode, level: int, module_str: str, alias: str) -> Any: - return self._load_import_helper(node, level, module_str, alias) + # the directory this (currently being analyzed) module is in + self_search_path = Path(self.ast.resolved_path).parent + + with self.input_bundle.search_path( + self_search_path + ) if level != 0 else contextlib.nullcontext(): + return self._load_import_helper(node, level, module_str, alias) def _load_import_helper( self, node: vy_ast.VyperNode, level: int, module_str: str, alias: str From bc7d5691e8ef36de9166026e46cbdb8272b0e198 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Sat, 5 Oct 2024 09:57:13 +0200 Subject: [PATCH 06/29] fix that relatives paths could break out of current directory --- vyper/compiler/input_bundle.py | 6 ++++-- vyper/semantics/analysis/module.py | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/vyper/compiler/input_bundle.py b/vyper/compiler/input_bundle.py index a928989393..011a66ee1e 100644 --- a/vyper/compiler/input_bundle.py +++ b/vyper/compiler/input_bundle.py @@ -103,12 +103,14 @@ def _generate_source_id(self, resolved_path: PathLike) -> int: return self._source_ids[resolved_path] - def load_file(self, path: PathLike | str) -> CompilerInput: + def load_file(self, path: PathLike | str, level: int = 0) -> CompilerInput: # search path precedence tried = [] + search_paths = self.search_paths if level == 0 else [self.search_paths[-1]] + if isinstance(path, str): path = PurePath(path) - for sp in reversed(self.search_paths): + for sp in reversed(search_paths): # note from pathlib docs: # > If the argument is an absolute path, the previous path is ignored. # Path("/a") / Path("/b") => Path("/b") diff --git a/vyper/semantics/analysis/module.py b/vyper/semantics/analysis/module.py index 54a2334a41..4abaecc553 100644 --- a/vyper/semantics/analysis/module.py +++ b/vyper/semantics/analysis/module.py @@ -817,7 +817,7 @@ def _load_import_helper( try: path_vy = path.with_suffix(".vy") - file = self.input_bundle.load_file(path_vy) + file = self.input_bundle.load_file(path_vy, level) assert isinstance(file, FileInput) # mypy hint module_ast = self._ast_from_file(file) @@ -838,7 +838,7 @@ def _load_import_helper( err = e try: - file = self.input_bundle.load_file(path.with_suffix(".vyi")) + file = self.input_bundle.load_file(path.with_suffix(".vyi"), level) assert isinstance(file, FileInput) # mypy hint module_ast = self._ast_from_file(file) @@ -857,7 +857,7 @@ def _load_import_helper( pass try: - file = self.input_bundle.load_file(path.with_suffix(".json")) + file = self.input_bundle.load_file(path.with_suffix(".json"), level) assert isinstance(file, ABIInput) # mypy hint return file, InterfaceT.from_json_abi(str(file.path), file.abi) except FileNotFoundError: From 64ed8c3ab177adb0ccd2f182647dfda69099281f Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Sat, 5 Oct 2024 10:56:58 +0200 Subject: [PATCH 07/29] add test for relative paths breaking out of current directory --- tests/functional/syntax/test_import.py | 27 ++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/functional/syntax/test_import.py b/tests/functional/syntax/test_import.py index fc07d8fab6..e405b78981 100644 --- a/tests/functional/syntax/test_import.py +++ b/tests/functional/syntax/test_import.py @@ -86,3 +86,30 @@ def foo(): {"top.vy": top, "subdir0/lib0.vy": lib0, "subdir0/subdir1/lib1.vy": lib1} ) compiler.compile_code(top, input_bundle=input_bundle) + +def test_relative_paths_stay_in_current_directory(make_input_bundle): + top = """ +from subdir import b as b +@external +def foo(): + b.foo() + """ + + a = """ +def foo(): + pass + """ + + b = """ +from . import a as a + +def foo(): + a.foo() + """ + + input_bundle = make_input_bundle( + {"top.vy": top, "a.vy": a, "subdir/b.vy": b } + ) + + with pytest.raises(ModuleNotFound): + compiler.compile_code(top, input_bundle=input_bundle) From 0463a790fb555b65d116b7c56f5c2c4265068b19 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Tue, 15 Oct 2024 10:53:51 +0200 Subject: [PATCH 08/29] add _load_file with modifies search paths to a relative path or all absolute search paths --- vyper/semantics/analysis/imports.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/vyper/semantics/analysis/imports.py b/vyper/semantics/analysis/imports.py index 3268f12e94..8ea205866e 100644 --- a/vyper/semantics/analysis/imports.py +++ b/vyper/semantics/analysis/imports.py @@ -80,6 +80,7 @@ def __init__(self, input_bundle: InputBundle, graph: _ImportGraph): self.seen: set[int] = set() self.integrity_sum = None + self.abosulte_search_paths = input_bundle.search_paths.copy() # should be all system paths + topmost module path def resolve_imports(self, module_ast: vy_ast.Module): self._resolve_imports_r(module_ast) @@ -149,15 +150,20 @@ def _add_import( alias, qualified_module_name, compiler_input, ast ) + def _load_file(self, path: PathLike, level: int): + if level == 0: + self.input_bundle.search_paths = self.abosulte_search_paths + else: + ast = self.graph.current_module + current_search_path = Path(ast.resolved_path).parent + self.input_bundle.search_paths = [current_search_path] + + return self.input_bundle.load_file(path) + # load an InterfaceT or ModuleInfo from an import. # raises FileNotFoundError def _load_import(self, node: vy_ast.VyperNode, level: int, module_str: str, alias: str) -> Any: - # the directory this (currently being analyzed) module is in - ast = self.graph.current_module - self_search_path = Path(ast.resolved_path).parent - - with self.input_bundle.poke_search_path(self_search_path): - return self._load_import_helper(node, level, module_str, alias) + return self._load_import_helper(node, level, module_str, alias) def _load_import_helper( self, node: vy_ast.VyperNode, level: int, module_str: str, alias: str @@ -177,7 +183,7 @@ def _load_import_helper( try: path_vy = path.with_suffix(".vy") - file = self.input_bundle.load_file(path_vy) + file = self._load_file(path_vy, level) assert isinstance(file, FileInput) # mypy hint module_ast = self._ast_from_file(file) @@ -191,7 +197,7 @@ def _load_import_helper( err = e try: - file = self.input_bundle.load_file(path.with_suffix(".vyi")) + file = self._load_file(path.with_suffix(".vyi"), level) assert isinstance(file, FileInput) # mypy hint module_ast = self._ast_from_file(file) self.resolve_imports(module_ast) @@ -205,7 +211,7 @@ def _load_import_helper( pass try: - file = self.input_bundle.load_file(path.with_suffix(".json")) + file = self._load_file(path.with_suffix(".json"), level) assert isinstance(file, ABIInput) # mypy hint return file, file.abi except FileNotFoundError: From 932e09aae2b93a1a211a776a994dcb0e6b99d753 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Tue, 15 Oct 2024 11:00:07 +0200 Subject: [PATCH 09/29] add tests --- tests/functional/syntax/test_import.py | 86 ++++++++++++++++---------- 1 file changed, 53 insertions(+), 33 deletions(-) diff --git a/tests/functional/syntax/test_import.py b/tests/functional/syntax/test_import.py index e405b78981..4f64e0c0f2 100644 --- a/tests/functional/syntax/test_import.py +++ b/tests/functional/syntax/test_import.py @@ -7,7 +7,6 @@ def test_implicitly_relative_import_crashes(make_input_bundle): top = """ import subdir0.lib0 as lib0 - @external def foo(): lib0.foo() @@ -15,13 +14,11 @@ def foo(): lib0 = """ import subdir1.lib1 as lib1 - def foo(): lib1.foo() """ lib1 = """ - def foo(): pass """ @@ -35,7 +32,6 @@ def foo(): lib0 = """ from subdir1 import lib1 as lib1 - def foo(): lib1.foo() """ @@ -48,68 +44,92 @@ def foo(): compiler.compile_code(top, input_bundle=input_bundle) -def test_absolute_path_passes(make_input_bundle): +def test_relative_import_searches_only_current_path(make_input_bundle): top = """ -import subdir0.lib0 as lib0 - +from subdir import b as b @external def foo(): - lib0.foo() + b.foo() """ - lib0 = """ -import subdir0.subdir1.lib1 as lib1 - + a = """ def foo(): - lib1.foo() + pass """ - lib1 = """ - + b = """ +from . import a as a def foo(): - pass + a.foo() """ input_bundle = make_input_bundle( - {"top.vy": top, "subdir0/lib0.vy": lib0, "subdir0/subdir1/lib1.vy": lib1} + {"top.vy": top, "a.vy": a, "subdir/b.vy": b } ) - compiler.compile_code(top, input_bundle=input_bundle) - lib0 = """ -from .subdir1 import lib1 as lib1 + with pytest.raises(ModuleNotFound): + compiler.compile_code(top, input_bundle=input_bundle) +def test_absolute_import_within_relative_import(make_input_bundle): + top = """ +import subdir0.subdir1.c as c +@external def foo(): - lib1.foo() - """ + c.foo() + """ + a = """ +import subdir0.b as b +def foo(): + b.foo() + """ + b = """ +def foo(): + pass + """ + + c = """ +from .. import a as a +def foo(): + a.foo() + """ input_bundle = make_input_bundle( - {"top.vy": top, "subdir0/lib0.vy": lib0, "subdir0/subdir1/lib1.vy": lib1} + {"top.vy": top, "subdir0/a.vy": a, "subdir0/b.vy": b, "subdir0/subdir1/c.vy": c} ) compiler.compile_code(top, input_bundle=input_bundle) -def test_relative_paths_stay_in_current_directory(make_input_bundle): + +def test_absolute_path_passes(make_input_bundle): top = """ -from subdir import b as b +import subdir0.lib0 as lib0 @external def foo(): - b.foo() + lib0.foo() """ - a = """ + lib0 = """ +import subdir0.subdir1.lib1 as lib1 +def foo(): + lib1.foo() + """ + + lib1 = """ def foo(): pass """ - b = """ -from . import a as a + input_bundle = make_input_bundle( + {"top.vy": top, "subdir0/lib0.vy": lib0, "subdir0/subdir1/lib1.vy": lib1} + ) + compiler.compile_code(top, input_bundle=input_bundle) + lib0 = """ +from .subdir1 import lib1 as lib1 def foo(): - a.foo() + lib1.foo() """ input_bundle = make_input_bundle( - {"top.vy": top, "a.vy": a, "subdir/b.vy": b } + {"top.vy": top, "subdir0/lib0.vy": lib0, "subdir0/subdir1/lib1.vy": lib1} ) - - with pytest.raises(ModuleNotFound): - compiler.compile_code(top, input_bundle=input_bundle) + compiler.compile_code(top, input_bundle=input_bundle) \ No newline at end of file From 67cb7d3d56b42c447f8ea1cf61cf569dc19049d2 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Tue, 15 Oct 2024 18:07:00 +0200 Subject: [PATCH 10/29] add resolved paths to import tests --- tests/functional/codegen/test_interfaces.py | 21 +++++++++++++++---- .../unit/cli/vyper_json/test_compile_json.py | 2 +- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/tests/functional/codegen/test_interfaces.py b/tests/functional/codegen/test_interfaces.py index 8887bf07cb..b33e1064b4 100644 --- a/tests/functional/codegen/test_interfaces.py +++ b/tests/functional/codegen/test_interfaces.py @@ -161,8 +161,6 @@ def bar() -> uint256: ("import Foo as Foo", "Foo.vyi"), ("from a import Foo", "a/Foo.vyi"), ("from b.a import Foo", "b/a/Foo.vyi"), - ("from .a import Foo", "./a/Foo.vyi"), - ("from ..a import Foo", "../a/Foo.vyi"), ] @@ -171,7 +169,22 @@ def bar() -> uint256: def test_extract_file_interface_imports(code, filename, make_input_bundle): input_bundle = make_input_bundle({filename: ""}) - assert compile_code(code, input_bundle=input_bundle) is not None + assert compile_code(code,resolved_path=input_bundle.search_paths[0]/filename ,input_bundle=input_bundle) is not None + +VALID_RELATIVE_IMPORT_CODE = [ + # import statement, import path without suffix + ("from .a import Foo", "a"), + ("from ..a import Foo", "a/b"), +] + + +# TODO CMC 2024-10-13: should probably be in syntax tests +@pytest.mark.parametrize("code,subdirs", VALID_RELATIVE_IMPORT_CODE) +def test_extract_file_interface_relative_imports(code, subdirs, make_input_bundle): + input_bundle = make_input_bundle({"a/Foo.vyi": ""}) + + assert compile_code(code,resolved_path=(input_bundle.search_paths[0])/subdirs ,input_bundle=input_bundle) is not None + BAD_IMPORT_CODE = [ @@ -191,7 +204,7 @@ def test_extract_file_interface_imports_raises( ): input_bundle = make_input_bundle({"a.vyi": "", "b/a.vyi": "", "c.vyi": ""}) with pytest.raises(exception_type): - compile_code(code, input_bundle=input_bundle) + compile_code(code, resolved_path=input_bundle.search_paths[0]/"mock.vy", input_bundle=input_bundle) def test_external_call_to_interface(env, get_contract, make_input_bundle): diff --git a/tests/unit/cli/vyper_json/test_compile_json.py b/tests/unit/cli/vyper_json/test_compile_json.py index 1088804a93..d299c316ed 100644 --- a/tests/unit/cli/vyper_json/test_compile_json.py +++ b/tests/unit/cli/vyper_json/test_compile_json.py @@ -318,4 +318,4 @@ def test_compile_json_with_abi_top(make_input_bundle): from . import stream """ input_bundle = make_input_bundle({"stream.json": stream, "code.vy": code}) - vyper.compiler.compile_code(code, input_bundle=input_bundle) + vyper.compiler.compile_code(code, resolved_path=input_bundle.search_paths[0]/"code.vy", input_bundle=input_bundle) From 052e89541ccb01b03e1b75227c96332f4fe14570 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Tue, 15 Oct 2024 18:08:19 +0200 Subject: [PATCH 11/29] lint --- tests/functional/codegen/test_interfaces.py | 20 +++++++++++++++---- tests/functional/syntax/test_import.py | 7 +++---- .../unit/cli/vyper_json/test_compile_json.py | 4 +++- vyper/semantics/analysis/imports.py | 4 +++- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/tests/functional/codegen/test_interfaces.py b/tests/functional/codegen/test_interfaces.py index b33e1064b4..7604e6e00e 100644 --- a/tests/functional/codegen/test_interfaces.py +++ b/tests/functional/codegen/test_interfaces.py @@ -169,7 +169,13 @@ def bar() -> uint256: def test_extract_file_interface_imports(code, filename, make_input_bundle): input_bundle = make_input_bundle({filename: ""}) - assert compile_code(code,resolved_path=input_bundle.search_paths[0]/filename ,input_bundle=input_bundle) is not None + assert ( + compile_code( + code, resolved_path=input_bundle.search_paths[0] / filename, input_bundle=input_bundle + ) + is not None + ) + VALID_RELATIVE_IMPORT_CODE = [ # import statement, import path without suffix @@ -183,8 +189,12 @@ def test_extract_file_interface_imports(code, filename, make_input_bundle): def test_extract_file_interface_relative_imports(code, subdirs, make_input_bundle): input_bundle = make_input_bundle({"a/Foo.vyi": ""}) - assert compile_code(code,resolved_path=(input_bundle.search_paths[0])/subdirs ,input_bundle=input_bundle) is not None - + assert ( + compile_code( + code, resolved_path=(input_bundle.search_paths[0]) / subdirs, input_bundle=input_bundle + ) + is not None + ) BAD_IMPORT_CODE = [ @@ -204,7 +214,9 @@ def test_extract_file_interface_imports_raises( ): input_bundle = make_input_bundle({"a.vyi": "", "b/a.vyi": "", "c.vyi": ""}) with pytest.raises(exception_type): - compile_code(code, resolved_path=input_bundle.search_paths[0]/"mock.vy", input_bundle=input_bundle) + compile_code( + code, resolved_path=input_bundle.search_paths[0] / "mock.vy", input_bundle=input_bundle + ) def test_external_call_to_interface(env, get_contract, make_input_bundle): diff --git a/tests/functional/syntax/test_import.py b/tests/functional/syntax/test_import.py index 4f64e0c0f2..6baa52e8c0 100644 --- a/tests/functional/syntax/test_import.py +++ b/tests/functional/syntax/test_import.py @@ -63,13 +63,12 @@ def foo(): a.foo() """ - input_bundle = make_input_bundle( - {"top.vy": top, "a.vy": a, "subdir/b.vy": b } - ) + input_bundle = make_input_bundle({"top.vy": top, "a.vy": a, "subdir/b.vy": b}) with pytest.raises(ModuleNotFound): compiler.compile_code(top, input_bundle=input_bundle) + def test_absolute_import_within_relative_import(make_input_bundle): top = """ import subdir0.subdir1.c as c @@ -132,4 +131,4 @@ def foo(): input_bundle = make_input_bundle( {"top.vy": top, "subdir0/lib0.vy": lib0, "subdir0/subdir1/lib1.vy": lib1} ) - compiler.compile_code(top, input_bundle=input_bundle) \ No newline at end of file + compiler.compile_code(top, input_bundle=input_bundle) diff --git a/tests/unit/cli/vyper_json/test_compile_json.py b/tests/unit/cli/vyper_json/test_compile_json.py index d299c316ed..63b433b685 100644 --- a/tests/unit/cli/vyper_json/test_compile_json.py +++ b/tests/unit/cli/vyper_json/test_compile_json.py @@ -318,4 +318,6 @@ def test_compile_json_with_abi_top(make_input_bundle): from . import stream """ input_bundle = make_input_bundle({"stream.json": stream, "code.vy": code}) - vyper.compiler.compile_code(code, resolved_path=input_bundle.search_paths[0]/"code.vy", input_bundle=input_bundle) + vyper.compiler.compile_code( + code, resolved_path=input_bundle.search_paths[0] / "code.vy", input_bundle=input_bundle + ) diff --git a/vyper/semantics/analysis/imports.py b/vyper/semantics/analysis/imports.py index 8ea205866e..4cb636b402 100644 --- a/vyper/semantics/analysis/imports.py +++ b/vyper/semantics/analysis/imports.py @@ -80,7 +80,9 @@ def __init__(self, input_bundle: InputBundle, graph: _ImportGraph): self.seen: set[int] = set() self.integrity_sum = None - self.abosulte_search_paths = input_bundle.search_paths.copy() # should be all system paths + topmost module path + self.abosulte_search_paths = ( + input_bundle.search_paths.copy() + ) # should be all system paths + topmost module path def resolve_imports(self, module_ast: vy_ast.Module): self._resolve_imports_r(module_ast) From a4edbe902fa0e11a374f1d42802cca83b1e29680 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Tue, 15 Oct 2024 18:20:35 +0200 Subject: [PATCH 12/29] revert back to old load_file --- vyper/compiler/input_bundle.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/vyper/compiler/input_bundle.py b/vyper/compiler/input_bundle.py index c42db4142c..a288c0b006 100644 --- a/vyper/compiler/input_bundle.py +++ b/vyper/compiler/input_bundle.py @@ -105,14 +105,13 @@ def _generate_source_id(self, resolved_path: PathLike) -> int: return self._source_ids[resolved_path] - def load_file(self, path: PathLike | str, level: int = 0) -> CompilerInput: + def load_file(self, path: PathLike | str) -> CompilerInput: # search path precedence tried = [] - search_paths = self.search_paths if level == 0 else [self.search_paths[-1]] if isinstance(path, str): path = PurePath(path) - for sp in reversed(search_paths): + for sp in reversed(self.search_paths): # note from pathlib docs: # > If the argument is an absolute path, the previous path is ignored. # Path("/a") / Path("/b") => Path("/b") From 32eb37697322d2f87bc0d22181e409310f34ae54 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Tue, 15 Oct 2024 18:21:28 +0200 Subject: [PATCH 13/29] fuse _load_import with _load_import_helper --- vyper/semantics/analysis/imports.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/vyper/semantics/analysis/imports.py b/vyper/semantics/analysis/imports.py index 4cb636b402..8ab60254f6 100644 --- a/vyper/semantics/analysis/imports.py +++ b/vyper/semantics/analysis/imports.py @@ -164,12 +164,7 @@ def _load_file(self, path: PathLike, level: int): # load an InterfaceT or ModuleInfo from an import. # raises FileNotFoundError - def _load_import(self, node: vy_ast.VyperNode, level: int, module_str: str, alias: str) -> Any: - return self._load_import_helper(node, level, module_str, alias) - - def _load_import_helper( - self, node: vy_ast.VyperNode, level: int, module_str: str, alias: str - ) -> tuple[CompilerInput, Any]: + def _load_import(self, node: vy_ast.VyperNode, level: int, module_str: str, alias: str) -> tuple[CompilerInput, Any]: if _is_builtin(module_str): return _load_builtin_import(level, module_str) From e20b381841fab41e89984594246247a1ee71b1e9 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Tue, 15 Oct 2024 18:22:09 +0200 Subject: [PATCH 14/29] lint --- vyper/semantics/analysis/imports.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vyper/semantics/analysis/imports.py b/vyper/semantics/analysis/imports.py index 8ab60254f6..9414bbe68e 100644 --- a/vyper/semantics/analysis/imports.py +++ b/vyper/semantics/analysis/imports.py @@ -164,7 +164,9 @@ def _load_file(self, path: PathLike, level: int): # load an InterfaceT or ModuleInfo from an import. # raises FileNotFoundError - def _load_import(self, node: vy_ast.VyperNode, level: int, module_str: str, alias: str) -> tuple[CompilerInput, Any]: + def _load_import( + self, node: vy_ast.VyperNode, level: int, module_str: str, alias: str + ) -> tuple[CompilerInput, Any]: if _is_builtin(module_str): return _load_builtin_import(level, module_str) From a843639047a81e1916ee56bbfce02a4bb9cdf1fc Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Tue, 15 Oct 2024 19:20:03 +0200 Subject: [PATCH 15/29] fix typo and remove multiline expr --- vyper/semantics/analysis/imports.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vyper/semantics/analysis/imports.py b/vyper/semantics/analysis/imports.py index 9414bbe68e..2afadb71f0 100644 --- a/vyper/semantics/analysis/imports.py +++ b/vyper/semantics/analysis/imports.py @@ -80,9 +80,9 @@ def __init__(self, input_bundle: InputBundle, graph: _ImportGraph): self.seen: set[int] = set() self.integrity_sum = None - self.abosulte_search_paths = ( - input_bundle.search_paths.copy() - ) # should be all system paths + topmost module path + + # should be all system paths + topmost module path + self.absolute_search_paths = input_bundle.search_paths.copy() def resolve_imports(self, module_ast: vy_ast.Module): self._resolve_imports_r(module_ast) @@ -154,7 +154,7 @@ def _add_import( def _load_file(self, path: PathLike, level: int): if level == 0: - self.input_bundle.search_paths = self.abosulte_search_paths + self.input_bundle.search_paths = self.absolute_search_paths else: ast = self.graph.current_module current_search_path = Path(ast.resolved_path).parent From b98ea67fc8a57e4942296a52745f1b49109c6755 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Tue, 15 Oct 2024 19:20:56 +0200 Subject: [PATCH 16/29] remove newly redundant methods --- vyper/compiler/input_bundle.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/vyper/compiler/input_bundle.py b/vyper/compiler/input_bundle.py index a288c0b006..4b38101a40 100644 --- a/vyper/compiler/input_bundle.py +++ b/vyper/compiler/input_bundle.py @@ -138,8 +138,6 @@ def load_file(self, path: PathLike | str) -> CompilerInput: return res - def add_search_path(self, path: PathLike) -> None: - self.search_paths.append(path) # temporarily add something to the search path (within the # scope of the context manager) with highest precedence. @@ -156,17 +154,6 @@ def search_path(self, path: Optional[PathLike]) -> Iterator[None]: finally: self.search_paths.pop() - # temporarily modify the top of the search path (within the - # scope of the context manager) with highest precedence to something else - @contextlib.contextmanager - def poke_search_path(self, path: PathLike) -> Iterator[None]: - tmp = self.search_paths[-1] - self.search_paths[-1] = path - try: - yield - finally: - self.search_paths[-1] = tmp - # regular input. takes a search path(s), and `load_file()` will search all # search paths for the file and read it from the filesystem From d75c29239a049e8763570a4886d9adfd77e4ec17 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Tue, 15 Oct 2024 19:21:37 +0200 Subject: [PATCH 17/29] lint --- vyper/compiler/input_bundle.py | 1 - vyper/semantics/analysis/imports.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/vyper/compiler/input_bundle.py b/vyper/compiler/input_bundle.py index 4b38101a40..4c5375a57d 100644 --- a/vyper/compiler/input_bundle.py +++ b/vyper/compiler/input_bundle.py @@ -138,7 +138,6 @@ def load_file(self, path: PathLike | str) -> CompilerInput: return res - # temporarily add something to the search path (within the # scope of the context manager) with highest precedence. # if `path` is None, do nothing diff --git a/vyper/semantics/analysis/imports.py b/vyper/semantics/analysis/imports.py index 2afadb71f0..3867bf754a 100644 --- a/vyper/semantics/analysis/imports.py +++ b/vyper/semantics/analysis/imports.py @@ -82,7 +82,7 @@ def __init__(self, input_bundle: InputBundle, graph: _ImportGraph): self.integrity_sum = None # should be all system paths + topmost module path - self.absolute_search_paths = input_bundle.search_paths.copy() + self.absolute_search_paths = input_bundle.search_paths.copy() def resolve_imports(self, module_ast: vy_ast.Module): self._resolve_imports_r(module_ast) From 5ddc9b511b2896ad55d803e6fc9341733f37f3c1 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Mon, 21 Oct 2024 17:09:47 +0200 Subject: [PATCH 18/29] fix tests --- tests/functional/codegen/test_interfaces.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/functional/codegen/test_interfaces.py b/tests/functional/codegen/test_interfaces.py index 7604e6e00e..2bf3e20ef3 100644 --- a/tests/functional/codegen/test_interfaces.py +++ b/tests/functional/codegen/test_interfaces.py @@ -179,19 +179,19 @@ def test_extract_file_interface_imports(code, filename, make_input_bundle): VALID_RELATIVE_IMPORT_CODE = [ # import statement, import path without suffix - ("from .a import Foo", "a"), - ("from ..a import Foo", "a/b"), + ("from .a import Foo", "mock.vy"), + ("from a import Foo", "b/mock.vy"), ] # TODO CMC 2024-10-13: should probably be in syntax tests -@pytest.mark.parametrize("code,subdirs", VALID_RELATIVE_IMPORT_CODE) -def test_extract_file_interface_relative_imports(code, subdirs, make_input_bundle): - input_bundle = make_input_bundle({"a/Foo.vyi": ""}) +@pytest.mark.parametrize("code,filename", VALID_RELATIVE_IMPORT_CODE) +def test_extract_file_interface_relative_imports(code, filename, make_input_bundle): + input_bundle = make_input_bundle({"a/Foo.vyi": "", filename: code}) assert ( compile_code( - code, resolved_path=(input_bundle.search_paths[0]) / subdirs, input_bundle=input_bundle + code, resolved_path=(input_bundle.search_paths[0]) / filename, input_bundle=input_bundle ) is not None ) From 6a7d5cc218ac88394aeaabb81e77066ad513aa49 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Mon, 21 Oct 2024 17:18:15 +0200 Subject: [PATCH 19/29] remove redundancy and fixup --- tests/functional/codegen/test_interfaces.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tests/functional/codegen/test_interfaces.py b/tests/functional/codegen/test_interfaces.py index 2bf3e20ef3..ae7e038e10 100644 --- a/tests/functional/codegen/test_interfaces.py +++ b/tests/functional/codegen/test_interfaces.py @@ -169,18 +169,13 @@ def bar() -> uint256: def test_extract_file_interface_imports(code, filename, make_input_bundle): input_bundle = make_input_bundle({filename: ""}) - assert ( - compile_code( - code, resolved_path=input_bundle.search_paths[0] / filename, input_bundle=input_bundle - ) - is not None - ) + assert compile_code(code, input_bundle=input_bundle) is not None VALID_RELATIVE_IMPORT_CODE = [ # import statement, import path without suffix ("from .a import Foo", "mock.vy"), - ("from a import Foo", "b/mock.vy"), + ("from ..a import Foo", "b/mock.vy"), ] From de79ba5baeffdf4854f241cede044f29d2ed58ff Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Mon, 21 Oct 2024 19:07:58 +0200 Subject: [PATCH 20/29] move function down --- vyper/semantics/analysis/imports.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/vyper/semantics/analysis/imports.py b/vyper/semantics/analysis/imports.py index 3867bf754a..a067a558b3 100644 --- a/vyper/semantics/analysis/imports.py +++ b/vyper/semantics/analysis/imports.py @@ -152,16 +152,6 @@ def _add_import( alias, qualified_module_name, compiler_input, ast ) - def _load_file(self, path: PathLike, level: int): - if level == 0: - self.input_bundle.search_paths = self.absolute_search_paths - else: - ast = self.graph.current_module - current_search_path = Path(ast.resolved_path).parent - self.input_bundle.search_paths = [current_search_path] - - return self.input_bundle.load_file(path) - # load an InterfaceT or ModuleInfo from an import. # raises FileNotFoundError def _load_import( @@ -224,6 +214,16 @@ def _load_import( search_paths = self.input_bundle.search_paths.copy() # noqa: F841 raise ModuleNotFound(module_str, hint=hint) from err + def _load_file(self, path: PathLike, level: int): + if level == 0: + self.input_bundle.search_paths = self.absolute_search_paths + else: + ast = self.graph.current_module + current_search_path = Path(ast.resolved_path).parent + self.input_bundle.search_paths = [current_search_path] + + return self.input_bundle.load_file(path) + def _ast_from_file(self, file: FileInput) -> vy_ast.Module: # cache ast if we have seen it before. # this gives us the additional property of object equality on From e4d6c6246ea08f41ea7dfe5fc5d33563b46e899d Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Mon, 21 Oct 2024 19:27:18 +0200 Subject: [PATCH 21/29] remove newline --- vyper/compiler/input_bundle.py | 1 - 1 file changed, 1 deletion(-) diff --git a/vyper/compiler/input_bundle.py b/vyper/compiler/input_bundle.py index 4c5375a57d..abaf65ddf8 100644 --- a/vyper/compiler/input_bundle.py +++ b/vyper/compiler/input_bundle.py @@ -108,7 +108,6 @@ def _generate_source_id(self, resolved_path: PathLike) -> int: def load_file(self, path: PathLike | str) -> CompilerInput: # search path precedence tried = [] - if isinstance(path, str): path = PurePath(path) for sp in reversed(self.search_paths): From ec686f8d816a686532ffa4552f9a67e56c5733b4 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Tue, 22 Oct 2024 13:42:37 +0200 Subject: [PATCH 22/29] restore search paths after loading file --- vyper/compiler/input_bundle.py | 10 ++++++++++ vyper/semantics/analysis/imports.py | 22 +++++++++++++--------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/vyper/compiler/input_bundle.py b/vyper/compiler/input_bundle.py index abaf65ddf8..06fee78613 100644 --- a/vyper/compiler/input_bundle.py +++ b/vyper/compiler/input_bundle.py @@ -152,6 +152,16 @@ def search_path(self, path: Optional[PathLike]) -> Iterator[None]: finally: self.search_paths.pop() + # temporarily set search paths to a given list + @contextlib.contextmanager + def temporary_search_paths(self, new_paths: list[PathLike]) -> Iterator[None]: + original_paths = self.search_paths + self.search_paths = new_paths + try: + yield + finally: + self.search_paths = original_paths + # regular input. takes a search path(s), and `load_file()` will search all # search paths for the file and read it from the filesystem diff --git a/vyper/semantics/analysis/imports.py b/vyper/semantics/analysis/imports.py index a067a558b3..17a75a32e9 100644 --- a/vyper/semantics/analysis/imports.py +++ b/vyper/semantics/analysis/imports.py @@ -214,15 +214,19 @@ def _load_import( search_paths = self.input_bundle.search_paths.copy() # noqa: F841 raise ModuleNotFound(module_str, hint=hint) from err - def _load_file(self, path: PathLike, level: int): - if level == 0: - self.input_bundle.search_paths = self.absolute_search_paths - else: - ast = self.graph.current_module - current_search_path = Path(ast.resolved_path).parent - self.input_bundle.search_paths = [current_search_path] - - return self.input_bundle.load_file(path) + def _load_file(self, path: PathLike, level: int) -> CompilerInput: + ast = self.graph.current_module + current_search_path = Path(ast.resolved_path).parent + + search_paths = self.absolute_search_paths if level == 0 else [current_search_path] + + with self.input_bundle.temporary_search_paths(search_paths): + res = self.input_bundle.load_file(path) + + if level != 0: + self.input_bundle.search_paths += [current_search_path] + + return res def _ast_from_file(self, file: FileInput) -> vy_ast.Module: # cache ast if we have seen it before. From f0f325a942a9bc7a8e3ca9aba3ca978d46c9d56a Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Wed, 11 Dec 2024 10:56:25 +0100 Subject: [PATCH 23/29] change "+=" to "append" --- vyper/semantics/analysis/imports.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vyper/semantics/analysis/imports.py b/vyper/semantics/analysis/imports.py index 17a75a32e9..352ed7417b 100644 --- a/vyper/semantics/analysis/imports.py +++ b/vyper/semantics/analysis/imports.py @@ -224,7 +224,7 @@ def _load_file(self, path: PathLike, level: int) -> CompilerInput: res = self.input_bundle.load_file(path) if level != 0: - self.input_bundle.search_paths += [current_search_path] + self.input_bundle.search_paths.append(current_search_path) return res From a140226e89d803fdf3d254b3400f2af165238134 Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Fri, 13 Dec 2024 09:55:25 -0500 Subject: [PATCH 24/29] clean up recursion --- vyper/semantics/analysis/imports.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/vyper/semantics/analysis/imports.py b/vyper/semantics/analysis/imports.py index 352ed7417b..b8fbe9646f 100644 --- a/vyper/semantics/analysis/imports.py +++ b/vyper/semantics/analysis/imports.py @@ -216,17 +216,14 @@ def _load_import( def _load_file(self, path: PathLike, level: int) -> CompilerInput: ast = self.graph.current_module - current_search_path = Path(ast.resolved_path).parent - search_paths = self.absolute_search_paths if level == 0 else [current_search_path] + if level != 0: # relative import + search_paths = [Path(ast.resolved_path).parent] + else: + search_paths = self.absolute_search_paths with self.input_bundle.temporary_search_paths(search_paths): - res = self.input_bundle.load_file(path) - - if level != 0: - self.input_bundle.search_paths.append(current_search_path) - - return res + return self.input_bundle.load_file(path) def _ast_from_file(self, file: FileInput) -> vy_ast.Module: # cache ast if we have seen it before. From 99f0af231b8e25f5795a7413bb3163c3f94935d5 Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Fri, 13 Dec 2024 10:12:57 -0500 Subject: [PATCH 25/29] fix lint --- vyper/semantics/analysis/imports.py | 1 + 1 file changed, 1 insertion(+) diff --git a/vyper/semantics/analysis/imports.py b/vyper/semantics/analysis/imports.py index b8fbe9646f..4f8daefa97 100644 --- a/vyper/semantics/analysis/imports.py +++ b/vyper/semantics/analysis/imports.py @@ -217,6 +217,7 @@ def _load_import( def _load_file(self, path: PathLike, level: int) -> CompilerInput: ast = self.graph.current_module + search_paths: list[PathLike] # help mypy if level != 0: # relative import search_paths = [Path(ast.resolved_path).parent] else: From 3359eaed90c89b52a525f68888be4ad14644630e Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Fri, 13 Dec 2024 10:17:01 -0500 Subject: [PATCH 26/29] clean up test --- tests/unit/cli/vyper_json/test_compile_json.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/unit/cli/vyper_json/test_compile_json.py b/tests/unit/cli/vyper_json/test_compile_json.py index 98fd3aa316..6ab3127a98 100644 --- a/tests/unit/cli/vyper_json/test_compile_json.py +++ b/tests/unit/cli/vyper_json/test_compile_json.py @@ -319,9 +319,8 @@ def test_compile_json_with_abi_top(make_input_bundle): from . import stream """ input_bundle = make_input_bundle({"stream.json": stream, "code.vy": code}) - vyper.compiler.compile_code( - code, resolved_path=input_bundle.search_paths[0] / "code.vy", input_bundle=input_bundle - ) + file_input = input_bundle.load_file("code.vy") + vyper.compiler.compile_from_file_input(file_input, input_bundle=input_bundle) def test_compile_json_with_experimental_codegen(): From f67dee811fa1e04b13ed12d12c1d7e5e1b9ba60d Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Fri, 13 Dec 2024 10:24:04 -0500 Subject: [PATCH 27/29] minor clean up for some tests --- tests/functional/codegen/test_interfaces.py | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/tests/functional/codegen/test_interfaces.py b/tests/functional/codegen/test_interfaces.py index e21f052d60..e46a7d3dd4 100644 --- a/tests/functional/codegen/test_interfaces.py +++ b/tests/functional/codegen/test_interfaces.py @@ -4,7 +4,7 @@ from eth_utils import to_wei from tests.utils import decimal_to_int -from vyper.compiler import compile_code +from vyper.compiler import compile_code, compile_from_file_input from vyper.exceptions import ( ArgumentException, DuplicateImport, @@ -184,12 +184,8 @@ def test_extract_file_interface_imports(code, filename, make_input_bundle): def test_extract_file_interface_relative_imports(code, filename, make_input_bundle): input_bundle = make_input_bundle({"a/Foo.vyi": "", filename: code}) - assert ( - compile_code( - code, resolved_path=(input_bundle.search_paths[0]) / filename, input_bundle=input_bundle - ) - is not None - ) + file_input = input_bundle.load_file(filename) + assert compile_from_file_input(file_input, input_bundle=input_bundle) is not None BAD_IMPORT_CODE = [ @@ -204,14 +200,11 @@ def test_extract_file_interface_relative_imports(code, filename, make_input_bund # TODO CMC 2024-10-13: should probably be in syntax tests @pytest.mark.parametrize("code,exception_type", BAD_IMPORT_CODE) -def test_extract_file_interface_imports_raises( - code, exception_type, assert_compile_failed, make_input_bundle -): - input_bundle = make_input_bundle({"a.vyi": "", "b/a.vyi": "", "c.vyi": ""}) +def test_extract_file_interface_imports_raises(code, exception_type, make_input_bundle): + input_bundle = make_input_bundle({"a.vyi": "", "b/a.vyi": "", "c.vyi": "", "mock.vy": code}) + file_input = input_bundle.load_file("mock.vy") with pytest.raises(exception_type): - compile_code( - code, resolved_path=input_bundle.search_paths[0] / "mock.vy", input_bundle=input_bundle - ) + compile_from_file_input(file_input, input_bundle=input_bundle) def test_external_call_to_interface(env, get_contract, make_input_bundle): From 69ce28e306e184893224e060d9c18594f1be36ff Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Fri, 13 Dec 2024 10:28:11 -0500 Subject: [PATCH 28/29] some more test cleanup --- tests/functional/syntax/test_import.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/functional/syntax/test_import.py b/tests/functional/syntax/test_import.py index 6baa52e8c0..da672c0de5 100644 --- a/tests/functional/syntax/test_import.py +++ b/tests/functional/syntax/test_import.py @@ -27,8 +27,9 @@ def foo(): {"top.vy": top, "subdir0/lib0.vy": lib0, "subdir0/subdir1/lib1.vy": lib1} ) + file_input = input_bundle.load_file("top.vy") with pytest.raises(ModuleNotFound): - compiler.compile_code(top, input_bundle=input_bundle) + compiler.compile_from_file_input(file_input, input_bundle=input_bundle) lib0 = """ from subdir1 import lib1 as lib1 @@ -40,8 +41,9 @@ def foo(): {"top.vy": top, "subdir0/lib0.vy": lib0, "subdir0/subdir1/lib1.vy": lib1} ) + file_input = input_bundle.load_file("top.vy") with pytest.raises(ModuleNotFound): - compiler.compile_code(top, input_bundle=input_bundle) + compiler.compile_from_file_input(file_input, input_bundle=input_bundle) def test_relative_import_searches_only_current_path(make_input_bundle): From 0ad5e7f02e431fa666515d25ff8e64f374b24c98 Mon Sep 17 00:00:00 2001 From: Sand Bubbles Date: Sat, 14 Dec 2024 14:38:20 +0100 Subject: [PATCH 29/29] clean up tests some more --- tests/functional/syntax/test_import.py | 49 +++++++++++--------------- 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/tests/functional/syntax/test_import.py b/tests/functional/syntax/test_import.py index da672c0de5..07b1a336c3 100644 --- a/tests/functional/syntax/test_import.py +++ b/tests/functional/syntax/test_import.py @@ -3,34 +3,36 @@ from vyper import compiler from vyper.exceptions import ModuleNotFound - -def test_implicitly_relative_import_crashes(make_input_bundle): - top = """ +CODE_TOP = """ import subdir0.lib0 as lib0 @external def foo(): lib0.foo() - """ +""" + +CODE_LIB1 = """ +def foo(): + pass +""" + +def test_implicitly_relative_import_crashes(make_input_bundle): lib0 = """ import subdir1.lib1 as lib1 def foo(): lib1.foo() """ - lib1 = """ -def foo(): - pass - """ - input_bundle = make_input_bundle( - {"top.vy": top, "subdir0/lib0.vy": lib0, "subdir0/subdir1/lib1.vy": lib1} + {"top.vy": CODE_TOP, "subdir0/lib0.vy": lib0, "subdir0/subdir1/lib1.vy": CODE_LIB1} ) file_input = input_bundle.load_file("top.vy") with pytest.raises(ModuleNotFound): compiler.compile_from_file_input(file_input, input_bundle=input_bundle) + +def test_implicitly_relative_import_crashes_2(make_input_bundle): lib0 = """ from subdir1 import lib1 as lib1 def foo(): @@ -38,7 +40,7 @@ def foo(): """ input_bundle = make_input_bundle( - {"top.vy": top, "subdir0/lib0.vy": lib0, "subdir0/subdir1/lib1.vy": lib1} + {"top.vy": CODE_TOP, "subdir0/lib0.vy": lib0, "subdir0/subdir1/lib1.vy": CODE_LIB1} ) file_input = input_bundle.load_file("top.vy") @@ -66,9 +68,10 @@ def foo(): """ input_bundle = make_input_bundle({"top.vy": top, "a.vy": a, "subdir/b.vy": b}) + file_input = input_bundle.load_file("top.vy") with pytest.raises(ModuleNotFound): - compiler.compile_code(top, input_bundle=input_bundle) + compiler.compile_from_file_input(file_input, input_bundle=input_bundle) def test_absolute_import_within_relative_import(make_input_bundle): @@ -101,29 +104,19 @@ def foo(): def test_absolute_path_passes(make_input_bundle): - top = """ -import subdir0.lib0 as lib0 -@external -def foo(): - lib0.foo() - """ - lib0 = """ import subdir0.subdir1.lib1 as lib1 def foo(): lib1.foo() """ - lib1 = """ -def foo(): - pass - """ - input_bundle = make_input_bundle( - {"top.vy": top, "subdir0/lib0.vy": lib0, "subdir0/subdir1/lib1.vy": lib1} + {"top.vy": CODE_TOP, "subdir0/lib0.vy": lib0, "subdir0/subdir1/lib1.vy": CODE_LIB1} ) - compiler.compile_code(top, input_bundle=input_bundle) + compiler.compile_code(CODE_TOP, input_bundle=input_bundle) + +def test_absolute_path_passes_2(make_input_bundle): lib0 = """ from .subdir1 import lib1 as lib1 def foo(): @@ -131,6 +124,6 @@ def foo(): """ input_bundle = make_input_bundle( - {"top.vy": top, "subdir0/lib0.vy": lib0, "subdir0/subdir1/lib1.vy": lib1} + {"top.vy": CODE_TOP, "subdir0/lib0.vy": lib0, "subdir0/subdir1/lib1.vy": CODE_LIB1} ) - compiler.compile_code(top, input_bundle=input_bundle) + compiler.compile_code(CODE_TOP, input_bundle=input_bundle)