From 9d0b4e0f06901ab8350c1d8b0692a902693199b5 Mon Sep 17 00:00:00 2001 From: Juliya Smith Date: Mon, 25 Nov 2024 07:35:34 -0600 Subject: [PATCH] fix: issue with confg chang --- src/ape/api/networks.py | 88 +++++++++++++++++++----------------- src/ape/cli/options.py | 6 ++- src/ape/managers/networks.py | 37 +++++++++------ src/ape/managers/plugins.py | 7 ++- src/ape/managers/project.py | 1 + 5 files changed, 80 insertions(+), 59 deletions(-) diff --git a/src/ape/api/networks.py b/src/ape/api/networks.py index 601b2633a7..9288ce70ca 100644 --- a/src/ape/api/networks.py +++ b/src/ape/api/networks.py @@ -250,9 +250,53 @@ def networks(self) -> dict[str, "NetworkAPI"]: Returns: dict[str, :class:`~ape.api.networks.NetworkAPI`] """ - networks = {**self._networks_from_plugins} + return { + **self._networks_from_evmchains, + **self._networks_from_plugins, + **self._custom_networks, + } + + @cached_property + def _networks_from_plugins(self) -> dict[str, "NetworkAPI"]: + return { + network_name: network_class(name=network_name, ecosystem=self) + for _, (ecosystem_name, network_name, network_class) in self.plugin_manager.networks + if ecosystem_name == self.name + } + + @cached_property + def _networks_from_evmchains(self) -> dict[str, "NetworkAPI"]: + # NOTE: Purposely exclude plugins here so we also prefer plugins. + networks = { + network_name: create_network_type(data["chainId"], data["chainId"])( + name=network_name, ecosystem=self + ) + for network_name, data in PUBLIC_CHAIN_META.get(self.name, {}).items() + if network_name not in self._networks_from_plugins + } + forked_networks: dict[str, ForkedNetworkAPI] = {} + for network_name, network in networks.items(): + if network_name.endswith("-fork"): + # Already a fork. + continue - # Include configured custom networks. + fork_network_name = f"{network_name}-fork" + if any(x == fork_network_name for x in networks): + # The forked version of this network is already known. + continue + + forked_networks[fork_network_name] = ForkedNetworkAPI( + name=fork_network_name, ecosystem=self + ) + + return {**networks, **forked_networks} + + @property + def _custom_networks(self) -> dict[str, "NetworkAPI"]: + """ + Networks from config. + """ + networks: dict[str, "NetworkAPI"] = {} custom_networks: list[dict] = [ n for n in self.network_manager.custom_networks @@ -300,48 +344,8 @@ def networks(self) -> dict[str, "NetworkAPI"]: network_api._is_custom = True networks[net_name] = network_api - # Add any remaining networks from EVM chains here (but don't override). - # NOTE: Only applicable to EVM-based ecosystems, of course. - # Otherwise, this is a no-op. - networks = {**self._networks_from_evmchains, **networks} - return networks - @cached_property - def _networks_from_plugins(self) -> dict[str, "NetworkAPI"]: - return { - network_name: network_class(name=network_name, ecosystem=self) - for _, (ecosystem_name, network_name, network_class) in self.plugin_manager.networks - if ecosystem_name == self.name - } - - @cached_property - def _networks_from_evmchains(self) -> dict[str, "NetworkAPI"]: - # NOTE: Purposely exclude plugins here so we also prefer plugins. - networks = { - network_name: create_network_type(data["chainId"], data["chainId"])( - name=network_name, ecosystem=self - ) - for network_name, data in PUBLIC_CHAIN_META.get(self.name, {}).items() - if network_name not in self._networks_from_plugins - } - forked_networks: dict[str, ForkedNetworkAPI] = {} - for network_name, network in networks.items(): - if network_name.endswith("-fork"): - # Already a fork. - continue - - fork_network_name = f"{network_name}-fork" - if any(x == fork_network_name for x in networks): - # The forked version of this network is already known. - continue - - forked_networks[fork_network_name] = ForkedNetworkAPI( - name=fork_network_name, ecosystem=self - ) - - return {**networks, **forked_networks} - def __post_init__(self): if len(self.networks) == 0: raise NetworkError("Must define at least one network in ecosystem") diff --git a/src/ape/cli/options.py b/src/ape/cli/options.py index 3ad8908c5c..d279dc7aba 100644 --- a/src/ape/cli/options.py +++ b/src/ape/cli/options.py @@ -565,7 +565,11 @@ def _project_callback(ctx, param, val): def project_option(**kwargs): _type = kwargs.pop("type", None) - callback = _project_path_callback if issubclass(_type, Path) else _project_callback + callback = ( + _project_path_callback + if (isinstance(_type, type) and issubclass(_type, Path)) + else _project_callback + ) return click.option( "--project", help="The path to a local project or manifest", diff --git a/src/ape/managers/networks.py b/src/ape/managers/networks.py index 82873cdc23..576789c00a 100644 --- a/src/ape/managers/networks.py +++ b/src/ape/managers/networks.py @@ -209,24 +209,31 @@ def ecosystems(self) -> dict[str, "EcosystemAPI"]: """ All the registered ecosystems in ``ape``, such as ``ethereum``. """ - plugin_ecosystems = self._plugin_ecosystems - custom_ecosystems = self._custom_ecosystems - return {**custom_ecosystems, **plugin_ecosystems} + return { + **self._evmchains_ecosystems, + **self._plugin_ecosystems, + **self._custom_ecosystems, + } @cached_property 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] + # Load plugins (possibly for first time). + plugins: list[tuple] = self.plugin_manager.ecosystems + return {n: cls(name=n) for n, cls in plugins} @cached_property def _custom_ecosystems(self) -> dict[str, "EcosystemAPI"]: custom_networks: list = self.custom_networks plugin_ecosystems = self._plugin_ecosystems + evm_chains = self._evmchains_ecosystems custom_ecosystems: dict[str, "EcosystemAPI"] = {} for custom_network in custom_networks: ecosystem_name = custom_network["ecosystem"] - if ecosystem_name in plugin_ecosystems or ecosystem_name in custom_ecosystems: + if ( + ecosystem_name in plugin_ecosystems + or ecosystem_name in evm_chains + or ecosystem_name in custom_ecosystems + ): # Already included in a prior network. continue @@ -255,14 +262,8 @@ def _custom_ecosystems(self) -> dict[str, "EcosystemAPI"]: return {**self._evmchains_ecosystems, **plugin_ecosystems, **custom_ecosystems} @cached_property - 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] - - @cached_property - def _evmchains_ecosystems(self) -> dict[str, EcosystemAPI]: - ecosystems: dict[str, EcosystemAPI] = {} + def _evmchains_ecosystems(self) -> dict[str, "EcosystemAPI"]: + ecosystems: dict[str, "EcosystemAPI"] = {} for name in PUBLIC_CHAIN_META: ecosystem_name = name.lower().replace(" ", "-") symbol = None @@ -719,6 +720,12 @@ def _get_ecosystem_data( return ecosystem_data + def _invalidate_cache(self): + # NOTE: Called when changing config programmatically. + self.__dict__.pop("_custom_ecosystems", None) + self.__dict__.pop("_custom_networks_from_config", None) + self._custom_networks = [] + def _validate_filter(arg: Optional[Union[list[str], str]], options: set[str]): filters = arg or [] diff --git a/src/ape/managers/plugins.py b/src/ape/managers/plugins.py index bec91e742f..4bcc977313 100644 --- a/src/ape/managers/plugins.py +++ b/src/ape/managers/plugins.py @@ -124,8 +124,13 @@ def _register_plugins(self): if self.__registered: return - plugins = ({n.replace("-", "_") for n in get_plugin_dists()}) + handled = set() + plugins = (n.replace("-", "_") for n in get_plugin_dists()) for module_name in chain(plugins, iter(CORE_PLUGINS)): + if module_name in handled: + continue + + handled.add(module_name) try: module = import_module(module_name) pluggy_manager.register(module) diff --git a/src/ape/managers/project.py b/src/ape/managers/project.py index 8841f16fd6..6666d6754b 100644 --- a/src/ape/managers/project.py +++ b/src/ape/managers/project.py @@ -1941,6 +1941,7 @@ def reconfigure(self, **overrides): self._config_override = overrides _ = self.config self.account_manager.test_accounts.reset() + self.network_manager._invalidate_cache() def extract_manifest(self) -> PackageManifest: # Attempt to compile, if needed.