尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Hydra 插件开发实战指南:深入理解插件注册机制与基于示例的完整开发流程

Hydra 插件开发实战指南:深入理解插件注册机制与基于示例的完整开发流程 Hydra 插件开发实战指南深入理解插件注册机制与基于示例的完整开发流程【免费下载链接】hydraHydra is a framework for elegantly configuring complex applications项目地址: https://gitcode.com/GitHub_Trending/hyd/hydra本指南以 Hydra 官方文档develop.md为骨架结合本仓库中hydra/core/plugins.py的插件扫描与注册源码以及examples/plugins目录下的六类示例插件完整讲解 Hydra 插件的两种注册方式、自动发现机制的底层实现、基于示例插件搭建独立插件工程的完整步骤以及如何编写测试验证插件的正确性。读完本文你将能够从零开发、安装、验证并发布一个可被 Hydra 自动发现的插件。插件注册的两种方式发现机制与手动注册Hydra 插件在使用前必须先完成注册。注册插件有两种途径自动插件发现Automatic Plugin discoveryHydra 启动时会扫描hydra_plugins命名空间包下的所有子模块自动发现并注册其中的插件。这是发布型插件最常用的方式。手动调用Plugins.register通过 Hydra 的Plugins单例类上的register方法显式注册插件类。适用于不便放入hydra_plugins包、需要在应用代码中按需注册的场景如示例 example_registered_plugin。这两种方式最终都会把插件类写入Plugins单例内部的两个索引plugin_type_to_subclass_list插件类型 → 子类列表和class_name_to_class模块名.类名→ 类供 Hydra 在运行期按需实例化。自动插件发现机制顶层hydra_plugins命名空间包如果你希望插件被 Hydra 自动发现需要遵守以下关键约束源码依据hydra/core/plugins.py 中的_initialize与_scan_all_plugins插件必须位于顶层hydra_plugins命名空间包插件既可以是独立的 Python 包也可以是你现有 Python 包的一部分但无论哪种情况都必须放在命名空间模块hydra_plugins下。这是一个顶层模块——如果把插件放在mylib.hydra_pluginsHydra 将不会发现它。严禁在hydra_plugins中放置__init__.pyhydra_plugins必须是命名空间包namespace package。一旦放入__init__.py可能导致其他已安装的 Hydra 插件失效。导入速度影响全局启动性能插件发现流程在每次 Hydra 启动时运行会导入hydra_plugins下的所有子模块。任何导入缓慢的模块都会拖慢所有Hydra 应用的启动时间。因此重依赖应放在launch()等运行时方法内延迟导入或者放入以下划线_开头的文件中排除扫描。用_前缀排除扫描文件模块名以单个下划线_开头但不是双下划线__的文件不会被导入和扫描。例如_my_plugin_lib.py不会被扫描而my_plugin_lib.py会被扫描。从源码看_scan_all_plugins使用pkgutil.walk_packages遍历hydra_plugins的所有子模块对每个模块执行如下逻辑hydra/core/plugins.py解析模块短名若以_开头且不以__开头则直接跳过不导入、不扫描记录模块导入耗时累积到ScanStats若模块导入时产生警告则打印[Hydra plugins scanner] : warnings from 模块名并提示上报插件作者用inspect.getmembers遍历模块成员凡是满足_is_concrete_plugin_type是Plugin的子类、且不是抽象类的类即被收集为候选插件捕获导入异常并输出UserWarning提示插件与当前 Hydra 版本不兼容或存在缺陷。Plugins类在_initialize中会先导入hydra._internal.core_pluginsHydra 内置核心插件再尝试导入顶层hydra_plugins若未安装任何第三方插件则捕获ImportError跳过最后统一注册扫描到的所有插件类。六种内置插件类型扫描结果会按插件类型归类。PLUGIN_TYPES定义了六种插件基类hydra/core/plugins.py插件类型基类位置作用通用插件hydra/plugins/plugin.pyPlugin抽象基类所有插件的根类型配置源插件hydra/plugins/config_source.py提供自定义配置来源文件、DB、远程等补全插件hydra/plugins/completion_plugin.py为 shell 提供命令行补全如 Bash/Fish/Zsh启动器插件hydra/plugins/launcher.py控制任务执行环境本地、集群、云等搜索路径插件hydra/plugins/search_path_plugin.py向 Hydra 的配置搜索路径注入新目录搜索器插件hydra/plugins/sweeper.py控制多任务批量执行参数扫描、优化搜索当插件类被注册时_register会把它加入所有其继承的插件类型对应列表中如果它是ConfigSource的子类还会同步注册到SourcesRegistryhydra/core/plugins.py。另外需要注意的是插件实例化时类全名必须位于hydra_plugins.或hydra._internal.core_plugins.前缀之下否则_instantiate会抛出RuntimeError: Invalid plugin ... not the hydra_plugins packagehydra/core/plugins.py这一点从源码上保证了插件必须存在于批准的顶层模块内。通过Plugins.register手动注册插件插件也可以通过调用 HydraPlugins单例的register方法手动注册。官方文档给出了如下最小示例from hydra.core.plugins import Plugins from hydra.plugins.plugin import Plugin class MyPlugin(Plugin): ... def register_my_plugin() - None: Hydra users should call this function before invoking hydra.main Plugins.instance().register(MyPlugin)在仓库示例 example_registered_plugin 中可以看到完全一致的写法插件类ExampleRegisteredPlugin(Plugin)定义了业务方法add并通过register_example_plugin()函数在hydra.main调用之前完成注册。注意Plugins.instance()这一用法——Plugins使用了Singleton元类hydra/core/plugins.py必须通过单例访问实例若直接对类实例调用方法会触发check_usage校验并抛出异常Plugins is now a Singleton。手动注册的类同样要满足_is_concrete_plugin_type是Plugin子类且非抽象否则register会抛出ValueError(Not a valid Hydra Plugin)。基于示例插件搭建你的第一个插件工程官方推荐的起步方式是从示例插件复制子树改造仓库中提供了六类示例插件examples/pluginsexample_generic_plugin最简通用插件理解Plugin基类的最小实现example_launcher_plugin启动器插件展示Launcher.setup/Launcher.launch与本地多任务执行example_sweeper_plugin搜索器插件展示多任务批量执行的配置与驱动example_configsource_plugin配置源插件实现scheme()、load_config、is_group、is_config、list等方法example_searchpath_plugin搜索路径插件注入额外的配置目录example_registered_plugin手动注册插件演示Plugins.register用法以启动器插件为例其工程结构为example_launcher_plugin/ ├── setup.py # 打包配置 ├── MANIFEST.in # 打包清单yaml、py.typed 等数据文件 ├── hydra_plugins/ │ └── example_launcher_plugin/ │ ├── __init__.py │ ├── example_launcher.py # 插件实现 │ └── py.typed ├── example/ │ ├── conf/config.yaml # 示例应用配置 │ └── my_app.py # 示例应用 └── tests/ └── test_example_launcher_plugin.py复制并改造示例插件按照官方文档的步骤开始开发复制子树将 examples/plugins 中相关示例插件目录整体复制到独立的工程目录。编辑setup.py并重命名插件模块例如把hydra_plugins.example_xyz_plugin改名为hydra_plugins.my_xyz_plugin。注意示例 setup.py 中通过find_namespace_packages(include[hydra_plugins.*])将hydra_plugins作为命名空间包打进最终 Python 包这正是官方文档所提示的做法同时install_requires声明依赖hydra-core并建议考虑固定主版本如hydra-core1.0.*以避免插件与 Hydra 大版本升级发生破坏性变更。安装插件在插件目录执行pip install -e .。验证插件被发现运行随附的示例应用并打印插件列表$ python example/my_app.py --info plugins Installed Hydra Plugins *********************** ... Launcher: --------- MyLauncher ...--info plugins会触发Plugins.discover()遍历各插件类型对应的已注册子类hydra/core/plugins.py从而确认插件已被自动发现。运行示例应用观察插件是否真正生效。可选嵌入现有应用/库如果希望插件内嵌到你现有的应用或库中把hydra_plugins目录移入你的包结构并确保其作为命名空间模块被打包进最终 Python 包参考示例setup.py的find_namespace_packages(include[hydra_plugins.*])。持续开发确保官方推荐的测试套件与你新增的测试全部通过。将插件接入配置以启动器为例示例应用的配置文件 展示了如何让应用使用自定义启动器defaults: - db: mysql - override hydra/launcher: example而插件实现通过ConfigStore将自身的结构化配置注册到hydra/launcher组example_launcher.pydataclass class LauncherConfig: _target_: str ( hydra_plugins.example_launcher_plugin.example_launcher.ExampleLauncher ) foo: int 10 bar: str abcde ConfigStore.instance().store( grouphydra/launcher, nameexample, nodeLauncherConfig )_target_指向插件类的完整路径foo、bar等字段作为插件参数由配置注入。Launcher抽象基类要求实现两个方法hydra/plugins/launcher.pysetup(hydra_context, task_function, config)把运行所需上下文保存到插件实例launch(job_overrides, initial_job_idx)真正执行任务。示例中通过run_job逐个运行任务并在跨进程场景下用Singleton.get_state()/Singleton.set_state()传递单例状态example_launcher.py。插件代码顶部还给出了一个值得推广的实践注释重依赖务必延迟导入或放入_前缀文件因为已安装插件会在 Hydra 初始化期间被导入导入慢的插件会拖慢所有 Hydra 应用。打包数据文件如果插件需要随包发布配置如插件自带的 yaml 配置必须在MANIFEST.in中声明并在setup.py中开启include_package_dataTrue。示例 MANIFEST.in 展示了典型写法global-exclude *.pyc global-exclude __pycache__ recursive-include hydra_plugins/* *.yaml py.typed为插件编写测试示例插件测试 给出了插件测试的三件套def test_discovery() - None: # 验证插件能通过插件子系统被发现 assert ExampleLauncher.__name__ in [ x.__name__ for x in Plugins.instance().discover(Launcher) ] mark.parametrize(launcher_name, overrides, [(example, [])]) class TestExampleLauncher(LauncherTestSuite): 在启动器上运行官方 Launcher 测试套件。 mark.parametrize( task_launcher_cfg, extra_flags, [({}, [-m, hydra/launcherexample])], ) class TestExampleLauncherIntegration(IntegrationTestSuite): 让启动器通过集成测试套件。test_discovery验证插件能被Plugins.instance().discover(Launcher)发现LauncherTestSuite/IntegrationTestSuite来自 hydra/test_utils/launcher_common_tests.py是 Hydra 为插件作者提供的官方测试基础设施启动器、搜索器类插件可直接继承复用保证与 Hydra 主框架的行为契约一致。小结开发插件的完整检查清单插件类继承Plugin或六种具体插件基类之一实现抽象方法插件置于顶层hydra_plugins命名空间包不放__init__.py或通过Plugins.instance().register()手动注册通过ConfigStore把插件配置注册到对应的hydra/*组并给出_target_指向插件类重依赖延迟导入或用_前缀文件隔离避免拖慢全局启动setup.py使用find_namespace_packages(include[hydra_plugins.*])打包数据文件写入MANIFEST.inpip install -e .后用python example/my_app.py --info plugins验证发现再运行示例应用验证功能复用LauncherTestSuite/IntegrationTestSuite等官方测试套件确保插件与 Hydra 主框架兼容。按照上述流程你就能像仓库中六个示例插件一样开发出可自动发现、可独立分发、可被社区复用的 Hydra 插件。如需进一步参考可在本仓库 examples/plugins 目录下对照各插件类型的完整实现与测试。【免费下载链接】hydraHydra is a framework for elegantly configuring complex applications项目地址: https://gitcode.com/GitHub_Trending/hyd/hydra创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表