Skip to content

Commit

Permalink
test: add test
Browse files Browse the repository at this point in the history
  • Loading branch information
antazoey committed Jan 30, 2025
1 parent a3ea57a commit 1d391c8
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 25 deletions.
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,35 @@ Ape-Vyper supports Vyper 0.3.10's [new pragma formats](https://github.com/vyperl
```python
#pragma optimize codesize
```

### VVM CLI

You can install versions of Vyper using the `ape vyper vvm` CLI tools.
List installed versions using:

```shell
ape vyper vvm list
```

Install more versions using the command:

```shell
ape vyper vvm install 0.3.7 0.3.10
```

### Custom Output Format

To customize Vyper's output format (like the native `-f` flag), you can configure the output format:
For example, to only get the ABI, do:

```shell
vyper:
output_format:
- abi
```

To do this using the CLI only (adhoc), use the following command:

```shell
ape compile --config-override '{"vyper": {"output_format": ["abi"]}}'
```
48 changes: 35 additions & 13 deletions ape_vyper/compiler/_versions/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,13 +124,25 @@ def compile(
content = Content.model_validate(src_dict[source_id].get("content", ""))
for name, output in output_items.items():
# De-compress source map to get PC POS map.
ast = self._parse_ast(result["sources"][source_id]["ast"], content)
evm = output["evm"]
bytecode = evm["deployedBytecode"]
opcodes = bytecode["opcodes"].split(" ")
compressed_src_map = SourceMap(root=bytecode["sourceMap"])
src_map = list(compressed_src_map.parse())[1:]
pcmap = self._get_pcmap(vyper_version, ast, src_map, opcodes, bytecode)
if "ast" in result["sources"][source_id]:
ast = self._parse_ast(result["sources"][source_id]["ast"], content)
else:
ast = None

evm = output.get("evm", {})
runtime_bytecode = evm.get("deployedBytecode", {})
opcodes = runtime_bytecode.get("opcodes", "").split(" ")

if "sourceMap" in runtime_bytecode:
compressed_src_map = SourceMap(root=runtime_bytecode["sourceMap"])
src_map = list(compressed_src_map.parse())[1:]
pcmap = self._get_pcmap(
vyper_version, ast, src_map, opcodes, runtime_bytecode
)
else:
compressed_src_map = None
src_map = None
pcmap = None

# Find content-specified dev messages.
dev_messages = {}
Expand All @@ -144,18 +156,23 @@ def compile(
else:
final_source_id = source_id

deployment_bytecode = evm.get("bytecode", {}).get("object")
contract_type = ContractType.model_validate(
{
"ast": ast,
"contractName": name,
"sourceId": final_source_id,
"deploymentBytecode": {"bytecode": evm["bytecode"]["object"]},
"runtimeBytecode": {"bytecode": bytecode["object"]},
"abi": output["abi"],
"deploymentBytecode": (
{"bytecode": deployment_bytecode} if deployment_bytecode else {}
),
"runtimeBytecode": (
{"bytecode": runtime_bytecode["object"]} if runtime_bytecode else {}
),
"abi": output.get("abi"),
"sourcemap": compressed_src_map,
"pcmap": pcmap,
"userdoc": output["userdoc"],
"devdoc": output["devdoc"],
"userdoc": output.get("userdoc"),
"devdoc": output.get("devdoc"),
"dev_messages": dev_messages,
}
)
Expand Down Expand Up @@ -255,7 +272,12 @@ def _get_selection_dictionary(
# Interfaces cannot be in the sources dict for those versions
# (whereas in Vyper0.4, they must).
pm = project or self.local_project
return {s: ["*"] for s in selection if (pm.path / s).is_file() if "interfaces" not in s}
return {
s: self.output_format
for s in selection
if (pm.path / s).is_file()
if "interfaces" not in s
}

def _get_pcmap(
self,
Expand Down
45 changes: 33 additions & 12 deletions ape_vyper/compiler/_versions/vyper_04.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,13 +154,22 @@ def compile(

for source_id, output_items in result.items():
content = Content(root=src_dict[source_id].read_text(encoding="utf-8"))
# De-compress source map to get PC POS map.
ast_dict = json.loads(output_items["ast"])["ast"]
ast = self._parse_ast(ast_dict, content)
bytecode = output_items["bytecode_runtime"]

source_map = json.loads(output_items["source_map"])
pcmap = PCMap.model_validate(source_map["pc_pos_map"])
if "ast" in output_items:
# De-compress source map to get PC POS map.
ast_dict = json.loads(output_items["ast"])["ast"]
ast = self._parse_ast(ast_dict, content)
else:
ast = None

bytecode = output_items.get("bytecode_runtime")

if "source_map" in output_items:
source_map = json.loads(output_items["source_map"])
pcmap = PCMap.model_validate(source_map["pc_pos_map"])
else:
source_map = None
pcmap = None

# Find content-specified dev messages.
dev_messages = map_dev_messages(content.root)
Expand All @@ -176,13 +185,25 @@ def compile(
"ast": ast,
"contractName": f"{Path(final_source_id).stem}",
"sourceId": final_source_id,
"deploymentBytecode": {"bytecode": output_items["bytecode"]},
"runtimeBytecode": {"bytecode": bytecode},
"abi": json.loads(output_items["abi"]),
"sourcemap": output_items["source_map"],
"deploymentBytecode": (
{"bytecode": output_items["bytecode"]}
if "bytecode" in output_items
else {}
),
"runtimeBytecode": {"bytecode": bytecode} if bytecode else {},
"abi": json.loads(output_items["abi"]) if "abi" in output_items else None,
"sourcemap": (
output_items["source_map"] if "source_map" in output_items else None
),
"pcmap": pcmap,
"userdoc": json.loads(output_items["userdoc"]),
"devdoc": json.loads(output_items["devdoc"]),
"userdoc": (
json.loads(output_items["userdoc"])
if "userdoc" in output_items
else None
),
"devdoc": (
json.loads(output_items["devdoc"]) if "devdoc" in output_items else None
),
"dev_messages": dev_messages,
}
)
Expand Down
13 changes: 13 additions & 0 deletions tests/functional/test_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -833,3 +833,16 @@ def test_get_compiler_settings(project, compiler):
"tests/contracts/passing_contracts/zero_four.vy": ["*"]
}
assert vyper4_settings[v4_version_used]["gas%shanghai"]["evmVersion"] == "shanghai"


def test_compile_configured_output_format(project, compiler):
paths = [
project.contracts_folder / "zero_four.vy",
project.contracts_folder / "non_payable_default.vy",
]
with project.temp_config(vyper={"output_format": ["abi"]}):
result = list(compiler.compile(paths))
assert len(result) == 2
for contract_type in result:
assert contract_type.abi is not None
assert contract_type.runtime_bytecode.bytecode is None

0 comments on commit 1d391c8

Please sign in to comment.