Skip to content

chore(deps,tooling,ci): replace pyspelling with codespell in tox #1715

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Jun 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/coverage.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
echo "No python files were changed in ./tests/ - no action necessary"
exit 0

- name: Report changed python test moudules
- name: Report changed python test modules
if: steps.changed-tests.outputs.tests_any_changed == 'true'
run: |
echo "${{ toJson(steps.changed-tests.outputs) }}"
Expand Down
9 changes: 4 additions & 5 deletions .github/workflows/tox_verify.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
run: uvx --with=tox-uv tox -e typecheck

spellcheck:
name: Spellcheck sources with pyspelling
name: Spellcheck sources with codespell
runs-on: ubuntu-latest
steps:
- name: Checkout ethereum/execution-spec-tests
Expand All @@ -48,11 +48,10 @@ jobs:
cache-dependency-glob: "uv.lock"
version: ${{ vars.UV_VERSION }}
python-version: ${{ vars.DEFAULT_PYTHON_VERSION }}
- name: Install dependencies (aspell, aspell-en)
run: |
sudo apt-get update && sudo apt-get install -y aspell aspell-en
- name: Run spellcheck with pyspelling via tox
- name: Run spellcheck with codespell via tox
run: uvx --with=tox-uv tox -e spellcheck
env:
GITHUB_STEP_SUMMARY: ${{ env.GITHUB_STEP_SUMMARY }}

markdownlint:
name: Lint markdown files with markdownlint
Expand Down
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ repos:
hooks:
- id: tox
name: tox
entry: uvx --with=tox-uv tox --parallel -e lint,typecheck
entry: uvx --with=tox-uv tox --parallel -e lint,typecheck,spellcheck
language: system
types: [python]
pass_filenames: false
Expand Down
1 change: 1 addition & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ Users can select any of the artifacts depending on their testing needs for their
- ✨ Added [Post-Mortems of Missed Test Scenarios](https://eest.ethereum.org/main/writing_tests/post_mortems/) to the documentation that serves as a reference list of all cases that were missed during the test implementation phase of a new EIP, and includes the steps taken in order to prevent similar test cases to be missed in the future ([#1327](https://github.com/ethereum/execution-spec-tests/pull/1327)).
- ✨ Added a new `eest` sub-command, `eest info`, to easily print a cloned EEST repository's version and the versions of relevant tools, e.g., `python`, `uv` ([#1621](https://github.com/ethereum/execution-spec-tests/pull/1621)).
- ✨ Add `CONTRIBUTING.md` for execution-spec-tests and improve coding standards documentation ([#1604](https://github.com/ethereum/execution-spec-tests/pull/1604)).
- ✨ Use `codespell` instead of `pyspelling` to spell-check python and markdown sources ([#1715](https://github.com/ethereum/execution-spec-tests/pull/1715)).
- 🔀 Updated from pytest 7 to [pytest 8](https://docs.pytest.org/en/stable/changelog.html#features-and-improvements), benefits include improved type hinting and hook typing, stricter mark handling, and clearer error messages for plugin and metadata development ([#1433](https://github.com/ethereum/execution-spec-tests/pull/1433)).
- 🐞 Fix bug in ported-from plugin and coverage script that made PRs fail with modified tests that contained no ported tests ([#1661](https://github.com/ethereum/execution-spec-tests/pull/1661)).
- 🔀 Refactor the `click`-based CLI interface used for pytest-based commands (`fill`, `execute`, `consume`) to make them more extensible ([#1654](https://github.com/ethereum/execution-spec-tests/pull/1654)).
Expand Down
2 changes: 1 addition & 1 deletion docs/executing_tests/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ uv run execute remote --fork=Prague --rpc-endpoint=https://rpc.endpoint.io --rpc

## `execute` Command Test Execution

After executing wither `execute hive` or `execute remote`, the command will first create a random sender account from which all required test accounts will be deployed and funded, and this account is funded by sweeping (by default) the seed account.
After executing `execute hive` or `execute remote` the command will first create a random sender account from which all required test accounts will be deployed and funded, and this account is funded by sweeping (by default) the seed account.

The sweep amount can be configured by setting the `--seed-account-sweep-amount` flag:

Expand Down
2 changes: 1 addition & 1 deletion docs/getting_started/code_standards.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Code pushed to @ethereum/execution-spec-tests must fulfill the following checks
| EL Client test cases | `uvx --with=tox-uv tox -e tests-deployed` | All client test cases for deployed forks can be generated. |
| zkEVM EL Test cases | `uvx --with=tox-uv tox -e tests-deployed-zkevm` | All client test cases specific to zkEVMs for deployed forks can be generated. |
| HTML doc build | `uvx --with=tox-uv tox -e mkdocs` | Documentation generated without warnings. |
| Spellcheck | `uvx --with=tox-uv tox -e spellcheck` | Markdown spell-check (requires [additional dependency](code_standards_details.md#additional-dependencies)). |
| Spellcheck | `uvx --with=tox-uv tox -e spellcheck` | Code and documentation spell-check using codespell. |
| Markdown lint | `uvx --with=tox-uv tox -e markdownlint` | Markdown lint (requires [additional dependency](code_standards_details.md#additional-dependencies)). |

!!! tip "Running checks easily"
Expand Down
9 changes: 8 additions & 1 deletion docs/getting_started/code_standards_details.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,17 @@ Some checks require external (non-Python) packages:

#### For `spellcheck`

The spellcheck environment uses **codespell**, which is automatically installed via Python dependencies and checks for common spelling mistakes in code and documentation.

To fix spelling errors found by codespell:

```console
sudo apt-get install aspell aspell-en
uv run codespell *.md *.ini .github/ src/ tests/ docs/ --write-changes
```

!!! note "VS Code Integration"
The `whitelist.txt` file is still maintained for the VS Code cSpell extension, which provides real-time spell checking in the editor.

#### For `markdownlint`

```console
Expand Down
13 changes: 7 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,10 @@ Changelog = "https://eest.ethereum.org/main/CHANGELOG/"

[project.optional-dependencies]
test = ["pytest-cov>=4.1.0,<5"]
lint = [
"ruff==0.11.8",
"mypy>=1.15.0,<1.16",
"types-requests>=2.31,<2.33",
]
lint = ["ruff==0.11.8", "mypy>=1.15.0,<1.16", "types-requests>=2.31,<2.33"]
docs = [
"cairosvg>=2.7.0,<3",
"codespell>=2.4.1,<3",
"mike>=1.1.2,<2",
"mkdocs>=1.4.3,<2",
"mkdocs-click>=0.8,<1",
Expand Down Expand Up @@ -123,10 +120,14 @@ select = ["E", "F", "B", "W", "I", "A", "N", "D", "C"]
fixable = ["I", "B", "E", "F", "W", "D", "C"]
ignore = ["D205", "D203", "D212", "D415", "C901", "A005", "C420"]


[tool.mypy]
mypy_path = ["src", "$MYPY_CONFIG_FILE_DIR/stubs"]
plugins = ["pydantic.mypy"]

[tool.codespell]
skip = ".venv,__pycache__,.git,build,dist,*.pyc,*.lock"
check-filenames = true
ignore-words-list = "ingenuous"

[tool.uv.sources]
ethereum-spec-evm-resolver = { git = "https://github.com/petertdavies/ethereum-spec-evm-resolver", rev = "623ac4565025e72b65f45b926da2a3552041b469" }
123 changes: 122 additions & 1 deletion src/cli/tox_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,41 @@

import click
from pyspelling import __main__ as pyspelling_main # type: ignore
from rich.console import Console


def write_github_summary(title: str, tox_env: str, error_message: str, fix_commands: list[str]):
"""
Write a summary to GitHub Actions when a check fails.

Args:
title: The title of the check that failed
tox_env: The tox environment name (e.g., "spellcheck")
error_message: Description of what went wrong
fix_commands: List of commands to fix the issue locally

"""
if not os.environ.get("GITHUB_ACTIONS"):
return

summary_file = os.environ.get("GITHUB_STEP_SUMMARY")
if not summary_file:
return

with open(summary_file, "a") as f:
f.write(f"## ❌ {title}\n\n")
f.write(f"{error_message}\n\n")
f.write("### To reproduce this check locally:\n")
f.write("```bash\n")
f.write(f"uvx --with=tox-uv tox -e {tox_env}\n")
f.write("```\n\n")

if fix_commands:
f.write("### To verify and fix the issues:\n")
f.write("```bash\n")
for cmd in fix_commands:
f.write(f"{cmd}\n")
f.write("```\n")


@click.command(
Expand Down Expand Up @@ -57,11 +92,97 @@ def pyspelling():
if not shutil.which("aspell"):
click.echo("aspell not installed, skipping spellcheck.")
if os.environ.get("GITHUB_ACTIONS"):
write_github_summary(
title="Pyspelling Check Failed",
tox_env="spellcheck",
error_message=(
"aspell is not installed. This tool is required for spell checking "
" documentation."
),
fix_commands=[
"# Install aspell on Ubuntu/Debian",
"sudo apt-get install aspell aspell-en",
"",
"# Install aspell on macOS",
"brew install aspell",
],
)
sys.exit(1)
else:
click.echo(
"********* Install 'aspell' and 'aspell-en' to enable spellcheck *********"
)
sys.exit(0)

sys.exit(pyspelling_main.main())
result = pyspelling_main.main()
if result != 0:
write_github_summary(
title="Pyspelling Check Failed",
tox_env="spellcheck",
error_message="Pyspelling found spelling errors in the documentation.",
fix_commands=[
"# Check the pyspelling configuration",
"cat .pyspelling.yml",
"",
"# Review and fix spelling errors manually",
"# Pyspelling doesn't have an auto-fix option",
],
)
sys.exit(result)


@click.command()
def codespell():
"""
Run codespell on the codebase and provide helpful error messages.

Checks spelling in .github/, src/, tests/, and docs/ directories.
"""
console = Console()

# Define the paths to check
paths_to_check = ["*.md", "*.ini", ".github/", "src/", "tests/", "docs/"]
paths_str = " ".join(paths_to_check)

# Run codespell
result = subprocess.run(
["codespell"] + paths_to_check,
capture_output=True,
text=True,
)

# Print the output
if result.stdout:
console.print(result.stdout)
if result.stderr:
console.print(result.stderr, style="red")

# If there were spelling errors, show a helpful message
if result.returncode != 0:
console.print("\n[bold red]❌ Spellcheck Failed[/bold red]")
console.print(
"[yellow]Please review the errors above. For single-suggestion fixes, you can "
"automatically apply them with:[/yellow]"
)
console.print(f"[cyan]uv run codespell {paths_str} --write-changes[/cyan]\n")

# Write to GitHub Actions summary
write_github_summary(
title="Spellcheck Failed",
tox_env="spellcheck",
error_message="Codespell found spelling errors in the code.",
fix_commands=[
"# Ensure codespell is installed (part of docs extras)",
"uv sync --all-extras",
"",
"# Check for spelling errors",
f"uv run codespell {paths_str}",
"",
"# Automatically fix single-suggestion errors",
f"uv run codespell {paths_str} --write-changes",
],
)

sys.exit(1)

sys.exit(0)
2 changes: 1 addition & 1 deletion src/ethereum_clis/clis/besu.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def __init__(
def start_server(self):
"""
Start the t8n-server process, extract the port, and leave it running
for future re-use.
for future reuse.
"""
args = [
str(self.binary),
Expand Down
2 changes: 1 addition & 1 deletion src/ethereum_clis/clis/execution_specs.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def __init__(
def start_server(self):
"""
Start the t8n-server process, extract the port, and leave it running
for future re-use.
for future reuse.
"""
self.server_dir = TemporaryDirectory()
self.server_file_path = Path(self.server_dir.name) / "t8n.sock"
Expand Down
2 changes: 1 addition & 1 deletion src/ethereum_clis/ethereum_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def from_binary_path(cls, *, binary_path: Optional[Path], **kwargs) -> Any:
Instantiate the appropriate CLI subclass derived from the CLI's `binary_path`.

This method will attempt to detect the CLI version and instantiate the appropriate
subclass based on the version output by running hte CLI with the version flag.
subclass based on the version output by running the CLI with the version flag.
"""
assert cls.default_tool is not None, "default CLI implementation was never set"

Expand Down
2 changes: 1 addition & 1 deletion src/ethereum_clis/transition_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def is_fork_supported(self, fork: Fork) -> bool:
def start_server(self):
"""
Start the t8n-server process, extract the port, and leave it running
for future re-use.
for future reuse.
"""
pass

Expand Down
4 changes: 2 additions & 2 deletions src/ethereum_test_exceptions/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -800,11 +800,11 @@ class EOFException(ExceptionBase):
"""
INVALID_CODE_SECTION_INDEX = auto()
"""
CALLF Operation referes to a non-existent code section
CALLF Operation refers to a non-existent code section
"""
UNEXPECTED_HEADER_KIND = auto()
"""
Header parsing encounterd a section kind it wasn't expecting
Header parsing encountered a section kind it wasn't expecting
"""
CALLF_TO_NON_RETURNING = auto()
"""
Expand Down
2 changes: 1 addition & 1 deletion src/ethereum_test_tools/code/generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ def __new__(

bytecode = Bytecode()

# All conditions get pre-pended to this bytecode; if none are met, we reach the default
# All conditions get prepended to this bytecode; if none are met, we reach the default
if evm_code_type == EVMCodeType.LEGACY:
action_jump_length = sum(len(case.action) + 6 for case in cases) + 3
bytecode = default_action + Op.JUMP(Op.ADD(Op.PC, action_jump_length))
Expand Down
2 changes: 1 addition & 1 deletion src/ethereum_test_types/eof/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""EVM Object Format Libary to generate bytecode for testing purposes."""
"""EVM Object Format Library to generate bytecode for testing purposes."""

from .constants import LATEST_EOF_VERSION

Expand Down
2 changes: 1 addition & 1 deletion src/ethereum_test_vm/opcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -5062,7 +5062,7 @@ class Opcodes(Opcode, Enum):
Description
----
Exchanges two stack positions. Two nybbles, n is high 4 bits + 1, then m is 4 low bits + 1.
Exchanges tne n+1'th item with the n + m + 1 item.
Exchanges the n+1'th item with the n + m + 1 item.

Inputs x and y when the opcode is used as `EXCHANGE[x, y]`, are equal to:
- x = n + 1
Expand Down
Loading
Loading