diff --git a/src/ape/managers/networks.py b/src/ape/managers/networks.py index 320af9739d..68d33287e1 100644 --- a/src/ape/managers/networks.py +++ b/src/ape/managers/networks.py @@ -197,12 +197,24 @@ def ecosystems(self) -> dict[str, EcosystemAPI]: for custom_network in custom_networks: ecosystem_name = custom_network["ecosystem"] if ecosystem_name in plugin_ecosystems: - # Already included in previous network. + # Already included in a prior network. continue base_ecosystem_name = ( custom_network.get("base_ecosystem_plugin") or self.default_ecosystem_name ) + + if base_ecosystem_name not in plugin_ecosystems: + name = custom_network.get("name", "?") + if eco := custom_network.get("ecosystem"): + name = f"{eco}:{name}" + + msg = ( + f"Custom network '{name}' specified unknown base-ecosystem class " + f"'{base_ecosystem_name}'. Are you missing plugin 'ape-{base_ecosystem_name}'?" + ) + raise NetworkError(msg) + existing_cls = plugin_ecosystems[base_ecosystem_name] ecosystem_cls = existing_cls.model_copy( update={"name": ecosystem_name}, cache_clear=("_networks_from_plugins",) diff --git a/tests/functional/test_network_manager.py b/tests/functional/test_network_manager.py index 38e64e4c6a..daf5215e7b 100644 --- a/tests/functional/test_network_manager.py +++ b/tests/functional/test_network_manager.py @@ -290,6 +290,27 @@ def test_ecosystems_include_custom(networks, custom_networks_config_dict, projec assert "custom-ecosystem" in actual +def test_ecosystems_when_custom_has_bad_base_ecosystem( + networks, custom_networks_config_dict, project +): + data = copy.deepcopy(custom_networks_config_dict) + eco_name = "custom-ecosystem-bad" + eco_plugin_name = "plugin-ecosystem-not-installed" + # Only hits error if ecosystem is custom because it is unknown. + data["networks"]["custom"][0]["ecosystem"] = eco_name + # The plugin base is for the class-implementation. If it is not a real plugin, + # it should fail nicely. + data["networks"]["custom"][0]["base_ecosystem_plugin"] = eco_plugin_name + expected = ( + rf"Custom network '{eco_name}:apenet' specified unknown " + rf"base-ecosystem class '{eco_plugin_name}'\. " + rf"Are you missing plugin 'ape-{eco_plugin_name}'\?" + ) + with project.temp_config(**data): + with pytest.raises(NetworkError, match=expected): + _ = networks.ecosystems + + def test_fork_network_not_forkable(networks, eth_tester_provider): """ Show correct failure when trying to fork the local network.