Skip to content

Commit

Permalink
feat: show nicer errors during bad network choices (ApeWorX#2234)
Browse files Browse the repository at this point in the history
  • Loading branch information
antazoey authored Aug 22, 2024
1 parent 33b2fb5 commit 6d9a0a3
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 45 deletions.
13 changes: 12 additions & 1 deletion src/ape/cli/choices.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@

from ape.api.accounts import AccountAPI
from ape.api.providers import ProviderAPI
from ape.exceptions import AccountsError
from ape.exceptions import (
AccountsError,
EcosystemNotFoundError,
NetworkNotFoundError,
ProviderNotFoundError,
)
from ape.types import _LazySequence
from ape.utils.basemodel import ManagerAccessMixin

Expand Down Expand Up @@ -369,6 +374,12 @@ def convert(self, value: Any, param: Optional[Parameter], ctx: Optional[Context]
# (as-is the case for custom-forked networks).
try:
choice = networks.get_provider_from_choice(network_choice=value)

except (EcosystemNotFoundError, NetworkNotFoundError, ProviderNotFoundError) as err:
# This error makes more sense, as it has attempted parsing.
# Show this message as the BadParameter message.
raise click.BadParameter(str(err)) from err

except Exception as err:
# If an error was not raised for some reason, raise a simpler error.
# NOTE: Still avoid showing the massive network options list.
Expand Down
2 changes: 1 addition & 1 deletion src/ape/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ def __init__(
if options:
close_matches = difflib.get_close_matches(provider, options, cutoff=0.6)
if close_matches:
message = f"{message} Did you mean '{', '.join(close_matches)}'?"
message = f"{message}. Did you mean '{', '.join(close_matches)}'?"
else:
# No close matches. Show all provider options.
options_str = "\n".join(sorted(options))
Expand Down
104 changes: 61 additions & 43 deletions tests/functional/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import click
import pytest
from click import BadParameter

from ape.cli import (
AccountAliasPromptChoice,
Expand Down Expand Up @@ -839,49 +840,66 @@ def test_parse_network_when_explicit_none(mocker):
assert network_ctx is None


def test_network_choice():
network_choice = NetworkChoice()
actual = network_choice.convert("ethereum:local:test", None, None)
assert actual.name == "test"
assert actual.network.name == "local"


@pytest.mark.parametrize("prefix", ("", "ethereum:custom:"))
def test_network_choice_custom_adhoc_network(prefix):
network_choice = NetworkChoice()
uri = "https://example.com"
actual = network_choice.convert(f"{prefix}{uri}", None, None)
assert actual.uri == uri
assert actual.network.name == "custom"


def test_network_choice_custom_config_network(custom_networks_config_dict, project):
data = copy.deepcopy(custom_networks_config_dict)

# Was a bug where couldn't have this name.
data["networks"]["custom"][0]["name"] = "custom"

_get_networks_sequence_from_cache.cache_clear()

network_choice = NetworkChoice()
with project.temp_config(**data):
actual = network_choice.convert("ethereum:custom", None, None)

assert actual.network.name == "custom"


def test_network_choice_when_custom_local_network():
network_choice = NetworkChoice()
uri = "https://example.com"
actual = network_choice.convert(f"ethereum:local:{uri}", None, None)
assert actual.uri == uri
assert actual.network.name == "local"


def test_network_choice_explicit_none():
network_choice = NetworkChoice()
actual = network_choice.convert("None", None, None)
assert actual == _NONE_NETWORK
class TestNetworkChoice:
@pytest.fixture
def network_choice(self):
return NetworkChoice()

def test_test(self, network_choice):
actual = network_choice.convert("ethereum:local:test", None, None)
assert actual.name == "test"
assert actual.network.name == "local"

@pytest.mark.parametrize("prefix", ("", "ethereum:custom:"))
def test_adhoc(self, network_choice, prefix):
uri = "https://example.com"
actual = network_choice.convert(f"{prefix}{uri}", None, None)
assert actual.uri == uri
assert actual.network.name == "custom"

def test_custom_config_network(self, custom_networks_config_dict, project, network_choice):
data = copy.deepcopy(custom_networks_config_dict)

# Was a bug where couldn't have this name.
data["networks"]["custom"][0]["name"] = "custom"

_get_networks_sequence_from_cache.cache_clear()

with project.temp_config(**data):
actual = network_choice.convert("ethereum:custom", None, None)

assert actual.network.name == "custom"

def test_custom_local_network(self, network_choice):
uri = "https://example.com"
actual = network_choice.convert(f"ethereum:local:{uri}", None, None)
assert actual.uri == uri
assert actual.network.name == "local"

def test_explicit_none(self, network_choice):
actual = network_choice.convert("None", None, None)
assert actual == _NONE_NETWORK

def test_bad_ecosystem(self, network_choice):
# NOTE: "ethereum" is spelled wrong.
expected = r"No ecosystem named 'etheruem'\. Did you mean 'ethereum'\?"
with pytest.raises(BadParameter, match=expected):
network_choice.convert("etheruem:local:test", None, None)

def test_bad_network(self, network_choice):
# NOTE: "local" is spelled wrong.
expected = r"No network in 'ethereum' named 'lokal'\. Did you mean 'local'\?"
with pytest.raises(BadParameter, match=expected):
network_choice.convert("ethereum:lokal:test", None, None)

def test_bad_provider(self, network_choice):
# NOTE: "test" is spelled wrong.
expected = (
r"No provider named 'teest' in network 'local' in "
r"ecosystem 'ethereum'\. Did you mean 'test'\?"
)
with pytest.raises(BadParameter, match=expected):
network_choice.convert("ethereum:local:teest", None, None)


def test_config_override_option(runner):
Expand Down

0 comments on commit 6d9a0a3

Please sign in to comment.