From e31c42695032ac076fe6a041065d5f957f3b8982 Mon Sep 17 00:00:00 2001 From: antazoey Date: Fri, 8 Nov 2024 18:54:19 -0600 Subject: [PATCH] perf: `ape_node` plugin load time improvement (#2378) --- docs/userguides/developing_plugins.md | 8 ++++++++ src/ape_node/__init__.py | 20 +++++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/docs/userguides/developing_plugins.md b/docs/userguides/developing_plugins.md index 199e970cbb..f1a407cbea 100644 --- a/docs/userguides/developing_plugins.md +++ b/docs/userguides/developing_plugins.md @@ -61,6 +61,9 @@ from ape import plugins # Here, we register our provider plugin so we can use it in 'ape'. @plugins.register(plugins.ProviderPlugin) def providers(): + # NOTE: By keeping this import local, we avoid slower plugin load times. + from ape_my_plugin.provider import MyProvider + # NOTE: 'MyProvider' defined in a prior code-block. yield "ethereum", "local", MyProvider ``` @@ -69,6 +72,11 @@ This decorator hooks into ape core and ties everything together by looking for a Then, it will loop through these potential `ape` plugins and see which ones have created a plugin type registration. If the plugin type registration is found, then `ape` knows this package is a plugin and attempts to process it according to its registration interface. +```{warning} +Ensure your plugin's `__init__.py` file imports quickly by keeping all expensive imports in the hook functions locally. +This helps Ape register plugins faster, which is required when checking for API implementations. +``` + ### CLI Plugins The `ape` CLI is built using the python package [click](https://palletsprojects.com/p/click/). diff --git a/src/ape_node/__init__.py b/src/ape_node/__init__.py index f76e94a7c0..26c45369cb 100644 --- a/src/ape_node/__init__.py +++ b/src/ape_node/__init__.py @@ -1,16 +1,17 @@ from ape import plugins -from .provider import EthereumNetworkConfig, EthereumNodeConfig, GethDev, Node -from .query import OtterscanQueryEngine - @plugins.register(plugins.Config) def config_class(): + from ape_node.provider import EthereumNodeConfig + return EthereumNodeConfig @plugins.register(plugins.ProviderPlugin) def providers(): + from ape_node.provider import EthereumNetworkConfig, GethDev, Node + networks_dict = EthereumNetworkConfig().model_dump() networks_dict.pop("local") for network_name in networks_dict: @@ -21,9 +22,22 @@ def providers(): @plugins.register(plugins.QueryPlugin) def query_engines(): + from ape_node.query import OtterscanQueryEngine + yield OtterscanQueryEngine +def __getattr__(name: str): + if name == "OtterscanQueryEngine": + from ape_node.query import OtterscanQueryEngine + + return OtterscanQueryEngine + + import ape_node.provider as module + + return getattr(module, name) + + __all__ = [ "EthereumNetworkConfig", "EthereumNodeConfig",