From 7165801b7a8fa5a9bccf9980d9fa5ea637ea7fa4 Mon Sep 17 00:00:00 2001 From: antazoey Date: Tue, 26 May 2026 13:53:41 -0500 Subject: [PATCH 1/4] fix: auto compile not working projects outside dir --- ape_solidity/compiler.py | 20 ++++++-------------- tests/test_compiler.py | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/ape_solidity/compiler.py b/ape_solidity/compiler.py index dcfaecb..dc6ca64 100644 --- a/ape_solidity/compiler.py +++ b/ape_solidity/compiler.py @@ -416,18 +416,10 @@ def get_standard_input_json_from_settings( if solc_version >= Version("0.6.9"): arguments["base_path"] = pm.path - vers_settings["outputSelection"] = { - k: v for k, v in vers_settings["outputSelection"].items() if (pm.path / k).is_file() - } - if missing_sources := [ x for x in vers_settings["outputSelection"] if not (pm.path / x).is_file() ]: - # See if the missing sources are from dependencies (they likely are) - # and cater the error message accordingly. if dependencies_needed := [x for x in missing_sources if str(x).startswith("@")]: - # Missing dependencies. Should only get here if dependencies are found - # in import-strs but are not installed (not in project or globally). missing_str = ", ".join(dependencies_needed) raise CompilerError( f"Missing required dependencies '{missing_str}'. " @@ -435,11 +427,11 @@ def get_standard_input_json_from_settings( "in an ape-config.yaml or using the `ape pm install` command." ) - # Otherwise, we are missing project-level source files for some reason. - # This would only happen if the user passes in unexpected files outside - # of core. missing_src_str = ", ".join(missing_sources) - raise CompilerError(f"Sources '{missing_src_str}' not found in '{pm.name}'.") + raise CompilerError( + f"Sources '{missing_src_str}' not found in '{pm.name}' " + f"(project path: {pm.path})." + ) sources = { x: {"content": (pm.path / x).read_text(encoding="utf8")} @@ -462,8 +454,8 @@ def compile( ) -> Iterator[ContractType]: pm = project or self.local_project settings = settings or {} - paths = [p for p in contract_filepaths] # Handles generator. - source_ids = [f"{get_relative_path(p.absolute(), pm.path)}" for p in paths] + paths = [(p if Path(p).is_absolute() else pm.path / p) for p in contract_filepaths] + source_ids = [f"{get_relative_path(Path(p).absolute(), pm.path)}" for p in paths] _validate_can_compile(paths) # Compile in an isolated env so the .cache folder does not interfere with anything. diff --git a/tests/test_compiler.py b/tests/test_compiler.py index 9b47278..e2e147e 100644 --- a/tests/test_compiler.py +++ b/tests/test_compiler.py @@ -746,3 +746,19 @@ def test_compile_code(project, compiler): assert actual.ast is not None assert len(actual.runtime_bytecode.bytecode) > 0 assert len(actual.deployment_bytecode.bytecode) > 0 + + +def test_compile_relative_path_from_other_cwd(project, compiler, tmp_path, monkeypatch): + # Regression: a relative source path must be resolved against the + # project root, not the current working directory. + monkeypatch.chdir(tmp_path) + actual = [c for c in compiler.compile(("contracts/CompilesOnce.sol",), project=project)] + assert len(actual) == 1 + assert actual[0].name == "CompilesOnce" + assert actual[0].source_id == "contracts/CompilesOnce.sol" + + +def test_compile_missing_source_raises_clear_error(project, compiler, monkeypatch): + monkeypatch.chdir(project.path) + with pytest.raises(CompilerError, match=r"not found in .*project path:"): + list(compiler.compile(("contracts/DoesNotExist.sol",), project=project)) From c8dc11dd854cb8c186a31ce096a613798b5400fa Mon Sep 17 00:00:00 2001 From: antazoey Date: Tue, 26 May 2026 13:57:13 -0500 Subject: [PATCH 2/4] chore: swap black/isort/flake8 for ruff Match ape's linting setup: ruff (with `target-version = "py310"`, `line-length = 100`) replaces black, isort, and flake8. Drop `setup.cfg` (was flake8-only). Pre-commit hooks updated accordingly. Reformat to satisfy `ruff format`. Co-Authored-By: Claude Opus 4.7 --- .pre-commit-config.yaml | 20 +++++--------------- ape_solidity/_utils.py | 4 +++- ape_solidity/compiler.py | 20 ++++++++++++++++---- pyproject.toml | 31 +++++++++++++++---------------- setup.cfg | 10 ---------- tests/test_compiler.py | 5 ++++- 6 files changed, 43 insertions(+), 47 deletions(-) delete mode 100644 setup.cfg diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 58166e7..330b247 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,22 +4,12 @@ repos: hooks: - id: check-yaml -- repo: https://github.com/PyCQA/isort - rev: 6.0.0 +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.14.10 hooks: - - id: isort - -- repo: https://github.com/psf/black - rev: 25.1.0 - hooks: - - id: black - name: black - -- repo: https://github.com/pycqa/flake8 - rev: 7.1.2 - hooks: - - id: flake8 - additional_dependencies: [flake8-breakpoint, flake8-print, flake8-pydantic, flake8-type-checking] + - id: ruff + args: [--fix, --exit-non-zero-on-fix] + - id: ruff-format - repo: https://github.com/pre-commit/mirrors-mypy rev: v1.15.0 diff --git a/ape_solidity/_utils.py b/ape_solidity/_utils.py index 61278f6..2d6ca6c 100644 --- a/ape_solidity/_utils.py +++ b/ape_solidity/_utils.py @@ -65,7 +65,9 @@ def get_single_import_lines(source_path: Path) -> list[str]: return list(import_set) -def get_pragma_spec_from_path(source_file_path: Union[Path, str]) -> Optional["SpecifierSet"]: +def get_pragma_spec_from_path( + source_file_path: Union[Path, str], +) -> Optional["SpecifierSet"]: """ Extracts pragma information from Solidity source code. diff --git a/ape_solidity/compiler.py b/ape_solidity/compiler.py index dc6ca64..f6e804e 100644 --- a/ape_solidity/compiler.py +++ b/ape_solidity/compiler.py @@ -302,7 +302,10 @@ def get_import_remapping(self, project: Optional[ProjectManager] = None) -> dict return remapping def get_compiler_settings( - self, contract_filepaths: Iterable[Path], project: Optional[ProjectManager] = None, **kwargs + self, + contract_filepaths: Iterable[Path], + project: Optional[ProjectManager] = None, + **kwargs, ) -> dict[Version, dict]: pm = project or self.local_project paths = _validate_can_compile(contract_filepaths) @@ -342,9 +345,15 @@ def _get_settings_from_version_map( settings: dict = {} for solc_version, sources in version_map.items(): version_settings: dict[str, Union[Any, list[Any]]] = { - "optimizer": {"enabled": config.optimize, "runs": config.optimization_runs}, + "optimizer": { + "enabled": config.optimize, + "runs": config.optimization_runs, + }, "outputSelection": { - str(get_relative_path(p, pm.path)): {"*": OUTPUT_SELECTION, "": ["ast"]} + str(get_relative_path(p, pm.path)): { + "*": OUTPUT_SELECTION, + "": ["ast"], + } for p in sorted(sources) }, **kwargs, @@ -493,7 +502,10 @@ def _compile( logger.info(log_str) cleaned_version = Version(solc_version.base_version) solc_binary = get_executable(version=cleaned_version) - arguments: dict = {"solc_binary": solc_binary, "solc_version": cleaned_version} + arguments: dict = { + "solc_binary": solc_binary, + "solc_version": cleaned_version, + } if solc_version >= Version("0.6.9"): arguments["base_path"] = pm.path diff --git a/pyproject.toml b/pyproject.toml index 8991fa8..8beb45f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,16 +9,6 @@ plugins = ["pydantic.mypy"] [tool.setuptools_scm] write_to = "ape_solidity/version.py" -# NOTE: you have to use single-quoted strings in TOML for regular expressions. -# It's the equivalent of r-strings in Python. Multiline strings are treated as -# verbose regular expressions by Black. Use [ ] to denote a significant space -# character. - -[tool.black] -line-length = 100 -target-version = ['py39', 'py310', 'py311', 'py312', 'py313'] -include = '\.pyi?$' - [tool.pytest.ini_options] addopts = """ -p no:ape_test @@ -35,12 +25,21 @@ fuzzing: Run Hypothesis fuzz test suite install: Tests that will install a solc version (slow) """ -[tool.isort] -line_length = 100 -force_grid_wrap = 0 -include_trailing_comma = true -multi_line_output = 3 -use_parentheses = true +[tool.ruff] +target-version = "py310" +line-length = 100 + +[tool.ruff.lint.pydocstyle] +convention = "google" + +[tool.ruff.lint.isort] +known-first-party = ["ape_solidity"] + +[tool.ruff.format] +quote-style = "double" +line-ending = "auto" +indent-style = "space" +docstring-code-format = true [tool.mdformat] number = true diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 0bcc87f..0000000 --- a/setup.cfg +++ /dev/null @@ -1,10 +0,0 @@ -[flake8] -max-line-length = 100 -ignore = E704,W503,PYD002,TC003,TC006 -exclude = - *.venv* - venv* - docs - build - tests/node_modules -type-checking-pydantic-enabled = True diff --git a/tests/test_compiler.py b/tests/test_compiler.py index e2e147e..2a7c002 100644 --- a/tests/test_compiler.py +++ b/tests/test_compiler.py @@ -213,7 +213,10 @@ def test_get_version_map_importing_more_constrained_version(project, compiler): actual = compiler.get_version_map((path,), project=project) expected_version = Version("0.8.12+commit.f00d7308") - expected_sources = ("ImportSourceWithEqualSignVersion", "SpecificVersionWithEqualSign") + expected_sources = ( + "ImportSourceWithEqualSignVersion", + "SpecificVersionWithEqualSign", + ) assert expected_version in actual actual_ids = [x.stem for x in actual[expected_version]] From 20d396c25253b655fd99d96b0dcef49b4463fecf Mon Sep 17 00:00:00 2001 From: antazoey Date: Tue, 26 May 2026 15:16:35 -0500 Subject: [PATCH 3/4] fix: ci --- .github/workflows/test.yaml | 13 +++++-------- setup.py | 9 ++------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 831ca40..b412d49 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -26,14 +26,11 @@ jobs: python -m pip install --upgrade pip pip install .[lint] - - name: Run Black - run: black --check . + - name: Run ruff format + run: ruff format --check . - - name: Run isort - run: isort --check-only . - - - name: Run flake8 - run: flake8 . + - name: Run ruff check + run: ruff check . - name: Run mdformat run: mdformat . --check @@ -63,7 +60,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest] # eventually add `windows-latest` - python-version: [3.9, '3.10', '3.11', '3.12', '3.13'] + python-version: ['3.10', '3.11', '3.12', '3.13'] env: GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/setup.py b/setup.py index 1e464d4..b4956cb 100644 --- a/setup.py +++ b/setup.py @@ -12,14 +12,10 @@ "pytest-benchmark", # For performance tests ], "lint": [ - "black>=25.1.0,<26", # Auto-formatter and linter + "ruff>=0.14.10", # Linter and auto-formatter "mypy>=1.15.0,<2", # Static type analyzer "types-requests", # Needed for mypy type shed "types-setuptools", # Needed for mypy type shed - "flake8>=7.1.2,<8", # Style linter - "flake8-pydantic", # For detecting issues with Pydantic models - "flake8-type-checking", # Detect imports to move in/out of type-checking blocks - "isort>=5.13.2,<6", # Import sorting linter "mdformat>=0.7.22", # Auto-formatter for markdown "mdformat-gfm>=0.3.5", # Needed for formatting GitHub-flavored markdown "mdformat-frontmatter>=0.4.1", # Needed for frontmatters-style headers in issue templates @@ -76,7 +72,7 @@ "packaging", # Use the version ape requires "requests", ], - python_requires=">=3.9,<4", + python_requires=">=3.10,<4", extras_require=extras_require, py_modules=["ape_solidity"], entry_points={ @@ -97,7 +93,6 @@ "Operating System :: MacOS", "Operating System :: POSIX", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", From 20f56287961a27ed2b13815c06481ad51a310b3a Mon Sep 17 00:00:00 2001 From: antazoey Date: Tue, 26 May 2026 15:31:32 -0500 Subject: [PATCH 4/4] test: don't pin solc patch version in compiler-data manifest test CompilesOnce.sol uses `pragma solidity >=0.8.0`, so any 0.8.x is valid. Asserting an exact patch version makes the test break each time a new 0.8.x release ships. Co-Authored-By: Claude Opus 4.7 (1M context) --- tests/test_compiler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_compiler.py b/tests/test_compiler.py index 2a7c002..be14396 100644 --- a/tests/test_compiler.py +++ b/tests/test_compiler.py @@ -658,7 +658,7 @@ def test_compile_outputs_compiler_data_to_manifest(project, compiler): actual = project.manifest.compilers[0] assert actual.name == "solidity" assert "CompilesOnce" in actual.contractTypes - assert actual.version == "0.8.28+commit.7893614a" + assert actual.version.startswith("0.8.") # Compiling again should not add the same compiler again. _ = [c for c in compiler.compile((path,), project=project)] length_again = len(project.manifest.compilers or [])