Skip to content
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

fix: ir and metadata outputs for vyper-json #2600

Merged
merged 4 commits into from Jan 12, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion tests/cli/vyper_json/test_compile_from_input_dict.py
Expand Up @@ -121,7 +121,7 @@ def test_source_ids_increment():
def test_outputs():
result, _ = compile_from_input_dict(INPUT_JSON)
assert sorted(result.keys()) == ["contracts/bar.vy", "contracts/foo.vy"]
assert sorted(result["contracts/bar.vy"].keys()) == sorted(TRANSLATE_MAP.values())
assert sorted(result["contracts/bar.vy"].keys()) == sorted(set(TRANSLATE_MAP.values()))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there duplicates in TRANSLATE_MAP?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there duplicates in TRANSLATE_MAP?

yes - I made ir and ir_json both map to ir_json (it doesn't really make sense to get regular ir output for vyper-json when a json version is available).



def test_relative_import_paths():
Expand Down
3 changes: 2 additions & 1 deletion tests/cli/vyper_json/test_output_dict.py
Expand Up @@ -22,8 +22,9 @@ def test_keys():
"abi": data["abi"],
"devdoc": data["devdoc"],
"interface": data["interface"],
"ir": data["ir"],
"ir": data["ir_dict"],
"userdoc": data["userdoc"],
"metadata": data["metadata"],
"evm": {
"bytecode": {"object": data["bytecode"], "opcodes": data["opcodes"]},
"deployedBytecode": {
Expand Down
4 changes: 2 additions & 2 deletions tests/cli/vyper_json/test_output_selection.py
Expand Up @@ -35,7 +35,7 @@ def test_translate_map(output):
def test_star():
input_json = {"settings": {"outputSelection": {"*": ["*"]}}}
sources = {"foo.vy": "", "bar.vy": ""}
expected = sorted(TRANSLATE_MAP.values())
expected = sorted(set(TRANSLATE_MAP.values()))
result = get_input_dict_output_formats(input_json, sources)
assert result == {"foo.vy": expected, "bar.vy": expected}

Expand All @@ -51,4 +51,4 @@ def test_evm():
def test_solc_style():
input_json = {"settings": {"outputSelection": {"foo.vy": {"": ["abi"], "foo.vy": ["ir"]}}}}
sources = {"foo.vy": ""}
assert get_input_dict_output_formats(input_json, sources) == {"foo.vy": ["abi", "ir"]}
assert get_input_dict_output_formats(input_json, sources) == {"foo.vy": ["abi", "ir_dict"]}
12 changes: 9 additions & 3 deletions tests/cli/vyper_json/test_parse_args_vyperjson.py
Expand Up @@ -44,14 +44,20 @@ def bar(a: uint256) -> bool:
}


def _no_errors(output_json):
return "errors" not in output_json or not any(
err["severity"] == "error" for err in output_json["errors"]
)


def test_to_stdout(tmp_path, capfd):
path = tmp_path.joinpath("input.json")
with path.open("w") as fp:
json.dump(INPUT_JSON, fp)
_parse_args([path.absolute().as_posix()])
out, _ = capfd.readouterr()
output_json = json.loads(out)
assert "errors" not in output_json
assert _no_errors(output_json)
assert "contracts/foo.vy" in output_json["sources"]
assert "contracts/bar.vy" in output_json["sources"]

Expand All @@ -65,7 +71,7 @@ def test_to_file(tmp_path):
assert output_path.exists()
with output_path.open() as fp:
output_json = json.load(fp)
assert "errors" not in output_json
assert _no_errors(output_json)
assert "contracts/foo.vy" in output_json["sources"]
assert "contracts/bar.vy" in output_json["sources"]

Expand All @@ -91,6 +97,6 @@ def test_traceback(tmp_path, capfd):
_parse_args([path.absolute().as_posix()])
out, _ = capfd.readouterr()
output_json = json.loads(out)
assert "errors" in output_json
assert not _no_errors(output_json)
with pytest.raises(JSONError):
_parse_args([path.absolute().as_posix(), "--traceback"])
19 changes: 13 additions & 6 deletions vyper/cli/vyper_json.py
Expand Up @@ -25,7 +25,9 @@
"evm.deployedBytecode.opcodes": "opcodes_runtime",
"evm.deployedBytecode.sourceMap": "source_map",
"interface": "interface",
"ir": "ir",
"ir": "ir_dict",
"ir_json": "ir_dict",
# "metadata": "metadata", # don't include in "*" output for now
"layout": "layout",
"userdoc": "userdoc",
}
Expand Down Expand Up @@ -212,13 +214,15 @@ def get_input_dict_output_formats(input_dict: Dict, contract_sources: ContractCo
outputs.remove(key)
outputs.update([i for i in TRANSLATE_MAP if i.startswith(key)])
if "*" in outputs:
outputs = sorted(TRANSLATE_MAP.values())
outputs = TRANSLATE_MAP.values()
else:
try:
outputs = sorted(TRANSLATE_MAP[i] for i in outputs)
outputs = [TRANSLATE_MAP[i] for i in outputs]
except KeyError as e:
raise JSONError(f"Invalid outputSelection - {e}")

outputs = sorted(set(outputs))

if path == "*":
output_keys = list(contract_sources.keys())
else:
Expand Down Expand Up @@ -349,22 +353,25 @@ def format_to_output_dict(compiler_data: Dict) -> Dict:
output_dict["contracts"][path] = {name: {}}
output_contracts = output_dict["contracts"][path][name]

for key in ("abi", "devdoc", "interface", "ir", "userdoc"):
if "ir_dict" in data:
output_contracts["ir"] = data["ir_dict"]

for key in ("abi", "devdoc", "interface", "metadata", "userdoc"):
if key in data:
output_contracts[key] = data[key]

if "method_identifiers" in data:
output_contracts["evm"] = {"methodIdentifiers": data["method_identifiers"]}

evm_keys = ("bytecode", "opcodes")
if next((i for i in evm_keys if i in data), False):
if any(i in data for i in evm_keys):
evm = output_contracts.setdefault("evm", {}).setdefault("bytecode", {})
if "bytecode" in data:
evm["object"] = data["bytecode"]
if "opcodes" in data:
evm["opcodes"] = data["opcodes"]

if next((i for i in evm_keys if i + "_runtime" in data), False) or "source_map" in data:
if any(i + "_runtime" in data for i in evm_keys) or "source_map" in data:
evm = output_contracts.setdefault("evm", {}).setdefault("deployedBytecode", {})
if "bytecode_runtime" in data:
evm["object"] = data["bytecode_runtime"]
Expand Down
8 changes: 7 additions & 1 deletion vyper/compiler/__init__.py
Expand Up @@ -111,7 +111,13 @@ def compile_codes(
interfaces = interfaces[contract_name]

compiler_data = CompilerData(
source_code, contract_name, interfaces, source_id, no_optimize, storage_layout_override, show_gas_estimates
source_code,
contract_name,
interfaces,
source_id,
no_optimize,
storage_layout_override,
show_gas_estimates,
)
for output_format in output_formats[contract_name]:
if output_format not in OUTPUT_FORMATS:
Expand Down