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

feat: output_format #21

Merged
merged 9 commits into from
Sep 12, 2024
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Update contact information in `CONTRIBUTING.md`
- Update dependencies. Minimum python version is now 3.8 ([#22](https://github.com/vyperlang/vvm/pull/22))
- Add `output_format` argument to `compile_source` and `compile_files` ([#21](https://github.com/vyperlang/vvm/pull/21))

## [0.1.0](https://github.com/vyperlang/vvm/tree/v0.1.0) - 2020-10-07
### Added
Expand Down
24 changes: 13 additions & 11 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,19 +43,19 @@ def pytest_collection(session):
vvm.install_vyper(version)


# auto-parametrize the all_versions fixture with all target vyper versions
# auto-parametrize the vyper_version fixture with all target vyper versions
def pytest_generate_tests(metafunc):
if "all_versions" in metafunc.fixturenames:
if "vyper_version" in metafunc.fixturenames:
versions = VERSIONS.copy()
for marker in metafunc.definition.iter_markers(name="min_vyper"):
versions = [i for i in versions if i >= Version(marker.args[0])]
for marker in metafunc.definition.iter_markers(name="max_vyper"):
versions = [i for i in versions if i <= Version(marker.args[0])]
metafunc.parametrize("all_versions", versions, indirect=True)
metafunc.parametrize("vyper_version", versions, indirect=True)


@pytest.fixture
def all_versions(request):
def vyper_version(request):
"""
Run a test against all vyper versions.
"""
Expand All @@ -65,11 +65,13 @@ def all_versions(request):


@pytest.fixture
def foo_source(all_versions):
visibility = "external" if all_versions >= Version("0.2.0") else "public"
interface = "IERC20" if all_versions >= Version("0.4.0a") else "ERC20"
import_path = "ethereum.ercs" if all_versions >= Version("0.4.0a") else "vyper.interfaces"
def foo_source(vyper_version):
visibility = "external" if vyper_version >= Version("0.2.0") else "public"
interface = "IERC20" if vyper_version >= Version("0.4.0a") else "ERC20"
import_path = "ethereum.ercs" if vyper_version >= Version("0.4.0a") else "vyper.interfaces"
pragma_version = "pragma version" if vyper_version >= Version("0.3.8") else "@version"
yield f"""
#{pragma_version} {vyper_version}
from {import_path} import {interface}

@{visibility}
Expand All @@ -79,16 +81,16 @@ def foo() -> int128:


@pytest.fixture
def foo_path(tmp_path_factory, foo_source, all_versions):
source = tmp_path_factory.getbasetemp().joinpath(f"Foo-{all_versions}.sol")
def foo_path(tmp_path_factory, foo_source, vyper_version):
source = tmp_path_factory.getbasetemp().joinpath(f"Foo-{vyper_version}.vy")
if not source.exists():
with source.open("w") as fp:
fp.write(foo_source)
return source


@pytest.fixture
def input_json(all_versions):
def input_json(vyper_version):
json = {
"language": "Vyper",
"sources": {},
Expand Down
22 changes: 18 additions & 4 deletions tests/test_compile_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
import vvm


def test_compile_source(foo_source, all_versions):
if Version("0.4.0b1") <= all_versions <= Version("0.4.0b5"):
def test_compile_source(foo_source, vyper_version):
if Version("0.4.0b1") <= vyper_version <= Version("0.4.0b5"):
pytest.skip("vyper 0.4.0b1 to 0.4.0b5 have a bug with combined_json")
output = vvm.compile_source(foo_source)
assert "<stdin>" in output


def test_compile_files(foo_path, all_versions):
if Version("0.4.0b1") <= all_versions <= Version("0.4.0b5"):
def test_compile_files(foo_path, vyper_version):
if Version("0.4.0b1") <= vyper_version <= Version("0.4.0b5"):
pytest.skip("vyper 0.4.0b1 to 0.4.0b5 have a bug with combined_json")
output = vvm.compile_files([foo_path])
assert foo_path.as_posix() in output
Expand All @@ -35,3 +35,17 @@ def foo() -> int128:
return 42
"""
vvm.compile_source(source, vyper_version=version_str)


def test_compile_metadata(foo_source, vyper_version):
if vyper_version <= Version("0.3.1"):
pytest.skip("metadata output not supported in vyper < 0.3.2")
output = vvm.compile_source(foo_source, output_format="metadata")
assert "function_info" in output


def test_compile_metadata_from_file(foo_path, vyper_version):
if vyper_version <= Version("0.3.1"):
pytest.skip("metadata output not supported in vyper < 0.3.2")
output = vvm.compile_files([foo_path], output_format="metadata")
assert "function_info" in output
6 changes: 3 additions & 3 deletions tests/test_install.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import vvm


def test_get_installed_vyper_versions(all_versions):
assert "exe" not in str(all_versions)
assert all_versions in vvm.install.get_installed_vyper_versions()
def test_get_installed_vyper_versions(vyper_version):
assert "exe" not in str(vyper_version)
assert vyper_version in vvm.install.get_installed_vyper_versions()
64 changes: 41 additions & 23 deletions vvm/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ def compile_source(
base_path: Union[Path, str] = None,
evm_version: str = None,
vyper_binary: Union[str, Path] = None,
vyper_version: Version = None,
) -> Dict:
vyper_version: Union[str, Version, None] = None,
output_format: str = None,
) -> Any:
"""
Compile a Vyper contract.

Expand All @@ -51,34 +52,42 @@ def compile_source(
vyper_version: Version, optional
`vyper` version to use. If not given, the currently active version is used.
Ignored if `vyper_binary` is also given.
output_format: str, optional
Output format of the compiler. See `vyper --help` for more information.

Returns
-------
Dict
Compiler output. The source file name is given as `<stdin>`.
Any
Compiler output (depends on `output_format`).
For JSON output the return type is a dictionary, otherwise it is a string.
"""
source_path = tempfile.mkstemp(suffix=".vy", prefix="vyper-", text=True)[1]
with open(source_path, "w") as fp:
fp.write(source)

compiler_data = _compile(
vyper_binary=vyper_binary,
vyper_version=vyper_version,
source_files=[source_path],
base_path=base_path,
evm_version=evm_version,
)
with tempfile.NamedTemporaryFile(suffix=".vy", prefix="vyper-") as source_file:
source_file.write(source.encode())
source_file.flush()

compiler_data = _compile(
vyper_binary=vyper_binary,
vyper_version=vyper_version,
source_files=[source_file.name],
base_path=base_path,
evm_version=evm_version,
output_format=output_format,
)

return {"<stdin>": list(compiler_data.values())[0]}
if output_format in ("combined_json", None):
return {"<stdin>": list(compiler_data.values())[0]}
return compiler_data


def compile_files(
source_files: Union[List, Path, str],
base_path: Union[Path, str] = None,
evm_version: str = None,
vyper_binary: Union[str, Path] = None,
vyper_version: Version = None,
) -> Dict:
vyper_version: Union[str, Version, None] = None,
output_format: str = None,
) -> Any:
"""
Compile one or more Vyper source files.

Expand All @@ -100,36 +109,45 @@ def compile_files(
vyper_version: Version, optional
`vyper` version to use. If not given, the currently active version is used.
Ignored if `vyper_binary` is also given.
output_format: str, optional
Output format of the compiler. See `vyper --help` for more information.

Returns
-------
Dict
Compiler output
Any
Compiler output (depends on `output_format`).
For JSON output the return type is a dictionary, otherwise it is a string.
"""
return _compile(
vyper_binary=vyper_binary,
vyper_version=vyper_version,
source_files=source_files,
base_path=base_path,
evm_version=evm_version,
output_format=output_format,
)


def _compile(
base_path: Union[str, Path, None],
vyper_binary: Union[str, Path, None],
vyper_version: Optional[Version],
vyper_version: Union[str, Version, None],
output_format: Optional[str],
**kwargs: Any,
) -> Dict:
) -> Any:

if vyper_binary is None:
vyper_binary = get_executable(vyper_version)
if output_format is None:
output_format = "combined_json"

stdoutdata, stderrdata, command, proc = wrapper.vyper_wrapper(
vyper_binary=vyper_binary, f="combined_json", p=base_path, **kwargs
vyper_binary=vyper_binary, f=output_format, p=base_path, **kwargs
)

return json.loads(stdoutdata)
if output_format in ("combined_json", "standard_json", "metadata"):
return json.loads(stdoutdata)
return stdoutdata


def compile_standard(
Expand Down
Loading