diff --git a/docs/getting_started/repository_overview.md b/docs/getting_started/repository_overview.md index 669a464707..b4461c4e87 100644 --- a/docs/getting_started/repository_overview.md +++ b/docs/getting_started/repository_overview.md @@ -15,8 +15,7 @@ The most relevant folders and files in the repo are: │ ├── 📁 state_tests/ │ └── 📁 ... ├─╴📁 src/ # library & framework packages -│ ├── 📁 ethereum_test_fork/ -│ ├── 📁 ethereum_test_tools/ +│ ├── 📁 execution_testing/ │ └── 📁 ... ├─╴📁 docs/ # markdown documentation │ ├── 📁 getting_started diff --git a/docs/writing_tests/checklist_templates/eip_testing_checklist_template.md b/docs/writing_tests/checklist_templates/eip_testing_checklist_template.md index f6ecf8d8d9..09eb549e02 100644 --- a/docs/writing_tests/checklist_templates/eip_testing_checklist_template.md +++ b/docs/writing_tests/checklist_templates/eip_testing_checklist_template.md @@ -1039,10 +1039,10 @@ Verify, given multiple initial values, that a block is accepted or rejected depe ### Framework Changes - Add the new header field to the relevant objects: - - `ethereum_test_fixtures.FixtureHeader`. - - `ethereum_test_fixtures.FixtureExecutionPayload`. - - `ethereum_test_specs.Header`. -- Add the appropriate `header_*_required` fork method to `BaseFork` in `ethereum_test_forks`. + - `execution_testing.fixtures.FixtureHeader`. + - `execution_testing.fixtures.FixtureExecutionPayload`. + - `execution_testing.specs.Header`. +- Add the appropriate `header_*_required` fork method to `BaseFork` in `execution_testing.forks`. ## New Block Body Field @@ -1067,10 +1067,10 @@ Verify, given multiple initial values, that a block is accepted or rejected depe ### Framework Changes - Add the new body field to the relevant objects. - - `ethereum_test_fixtures.FixtureBlockBase`. - - `ethereum_test_fixtures.FixtureEngineNewPayload`. - - `ethereum_test_specs.Block`. -- Modify `ethereum_test_specs.BlockchainTest` filling behavior to account for the new block field. + - `execution_testing.fixtures.FixtureBlockBase`. + - `execution_testing.fixtures.FixtureEngineNewPayload`. + - `execution_testing.specs.Block`. +- Modify `execution_testing.specs.BlockchainTest` filling behavior to account for the new block field. ## Gas Cost Changes diff --git a/packages/testing/src/execution_testing/cli/eest/make/commands/test.py b/packages/testing/src/execution_testing/cli/eest/make/commands/test.py index 1910785429..280cb9f400 100644 --- a/packages/testing/src/execution_testing/cli/eest/make/commands/test.py +++ b/packages/testing/src/execution_testing/cli/eest/make/commands/test.py @@ -8,12 +8,15 @@ """ import os +import shutil +import subprocess import sys from pathlib import Path import click import jinja2 +from execution_testing.config import AppConfig from execution_testing.config.docs import DocsConfig from execution_testing.forks import get_development_forks, get_forks @@ -34,6 +37,52 @@ def exit_now() -> None: exit(0) +def _format_file_if_ruff_available(file_path: Path) -> None: + """ + Format a Python file using ruff if ruff is available. + + If ruff is not available, this function does nothing. This allows + package users to use the command without requiring ruff as a dependency. + + Args: + file_path: Path to the Python file to format. + """ + # Get the path to the formatter executable in the virtual environment + if sys.platform.startswith("win"): + formatter_path = Path(sys.prefix) / "Scripts" / "ruff.exe" + else: + formatter_path = Path(sys.prefix) / "bin" / "ruff" + + # Check if ruff is available + if not formatter_path.exists(): + # Try to find ruff in PATH + ruff_in_path = shutil.which("ruff") + if ruff_in_path is None: + # Ruff is not available, skip formatting + return + formatter_path = Path(ruff_in_path) + + # Get the config path + config_path = AppConfig().ROOT_DIR.parent / "pyproject.toml" + + try: + subprocess.run( + [ + str(formatter_path), + "format", + str(file_path), + "--quiet", + "--config", + str(config_path), + ], + check=True, + capture_output=True, + ) + except (subprocess.CalledProcessError, FileNotFoundError): + # If formatting fails, silently continue + pass + + @click.command( short_help="Generate a new test file for an EIP.", epilog=f"Further help: {DocsConfig().DOCS_URL__WRITING_TESTS}", @@ -159,6 +208,9 @@ def test() -> None: with open(module_path, "w") as file: file.write(rendered_template) + # Try to format the generated file with ruff if available + _format_file_if_ruff_available(module_path) + click.echo( click.style( f"\n 🎉 Success! Test file created at: {module_path}", diff --git a/packages/testing/src/execution_testing/cli/gentest/source_code_generator.py b/packages/testing/src/execution_testing/cli/gentest/source_code_generator.py index ad98f5dc78..47cc3a05b7 100644 --- a/packages/testing/src/execution_testing/cli/gentest/source_code_generator.py +++ b/packages/testing/src/execution_testing/cli/gentest/source_code_generator.py @@ -4,6 +4,7 @@ This module maps a test provider instance to pytest source code. """ +import shutil import subprocess import sys import tempfile @@ -53,20 +54,36 @@ def get_test_source(provider: Provider, template_path: str) -> str: def format_code(code: str) -> str: """ - Format the provided Python code using the Black code formatter. + Format the provided Python code using ruff formatter. This function writes the given code to a temporary Python file, formats it - using the Black formatter, and returns the formatted code as a string. + using ruff if available, and returns the formatted (or original) code as a string. + If ruff is not available, the code is returned unformatted. Args: code (str): The Python code to be formatted. Returns: - str: The formatted Python code. + str: The formatted Python code (or original if ruff is not available). """ + # Get the path to the formatter executable in the virtual environment + if sys.platform.startswith("win"): + formatter_path = Path(sys.prefix) / "Scripts" / "ruff.exe" + else: + formatter_path = Path(sys.prefix) / "bin" / "ruff" + + # Check if ruff is available + if not formatter_path.exists(): + # Try to find ruff in PATH + ruff_in_path = shutil.which("ruff") + if ruff_in_path is None: + # Ruff is not available, return code unformatted + return code + formatter_path = Path(ruff_in_path) + # Create a temporary python file - with tempfile.NamedTemporaryFile(suffix=".py") as temp_file: + with tempfile.NamedTemporaryFile(suffix=".py", delete=False) as temp_file: # Write the code to the temporary file temp_file.write(code.encode("utf-8")) # Ensure the file is written @@ -75,31 +92,32 @@ def format_code(code: str) -> str: # Create a Path object for the input file input_file_path = Path(temp_file.name) - # Get the path to the formatter executable in the virtual environment - if sys.platform.startswith("win"): - formatter_path = Path(sys.prefix) / "Scripts" / "ruff.exe" - else: - formatter_path = Path(sys.prefix) / "bin" / "ruff" - - # Call ruff to format the file - config_path = AppConfig().ROOT_DIR.parent / "pyproject.toml" - + # Call ruff to format the file + config_path = AppConfig().ROOT_DIR.parent / "pyproject.toml" + + try: + subprocess.run( + [ + str(formatter_path), + "format", + str(input_file_path), + "--quiet", + "--config", + str(config_path), + ], + check=True, + capture_output=True, + ) + # Read the formatted source code + formatted_code = input_file_path.read_text() + except (subprocess.CalledProcessError, FileNotFoundError): + # If formatting fails or ruff is not found, return original code + formatted_code = code + finally: + # Clean up the temporary file try: - subprocess.run( - [ - str(formatter_path), - "format", - str(input_file_path), - "--quiet", - "--config", - str(config_path), - ], - check=True, - ) - except subprocess.CalledProcessError as e: - raise Exception( - f"Error formatting code using formatter '{formatter_path}'" - ) from e - - # Return the formatted source code - return input_file_path.read_text() + input_file_path.unlink() + except OSError: + pass + + return formatted_code diff --git a/tox.ini b/tox.ini index 91356f20a3..82929a5d2b 100644 --- a/tox.ini +++ b/tox.ini @@ -46,7 +46,6 @@ description = Run the testing package unit tests (with PyPy) # overwrite default groups (dev) to avoid installing optimized in tox envs using pypy dependency_groups = test - lint # TODO: add ruff for gentest; remove as part of ethereum/execution-specs#1715 passenv = PYPY_GC_MAX PYPY_GC_MIN