diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..eb3711c6 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,34 @@ +name: "CodeQL" + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: python + + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 1b2d345c..84714f16 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -65,8 +65,10 @@ jobs: strategy: matrix: - os: [ubuntu-latest, macos-latest] # eventually add `windows-latest` - python-version: [3.8, 3.9, "3.10", "3.11"] + # TODO: Replace with macos-latest when works again. + # https://github.com/actions/setup-python/issues/808 + os: [ubuntu-latest, macos-12] # eventually add `windows-latest` + python-version: [3.8, 3.9, "3.10", "3.11", "3.12"] env: GETH_VERSION: 1.12.0 @@ -109,7 +111,7 @@ jobs: - name: Run Tests run: | - pytest tests/test_compiler.py -m "not fuzzing" -n 0 -s \ + pytest -k "not test_coverage" -m "not fuzzing" -n 0 -s \ --cov=ape_vyper \ --cov-branch \ --cov-report term \ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 60e734ca..23d53854 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,13 +4,13 @@ repos: hooks: - id: check-yaml -- repo: https://github.com/pre-commit/mirrors-isort - rev: v5.10.1 +- repo: https://github.com/PyCQA/isort + rev: 5.13.2 hooks: - id: isort - repo: https://github.com/psf/black - rev: 24.3.0 + rev: 24.4.2 hooks: - id: black name: black @@ -21,7 +21,7 @@ repos: - id: flake8 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.9.0 + rev: v1.10.0 hooks: - id: mypy additional_dependencies: [types-setuptools, pydantic==1.10.4] diff --git a/README.md b/README.md index 3d728800..fd688607 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Ape compiler plugin around [VVM](https://github.com/vyperlang/vvm) ## Dependencies -- [python3](https://www.python.org/downloads) version 3.8 up to 3.11. +- [python3](https://www.python.org/downloads) version 3.8 up to 3.12. ## Installation diff --git a/ape_vyper/compiler.py b/ape_vyper/compiler.py index e7691fd0..85fb3b58 100644 --- a/ape_vyper/compiler.py +++ b/ape_vyper/compiler.py @@ -52,6 +52,21 @@ _NON_PAYABLE_STR = f"dev: {RuntimeErrorType.NONPAYABLE_CHECK.value}" Optimization = Union[str, bool] +EVM_VERSION_DEFAULT = { + "0.2.15": "berlin", + "0.2.16": "berlin", + "0.3.0": "berlin", + "0.3.1": "berlin", + "0.3.2": "berlin", + "0.3.3": "berlin", + "0.3.4": "berlin", + "0.3.6": "berlin", + "0.3.7": "paris", + "0.3.8": "shanghai", + "0.3.9": "shanghai", + "0.3.10": "shanghai", +} + class VyperConfig(PluginConfig): version: Optional[SpecifierSet] = None @@ -723,7 +738,9 @@ def get_version_map( # Handle no-pragma sources if source_paths_without_pragma: max_installed_vyper_version = ( - max(version_map) if version_map else max(self.installed_versions) + max(version_map) + if version_map + else max(v for v in self.installed_versions if not v.pre) ) _safe_append(version_map, max_installed_vyper_version, source_paths_without_pragma) @@ -748,7 +765,11 @@ def get_compiler_settings( output_selection: Dict[str, Set[str]] = {} optimizations_map = get_optimization_pragma_map(source_paths, contracts_path) evm_version_map = get_evm_version_pragma_map(source_paths, contracts_path) - default_evm_version = data.get("evm_version", data.get("evmVersion")) + default_evm_version = ( + data.get("evm_version") + or data.get("evmVersion") + or EVM_VERSION_DEFAULT.get(version.base_version) + ) for source_path in source_paths: source_id = str(get_relative_path(source_path.absolute(), contracts_path)) optimization = optimizations_map.get(source_id, True) @@ -963,7 +984,8 @@ def _get_compiler_arguments(self, version_map: Dict, base_path: Path) -> Dict[Ve bin_arg = self._get_vyper_bin(vyper_version) arguments_map[vyper_version] = { "base_path": str(base_path), - "evm_version": self.evm_version, + "evm_version": self.evm_version + or EVM_VERSION_DEFAULT.get(vyper_version.base_version), "vyper_version": str(vyper_version), "vyper_binary": bin_arg, } diff --git a/pyproject.toml b/pyproject.toml index 05384a48..4f748355 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,7 +15,7 @@ write_to = "ape_vyper/version.py" [tool.black] line-length = 100 -target-version = ['py38', 'py39', 'py310', 'py311'] +target-version = ['py38', 'py39', 'py310', 'py311', 'py312'] include = '\.pyi?$' [tool.pytest.ini_options] diff --git a/setup.py b/setup.py index 8f83010c..16326b9a 100644 --- a/setup.py +++ b/setup.py @@ -11,11 +11,11 @@ "hypothesis>=6.2.0,<7.0", # Strategy-based fuzzer ], "lint": [ - "black>=24.3.0,<25", # Auto-formatter and linter - "mypy>=1.9.0", # Static type analyzer + "black>=24.4.2,<25", # Auto-formatter and linter + "mypy>=1.10.0,<2", # Static type analyzer "types-setuptools", # Needed due to mypy typeshed "flake8>=7.0.0,<8", # Style linter - "isort>=5.10.1", # Import sorting linter + "isort>=5.13.2", # Import sorting linter "mdformat>=0.7.17", # 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 @@ -90,5 +90,6 @@ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ], ) diff --git a/tests/ape-config.yaml b/tests/ape-config.yaml index 1677b3e9..ec6f7227 100644 --- a/tests/ape-config.yaml +++ b/tests/ape-config.yaml @@ -7,8 +7,6 @@ dependencies: local: ./ExampleDependency vyper: - evm_version: istanbul - # Allows importing dependencies. import_remapping: - "exampledep=ExampleDependency" diff --git a/tests/conftest.py b/tests/conftest.py index 54b79248..c75352c4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,7 +1,6 @@ import os import shutil from contextlib import contextmanager -from distutils.dir_util import copy_tree from pathlib import Path from tempfile import mkdtemp from typing import List @@ -153,22 +152,20 @@ def config(): @pytest.fixture(autouse=True) -def project(config): +def project(config, project_folder): project_source_dir = Path(__file__).parent - project_dest_dir = config.PROJECT_FOLDER / project_source_dir.name + project_dest_dir = project_folder / project_source_dir.name + shutil.rmtree(project_dest_dir, ignore_errors=True) # Delete build / .cache that may exist pre-copy project_path = Path(__file__).parent cache = project_path / ".build" + shutil.rmtree(cache, ignore_errors=True) - if cache.is_dir(): - shutil.rmtree(cache) - - copy_tree(project_source_dir.as_posix(), project_dest_dir.as_posix()) + shutil.copytree(project_source_dir, project_dest_dir, dirs_exist_ok=True) with config.using_project(project_dest_dir) as project: yield project - if project.local_project._cache_folder.is_dir(): - shutil.rmtree(project.local_project._cache_folder) + shutil.rmtree(project.local_project._cache_folder, ignore_errors=True) @pytest.fixture diff --git a/tests/test_cli.py b/tests/test_cli.py index 4be8b562..fa9a55db 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,7 +1,5 @@ -from pathlib import Path -from tempfile import NamedTemporaryFile - import pytest +from ape.utils import create_tempdir from ape_vyper._cli import cli @@ -23,9 +21,10 @@ ) def test_cli_flatten(project, contract_name, expected, cli_runner): path = project.contracts_folder / contract_name - with NamedTemporaryFile() as tmpfile: - result = cli_runner.invoke(cli, ["flatten", str(path), tmpfile.name]) + with create_tempdir() as tmpdir: + file = tmpdir / "flatten.vy" + result = cli_runner.invoke(cli, ("flatten", str(path), str(file)), catch_exceptions=False) assert result.exit_code == 0, result.stderr_bytes - output = Path(tmpfile.name).read_text() + output = file.read_text() for expect in expected: assert expect in output diff --git a/tests/test_compiler.py b/tests/test_compiler.py index 98f00972..7e3cae92 100644 --- a/tests/test_compiler.py +++ b/tests/test_compiler.py @@ -151,7 +151,10 @@ def run_test(manifest): for compiler in (vyper_028, codesize_latest, true_latest): assert compiler.name == "vyper" - assert compiler.settings["evmVersion"] == "istanbul" + + assert vyper_028.settings["evmVersion"] == "berlin" + assert codesize_latest.settings["evmVersion"] == "shanghai" + assert true_latest.settings["evmVersion"] == "shanghai" # There is only one contract with codesize pragma. assert codesize_latest.contractTypes == ["optimize_codesize"] diff --git a/tests/test_coverage.py b/tests/test_coverage.py index 4d55b45c..3a8d5287 100644 --- a/tests/test_coverage.py +++ b/tests/test_coverage.py @@ -1,11 +1,11 @@ import re import shutil -import tempfile import xml.etree.ElementTree as ET from pathlib import Path from typing import List import pytest +from ape.utils import create_tempdir LINES_VALID = 8 MISSES = 0 @@ -50,11 +50,9 @@ def coverage_project_path(projects_path): def coverage_project(config, coverage_project_path): build_dir = coverage_project_path / ".build" shutil.rmtree(build_dir, ignore_errors=True) - with tempfile.TemporaryDirectory() as base_dir: - # Copy Coverage project - project_dir = Path(base_dir) / "coverage_project" - shutil.copytree(coverage_project_path, project_dir) - with config.using_project(project_dir) as project: + with create_tempdir(name="coverage_project") as base_dir: + shutil.copytree(coverage_project_path, base_dir, dirs_exist_ok=True) + with config.using_project(base_dir) as project: yield project shutil.rmtree(build_dir, ignore_errors=True)