diff --git a/brownie/project/compiler/utils.py b/brownie/project/compiler/utils.py index 7c0627094..98c947252 100644 --- a/brownie/project/compiler/utils.py +++ b/brownie/project/compiler/utils.py @@ -8,6 +8,13 @@ def expand_source_map(source_map_str: str) -> List: # Expands the compressed sourceMap supplied by solc into a list of lists + + if isinstance(source_map_str, dict): + # NOTE: vyper >= 0.4 gives us a dict that contains the source map + source_map_str = source_map_str["pc_pos_map_compressed"] + if not isinstance(source_map_str, str): + raise TypeError(source_map_str) + source_map: List = [_expand_row(i) if i else None for i in source_map_str.split(";")] for i, value in enumerate(source_map[1:], 1): if value is None: diff --git a/brownie/project/compiler/vyper.py b/brownie/project/compiler/vyper.py index 1dafedfe2..acd754904 100644 --- a/brownie/project/compiler/vyper.py +++ b/brownie/project/compiler/vyper.py @@ -7,6 +7,7 @@ import vvm import vyper +from packaging.version import Version as PVersion from requests.exceptions import ConnectionError from semantic_version import Version from vyper.cli import vyper_json @@ -46,11 +47,14 @@ def set_vyper_version(version: Union[str, Version]) -> str: if isinstance(version, str): version = Version(version) if version != Version(vyper.__version__): + # NOTE: vvm uses `packaging.version.Version` which is not compatible with + # `semantic_version.Version` so we first must cast it as a string + version_str = str(version) try: - vvm.set_vyper_version(version, silent=True) + vvm.set_vyper_version(version_str, silent=True) except vvm.exceptions.VyperNotInstalled: install_vyper(version) - vvm.set_vyper_version(version, silent=True) + vvm.set_vyper_version(version_str, silent=True) _active_version = version return str(_active_version) @@ -82,13 +86,13 @@ def get_abi(contract_source: str, name: str) -> Dict: def _get_vyper_version_list() -> Tuple[List, List]: global AVAILABLE_VYPER_VERSIONS - installed_versions = vvm.get_installed_vyper_versions() + installed_versions = _convert_to_semver(vvm.get_installed_vyper_versions()) lib_version = Version(vyper.__version__) if lib_version not in installed_versions: installed_versions.append(lib_version) if AVAILABLE_VYPER_VERSIONS is None: try: - AVAILABLE_VYPER_VERSIONS = vvm.get_installable_vyper_versions() + AVAILABLE_VYPER_VERSIONS = _convert_to_semver(vvm.get_installable_vyper_versions()) except ConnectionError: if not installed_versions: raise ConnectionError("Vyper not installed and cannot connect to GitHub") @@ -237,11 +241,14 @@ def compile_from_input_json( outputs.remove("devdoc") if version == Version(vyper.__version__): try: - return vyper_json.compile_json(input_json, root_path=allow_paths) + return vyper_json.compile_json(input_json) except VyperException as exc: raise exc.with_traceback(None) else: try: + # NOTE: vvm uses `packaging.version.Version` which is not compatible with + # `semantic_version.Version` so we first must cast it as a string + version = str(version) return vvm.compile_standard(input_json, base_path=allow_paths, vyper_version=version) except vvm.exceptions.VyperError as exc: raise CompilerError(exc, "vyper") @@ -397,7 +404,7 @@ def _generate_coverage_data( if node["ast_type"] in ("Assert", "If") or ( node["ast_type"] == "Expr" - and node["value"]["func"].get("id", None) == "assert_modifiable" + and node["value"].get("func", {}).get("id", None) == "assert_modifiable" ): # branch coverage pc_list[-1]["branch"] = count @@ -449,3 +456,24 @@ def _get_statement_nodes(ast_json: List) -> List: else: stmt_nodes.append(node) return stmt_nodes + + +def _convert_to_semver(versions: List[PVersion]) -> List[Version]: + """ + Converts a list of `packaging.version.Version` objects to a list of + `semantic_version.Version` objects. + + vvm 0.2.0 switched to packaging.version but we are not ready to + migrate brownie off of semantic-version. + + This function serves as a stopgap. + """ + return [ + Version( + major=version.major, + minor=version.minor, + patch=version.micro, + prerelease="".join(str(x) for x in version.pre) if version.pre else None, + ) + for version in versions + ] diff --git a/requirements.in b/requirements.in index 56d07b964..405ae2cd6 100644 --- a/requirements.in +++ b/requirements.in @@ -23,7 +23,7 @@ requests>=2.25.0,<3 rlp semantic-version<3 tqdm<5 -vvm==0.1.0 # 0.2.0 switches from semantic-version to packaging.version and things break -vyper>=0.3.8,<0.4 +vvm==0.2.1 +vyper>=0.4.0,<0.5 web3>=6,<7 wrapt>=1.12.1,<2 diff --git a/requirements.txt b/requirements.txt index 9758d4e63..410e36a15 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ # -# This file is autogenerated by pip-compile with Python 3.11 +# This file is autogenerated by pip-compile with Python 3.10 # by the following command: # # pip-compile requirements.in @@ -10,6 +10,8 @@ aiosignal==1.3.1 # via aiohttp asttokens==2.4.1 # via vyper +async-timeout==4.0.3 + # via aiohttp attrs==23.2.0 # via # aiohttp @@ -125,6 +127,7 @@ packaging==23.2 # via # black # pytest + # vvm # vyper parsimonious==0.9.0 # via eth-abi @@ -200,7 +203,6 @@ semantic-version==2.10.0 # via # -r requirements.in # py-solc-x - # vvm six==1.16.0 # via # asttokens @@ -209,20 +211,23 @@ sortedcontainers==2.4.0 # via hypothesis toml==0.10.2 # via pytest +tomli==2.0.1 + # via black toolz==0.12.1 # via cytoolz tqdm==4.66.2 # via -r requirements.in typing-extensions==4.9.0 # via + # black # eth-rlp # eth-typing # web3 urllib3==2.2.1 # via requests -vvm==0.1.0 +vvm==0.2.1 # via -r requirements.in -vyper==0.3.10 +vyper==0.4.0 # via -r requirements.in wcwidth==0.2.13 # via prompt-toolkit