Vvinod820

apeshift

Production-grade Brownie to Ape Framework migration workflow.

cross-migrationbrownieapeethereumast-grep
Public
24 executions

Run locally

npx codemod apeshift

ApeShift

Codemod Registry
license

Production-grade, self-sufficient Brownie -> Ape migration that automates measured Python migration patterns with 0 false positives and 0 false negatives on audited repos, including large multi-file codebases (see Real-world results).

Install and usage

bash

For local development:

bash

Real-world results

ApeShift was validated against 9 real-world Brownie repositories across different sizes and dependency profiles. All Python migrations produced 0 false positives and 0 false negatives (strict audit + exhaustive FN scan).

Benchmark clone URLs (use these — smartcontractkit/brownie_fund_me, brownie_simple_storage, and nft-mix do not exist on GitHub):

These match src/benchmark.ts (brownie-nft-coursePatrickAlphaC/nft-mix).

RepositoryPython FilesPatterns DetectedTransforms AppliedFPFNSyntax OKape compile
PatrickAlphaC/brownie_simple_storage4121200✅ PASS
brownie-mix/token-mix6646400✅ PASS
brownie-mix/vyper-token-mix51026500✅ PASS
brownie-mix/github-actions-mix22000✅ PASS
curvefi/curve-dao-contracts2223855,68700✅ PASS
brownie-mix/upgrades-mix776700see note
smartcontractkit/chainlink-mix2110400see note
PatrickAlphaC/brownie_fund_me72300see note
PatrickAlphaC/nft-mix187600see note
Combined2926836,095+00

The largest test — curvefi/curve-dao-contracts — had 222 Python files and 385 detected Brownie patterns, resulting in 5,687 individual transforms applied. ape compile passed on all Vyper contracts (versions 0.2.4 through 0.3.7).

Note: Repos marked see note have Solidity contracts that import @chainlink or @openzeppelin packages. Run ape pm install before expecting ape compile to succeed; that is unrelated to Python migration correctness.

Differentiators

  • Runtime validation is built in: ApeShift records ape compile and ape test results when Ape is available.
  • Each migration produces a confidence score report under apeshift-report/.
  • Zero false positives are enforced by only rewriting deterministic patterns and leaving ambiguous cases as TODO(apeshift) manual-review notes.
  • ApeWorX docs PR content is included under docs/userguides/brownie-migration.md.

What ApeShift migrates

  1. Brownie imports to Ape imports / project access
  2. Multiline Brownie imports
  3. Contract class use to project.ContractName
  4. accounts[n] in scripts to accounts.test_accounts[n]
  5. accounts[n] in Ape pytest fixture contexts preserved
  6. accounts.add(...) flagged with TODO(apeshift) because Ape live accounts must be imported and loaded by alias
  7. network.show_active() to networks.provider.network.name
  8. Contract.deploy(..., {"from": acct}) to project.Contract.deploy(..., sender=acct)
  9. Transaction sender dictionaries to sender=
  10. Transaction value/gas dictionaries to explicit Ape kwargs
  11. brownie.reverts and bare reverts imports to Ape
  12. VirtualMachineError to ContractLogicError
  13. Exact web3.eth legacy accessors to Ape provider/network/chain APIs
  14. Brownie config to Ape config skeleton

Why this exists

Brownie is no longer actively maintained, and the Brownie README points users toward Ape Framework. ApeShift targets the remaining migration edge cases and produces documentation content for ApeWorX/ape issue #640.

What is left to AI

  1. web3.eth.contract(...)
    • Prompt: "Inspect the ABI/address source and replace this with ape.Contract(address, contract_type=...) or a typed project.ContractName.at(address) call."
  2. accounts.add(...) live-account migration
    • Prompt: "Choose the account alias for this project, run ape accounts import <alias>, and replace accounts.add(...) with accounts.load(<alias>)."
  3. Complex event filters
    • Prompt: "Identify the emitting contract and event class, then replace positional event access with tx.events.filter(Contract.EventName)[index].field."
  4. from brownie.network import priority_fee
    • Prompt: "Move fee configuration to provider/network settings or explicit Ape transaction kwargs after confirming the target network fee strategy."

Zero false positive strategy

ApeShift only rewrites deterministic Brownie patterns with clear Ape equivalents. Ambiguous cases are left in place with TODO(apeshift) comments so humans (or downstream AI agents) can resolve them without risking an unsafe rewrite.

Validation and reports

After migration, ApeShift checks for the ape CLI on PATH. If Ape is available, it runs:

bash

If Ape is missing, validation is skipped gracefully and the report records the reason. Reports are generated under apeshift-report/ as Markdown and JSON.

Known Limitations

Chainlink Dependency Layout (affects chainlink-mix, brownie-nft-course, brownie-fund-me)

Why compile fails:
Brownie resolved Chainlink contracts via GitHub-sourced packages with non-standard paths like:

text

Ape's solc resolver uses a different import resolution strategy and does not accept this folder layout out of the box. The Solidity compiler throws:

text

This is NOT a Python migration failure — all 109 Python patterns in chainlink-mix and 68 in brownie-nft-course were migrated correctly with zero false positives. The failure is purely at the Solidity dependency resolution layer.

Fix (AI handoff prompt):

Vendor the required Chainlink contracts directly into contracts/_vendor_chainlink/.
Then update ape-config.yaml with:

yaml

Copy these files from smartcontractkit/chainlink at the matching tag:

  • interfaces/AggregatorV3Interface.sol
  • interfaces/AggregatorV2V3Interface.sol
  • vendor/SafeMathChainlink.sol
  • src/v0.4/ERC677Token.sol (for LinkToken repos)

Then run ape compile to verify.

Proof this is not a migration bug:
brownie_fund_me had the same Chainlink layout issue and was fixed by vendoring 4 contracts. After vendoring, ape compile PASSED and ape test returned 2/2 PASS — confirming the Python migration was correct all along.

tx.events["EventName"] (token-mix, 3 tests)

Why tests fail:
Brownie exposes tx.events as a dict keyed by event name. Ape exposes tx.events as a list of ContractLog objects.

python

AI handoff prompt:

Replace tx.events['EventName'] with:

python

Then access fields directly by name: event.owner, event.spender, event.value.

tx.return_value (token-mix, 2 tests)

Why tests fail:
Brownie automatically extracts return values from state-changing transactions via its tracer. Ape does not expose return_value for non-view calls — receipt.return_value is always None.

AI handoff prompt:

Replace:

python

With:

python

Other notes

  • fn_isolation and other project-specific pytest fixtures may require manual Ape fixture migration.
  • Private key / account alias migration requires user-controlled ape accounts import.

Links

Credit

ApeShift is a standalone migration workflow, but it credits the earlier brownie-to-ape codemod as prior ecosystem work. ApeShift does not depend on brownie-to-ape at runtime.

Ready to contribute?

Build your own codemod and share it with the community.