Skip to content

fix(ci,tooling,test-types,test-forks): import ethereum lazily so xdist fill coverage measures it#3059

Open
danceratopz wants to merge 2 commits into
ethereum:forks/amsterdamfrom
danceratopz:fix-cov-warnings
Open

fix(ci,tooling,test-types,test-forks): import ethereum lazily so xdist fill coverage measures it#3059
danceratopz wants to merge 2 commits into
ethereum:forks/amsterdamfrom
danceratopz:fix-cov-warnings

Conversation

@danceratopz

@danceratopz danceratopz commented Jun 29, 2026

Copy link
Copy Markdown
Member

🗒️ Description

This PR improves the coverage measurement for ethereum and fixes the following warning that every fill job logs, once per pytest-xdist worker:

CoverageWarning: Module ethereum was previously imported, but not measured (module-not-measured)

Root cause

pytest-cov starts an xdist worker's coverage session late — in pytest_sessionstart. The execution_testing framework, however, imports the measured ethereum package at import time, well before that, from four module locations:

  • base_types and test_types.trie import ethereum.crypto.hash.keccak256 at module level — executed as soon as the fill CLI and its plugins are imported;
  • ExecutionSpecsTransitionTool imports the EELS t8n (T8N / ForkCache / create_parser / get_supported_forks / ethereum) at module level, and the forks plugin calls t8n.is_fork_supported() from pytest_configure.

So by the time a worker starts measuring, ethereum is already in sys.modules. pytest-cov's Central/DistMaster engines suppress this warning; DistWorker does not — hence it surfaces only on xdist workers.

Coverage impact

Pre-importing the source package also makes coverage under-count ethereum — in every mode, -n 0 and -n 1 alike.

On a small sample, deferring the import raises the measured statement total from 36,926 → 39,000 (+2,074 across 152 files). The xdist warning was the visible symptom of a measurement gap that affected all runs.

Update: the ~2,074 figure above was a measurement error (the "baseline" was a dirty checkout). A same-checkout A/B shows the statement denominator is unchanged (39,000). The real effect is small and constant: fill measures ~300 more ethereum statements — the import-time/header lines of modules loaded before the worker's coverage starts — ≈304 on a narrow Frontier slice and ≈303 on a 2,709-test Frontier→Cancun run, so it does not scale with the test set. At <1% it rounds to a ~0% codecov diff (see comment).

The fix

Defer all four ethereum imports to first use, so they run after the worker's coverage session has started (collection / test execution / the trylast report header). Specifically: lazy keccak256 imports; a lazy ForkCache property + in-function t8n imports + importlib.metadata for the tool version; and a lazily-computed, cached unsupported-fork set. Nothing is silenced — no filterwarnings, no --disable-warnings, no disable_warnings.

Results

  • module-not-measured gone — verified on the minimal repro, repeated -n 4 runs, and a 2,709-test Frontier→Cancun fill.
  • -n 0 and -n 1 report identical coverage; fill measures ~300 more ethereum statements (import-time lines) on the same 39,000-statement denominator — a constant <1% gain, not test-set-dependent.
  • eels_base_coverage --cov-fail-under=85 gate passes (91.45%).
  • 637 framework unit tests pass; just static clean.

⚠️ For reviewers: the statement denominator is unchanged; the coverage % moves by <1% (≈0% codecov diff), and the --cov-fail-under=85 gate still passes comfortably (91.45%).

Alternative considered

A runner-only approach was prototyped (start coverage earlier via COVERAGE_PROCESS_START + a dedicated coverage_fill.cfg in the Justfile, dropping pytest-cov's --cov and combining manually). It works, but we preferred fixing the source because it:

  • removes the warning for every --cov=ethereum invocation, not just the just fill recipe (direct pytest/fill runs, json-loader, IDE runs, contributors);
  • keeps the pytest-cov integration rather than hand-rolling coverage erase/combine/report/xml and a second coverage config to keep in sync with pyproject.toml;
  • addresses the actual root cause — a test framework shouldn't import the package-under-test at import time.

The prototype lives on a local branch fix-coverage-warnings-start-coverage-earlier (currently based off the wrong base), kept only for reference.

🔗 Related Issues or PRs

N/A.

✅ Checklist

  • All: Ran fast static checks to avoid unnecessary CI fails, see also Code Standards and Enabling Pre-commit Checks:
    just static
  • All: PR title adheres to the repo standard - it will be used as the squash commit message and should start type(scope):.
  • All: Considered updating the online docs in the ./docs/ directory — no user-facing change.
  • All: Set appropriate labels for the changes (only maintainers can apply labels).

`base_types` and `test_types.trie` import `ethereum.crypto.hash.keccak256`
at module level, so importing the test framework (the `fill` CLI and its
plugins) imports the measured `ethereum` package immediately -- before a
pytest-xdist worker starts its coverage session in `pytest_sessionstart`.
Coverage then reports `ethereum` as `module-not-measured`, and under-counts
it (the statement total is lower in every mode, not only under xdist).

Import keccak256 lazily, at first use during collection / test execution,
so the `ethereum` import happens while the worker's coverage session is
active.
`ExecutionSpecsTransitionTool` imported `ethereum` and the EELS t8n
(`T8N`, `ForkCache`, `create_parser`, `get_supported_forks`) at module
level, and the `forks` plugin called `t8n.is_fork_supported()` from
`pytest_configure`. Both pull the measured `ethereum` package into
`sys.modules` before a pytest-xdist worker starts its coverage session,
leaving it `module-not-measured` and under-counted.

Defer the imports to first use:
- build `ForkCache` lazily via a property and import
  `create_parser`/`T8N`/`get_supported_forks` inside the methods that use
  them; read the tool version via `importlib.metadata`.
- compute the unsupported-fork set lazily (cached), from collection and the
  report header, which run after the worker's coverage session starts.
@danceratopz danceratopz changed the title fix(test-tools): import ethereum lazily so xdist fill coverage measures it fix(test-tools): import ethereum lazily so xdist fill coverage measures it Jun 29, 2026
@danceratopz danceratopz changed the title fix(test-tools): import ethereum lazily so xdist fill coverage measures it fix(tooling,test-types,test-forks): import ethereum lazily so xdist fill coverage measures it Jun 29, 2026
@codecov

codecov Bot commented Jun 29, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.22%. Comparing base (3f888bc) to head (7a858f2).

Additional details and impacted files
@@               Coverage Diff                @@
##           forks/amsterdam    #3059   +/-   ##
================================================
  Coverage            93.22%   93.22%           
================================================
  Files                  624      624           
  Lines                36926    36926           
  Branches              3377     3377           
================================================
  Hits                 34424    34424           
  Misses                1708     1708           
  Partials               794      794           
Flag Coverage Δ
unittests 93.22% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@danceratopz danceratopz added A-test-forks Area: execution_testing.forks A-tooling Area: Improvements or changes to auxiliary tooling such as uv, ruff, mypy, ... A-test-types Area: execution_testing.base_types and execution_testing.test_types A-ci Area: Continuous Integration labels Jun 29, 2026
@danceratopz danceratopz changed the title fix(tooling,test-types,test-forks): import ethereum lazily so xdist fill coverage measures it fix(ci,tooling,test-types,test-forks): import ethereum lazily so xdist fill coverage measures it Jun 29, 2026
@danceratopz danceratopz added the C-bug Category: this is a bug, deviation, or other problem label Jun 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-ci Area: Continuous Integration A-test-forks Area: execution_testing.forks A-test-types Area: execution_testing.base_types and execution_testing.test_types A-tooling Area: Improvements or changes to auxiliary tooling such as uv, ruff, mypy, ... C-bug Category: this is a bug, deviation, or other problem

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant