Skip to content

Commit

Permalink
perf: console perfs
Browse files Browse the repository at this point in the history
  • Loading branch information
antazoey committed Nov 7, 2024
1 parent 4c95af2 commit afbcaae
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 77 deletions.
83 changes: 16 additions & 67 deletions src/ape/cli/choices.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,9 @@
from typing import TYPE_CHECKING, Any, Optional, Union

import click
from click import BadParameter, Choice, Context, Parameter
from click import Choice, Context, Parameter

from ape.exceptions import (
AccountsError,
EcosystemNotFoundError,
NetworkNotFoundError,
ProviderNotFoundError,
)
from ape.exceptions import AccountsError

if TYPE_CHECKING:
from ape.api.accounts import AccountAPI
Expand Down Expand Up @@ -360,7 +355,7 @@ def __init__(
ecosystem: _NETWORK_FILTER = None,
network: _NETWORK_FILTER = None,
provider: _NETWORK_FILTER = None,
base_type: Optional[type] = None,
base_type: Optional[Union[type, str]] = None,
callback: Optional[Callable] = None,
):
self._base_type = base_type
Expand All @@ -372,15 +367,14 @@ def __init__(
# NOTE: Purposely avoid super().init for performance reasons.

@property
def base_type(self) -> type["ProviderAPI"]:
def base_type(self) -> Union[type["ProviderAPI"], str]:
if self._base_type is not None:
return self._base_type

# perf: property exists to delay import ProviderAPI at init time.
from ape.api.providers import ProviderAPI

self._base_type = ProviderAPI
return ProviderAPI
# perf: Keep base-type as a forward-ref when only using the default.
# so things load faster.
self._base_type = "ProviderAPI"
return self._base_type

@base_type.setter
def base_type(self, value):
Expand All @@ -394,62 +388,17 @@ def get_metavar(self, param):
return "[ecosystem-name][:[network-name][:[provider-name]]]"

def convert(self, value: Any, param: Optional[Parameter], ctx: Optional[Context]) -> Any:
from ape.utils.basemodel import ManagerAccessMixin as access

choice: Optional[Union[str, "ProviderAPI"]]
networks = access.network_manager
if not value:
choice = None
if not value or value.lower() in ("none", "null"):
return self.callback(ctx, param, _NONE_NETWORK) if self.callback else _NONE_NETWORK

elif value.lower() in ("none", "null"):
choice = _NONE_NETWORK
if self.base_type == "ProviderAPI" or isinstance(self.base_type, type):
# Return the provider.
from ape.utils.basemodel import ManagerAccessMixin as access

elif self.is_custom_value(value):
# By-pass choice constraints when using custom network.
choice = value
networks = access.network_manager
value = networks.get_provider_from_choice(network_choice=value)

else:
# Regular conditions.
try:
# Validate result.
choice = super().convert(value, param, ctx)
except BadParameter:
# Attempt to get the provider anyway.
# Sometimes, depending on the provider, it'll still work.
# (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.
raise click.BadParameter(
"Invalid network choice. Use `ape networks list` to see options."
) from err

if choice not in (None, _NONE_NETWORK) and isinstance(choice, str):
from ape.api.providers import ProviderAPI

if issubclass(self.base_type, ProviderAPI):
# Return the provider.
choice = networks.get_provider_from_choice(network_choice=value)

return self.callback(ctx, param, choice) if self.callback else choice

@classmethod
def is_custom_value(cls, value) -> bool:
return (
value is not None
and isinstance(value, str)
and cls.CUSTOM_NETWORK_PATTERN.match(value) is not None
or str(value).startswith("http://")
or str(value).startswith("https://")
)
return self.callback(ctx, param, value) if self.callback else value


class OutputFormat(Enum):
Expand Down
17 changes: 9 additions & 8 deletions src/ape/managers/networks.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from evmchains import PUBLIC_CHAIN_META

from ape.api.networks import EcosystemAPI, NetworkAPI, ProviderContextManager
from ape.api.networks import ProviderContextManager
from ape.exceptions import EcosystemNotFoundError, NetworkError, NetworkNotFoundError
from ape.managers.base import BaseManager
from ape.utils.basemodel import (
Expand All @@ -17,6 +17,7 @@
from ape_ethereum.provider import EthereumNodeProvider

if TYPE_CHECKING:
from ape.api.networks import EcosystemAPI, NetworkAPI
from ape.api.providers import ProviderAPI
from ape.utils.rpc import RPCHeaders

Expand Down Expand Up @@ -62,7 +63,7 @@ def active_provider(self, new_value: "ProviderAPI"):
self._active_provider = new_value

@property
def network(self) -> NetworkAPI:
def network(self) -> "NetworkAPI":
"""
The current network if connected to one.
Expand All @@ -76,7 +77,7 @@ def network(self) -> NetworkAPI:
return self.provider.network

@property
def ecosystem(self) -> EcosystemAPI:
def ecosystem(self) -> "EcosystemAPI":
"""
The current ecosystem if connected to one.
Expand Down Expand Up @@ -203,7 +204,7 @@ def custom_networks(self) -> list[dict]:
]

@property
def ecosystems(self) -> dict[str, EcosystemAPI]:
def ecosystems(self) -> dict[str, "EcosystemAPI"]:
"""
All the registered ecosystems in ``ape``, such as ``ethereum``.
"""
Expand Down Expand Up @@ -244,7 +245,7 @@ def ecosystems(self) -> dict[str, EcosystemAPI]:
return plugin_ecosystems

@cached_property
def _plugin_ecosystems(self) -> dict[str, EcosystemAPI]:
def _plugin_ecosystems(self) -> dict[str, "EcosystemAPI"]:
# Load plugins.
plugins = self.plugin_manager.ecosystems
return {n: cls(name=n) for n, cls in plugins} # type: ignore[operator]
Expand Down Expand Up @@ -323,7 +324,7 @@ def __ape_extra_attributes__(self) -> Iterator[ExtraModelAttributes]:
)

@only_raise_attribute_error
def __getattr__(self, attr_name: str) -> EcosystemAPI:
def __getattr__(self, attr_name: str) -> "EcosystemAPI":
"""
Get an ecosystem via ``.`` access.
Expand Down Expand Up @@ -424,7 +425,7 @@ def get_network_choices(
if ecosystem_has_providers:
yield ecosystem_name

def get_ecosystem(self, ecosystem_name: str) -> EcosystemAPI:
def get_ecosystem(self, ecosystem_name: str) -> "EcosystemAPI":
"""
Get the ecosystem for the given name.
Expand Down Expand Up @@ -585,7 +586,7 @@ def default_ecosystem_name(self) -> str:
return self.config_manager.default_ecosystem or "ethereum"

@property
def default_ecosystem(self) -> EcosystemAPI:
def default_ecosystem(self) -> "EcosystemAPI":
"""
The default ecosystem. Call
:meth:`~ape.managers.networks.NetworkManager.set_default_ecosystem` to
Expand Down
4 changes: 2 additions & 2 deletions src/ape_console/_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,10 @@ def __setitem__(self, key, value):
# Override to set items directly into the dictionary
super().__setitem__(key, value)

def __contains__(self, item: str):
def __contains__(self, item: str) -> bool: # type: ignore
return self.get(item) is not None

def update(self, mapping, **kwargs) -> None:
def update(self, mapping, **kwargs) -> None: # type: ignore
# Override to update the dictionary directly
super().update(mapping, **kwargs)

Expand Down

0 comments on commit afbcaae

Please sign in to comment.