From 824ec2e9c6ac405222ed2c1e85ee852291203ea4 Mon Sep 17 00:00:00 2001 From: antazoey Date: Tue, 11 Jun 2024 12:50:00 -0500 Subject: [PATCH] fix: `project.unpack()` to include full contracts directory (#2123) --- pyproject.toml | 4 +- src/ape/cli/arguments.py | 20 ++- src/ape/managers/compilers.py | 1 - src/ape/managers/project.py | 32 +++-- src/ape_compile/__init__.py | 17 ++- src/ape_compile/_cli.py | 4 +- tests/conftest.py | 4 +- .../ApeProject/contracts/Path.with.sub.json | 1 + tests/functional/test_compilers.py | 20 +++ tests/functional/test_coverage.py | 2 +- tests/functional/test_project.py | 10 ++ tests/functional/utils/test_misc.py | 6 + tests/integration/cli/conftest.py | 17 ++- tests/integration/cli/test_compile.py | 127 ++++++++++-------- tests/integration/cli/test_console.py | 42 +++--- tests/integration/cli/test_init.py | 16 ++- tests/integration/cli/test_networks.py | 8 +- tests/integration/cli/test_pm.py | 64 ++++----- tests/integration/cli/test_run.py | 71 +++++----- tests/integration/cli/test_test.py | 72 +++++----- 20 files changed, 313 insertions(+), 225 deletions(-) create mode 100644 tests/functional/data/projects/ApeProject/contracts/Path.with.sub.json diff --git a/pyproject.toml b/pyproject.toml index 2043cc73a7..27b74b3597 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,7 @@ plugins = ["pydantic.mypy"] # This version is purposely set to really high minor so that it should always work # with newer, stricter plugin releases. # NOTE: This should be bumped with every minor release! -fallback_version = "0.7.999" +fallback_version = "0.8.999" write_to = "src/ape/version.py" # NOTE: you have to use single-quoted strings in TOML for regular expressions. @@ -21,7 +21,7 @@ write_to = "src/ape/version.py" # character. [tool.black] line-length = 100 -target-version = ['py38', 'py39', 'py310', 'py311', 'py312'] +target-version = ['py39', 'py310', 'py311', 'py312'] include = '\.pyi?$' [tool.pytest.ini_options] diff --git a/src/ape/cli/arguments.py b/src/ape/cli/arguments.py index a3ce2752d3..4f396e1c4d 100644 --- a/src/ape/cli/arguments.py +++ b/src/ape/cli/arguments.py @@ -1,5 +1,4 @@ from collections.abc import Iterable -from functools import cached_property from pathlib import Path from typing import TYPE_CHECKING, Optional, Union @@ -64,7 +63,7 @@ def callback(cls, ctx, param, value) -> set[Path]: project = ctx.params.get("project") return cls(value, project=project).filtered_paths - @cached_property + @property def filtered_paths(self) -> set[Path]: """ Get the filtered set of paths. @@ -78,9 +77,10 @@ def filtered_paths(self) -> set[Path]: elif not value or value == "*": # Get all file paths in the project. return {p for p in self.project.sources.paths} - else: - # Given a sequence of paths. + elif isinstance(value, Iterable): contract_paths = value + else: + raise BadArgumentUsage(f"Not a path or iter[Path]: {value}") # Convert source IDs or relative paths to absolute paths. path_set = self.lookup(contract_paths) @@ -120,8 +120,9 @@ def compiler_is_unknown(self, path: Union[Path, str]) -> bool: def lookup(self, path_iter: Iterable, path_set: Optional[set] = None) -> set[Path]: path_set = path_set or set() + given_paths = [p for p in path_iter] # Handle iterators w/o losing it. - for path_id in path_iter: + for path_id in given_paths: path = Path(path_id) contracts_folder = self.project.contracts_folder if ( @@ -148,13 +149,8 @@ def lookup(self, path_iter: Iterable, path_set: Optional[set] = None) -> set[Pat # NOTE: ^ Also tracks. continue - suffix = get_full_extension(resolved_path) - if suffix in self.compiler_manager.registered_compilers: - # File exists and is compile-able. - path_set.add(resolved_path) - - elif suffix: - raise BadArgumentUsage(f"Source file '{resolved_path.name}' not found.") + # We know here that the compiler is known. + path_set.add(resolved_path) else: raise BadArgumentUsage(f"Source file '{path.name}' not found.") diff --git a/src/ape/managers/compilers.py b/src/ape/managers/compilers.py index b8900c62d2..8d8ee946ff 100644 --- a/src/ape/managers/compilers.py +++ b/src/ape/managers/compilers.py @@ -122,7 +122,6 @@ def compile( pm = project or self.local_project files_by_ext = defaultdict(list) - if isinstance(contract_filepaths, (str, Path)): contract_filepaths = (contract_filepaths,) diff --git a/src/ape/managers/project.py b/src/ape/managers/project.py index 002cc95e15..6d4f82f694 100644 --- a/src/ape/managers/project.py +++ b/src/ape/managers/project.py @@ -77,7 +77,7 @@ def __len__(self) -> int: if self._path_cache is not None: return len(self._path_cache) - # Will set _path_cache, eliminates need to iterte (perf). + # Will set _path_cache, eliminates need to iterate (perf). return len(list(self.paths)) def __iter__(self) -> Iterator[str]: @@ -216,9 +216,11 @@ def is_excluded(self, path: Path) -> bool: for excl in self.exclude_globs: if isinstance(excl, Pattern): for opt in options: - if excl.match(opt): - self._exclude_cache[source_id] = True - return True + if not excl.match(opt): + continue + + self._exclude_cache[source_id] = True + return True else: # perf: Check parent directory first to exclude faster by marking them all. @@ -280,13 +282,10 @@ def find_in_dir(dir_path: Path, path: Path) -> Optional[Path]: for file in full_path.parent.iterdir(): if not file.is_file(): continue - elif not (file_ext := get_full_extension(file)): - continue # Check exact match w/o extension. - prefix = file_ext.join(str(file).split(file_ext)[:-1]) - - if str(full_path) == prefix: + prefix = str(file.with_suffix("")).strip(" /\\") + if str(full_path).strip(" /\\") == prefix: return file # Look for stem-only matches (last resort). @@ -1786,6 +1785,7 @@ def extract_manifest(self) -> PackageManifest: def clean(self): self._manifest.contract_types = None + self._config_override = {} class DeploymentManager(ManagerAccessMixin): @@ -2246,7 +2246,17 @@ def isolate_in_tempdir(self, **config_override) -> Iterator["LocalProject"]: yield project def unpack(self, destination: Path, config_override: Optional[dict] = None) -> "LocalProject": - project = super().unpack(destination, config_override=config_override) + config_override = {**self._config_override, **(config_override or {})} + + # Unpack contracts. + if self.contracts_folder.is_dir(): + contracts_path = get_relative_path(self.contracts_folder, self.path) + contracts_destination = destination / contracts_path + shutil.copytree(self.contracts_folder, contracts_destination, dirs_exist_ok=True) + + # Unpack config file. + if not (destination / "ape-config.yaml").is_file(): + self.config.write_to_disk(destination / "ape-config.yaml") # Unpack scripts folder. if self.scripts_folder.is_dir(): @@ -2265,7 +2275,7 @@ def unpack(self, destination: Path, config_override: Optional[dict] = None) -> " interfaces_destination.parent.mkdir(parents=True, exist_ok=True) shutil.copytree(self.interfaces_folder, interfaces_destination, dirs_exist_ok=True) - return project + return LocalProject(destination, config_override=config_override) def load_manifest(self) -> PackageManifest: """ diff --git a/src/ape_compile/__init__.py b/src/ape_compile/__init__.py index ea33d69f3f..f9cac3e8d6 100644 --- a/src/ape_compile/__init__.py +++ b/src/ape_compile/__init__.py @@ -2,7 +2,7 @@ from re import Pattern from typing import Union -from pydantic import field_validator +from pydantic import field_serializer, field_validator from ape import plugins from ape.api.config import ConfigEnum, PluginConfig @@ -74,6 +74,21 @@ def validate_exclude(cls, value): # Include defaults. return {*given_values, *SOURCE_EXCLUDE_PATTERNS} + @field_serializer("exclude", when_used="json") + def serialize_exclude(self, exclude, info): + """ + Exclude is put back with the weird r-prefix so we can + go to-and-from. + """ + result: list[str] = [] + for excl in exclude: + if isinstance(excl, Pattern): + result.append(f'r"{excl.pattern}"') + else: + result.append(excl) + + return result + @plugins.register(plugins.Config) def config_class(): diff --git a/src/ape_compile/_cli.py b/src/ape_compile/_cli.py index 8e5bba71e9..30b1425793 100644 --- a/src/ape_compile/_cli.py +++ b/src/ape_compile/_cli.py @@ -6,6 +6,7 @@ from ape.cli.arguments import contract_file_paths_argument from ape.cli.options import ape_cli_context, config_override_option, project_option +from ape.utils.os import clean_path def _include_dependencies_callback(ctx, param, value): @@ -92,7 +93,8 @@ def cli( _display_byte_code_sizes(cli_ctx, contract_types) if not compiled: - cli_ctx.logger.warning("Nothing to compile.") + folder = clean_path(project.contracts_folder) + cli_ctx.logger.warning(f"Nothing to compile ({folder}).") if errored: # Ensure exit code. diff --git a/tests/conftest.py b/tests/conftest.py index 3e5c4e33a5..55b278288f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -79,8 +79,8 @@ def validate_cwd(start_dir): os.chdir(start_dir) -@pytest.fixture(scope="session") -def project(config): +@pytest.fixture +def project(): path = "functional/data/contracts/local" with ape.project.temp_config(contracts_folder=path): yield ape.project diff --git a/tests/functional/data/projects/ApeProject/contracts/Path.with.sub.json b/tests/functional/data/projects/ApeProject/contracts/Path.with.sub.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/tests/functional/data/projects/ApeProject/contracts/Path.with.sub.json @@ -0,0 +1 @@ +{} diff --git a/tests/functional/test_compilers.py b/tests/functional/test_compilers.py index 1d41447474..26c718a08b 100644 --- a/tests/functional/test_compilers.py +++ b/tests/functional/test_compilers.py @@ -1,4 +1,5 @@ from pathlib import Path +from re import Pattern from typing import cast import pytest @@ -7,6 +8,7 @@ from ape.contracts import ContractContainer from ape.exceptions import APINotImplementedError, CompilerError, ContractLogicError, CustomError from ape.types import AddressType +from ape_compile import Config def test_get_imports(project, compilers): @@ -162,3 +164,21 @@ def test_enrich_error_custom_error_with_inputs(compilers, setup_custom_error): assert actual.__class__.__name__ == "AllowanceExpired" assert actual.inputs["deadline"] == deadline assert repr(actual) == f"AllowanceExpired(deadline={deadline})" + + +def test_config_exclude_regex_serialize(): + """ + Show we can to-and-fro with exclude regexes. + """ + raw_value = 'r"FooBar"' + cfg = Config(exclude=[raw_value]) + excl = [x for x in cfg.exclude if isinstance(x, Pattern)] + assert len(excl) == 1 + assert excl[0].pattern == "FooBar" + # NOTE: Use json mode to ensure we can go from most minimum value back. + model_dump = cfg.model_dump(mode="json", by_alias=True) + assert raw_value in model_dump.get("exclude", []) + new_cfg = Config.model_validate(cfg.model_dump(mode="json", by_alias=True)) + excl = [x for x in new_cfg.exclude if isinstance(x, Pattern)] + assert len(excl) == 1 + assert excl[0].pattern == "FooBar" diff --git a/tests/functional/test_coverage.py b/tests/functional/test_coverage.py index 2b9eb5a68c..00a3fcdd18 100644 --- a/tests/functional/test_coverage.py +++ b/tests/functional/test_coverage.py @@ -173,7 +173,7 @@ def src(self): def contract_source(self, vyper_contract_type, src): return ContractSource(contract_type=vyper_contract_type, source=src) - @pytest.fixture(scope="class") + @pytest.fixture def coverage_data(self, project, contract_source): return CoverageData(project, (contract_source,)) diff --git a/tests/functional/test_project.py b/tests/functional/test_project.py index 0ba00d4c37..301973d266 100644 --- a/tests/functional/test_project.py +++ b/tests/functional/test_project.py @@ -13,6 +13,7 @@ from ape.contracts import ContractContainer from ape.exceptions import ProjectError from ape.logging import LogLevel +from ape.utils import create_tempdir from ape_pm import BrownieProject, FoundryProject from tests.conftest import skip_if_plugin_installed @@ -415,6 +416,15 @@ def test_clean(tmp_project): assert tmp_project.sources._path_cache is None +def test_unpack(project_with_source_files_contract): + with create_tempdir() as path: + project_with_source_files_contract.unpack(path) + assert (path / "contracts" / "Contract.json").is_file() + + # Show that even non-sources end up in the unpacked destination. + assert (path / "contracts" / "Path.with.sub.json").is_file() + + def test_add_compiler_data(project_with_dependency_config): # NOTE: Using different project than default to lessen # chance of race-conditions from multi-process test runners. diff --git a/tests/functional/utils/test_misc.py b/tests/functional/utils/test_misc.py index 8182512c72..c183fc4ba4 100644 --- a/tests/functional/utils/test_misc.py +++ b/tests/functional/utils/test_misc.py @@ -1,3 +1,5 @@ +import asyncio + import pytest from eth_pydantic_types import HexBytes from packaging.version import Version @@ -73,6 +75,8 @@ def test_run_until_complete_coroutine(): async def foo(): return 3 + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) actual = run_until_complete(foo()) assert actual == 3 @@ -84,6 +88,8 @@ async def foo(): async def bar(): return 4 + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) actual = run_until_complete(foo(), bar()) assert actual == [3, 4] diff --git a/tests/integration/cli/conftest.py b/tests/integration/cli/conftest.py index 731dc3eeeb..cfc637695c 100644 --- a/tests/integration/cli/conftest.py +++ b/tests/integration/cli/conftest.py @@ -85,7 +85,7 @@ def pytest_collection_modifyitems(session, config, items): items[:] = modified_items -@pytest.fixture(autouse=True) +@pytest.fixture(autouse=True, scope="session") def project_dir_map(): """ Ensure only copying projects once to prevent `TooManyOpenFilesError`. @@ -97,9 +97,12 @@ class ProjectDirCache: def load(self, name: str) -> Path: base_path = Path(__file__).parent / "projects" if name in self.project_map: - # Already copied. - return self.project_map[name] + res = self.project_map[name] + if res.is_dir(): + # Already copied and still exists! + return res + # Either re-copy or copy for the first time. project_source_dir = __projects_directory__ / name project_dest_dir = base_path / project_source_dir.name project_dest_dir.parent.mkdir(exist_ok=True, parents=True) @@ -114,11 +117,17 @@ def load(self, name: str) -> Path: @pytest.fixture(autouse=True, params=__project_names__) -def project(request, config, project_dir_map): +def integ_project(request, project_dir_map): project_dir = project_dir_map.load(request.param) + if not project_dir.is_dir(): + # Should not happen because of logic in fixture, + # but just in case! + pytest.fail("Setup failed - project dir not exists.") + root_project = Project(project_dir) # Using tmp project so no .build folder get kept around. with root_project.isolate_in_tempdir(name=request.param) as tmp_project: + assert tmp_project.path.is_dir(), "Setup failed - tmp-project dir not exists" yield tmp_project diff --git a/tests/integration/cli/test_compile.py b/tests/integration/cli/test_compile.py index 1b49e01c3c..c7822959a5 100644 --- a/tests/integration/cli/test_compile.py +++ b/tests/integration/cli/test_compile.py @@ -4,6 +4,7 @@ import pytest from ape.contracts import ContractContainer +from ape.utils import get_full_extension from .utils import skip_projects, skip_projects_except @@ -37,16 +38,16 @@ def test_compile_missing_contracts_dir(ape_cli, runner, project): @skip_non_compilable_projects -def test_compile(ape_cli, runner, project, clean_cache): - assert not project.manifest.contract_types, "Setup failed - expecting clean start" - cmd = ("compile", "--project", f"{project.path}") +def test_compile(ape_cli, runner, integ_project, clean_cache): + assert not integ_project.manifest.contract_types, "Setup failed - expecting clean start" + cmd = ("compile", "--project", f"{integ_project.path}") result = runner.invoke(ape_cli, cmd, catch_exceptions=False) assert result.exit_code == 0, result.output - assert project.manifest.contract_types + assert integ_project.manifest.contract_types # First time it compiles, it compiles the files with registered compilers successfully. # Files with multiple extensions are currently not supported. - all_files = [f for f in project.path.glob("contracts/**/*") if f.is_file()] + all_files = [f for f in integ_project.path.glob("contracts/**/*") if f.is_file()] # Don't expect directories that may happen to have `.json` in name # as well as hidden files, such as `.gitkeep`. Both examples are present @@ -66,19 +67,19 @@ def test_compile(ape_cli, runner, project, clean_cache): and f.is_file() and not f.name.startswith(".") and f.name not in excluded - and f.suffix == ".json" + and get_full_extension(f) == ".json" and ".cache" not in [p.name for p in f.parents] ] unexpected_files = [f for f in all_files if f not in expected_files] # Extract manifest (note: same project is used in 2 instances here). - manifest = project.extract_manifest() + manifest = integ_project.extract_manifest() - non_json = [f for f in expected_files if f.suffix != ".json"] + non_json = [f for f in expected_files if get_full_extension(f) != ".json"] if len(non_json) > 0: assert manifest.compilers for file in expected_files: - assert f"{project.contracts_folder.name}/{file.name}" in manifest.sources + assert f"{integ_project.contracts_folder.name}/{file.name}" in manifest.sources missing = [f.name for f in expected_files if f.stem not in result.output] @@ -89,9 +90,9 @@ def test_compile(ape_cli, runner, project, clean_cache): # Copy in .build to show that those file won't compile. # (Anything in a .build is ignored, even if in a contracts folder to prevent accidents). - build_path = project.path / ".build" - if project.path != project.contracts_folder: - shutil.copytree(build_path, project.contracts_folder / ".build") + build_path = integ_project.path / ".build" + if integ_project.path != integ_project.contracts_folder: + shutil.copytree(build_path, integ_project.contracts_folder / ".build") assert build_path.is_dir() try: @@ -99,35 +100,35 @@ def test_compile(ape_cli, runner, project, clean_cache): assert result.exit_code == 0, result.output assert "__local__.json" not in result.output # First time it compiles, it caches - for file in project.path.glob("contracts/**/*"): + for file in integ_project.path.glob("contracts/**/*"): if file.is_file(): assert file.name not in result.output finally: - shutil.rmtree(project.contracts_folder / ".build", ignore_errors=True) + shutil.rmtree(integ_project.contracts_folder / ".build", ignore_errors=True) @skip_projects_except("multiple-interfaces") -def test_compile_when_sources_change(ape_cli, runner, project, clean_cache): - source_path = project.contracts_folder / "Interface.json" +def test_compile_when_sources_change(ape_cli, runner, integ_project, clean_cache): + source_path = integ_project.contracts_folder / "Interface.json" content = source_path.read_text() assert "bar" in content, "Test setup failed - unexpected content" result = runner.invoke( - ape_cli, ("compile", "--project", f"{project.path}"), catch_exceptions=False + ape_cli, ("compile", "--project", f"{integ_project.path}"), catch_exceptions=False ) assert result.exit_code == 0, result.output assert "contracts/Interface.json" in result.output assert "SUCCESS: 'local project' compiled." in result.output # Change the contents of a file. - source_path = project.contracts_folder / "Interface.json" + source_path = integ_project.contracts_folder / "Interface.json" modified_source_text = source_path.read_text().replace("bar", "foo") source_path.unlink() source_path.touch() source_path.write_text(modified_source_text) result = runner.invoke( - ape_cli, ("compile", "--project", f"{project.path}"), catch_exceptions=False + ape_cli, ("compile", "--project", f"{integ_project.path}"), catch_exceptions=False ) assert result.exit_code == 0, result.output assert "contracts/Interface.json" in result.output @@ -135,16 +136,16 @@ def test_compile_when_sources_change(ape_cli, runner, project, clean_cache): # Verify that the next time, it does not need to recompile (no changes) result = runner.invoke( - ape_cli, ("compile", "--project", f"{project.path}"), catch_exceptions=False + ape_cli, ("compile", "--project", f"{integ_project.path}"), catch_exceptions=False ) assert result.exit_code == 0, result.output assert "contracts/Interface.json" not in result.output @skip_projects_except("multiple-interfaces") -def test_compile_when_contract_type_collision(ape_cli, runner, project, clean_cache): - source_path = project.contracts_folder / "Interface.json" - temp_dir = project.contracts_folder / "temp" +def test_compile_when_contract_type_collision(ape_cli, runner, integ_project, clean_cache): + source_path = integ_project.contracts_folder / "Interface.json" + temp_dir = integ_project.contracts_folder / "temp" def clean(): if temp_dir.is_dir(): @@ -161,7 +162,7 @@ def clean(): source_copy.touch() source_copy.write_text(source_path.read_text()) result = runner.invoke( - ape_cli, ("compile", "--project", f"{project.path}"), catch_exceptions=False + ape_cli, ("compile", "--project", f"{integ_project.path}"), catch_exceptions=False ) assert result.exit_code == 1 actual = result.output @@ -176,19 +177,21 @@ def clean(): @skip_projects_except("multiple-interfaces") -def test_compile_when_source_contains_return_characters(ape_cli, runner, project, clean_cache): +def test_compile_when_source_contains_return_characters( + ape_cli, runner, integ_project, clean_cache +): """ This tests a bugfix where a source file contained return-characters and that triggered endless re-compiles because it technically contains extra bytes than the ones that show up in the text. """ - source_path = project.contracts_folder / "Interface.json" + source_path = integ_project.contracts_folder / "Interface.json" # Change the contents of a file to contain the '\r' character. modified_source_text = f"{source_path.read_text()}\r" source_path.unlink() source_path.touch() source_path.write_text(modified_source_text) - arguments = ("compile", "--project", f"{project.path}") + arguments = ("compile", "--project", f"{integ_project.path}") result = runner.invoke(ape_cli, arguments, catch_exceptions=False) assert result.exit_code == 0, result.output assert "contracts/Interface.json" in result.output @@ -200,19 +203,21 @@ def test_compile_when_source_contains_return_characters(ape_cli, runner, project @skip_projects_except("multiple-interfaces") -def test_can_access_contracts(project, clean_cache): +def test_can_access_contracts(integ_project, clean_cache): # This test does not use the CLI but still requires a project or run off of. - assert project.Interface, "Unable to access contract when needing to compile" - assert project.Interface, "Unable to access contract when not needing to compile" + assert integ_project.Interface, "Unable to access contract when needing to compile" + assert integ_project.Interface, "Unable to access contract when not needing to compile" @skip_projects_except("multiple-interfaces") @pytest.mark.parametrize( "contract_path", - ("Interface.json", "Interface", "contracts/Interface.json", "contracts/Interface"), + ("Interface", "Interface.json", "contracts/Interface.json", "contracts/Interface"), ) -def test_compile_specified_contracts(ape_cli, runner, project, contract_path, clean_cache): - arguments = ("compile", contract_path, "--project", f"{project.path}") +def test_compile_specified_contracts(clean_cache, ape_cli, runner, integ_project, contract_path): + assert integ_project.path.is_dir(), "Setup failed - project missing." + + arguments = ("compile", contract_path, "--project", f"{integ_project.path}") result = runner.invoke(ape_cli, arguments, catch_exceptions=False) assert result.exit_code == 0, result.output assert "contracts/Interface.json" in result.output @@ -229,8 +234,8 @@ def test_compile_specified_contracts(ape_cli, runner, project, contract_path, cl @skip_projects_except("multiple-interfaces") -def test_compile_unknown_extension_does_not_compile(ape_cli, runner, project, clean_cache): - arguments = ("compile", "Interface.js", "--project", f"{project.path}") +def test_compile_unknown_extension_does_not_compile(ape_cli, runner, integ_project, clean_cache): + arguments = ("compile", "Interface.js", "--project", f"{integ_project.path}") result = runner.invoke(ape_cli, arguments, catch_exceptions=False) assert result.exit_code == 2, result.output assert "Error: Source file 'Interface.js' not found." in result.output @@ -241,8 +246,8 @@ def test_compile_unknown_extension_does_not_compile(ape_cli, runner, project, cl "contract_path", (None, "contracts/", "Project", "contracts/Project.json"), ) -def test_compile_with_dependency(ape_cli, runner, project, contract_path): - cmd = ["compile", "--force", "--project", f"{project.path}"] +def test_compile_with_dependency(ape_cli, runner, integ_project, contract_path): + cmd = ["compile", "--force", "--project", f"{integ_project.path}"] if contract_path: cmd.append(contract_path) @@ -257,68 +262,80 @@ def test_compile_with_dependency(ape_cli, runner, project, contract_path): "renamed-contracts-folder-specified-in-config", "manifest-dependency", ): - assert name in list(project.dependencies.keys()) - dependency = project.dependencies[name]["local"] + assert name in list(integ_project.dependencies.keys()) + dependency = integ_project.dependencies[name]["local"] assert isinstance(dependency[name], ContractContainer) @skip_projects_except("with-dependencies") -def test_compile_individual_contract_excludes_other_contract(ape_cli, runner, project): - arguments = ("compile", "Project", "--force", "--project", f"{project.path}") +def test_compile_individual_contract_excludes_other_contract(ape_cli, runner, integ_project): + arguments = ("compile", "Project", "--force", "--project", f"{integ_project.path}") result = runner.invoke(ape_cli, arguments, catch_exceptions=False) assert result.exit_code == 0, result.output assert "Other" not in result.output @skip_projects_except("with-dependencies") -def test_compile_non_ape_project_deletes_ape_config_file(ape_cli, runner, project): - ape_config = project.path / "default" / "ape-config.yaml" +def test_compile_non_ape_project_deletes_ape_config_file(ape_cli, runner, integ_project): + ape_config = integ_project.path / "default" / "ape-config.yaml" if ape_config.is_file(): # Corrupted from a previous test. ape_config.unlink() - arguments = ("compile", "Project", "--force", "--project", f"{project.path}") + arguments = ("compile", "Project", "--force", "--project", f"{integ_project.path}") result = runner.invoke(ape_cli, arguments, catch_exceptions=False) assert result.exit_code == 0, result.output @skip_projects_except("only-dependencies") -def test_compile_only_dependency(ape_cli, runner, project, clean_cache, ape_caplog): +def test_compile_only_dependency(ape_cli, runner, integ_project, clean_cache, ape_caplog): expected_log_message = "Compiling sources/DependencyInProjectOnly.json" # Compile w/o --include-dependencies flag (nothing happens but it doesn't fail). - arguments: tuple[str, ...] = ("compile", "--force", "--project", f"{project.path}") + arguments: tuple[str, ...] = ("compile", "--force", "--project", f"{integ_project.path}") result = runner.invoke(ape_cli, arguments, catch_exceptions=False) assert result.exit_code == 0, result.output assert expected_log_message not in result.output # Now, actually compile (using --include-dependencies) - arguments = ("compile", "--force", "--project", f"{project.path}", "--include-dependencies") + arguments = ( + "compile", + "--force", + "--project", + f"{integ_project.path}", + "--include-dependencies", + ) result = runner.invoke(ape_cli, arguments, catch_exceptions=False) assert expected_log_message in result.output # It should not need to compile again (no force). - arguments = ("compile", "--project", f"{project.path}", "--include-dependencies") + arguments = ("compile", "--project", f"{integ_project.path}", "--include-dependencies") result = runner.invoke(ape_cli, arguments, catch_exceptions=False) assert expected_log_message not in result.output # Ensure config reading works. Note: have to edit file here # because in-memory config updates only works when on the subprocess, # and the CLI has to reload the project. - config_path = project.path / "ape-config.yaml" - project.config.compile.include_dependencies = True - project.config.write_to_disk(config_path, replace=True) + config_path = integ_project.path / "ape-config.yaml" + integ_project.config.compile.include_dependencies = True + integ_project.config.write_to_disk(config_path, replace=True) - arguments = ("compile", "--force", "--project", f"{project.path}", "--include-dependencies") + arguments = ( + "compile", + "--force", + "--project", + f"{integ_project.path}", + "--include-dependencies", + ) result = runner.invoke(ape_cli, arguments, catch_exceptions=False) assert result.exit_code == 0, result.output assert expected_log_message in result.output @skip_projects_except("with-contracts") -def test_raw_compiler_output_bytecode(project): - assert project.RawVyperOutput.contract_type.runtime_bytecode.bytecode - assert project.RawSolidityOutput.contract_type.deployment_bytecode.bytecode +def test_raw_compiler_output_bytecode(integ_project): + assert integ_project.RawVyperOutput.contract_type.runtime_bytecode.bytecode + assert integ_project.RawSolidityOutput.contract_type.deployment_bytecode.bytecode @skip_projects_except("with-contracts") diff --git a/tests/integration/cli/test_console.py b/tests/integration/cli/test_console.py index 789c373ae5..26371c6e92 100644 --- a/tests/integration/cli/test_console.py +++ b/tests/integration/cli/test_console.py @@ -7,11 +7,11 @@ @pytest.fixture(params=("path", "root")) -def extras_base_path(project, request): +def extras_base_path(integ_project, request): if request.param == "path": - yield project.path + yield integ_project.path else: - yield project.config_manager.DATA_FOLDER + yield integ_project.config_manager.DATA_FOLDER # Simple single namespace example @@ -99,9 +99,9 @@ def test_console(ape_cli, runner, item, project): @skip_projects("geth") -def test_console_extras(project, extras_base_path, ape_cli, runner): +def test_console_extras(integ_project, extras_base_path, ape_cli, runner): write_ape_console_extras(extras_base_path, EXTRAS_SCRIPT_1) - arguments = ("console", "--project", f"{project.path}") + arguments = ("console", "--project", f"{integ_project.path}") result = runner.invoke( ape_cli, @@ -123,9 +123,9 @@ def test_console_extras(project, extras_base_path, ape_cli, runner): @skip_projects("geth") -def test_console_init_extras(project, extras_base_path, ape_cli, runner): +def test_console_init_extras(integ_project, extras_base_path, ape_cli, runner): write_ape_console_extras(extras_base_path, EXTRAS_SCRIPT_2) - arguments = ("console", "--project", f"{project.path}") + arguments = ("console", "--project", f"{integ_project.path}") result = runner.invoke( ape_cli, arguments, @@ -137,18 +137,18 @@ def test_console_init_extras(project, extras_base_path, ape_cli, runner): @skip_projects("geth") -def test_console_init_extras_kwargs(project, extras_base_path, ape_cli, runner): +def test_console_init_extras_kwargs(integ_project, extras_base_path, ape_cli, runner): write_ape_console_extras(extras_base_path, EXTRAS_SCRIPT_3) - arguments = ("console", "--project", f"{project.path}") + arguments = ("console", "--project", f"{integ_project.path}") result = runner.invoke(ape_cli, arguments, input="exit\n", catch_exceptions=False) assert result.exit_code == 0, result.output assert no_console_error(result), result.output @skip_projects("geth") -def test_console_init_extras_return(project, extras_base_path, ape_cli, runner): +def test_console_init_extras_return(integ_project, extras_base_path, ape_cli, runner): write_ape_console_extras(extras_base_path, EXTRAS_SCRIPT_4) - arguments = ("console", "--project", f"{project.path}") + arguments = ("console", "--project", f"{integ_project.path}") # Test asserts returned A exists and B is not overwritten result = runner.invoke( @@ -170,7 +170,7 @@ def test_console_init_extras_return(project, extras_base_path, ape_cli, runner): @skip_projects_except("only-dependencies") -def test_console_import_local_path(project, ape_cli, runner): +def test_console_import_local_path(integ_project, ape_cli, runner): # NOTE: Don't use temp-path! Temp-path projects do not copy Python modules. path = Path(__file__).parent / "projects" / "only-dependencies" arguments = ("console", "--project", f"{path}") @@ -185,7 +185,7 @@ def test_console_import_local_path(project, ape_cli, runner): @skip_projects_except("only-dependencies") -def test_console_import_local_path_in_extras_file(project, extras_base_path, ape_cli, runner): +def test_console_import_local_path_in_extras_file(integ_project, extras_base_path, ape_cli, runner): # NOTE: Don't use tmp path! Temp projects do not copy Python modules. path = Path(__file__).parent / "projects" / "only-dependencies" write_ape_console_extras(extras_base_path, EXTRAS_SCRIPT_5) @@ -201,8 +201,8 @@ def test_console_import_local_path_in_extras_file(project, extras_base_path, ape @skip_projects_except("only-dependencies") -def test_console_ape_magic(project, ape_cli, runner): - arguments = ("console", "--project", f"{project.path}") +def test_console_ape_magic(integ_project, ape_cli, runner): + arguments = ("console", "--project", f"{integ_project.path}") result = runner.invoke( ape_cli, arguments, @@ -214,8 +214,8 @@ def test_console_ape_magic(project, ape_cli, runner): @skip_projects_except("only-dependencies") -def test_console_bal_magic(project, ape_cli, runner, keyfile_account): - arguments = ("console", "--project", f"{project.path}") +def test_console_bal_magic(integ_project, ape_cli, runner, keyfile_account): + arguments = ("console", "--project", f"{integ_project.path}") cases = ( "%load_ext ape_console.plugin", "%bal acct", @@ -236,7 +236,7 @@ def test_console_bal_magic(project, ape_cli, runner, keyfile_account): @skip_projects_except("with-contracts") -def test_uncaught_txn_err(project, ape_cli, runner, mocker): +def test_uncaught_txn_err(integ_project, ape_cli, runner, mocker): # For some reason, not showing in result.output, so captured another way. handler = mocker.patch("ape_console.plugin.handle_ape_exception") cmd_ls = [ @@ -248,7 +248,7 @@ def test_uncaught_txn_err(project, ape_cli, runner, mocker): "exit", ] cmd_str = "\n".join(cmd_ls) - arguments = ("console", "--project", f"{project.path}") + arguments = ("console", "--project", f"{integ_project.path}") runner.invoke( ape_cli, arguments, @@ -259,7 +259,7 @@ def test_uncaught_txn_err(project, ape_cli, runner, mocker): assert str(err) == "Transaction failed." -def test_console_none_network(project, ape_cli, runner): - arguments = ("console", "--project", f"{project.path}", "--network", "None") +def test_console_none_network(integ_project, ape_cli, runner): + arguments = ("console", "--project", f"{integ_project.path}", "--network", "None") result = runner.invoke(ape_cli, arguments, input="exit\n", catch_exceptions=False) assert result.exit_code == 0 diff --git a/tests/integration/cli/test_init.py b/tests/integration/cli/test_init.py index 085425b26c..e6514034c4 100644 --- a/tests/integration/cli/test_init.py +++ b/tests/integration/cli/test_init.py @@ -15,13 +15,14 @@ @run_once -def test_init_success(ape_cli, runner, project): - # Successfull creation of project +def test_init_success(ape_cli, runner, integ_project): + # Successful creation of project # ape init command # Changes cwd to a temporary directory - project_folder_path = project.path / "init_success" + project_folder_path = integ_project.path / "init_success" project_folder_path.mkdir() + start_path = os.curdir os.chdir(str(project_folder_path)) try: @@ -43,16 +44,17 @@ def test_init_success(ape_cli, runner, project): assert "init_success" in config.read_text() finally: - os.chdir(project.path) + os.chdir(start_path) @run_once -def test_fail_all_files_and_folders_exist(ape_cli, runner, project): +def test_fail_all_files_and_folders_exist(ape_cli, runner, integ_project): # failed to create all folders because they exist # ape init command # add project folder and directories - project_folder_path = project.path / "init_fail" + start_path = os.curdir + project_folder_path = integ_project.path / "init_fail" project_folder_path.mkdir() os.chdir(str(project_folder_path)) @@ -71,4 +73,4 @@ def test_fail_all_files_and_folders_exist(ape_cli, runner, project): assert "tests' exists" in result.output finally: - os.chdir(project.path) + os.chdir(start_path) diff --git a/tests/integration/cli/test_networks.py b/tests/integration/cli/test_networks.py index c6e99809fc..4e4f82bfb5 100644 --- a/tests/integration/cli/test_networks.py +++ b/tests/integration/cli/test_networks.py @@ -175,8 +175,8 @@ def test_list_filter_providers(ape_cli, runner, networks): @skip_projects_except("geth") -def test_list_custom_networks(project, networks_runner): - networks_runner.project = project +def test_list_custom_networks(integ_project, networks_runner): + networks_runner.project = integ_project result = networks_runner.invoke("list") assert result.exit_code == 0 actual = "ethereum (default)\n" + "".join(result.output.split("ethereum (default)\n")[-1]) @@ -203,8 +203,8 @@ def test_run_custom_network(ape_cli, runner): @geth_process_test @skip_projects_except("geth") -def test_run_already_running(networks_runner, project, geth_provider): - networks_runner.project = project +def test_run_already_running(networks_runner, integ_project, geth_provider): + networks_runner.project = integ_project cmd = ("run", "--network", f"ethereum:{LOCAL_NETWORK_NAME}:node") result = networks_runner.invoke(*cmd) assert result.exit_code != 0 diff --git a/tests/integration/cli/test_pm.py b/tests/integration/cli/test_pm.py index aed56c4397..020893d817 100644 --- a/tests/integration/cli/test_pm.py +++ b/tests/integration/cli/test_pm.py @@ -27,7 +27,7 @@ def test_install_path_not_exists(pm_runner): @run_once -def test_install_path_to_local_package(pm_runner, project): +def test_install_path_to_local_package(pm_runner, integ_project): project_name = "with-contracts" path = Path(__file__).parent / "projects" / project_name name = path.stem @@ -36,7 +36,7 @@ def test_install_path_to_local_package(pm_runner, project): assert f"Package '{path.as_posix()}' installed." # Ensure was installed correctly. - assert project.dependencies[name]["local"] + assert integ_project.dependencies[name]["local"] @run_once @@ -65,7 +65,7 @@ def test_install_force(pm_runner): @run_once @github_xfail() -def test_install_github_dependency_with_version(pm_runner, project): +def test_install_github_dependency_with_version(pm_runner): result = pm_runner.invoke( "install", "gh:OpenZeppelin/openzeppelin-contracts", @@ -96,11 +96,11 @@ def test_install_github_dependency_with_ref(pm_runner): @skip_projects_except("with-contracts") -def test_install_config_override(pm_runner, project): +def test_install_config_override(pm_runner, integ_project): actual_dep = Path(__file__).parent / "projects" / "with-contracts" / "dep" - shutil.copytree(actual_dep, project.path / "dep") + shutil.copytree(actual_dep, integ_project.path / "dep") config_override = '{"contracts_folder": "src"}' - dep_path = project.path / "dep" + dep_path = integ_project.path / "dep" name = "foodep2" pm_runner.invoke( "install", @@ -111,13 +111,13 @@ def test_install_config_override(pm_runner, project): config_override, "--force", ) - actual = project.dependencies["foodep2"]["local"].config.contracts_folder + actual = integ_project.dependencies["foodep2"]["local"].config.contracts_folder assert actual == "src" @run_once -def test_compile_package_not_exists(pm_runner, project): - pm_runner.project = project +def test_compile_package_not_exists(pm_runner, integ_project): + pm_runner.project = integ_project name = "NOT_EXISTS" result = pm_runner.invoke("compile", name) expected = f"Dependency '{name}' unknown. Is it installed?" @@ -126,13 +126,13 @@ def test_compile_package_not_exists(pm_runner, project): @skip_projects_except("with-contracts", "with-dependencies") -def test_compile(pm_runner, project): - pm_runner.project = project +def test_compile(pm_runner, integ_project): + pm_runner.project = integ_project result = pm_runner.invoke("compile", "--force") output = result.output or str(result._completed_process.stderr) assert result.exit_code == 0, output - if project.path.as_posix().endswith("contracts"): + if integ_project.path.as_posix().endswith("contracts"): assert "Package 'foodep@local' compiled." in output, output else: # Tests against a bug where we couldn't have hyphens in @@ -141,8 +141,8 @@ def test_compile(pm_runner, project): @skip_projects_except("with-contracts") -def test_compile_config_override(pm_runner, project): - pm_runner.project = project +def test_compile_config_override(pm_runner, integ_project): + pm_runner.project = integ_project cmd = ("compile", "--force", "--config-override", '{"contracts_folder": "src"}') result = pm_runner.invoke(*cmd) output = result.output or str(result._completed_process.stderr) @@ -150,8 +150,8 @@ def test_compile_config_override(pm_runner, project): @skip_projects_except("with-contracts") -def test_compile_dependency(pm_runner, project): - pm_runner.project = project +def test_compile_dependency(pm_runner, integ_project): + pm_runner.project = integ_project name = "foodep" result = pm_runner.invoke("compile", name, "--force") assert result.exit_code == 0, result.output @@ -159,8 +159,8 @@ def test_compile_dependency(pm_runner, project): @skip_projects_except("only-dependencies") -def test_uninstall(pm_runner, project): - pm_runner.project = project +def test_uninstall(pm_runner, integ_project): + pm_runner.project = integ_project package_name = "dependency-in-project-only" # Install packages @@ -172,8 +172,8 @@ def test_uninstall(pm_runner, project): @skip_projects_except("only-dependencies") -def test_uninstall_not_exists(pm_runner, project): - pm_runner.project = project +def test_uninstall_not_exists(pm_runner, integ_project): + pm_runner.project = integ_project package_name = "_this_does_not_exist_" result = pm_runner.invoke("uninstall", package_name, "--yes") expected_message = f"ERROR: Package(s) '{package_name}' not installed." @@ -182,8 +182,8 @@ def test_uninstall_not_exists(pm_runner, project): @skip_projects_except("only-dependencies") -def test_uninstall_specific_version(pm_runner, project): - pm_runner.project = project +def test_uninstall_specific_version(pm_runner, integ_project): + pm_runner.project = integ_project package_name = "dependency-in-project-only" version = "local" @@ -196,8 +196,8 @@ def test_uninstall_specific_version(pm_runner, project): @skip_projects_except("only-dependencies") -def test_uninstall_all_versions(pm_runner, project): - pm_runner.project = project +def test_uninstall_all_versions(pm_runner, integ_project): + pm_runner.project = integ_project # Install packages pm_runner.invoke("install", ".", "--force") package_name = "dependency-in-project-only" @@ -208,16 +208,16 @@ def test_uninstall_all_versions(pm_runner, project): @skip_projects_except("only-dependencies") -def test_uninstall_invalid_version(pm_runner, project): - pm_runner.project = project +def test_uninstall_invalid_version(pm_runner, integ_project): + pm_runner.project = integ_project package_name = "dependency-in-project-only" # Install packages pm_runner.invoke("install", ".", "--force") # Ensure was installed correctly. - assert package_name in project.dependencies - assert project.dependencies[package_name]["local"] + assert package_name in integ_project.dependencies + assert integ_project.dependencies[package_name]["local"] invalid_version = "0.0.0" result = pm_runner.invoke("uninstall", package_name, invalid_version, "--yes") @@ -228,8 +228,8 @@ def test_uninstall_invalid_version(pm_runner, project): @skip_projects_except("only-dependencies") -def test_uninstall_cancel(pm_runner, project): - pm_runner.project = project +def test_uninstall_cancel(pm_runner, integ_project): + pm_runner.project = integ_project package_name = "dependency-in-project-only" version = "local" @@ -243,8 +243,8 @@ def test_uninstall_cancel(pm_runner, project): @skip_projects_except("only-dependencies") -def test_list(pm_runner, project): - pm_runner.project = project +def test_list(pm_runner, integ_project): + pm_runner.project = integ_project package_name = "dependency-in-project-only" result = pm_runner.invoke("list") assert result.exit_code == 0, result.output diff --git a/tests/integration/cli/test_run.py b/tests/integration/cli/test_run.py index 39c9b6f644..6f9db5836a 100644 --- a/tests/integration/cli/test_run.py +++ b/tests/integration/cli/test_run.py @@ -19,16 +19,16 @@ def __init__(self): @skip_projects_except("script") -def test_run_unknown_script(scripts_runner, project): - scripts_runner.project = project +def test_run_unknown_script(scripts_runner, integ_project): + scripts_runner.project = integ_project result = scripts_runner.invoke(BAD_COMMAND) assert result.exit_code == 2 assert f"No such command '{BAD_COMMAND}'." in result._completed_process.stderr @skip_projects_except("script") -def test_run(scripts_runner, project): - scripts_runner.project = project +def test_run(scripts_runner, integ_project): + scripts_runner.project = integ_project result = scripts_runner.invoke() assert result.exit_code == 0, result.output # By default, no commands are run @@ -37,7 +37,7 @@ def test_run(scripts_runner, project): not_part_of_test = ("output_contract_view_methods",) scripts = [ s - for s in project.scripts_folder.glob("*.py") + for s in integ_project.scripts_folder.glob("*.py") if not s.name.startswith("error") and s.stem not in not_part_of_test ] for script_file in scripts: @@ -54,22 +54,22 @@ def test_run(scripts_runner, project): @skip_projects_except("script") -def test_run_with_verbosity(scripts_runner, project): - scripts_runner.project = project +def test_run_with_verbosity(scripts_runner, integ_project): + scripts_runner.project = integ_project result = scripts_runner.invoke("click", "--verbosity", "DEBUG") assert result.exit_code == 0, result.output or result._completed_process.stderr @skip_projects_except("script") -def test_run_subdirectories(scripts_runner, project): - scripts_runner.project = project +def test_run_subdirectories(scripts_runner, integ_project): + scripts_runner.project = integ_project result = scripts_runner.invoke() assert result.exit_code == 0, result.output # By default, no commands are run assert "Super secret script output" not in result.output subdirectory_scripts = [ s - for s in (project.scripts_folder / "subdirectory").rglob("*.py") + for s in (integ_project.scripts_folder / "subdirectory").rglob("*.py") if not s.name.startswith("error") ] for each in subdirectory_scripts: @@ -79,15 +79,15 @@ def test_run_subdirectories(scripts_runner, project): @skip_projects_except("only-script-subdirs") -def test_run_only_subdirs(scripts_runner, project): - scripts_runner.project = project +def test_run_only_subdirs(scripts_runner, integ_project): + scripts_runner.project = integ_project result = scripts_runner.invoke() assert result.exit_code == 0, result.output # By default, no commands are run assert "Super secret script output" not in result.output subdirectory_scripts = [ s - for s in (project.scripts_folder / "subdirectory").rglob("*.py") + for s in (integ_project.scripts_folder / "subdirectory").rglob("*.py") if not s.name.startswith("error") ] for each in subdirectory_scripts: @@ -97,11 +97,11 @@ def test_run_only_subdirs(scripts_runner, project): @skip_projects_except("script") -def test_run_when_script_errors(scripts_runner, project): - scripts_runner.project = project +def test_run_when_script_errors(scripts_runner, integ_project): + scripts_runner.project = integ_project scripts = [ s - for s in project.scripts_folder.glob("*.py") + for s in integ_project.scripts_folder.glob("*.py") if s.name.startswith("error") and not s.name.endswith("forgot_click.py") ] for script_file in scripts: @@ -115,11 +115,10 @@ def test_run_when_script_errors(scripts_runner, project): @skip_projects_except("script") -def test_run_interactive(scripts_runner, project): - scripts_runner.project = project - scripts = [ - project.scripts_folder / f"{s}.py" for s in ("error_main", "error_cli", "error_no_def") - ] +def test_run_interactive(scripts_runner, integ_project): + scripts_runner.project = integ_project + error_names = ("error_main", "error_cli", "error_no_def") + scripts = [integ_project.scripts_folder / f"{s}.py" for s in error_names] # Show that the variable namespace from the script is available in the console. user_input = "local_variable\nape.chain.provider.mine()\nape.chain.blocks.head\nexit\n" @@ -133,8 +132,8 @@ def test_run_interactive(scripts_runner, project): @skip_projects_except("script") -def test_run_custom_provider(scripts_runner, project): - scripts_runner.project = project +def test_run_custom_provider(scripts_runner, integ_project): + scripts_runner.project = integ_project result = scripts_runner.invoke("deploy", "--network", "ethereum:mainnet:http://127.0.0.1:9545") # Show that it attempts to connect @@ -143,8 +142,8 @@ def test_run_custom_provider(scripts_runner, project): @skip_projects_except("script") -def test_run_custom_network(scripts_runner, project): - scripts_runner.project = project +def test_run_custom_network(scripts_runner, integ_project): + scripts_runner.project = integ_project result = scripts_runner.invoke("deploy", "--network", "http://127.0.0.1:9545") # Show that it attempts to connect @@ -153,20 +152,20 @@ def test_run_custom_network(scripts_runner, project): @skip_projects_except("script") -def test_try_run_script_missing_cli_decorator(scripts_runner, project): +def test_try_run_script_missing_cli_decorator(scripts_runner, integ_project): """ Shows that we cannot run a script defining a `cli()` method without it being a click command. The script is not recognized, so you get a usage error. """ - scripts_runner.project = project + scripts_runner.project = integ_project result = scripts_runner.invoke("error_forgot_click") assert "Usage: ape run" in result._completed_process.stderr @skip_projects_except("with-contracts") -def test_uncaught_tx_err(scripts_runner, project): - scripts_runner.project = project +def test_uncaught_tx_err(scripts_runner, integ_project): + scripts_runner.project = integ_project result = scripts_runner.invoke("txerr") assert '/scripts/txerr.py", line 12, in main' in result.output assert "contract.setNumber(5, sender=account)" in result.output @@ -174,12 +173,12 @@ def test_uncaught_tx_err(scripts_runner, project): @skip_projects_except("script") -def test_scripts_module_already_installed(project, scripts_runner, mocker): +def test_scripts_module_already_installed(integ_project, scripts_runner, mocker): """ Make sure that if there is for some reason a python module names `scripts` installed, it does not interfere with Ape's scripting mechanism. """ - scripts_runner.project = project + scripts_runner.project = integ_project mock_scripts = mocker.MagicMock() mock_path = mocker.MagicMock() mock_path._path = "path/to/scripts" @@ -192,19 +191,19 @@ def test_scripts_module_already_installed(project, scripts_runner, mocker): @skip_projects_except("script") -def test_run_recompiles_if_needed(runner, ape_cli, scripts_runner, project): +def test_run_recompiles_if_needed(runner, ape_cli, scripts_runner, integ_project): """ Ensure that when a change is made to a contract, when we run a script, it re-compiles the script first. """ - scripts_runner.project = project + scripts_runner.project = integ_project # Ensure we begin compiled. - runner.invoke(ape_cli, ("compile", "--force", "--project", f"{project.path}")) + runner.invoke(ape_cli, ("compile", "--force", "--project", f"{integ_project.path}")) # Make a change to the contract. - contract = project.contracts_folder / "VyperContract.json" - method_name = project.VyperContract.contract_type.view_methods[0].name + contract = integ_project.contracts_folder / "VyperContract.json" + method_name = integ_project.VyperContract.contract_type.view_methods[0].name new_method_name = f"f__{method_name}__" new_contract_text = contract.read_text().replace(method_name, new_method_name) contract.write_text(new_contract_text) diff --git a/tests/integration/cli/test_test.py b/tests/integration/cli/test_test.py index c43a9c1366..5b57c48aa5 100644 --- a/tests/integration/cli/test_test.py +++ b/tests/integration/cli/test_test.py @@ -68,9 +68,9 @@ def path_check(): @pytest.fixture(autouse=True) -def load_dependencies(project): +def load_dependencies(integ_project): """Ensure these are loaded before setting up pytester.""" - project.dependencies.install() + integ_project.dependencies.install() @pytest.fixture @@ -172,9 +172,9 @@ def run_gas_test( @skip_projects_except("test", "with-contracts") -def test_test(setup_pytester, project, pytester, eth_tester_provider): +def test_test(setup_pytester, integ_project, pytester, eth_tester_provider): _ = eth_tester_provider # Ensure using EthTester for this test. - passed, failed = setup_pytester(project) + passed, failed = setup_pytester(integ_project) from ape.logging import logger logger.set_level("DEBUG") @@ -186,9 +186,9 @@ def test_test(setup_pytester, project, pytester, eth_tester_provider): @skip_projects_except("with-contracts") -def test_uncaught_txn_err(setup_pytester, project, pytester, eth_tester_provider): +def test_uncaught_txn_err(setup_pytester, integ_project, pytester, eth_tester_provider): _ = eth_tester_provider # Ensure using EthTester for this test. - setup_pytester(project) + setup_pytester(integ_project) result = pytester.runpytest_subprocess() expected = """ contract_in_test.setNumber(5, sender=owner) @@ -198,9 +198,9 @@ def test_uncaught_txn_err(setup_pytester, project, pytester, eth_tester_provider @skip_projects_except("with-contracts") -def test_show_internal(setup_pytester, project, pytester, eth_tester_provider): +def test_show_internal(setup_pytester, integ_project, pytester, eth_tester_provider): _ = eth_tester_provider # Ensure using EthTester for this test. - setup_pytester(project) + setup_pytester(integ_project) result = pytester.runpytest_subprocess("--show-internal") expected = """ raise vm_err from err @@ -210,16 +210,16 @@ def test_show_internal(setup_pytester, project, pytester, eth_tester_provider): @skip_projects_except("test", "with-contracts") -def test_test_isolation_disabled(setup_pytester, project, pytester, eth_tester_provider): +def test_test_isolation_disabled(setup_pytester, integ_project, pytester, eth_tester_provider): # check the disable isolation option actually disables built-in isolation _ = eth_tester_provider # Ensure using EthTester for this test. - setup_pytester(project) + setup_pytester(integ_project) result = pytester.runpytest_subprocess("--disable-isolation", "--setup-show") assert "F _function_isolation" not in "\n".join(result.outlines) @skip_projects_except("test", "with-contracts") -def test_fixture_docs(setup_pytester, project, pytester, eth_tester_provider): +def test_fixture_docs(setup_pytester, integ_project, pytester, eth_tester_provider): _ = eth_tester_provider # Ensure using EthTester for this test. result = pytester.runpytest_subprocess("-q", "--fixtures") actual = "\n".join(result.outlines) @@ -233,10 +233,10 @@ def test_fixture_docs(setup_pytester, project, pytester, eth_tester_provider): @skip_projects_except("with-contracts") -def test_gas_flag_when_not_supported(setup_pytester, project, pytester, eth_tester_provider): +def test_gas_flag_when_not_supported(setup_pytester, integ_project, pytester, eth_tester_provider): _ = eth_tester_provider # Ensure using EthTester for this test. - setup_pytester(project) - path = f"{project.path}/tests/test_contract.py::test_contract_interaction_in_tests" + setup_pytester(integ_project) + path = f"{integ_project.path}/tests/test_contract.py::test_contract_interaction_in_tests" result = pytester.runpytest(path, "--gas") actual = "\n".join(result.outlines) expected = ( @@ -248,36 +248,38 @@ def test_gas_flag_when_not_supported(setup_pytester, project, pytester, eth_test @geth_process_test @skip_projects_except("geth") -def test_gas_flag_in_tests(geth_provider, setup_pytester, project, pytester, owner): +def test_gas_flag_in_tests(geth_provider, setup_pytester, integ_project, pytester, owner): owner.transfer(owner, "1 wei") # Do this to force a clean slate. - passed, failed = setup_pytester(project) + passed, failed = setup_pytester(integ_project) result = pytester.runpytest_subprocess("--gas", "--network", "ethereum:local:node") run_gas_test(result, passed, failed) @geth_process_test @skip_projects_except("geth") -def test_gas_flag_set_in_config(geth_provider, setup_pytester, project, pytester, geth_account): +def test_gas_flag_set_in_config( + geth_provider, setup_pytester, integ_project, pytester, geth_account +): geth_account.transfer(geth_account, "1 wei") # Force a clean block. - cfg = project.config.model_dump(by_alias=True, mode="json") + cfg = integ_project.config.model_dump(by_alias=True, mode="json") cfg["test"]["gas"] = {"reports": ["terminal"]} - with project.temp_config(**cfg): - passed, failed = setup_pytester(project) + with integ_project.temp_config(**cfg): + passed, failed = setup_pytester(integ_project) result = pytester.runpytest_subprocess("--network", "ethereum:local:node") run_gas_test(result, passed, failed) @geth_process_test @skip_projects_except("geth") -def test_gas_when_estimating(geth_provider, setup_pytester, project, pytester, geth_account): +def test_gas_when_estimating(geth_provider, setup_pytester, integ_project, pytester, geth_account): """ Shows that gas reports still work when estimating gas. """ - cfg = project.config.model_dump(by_alias=True, mode="json") + cfg = integ_project.config.model_dump(by_alias=True, mode="json") cfg["test"]["gas"] = {"reports": ["terminal"]} geth_account.transfer(geth_account, "1 wei") # Force a clean block. - with project.temp_config(**cfg): - passed, failed = setup_pytester(project) + with integ_project.temp_config(**cfg): + passed, failed = setup_pytester(integ_project) result = pytester.runpytest_subprocess() run_gas_test(result, passed, failed) @@ -285,10 +287,10 @@ def test_gas_when_estimating(geth_provider, setup_pytester, project, pytester, g @geth_process_test @skip_projects_except("geth") def test_gas_flag_exclude_using_cli_option( - geth_provider, setup_pytester, project, pytester, geth_account + geth_provider, setup_pytester, integ_project, pytester, geth_account ): geth_account.transfer(geth_account, "1 wei") # Force a clean block. - passed, failed = setup_pytester(project) + passed, failed = setup_pytester(integ_project) # NOTE: Includes both a mutable and a view method. expected = filter_expected_methods("fooAndBar", "myNumber") # Also ensure can filter out whole class @@ -306,14 +308,14 @@ def test_gas_flag_exclude_using_cli_option( @geth_process_test @skip_projects_except("geth") def test_gas_flag_exclusions_set_in_config( - geth_provider, setup_pytester, project, pytester, geth_account + geth_provider, setup_pytester, integ_project, pytester, geth_account ): geth_account.transfer(geth_account, "1 wei") # Force a clean block. # NOTE: Includes both a mutable and a view method. expected = filter_expected_methods("fooAndBar", "myNumber") # Also ensure can filter out whole class expected = expected.replace(TOKEN_B_GAS_REPORT, "") - cfg = project.config.model_dump(by_alias=True, mode="json") + cfg = integ_project.config.model_dump(by_alias=True, mode="json") cfg["test"]["gas"] = { "exclude": [ {"method_name": "fooAndBar"}, @@ -321,8 +323,8 @@ def test_gas_flag_exclusions_set_in_config( {"contract_name": "TokenB"}, ] } - with project.temp_config(**cfg): - passed, failed = setup_pytester(project) + with integ_project.temp_config(**cfg): + passed, failed = setup_pytester(integ_project) result = pytester.runpytest_subprocess("--gas", "--network", "ethereum:local:node") run_gas_test(result, passed, failed, expected_report=expected) @@ -330,10 +332,10 @@ def test_gas_flag_exclusions_set_in_config( @geth_process_test @skip_projects_except("geth") def test_gas_flag_excluding_contracts( - geth_provider, setup_pytester, project, pytester, geth_account + geth_provider, setup_pytester, integ_project, pytester, geth_account ): geth_account.transfer(geth_account, "1 wei") # Force a clean block. - passed, failed = setup_pytester(project) + passed, failed = setup_pytester(integ_project) result = pytester.runpytest_subprocess( "--gas", "--gas-exclude", "VyperContract,TokenA", "--network", "ethereum:local:node" ) @@ -342,7 +344,7 @@ def test_gas_flag_excluding_contracts( @geth_process_test @skip_projects_except("geth") -def test_coverage(geth_provider, setup_pytester, project, pytester, geth_account): +def test_coverage(geth_provider, setup_pytester, integ_project, pytester, geth_account): """ Ensures the --coverage flag works. For better coverage tests, see ape-vyper because the Vyper @@ -350,7 +352,7 @@ def test_coverage(geth_provider, setup_pytester, project, pytester, geth_account of the coverage work. """ geth_account.transfer(geth_account, "1 wei") # Force a clean block. - passed, failed = setup_pytester(project) + passed, failed = setup_pytester(integ_project) result = pytester.runpytest_subprocess( "--coverage", "--show-internal", "--network", "ethereum:local:node" ) @@ -358,7 +360,7 @@ def test_coverage(geth_provider, setup_pytester, project, pytester, geth_account @skip_projects_except("with-contracts") -def test_interactive(eth_tester_provider, project, pytester, monkeypatch): +def test_interactive(eth_tester_provider, integ_project, pytester, monkeypatch): secret = "__ 123 super secret 123 __" test = f""" def test_fails():