Skip to content

refactor: normalize compiler version handling#2149

Open
banteg wants to merge 8 commits into
eth-brownie:masterfrom
banteg:feat/compiler-version-normalization
Open

refactor: normalize compiler version handling#2149
banteg wants to merge 8 commits into
eth-brownie:masterfrom
banteg:feat/compiler-version-normalization

Conversation

@banteg
Copy link
Copy Markdown
Collaborator

@banteg banteg commented May 9, 2026

Stack

Summary

This PR separates Brownie's compiler version value type from pragma range parsing:

  • Compiler version values now use packaging.version.Version, matching py-solc-x and vvm.
  • Solidity pragmas and legacy Vyper # @version pragmas continue to use npm-style range grammar through semantic_version.NpmSpec.
  • Modern Vyper pragmas use Vyper's current PEP 440 packaging.specifiers.SpecifierSet behavior.

That gives Brownie the same version object type as its compiler-manager dependencies without replacing Solidity/Vyper pragma syntax with PEP 440.

Details

  • Adds brownie._versioning for compiler version normalization and language-specific pragma wrappers.
  • Normalizes compiler-originated strings such as v0.8.20 and 0.8.20+commit... into packaging.version.Version.
  • Keeps Solidity pragma extraction closer to solc behavior: comments and strings are ignored, multiple pragma solidity directives are intersected, and pragma solidityx; is not treated as a Solidity version pragma.
  • Wraps NpmSpec for Solidity-specific input cleanup: operator spacing, quoted range tokens, adjacent operator splitting, rejection of v-prefixed Solidity literals, rejection of prerelease/build-qualified match expressions, and solc's wider ^0.0.patch behavior.
  • Keeps legacy Vyper # @version matching on NpmSpec, including old prerelease spellings such as 0.1.0b16.
  • Keeps modern Vyper #pragma version / # @version matching on SpecifierSet, including Vyper's leading ^ to ~= compatibility rewrite.
  • Parses Vyper version pragmas from Python comment tokens so strings and unrelated pragmas such as #pragma optimize are ignored.
  • Preserves already-installed compiler selection when the installable/available version list does not contain a matching compiler.

Compatibility Notes

  • brownie.project.compiler.solidity.get_version() and brownie.project.compiler.vyper.get_version() now return packaging.version.Version.
  • Downstream code that used semantic_version.Version conveniences such as .truncate(), .next_minor(), or .next_patch() on those return values should switch to packaging.Version properties/helpers.
  • semantic-version remains a runtime dependency because Brownie still accepts npm-style Solidity and legacy Vyper pragma syntax.
  • packaging is now a direct runtime dependency because Brownie imports it directly.
  • install_solc("latest") is preserved and still forwards "latest" to py-solc-x.
  • Duplicate Vyper version pragmas are rejected consistently with modern Vyper.

Generated Files

  • The branch includes regenerated mypyc output under build/.
  • For code review, the useful diff is the non-generated review diff: feat/fix-pr-ci..feat/compiler-version-normalization -- . ':!build/__native_eth_brownie.c' ':!build/__native_eth_brownie.h' ':!build/__native_internal_eth_brownie.h'.

Validation

  • uv run --python /opt/homebrew/bin/python3.13 --with-requirements requirements.txt --with pytest-cov==2.10.1 --with eth-retry==0.3.5 python -m pytest tests/project/test_sources.py tests/project/compiler/test_utils.py tests/project/compiler/test_solidity.py -k 'not first_revert' -q
  • uv run --python /opt/homebrew/bin/python3.13 --with-requirements requirements.txt --with pytest-cov==2.10.1 --with eth-retry==0.3.5 python -m pytest tests/project/compiler/test_vyper.py -k 'find_vyper_versions_uses_installed_when_available_list_does_not_match or set_vyper_version_normalizes_version_like_objects' -q
  • uv run --isolated python -m py_compile brownie/_versioning.py brownie/project/sources.py brownie/project/compiler/solidity.py brownie/project/compiler/vyper.py tests/project/test_sources.py tests/project/compiler/test_solidity.py tests/project/compiler/test_vyper.py tests/project/compiler/test_utils.py
  • uvx --from black==24.1.1 black --check brownie/_versioning.py brownie/project/sources.py brownie/project/compiler/solidity.py brownie/project/compiler/vyper.py tests/project/test_sources.py tests/project/compiler/test_solidity.py tests/project/compiler/test_vyper.py tests/project/compiler/test_utils.py
  • uvx --from isort==5.13.2 isort --check-only --diff brownie/_versioning.py brownie/project/sources.py brownie/project/compiler/solidity.py brownie/project/compiler/vyper.py tests/project/test_sources.py tests/project/compiler/test_solidity.py tests/project/compiler/test_vyper.py tests/project/compiler/test_utils.py --skip brownie/__init__.py
  • uvx --python /opt/homebrew/bin/python3.13 --from build python -m build --wheel
  • git diff --check feat/fix-pr-ci..feat/compiler-version-normalization -- . ':!build/__native_eth_brownie.c'

Note: generated mypyc C output still contains generator-emitted trailing whitespace, so the whitespace check excludes the generated C artifact.

@banteg banteg force-pushed the feat/compiler-version-normalization branch 8 times, most recently from db86ec7 to 05b06b2 Compare May 9, 2026 10:05
@banteg banteg force-pushed the feat/compiler-version-normalization branch from 05b06b2 to 00f251a Compare May 9, 2026 10:10
@banteg banteg force-pushed the feat/compiler-version-normalization branch from 00f251a to 278c036 Compare May 9, 2026 10:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant