Skip to content

Commit

Permalink
feat: arg err improve (#1527)
Browse files Browse the repository at this point in the history
  • Loading branch information
antazoey authored Jul 6, 2023
1 parent 8ea34e5 commit 2490f02
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 11 deletions.
4 changes: 2 additions & 2 deletions src/ape/contracts/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ def _select_method_abi(abis: List[MethodABI], args: Union[Tuple, List]) -> Metho
selected_abi = abi

if not selected_abi:
raise ArgumentsLengthError(len(args))
raise ArgumentsLengthError(len(args), inputs=abis)

return selected_abi

Expand Down Expand Up @@ -1276,7 +1276,7 @@ def __call__(self, *args, **kwargs) -> TransactionAPI:
else 0
)
if inputs_length != args_length:
raise ArgumentsLengthError(args_length, inputs_length=inputs_length)
raise ArgumentsLengthError(args_length, inputs=self.constructor.abi)

return self.constructor.serialize_transaction(*args, **kwargs)

Expand Down
45 changes: 38 additions & 7 deletions src/ape/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import click
from eth_utils import humanize_hash
from ethpm_types import ContractType
from ethpm_types.abi import ErrorABI
from ethpm_types.abi import ConstructorABI, ErrorABI, MethodABI
from rich import print as rich_print

from ape.logging import LogLevel, logger
Expand Down Expand Up @@ -73,14 +73,45 @@ class ArgumentsLengthError(ContractError):
Raised when calling a contract method with the wrong number of arguments.
"""

def __init__(self, arguments_length: int, inputs_length: Optional[int] = None):
abi_suffix = f" ({inputs_length})" if inputs_length else ""
message = (
def __init__(
self,
arguments_length: int,
inputs: Union[MethodABI, ConstructorABI, int, List, None] = None,
**kwargs,
):
# For backwards compat. # TODO: Remove in 0.7
if "inputs_length" in kwargs and not inputs:
inputs = kwargs["inputs_length"]

prefix = (
f"The number of the given arguments ({arguments_length}) "
f"do not match what is defined in the "
f"ABI{abi_suffix}."
f"do not match what is defined in the ABI"
)
super().__init__(message)
if inputs is None:
super().__init__(f"{prefix}.")
return

inputs_ls: List[Union[MethodABI, ConstructorABI, int]] = (
inputs if isinstance(inputs, list) else [inputs]
)
if not inputs_ls:
suffix = ""
elif any(not isinstance(x, int) for x in inputs_ls):
# Handle ABI arguments
parts = ""
for idx, ipt in enumerate(inputs_ls):
part = f"{ipt}" if isinstance(ipt, int) else ipt.selector
parts = f"{parts}\n\t{click.style(part, italic=True)}"

suffix = f":\n{parts}"

else:
# Was only given integers.
options = ", ".join([str(x) for x in inputs_ls])
one_of = "one of " if len(inputs_ls) > 1 else ""
suffix = f" ({one_of}{options})"

super().__init__(f"{prefix}{suffix}")


class DecodingError(ContractError):
Expand Down
13 changes: 12 additions & 1 deletion tests/functional/test_contract_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from ape import Contract
from ape.contracts import ContractInstance
from ape.exceptions import NetworkError, ProjectError
from ape.exceptions import ArgumentsLengthError, NetworkError, ProjectError
from ape_ethereum.ecosystem import ProxyType


Expand All @@ -20,6 +20,17 @@ def test_deploy(
assert contract_from_cache.txn_hash == contract.txn_hash


def test_deploy_wrong_number_of_arguments(
sender, contract_container, networks_connected_to_tester, project, chain, clean_contracts_cache
):
expected = (
r"The number of the given arguments \(0\) do not match what is defined in the "
r"ABI:\n\n\t.*constructor\(uint256\).*"
)
with pytest.raises(ArgumentsLengthError, match=expected):
contract_container.deploy(sender=sender)


def test_deploy_and_publish_local_network(owner, contract_container):
with pytest.raises(ProjectError, match="Can only publish deployments on a live network"):
contract_container.deploy(0, sender=owner, publish=True)
Expand Down
18 changes: 17 additions & 1 deletion tests/functional/test_contract_instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from ape.contracts import ContractInstance
from ape.exceptions import (
APINotImplementedError,
ArgumentsLengthError,
ChainError,
ContractError,
ContractLogicError,
Expand Down Expand Up @@ -55,11 +56,26 @@ def test_eq(vyper_contract_instance, chain):
assert other == vyper_contract_instance


def test_contract_calls(owner, contract_instance):
def test_contract_transactions(owner, contract_instance):
contract_instance.setNumber(2, sender=owner)
assert contract_instance.myNumber() == 2


def test_wrong_number_of_arguments(owner, contract_instance):
if "sol" in contract_instance.contract_type.source_id.lower():
second = r"\n\t.*setNumber\(uint256,address\).*"
else:
second = ""

expected = (
r"The number of the given arguments \(4\) do not match what is defined in the ABI:\n"
r"\n\t.*setNumber\(uint256\).*"
f"{second}"
)
with pytest.raises(ArgumentsLengthError, match=expected):
contract_instance.setNumber(2, 3, 5, 6, sender=owner)


@pytest.mark.parametrize("type_param", (0, "0", HexBytes(0)))
def test_static_fee_txn(owner, vyper_contract_instance, type_param):
receipt = vyper_contract_instance.setNumber(4, sender=owner, type=type_param)
Expand Down

0 comments on commit 2490f02

Please sign in to comment.