diff --git a/src/ape/api/projects.py b/src/ape/api/projects.py index 9017c07149..695dbad32d 100644 --- a/src/ape/api/projects.py +++ b/src/ape/api/projects.py @@ -125,13 +125,25 @@ def is_valid(self) -> bool: @cached_property def config_file(self) -> Path: + if self._using_pyproject_toml: + return self._pyproject_toml + + # else: check for an ape-config file. for ext in self.EXTENSIONS: path = self.path / f"{self.CONFIG_FILE_NAME}{ext}" if path.is_file(): return path - # Default + # Default: non-existing ape-config.yaml file. return self.path / f"{self.CONFIG_FILE_NAME}.yaml" + @property + def _pyproject_toml(self) -> Path: + return self.path / "pyproject.toml" + + @property + def _using_pyproject_toml(self) -> bool: + return self._pyproject_toml.is_file() and "[tool.ape" in self._pyproject_toml.read_text() + def extract_config(self, **overrides) -> ApeConfig: return ApeConfig.validate_file(self.config_file, **overrides) diff --git a/src/ape/managers/project.py b/src/ape/managers/project.py index 0d0c4d9a8b..f84e19e67a 100644 --- a/src/ape/managers/project.py +++ b/src/ape/managers/project.py @@ -1763,6 +1763,8 @@ def unpack(self, destination: Path, config_override: Optional[dict] = None) -> " path.write_text(str(src.content), encoding="utf8") # Unpack config file. + # NOTE: Always unpacks into a regular .yaml config file for simplicity + # and maximum portibility. self.config.write_to_disk(destination / "ape-config.yaml") return LocalProject(destination, config_override=config_override) diff --git a/tests/functional/test_config.py b/tests/functional/test_config.py index 5ea8d814dd..7612446f23 100644 --- a/tests/functional/test_config.py +++ b/tests/functional/test_config.py @@ -1,4 +1,5 @@ import os +import re from pathlib import Path from typing import Optional, Union @@ -15,6 +16,90 @@ from ape_networks import CustomNetwork from tests.functional.conftest import PROJECT_WITH_LONG_CONTRACTS_FOLDER +CONTRACTS_FOLDER = "pathsomewhwere" +NUMBER_OF_TEST_ACCOUNTS = 31 +YAML_CONTENT = rf""" +contracts_folder: "{CONTRACTS_FOLDER}" + +dependencies: + - name: "openzeppelin" + github: "OpenZeppelin/openzeppelin-contracts" + version: "4.5.0" + +plugins: + - name: "hardhat" + - name: "solidity" + version: "0.8.1" + +test: + number_of_accounts: "{NUMBER_OF_TEST_ACCOUNTS}" + +compile: + exclude: + - "exclude_dir" + - "Excl*.json" + - r"Ignore\w*\.json" +""".lstrip() +JSON_CONTENT = f""" +{{ + "contracts_folder": "{CONTRACTS_FOLDER}", + "dependencies": [ + {{ + "name": "openzeppelin", + "github": "OpenZeppelin/openzeppelin-contracts", + "version": "4.5.0" + }} + ], + "plugins": [ + {{ + "name": "hardhat" + }}, + {{ + "name": "solidity", + "version": "0.8.1" + }} + ], + "test": {{ + "number_of_accounts": "{NUMBER_OF_TEST_ACCOUNTS}" + }}, + "compile": {{ + "exclude": [ + "exclude_dir", + "Excl*.json", + "r\\"Ignore\\\\w*\\\\.json\\"" + ] + }} +}} +""".lstrip() +PYPROJECT_TOML = rf""" +[tool.ape] +contracts_folder = "{CONTRACTS_FOLDER}" + +[[tool.ape.dependencies]] +name = "openzeppelin" +github = "OpenZeppelin/openzeppelin-contracts" +version = "4.5.0" + +[[tool.ape.plugins]] +name = "hardhat" + +[[tool.ape.plugins]] +name = "solidity" +version = "0.8.1" + +[tool.ape.test] +number_of_accounts = {NUMBER_OF_TEST_ACCOUNTS} + +[tool.ape.compile] +exclude = ["exclude_dir", "Excl*.json", 'r"Ignore\w*\.json"'] +""".lstrip() +EXT_TO_CONTENT = { + ".yml": YAML_CONTENT, + ".yaml": YAML_CONTENT, + ".json": JSON_CONTENT, + ".toml": PYPROJECT_TOML, +} + def test_model_validate_empty(): data: dict = {} @@ -41,61 +126,27 @@ def test_model_validate_path_contracts_folder(): assert cfg.contracts_folder == str(path) -@pytest.mark.parametrize("ext", ("yml", "yaml")) -def test_validate_file_config(ext): - contracts_folder = "pathtowherever" - with create_tempdir() as temp_dir: - file = temp_dir / f"ape-config.{ext}" - file.write_text(f"contracts_folder: {contracts_folder}") - actual = ApeConfig.validate_file(file) - - assert actual.contracts_folder == contracts_folder - - -def test_validate_json_file(): - value = "pathtowherever" - with create_tempdir() as temp_dir: - file = temp_dir / "ape-config.json" - file.write_text(f'{{"contracts_folder": "{value}"}}') - actual = ApeConfig.validate_file(file) - - assert actual.contracts_folder == value - - -def test_validate_pyproject_toml(): - contracts_folder = "pathtowherever" - number_of_test_accounts = 31 - content = f""" -[tool.ape] -contracts_folder = "{contracts_folder}" - -[[tool.ape.dependencies]] -name = "openzeppelin" -github = "OpenZeppelin/openzeppelin-contracts" -version = "4.5.0" - -[[tool.ape.plugins]] -name = "hardhat" - -[[tool.ape.plugins]] -name = "solidity" -version = "0.8.1" - -[tool.ape.test] -number_of_accounts = {number_of_test_accounts} - """.lstrip() +@pytest.mark.parametrize( + "file", ("ape-config.yml", "ape-config.yaml", "ape-config.json", "pyproject.toml") +) +def test_validate_file(file): + content = EXT_TO_CONTENT[Path(file).suffix] with create_tempdir() as temp_dir: - file = temp_dir / "pyproject.toml" - file.write_text(content) - actual = ApeConfig.validate_file(file) + path = temp_dir / file + path.write_text(content) + actual = ApeConfig.validate_file(path) - assert actual.contracts_folder == contracts_folder - assert actual.test.number_of_accounts == number_of_test_accounts + assert actual.contracts_folder == CONTRACTS_FOLDER + assert actual.test.number_of_accounts == NUMBER_OF_TEST_ACCOUNTS assert len(actual.dependencies) == 1 assert actual.dependencies[0]["name"] == "openzeppelin" assert actual.dependencies[0]["github"] == "OpenZeppelin/openzeppelin-contracts" assert actual.dependencies[0]["version"] == "4.5.0" assert actual.plugins == [{"name": "hardhat"}, {"name": "solidity", "version": "0.8.1"}] + assert re.compile("Ignore\\w*\\.json") in actual.compile.exclude + assert "exclude_dir" in actual.compile.exclude + assert ".cache" in actual.compile.exclude + assert "Excl*.json" in actual.compile.exclude def test_validate_file_expands_env_vars(): diff --git a/tests/integration/cli/projects/with-contracts/ape-config.yaml b/tests/integration/cli/projects/with-contracts/ape-config.yaml deleted file mode 100644 index b0848b112e..0000000000 --- a/tests/integration/cli/projects/with-contracts/ape-config.yaml +++ /dev/null @@ -1,25 +0,0 @@ -name: withcontracts - -dependencies: - - name: foodep - local: ./dep - - # Showing we can have dependencies with contracts_folder - # equal to the path. (used in `tests/integration/cli/test_pm.py -k test_install`) - - name: depcontractsfolderroot - local: ./dep_contracts_folder_root - config_override: - contracts_folder: . - - - name: depwithunregisteredcontracts - local: ./dep_with_sol_and_vy - -test: - # `false` because running pytest within pytest. - disconnect_providers_after: false - -compile: - exclude: - - exclude_dir - - Excl*.json - - r"Ignore\w*\.json" diff --git a/tests/integration/cli/projects/with-contracts/pyproject.toml b/tests/integration/cli/projects/with-contracts/pyproject.toml new file mode 100644 index 0000000000..e761a00178 --- /dev/null +++ b/tests/integration/cli/projects/with-contracts/pyproject.toml @@ -0,0 +1,23 @@ +[tool.ape] +name = "withcontracts" + +[[tool.ape.dependencies]] +name = "foodep" +local = "./dep" + +[[tool.ape.dependencies]] +name = "depcontractsfolderroot" +local = "./dep_contracts_folder_root" + +[tool.ape.dependencies.config_override] +contracts_folder = "." + +[[tool.ape.dependencies]] +name = "depwithunregisteredcontracts" +local = "./dep_with_sol_and_vy" + +[tool.ape.test] +disconnect_providers_after = false + +[tool.ape.compile] +exclude = ["exclude_dir", "Excl*.json", 'r"Ignore\w*\.json"']