从 Python sub/sub-sub-directory 模块引用 Hydra 的 `conf` 目录

blu*_*609 4 python config path fb-hydra

假设我们有一个具有以下结构的 Python 项目:

\n
hydra_config\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 conf\n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 api_key\n\xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 non_prod.yaml\n\xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 prod.yaml\n\xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 db\n\xe2\x94\x82       \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 mysql.yaml\n\xe2\x94\x82       \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 postgresql.yaml\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 modules\n\xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 module.py\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 my_app.py\n
Run Code Online (Sandbox Code Playgroud)\n

现在,在 Hydra 的配置文档中,他们指出我们需要在我们想要访问配置文件的函数之上添加一个 Python 装饰器。my_app.py但是,文档仅展示了如何对项目主模块的函数执行此操作。

\n

问题是,如何添加

\n
@hydra.main(config_path="conf")\n
Run Code Online (Sandbox Code Playgroud)\n

函数的 Python 装饰器,假设module_function哪个位于modules/module.py? 以下是 的内容module.py

\n
import hydra\nfrom omegaconf import DictConfig, OmegaConf\n\n@hydra.main(config_path="conf")\ndef module_function(cfg: DictConfig):\n    print(OmegaConf.to_yaml(cfg))\n
Run Code Online (Sandbox Code Playgroud)\n

下面是主要Python模块的内容my_app.py

\n
from modules.module import module_function\n\ndef main():\n    module_function()\n\nif __name__ == "__main__":\n    main()\n
Run Code Online (Sandbox Code Playgroud)\n

当我尝试使用 运行主 Python 模块时my_app.pypython my_app.py我立即收到一条错误消息

\n
Primary config module 'modules.conf' not found.\nCheck that it's correct and contains an __init__.py file\n\nSet the environment variable HYDRA_FULL_ERROR=1 for a complete stack trace.\n
Run Code Online (Sandbox Code Playgroud)\n

module_function我知道这意味着添加到内部的装饰器module.py找不到conf包含api_keydb配置组的目录。

\n

这里有人有这方面的经验并且知道如何修复这个错误吗?

\n

Jas*_*sha 7

首先,我将讨论一些可能的解决方案,然后给出解释。\n为了使示例正常工作,您可以执行以下三件事:

\n
修复 1:创建conf/__init__.py并更改config_path="conf"config_path="../conf"
\n
\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 conf\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 config.yaml\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 __init__.py\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 modules\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 module.py\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 my_app.py\n
Run Code Online (Sandbox Code Playgroud)\n
\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 conf\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 config.yaml\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 __init__.py\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 modules\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 module.py\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 my_app.py\n
Run Code Online (Sandbox Code Playgroud)\n
修复 2:移动confmodules/conf并创建modules/conf/__init__.py
\n
# modules/module.py\nimport hydra\nfrom omegaconf import DictConfig, OmegaConf\n\n@hydra.main(config_path="../conf", config_name="config")  # relative path\ndef module_function(cfg: DictConfig):\n    print(OmegaConf.to_yaml(cfg))\n
Run Code Online (Sandbox Code Playgroud)\n
修复 3:在模块中定义您的修饰函数,该函数将被调用为__main__
\n
\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 modules\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 conf\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 config.yaml\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 __init__.py\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 module.py\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 my_app.py\n
Run Code Online (Sandbox Code Playgroud)\n
\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 conf\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 config.yaml\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 my_app.py\n
Run Code Online (Sandbox Code Playgroud)\n

修复 3 不会让 OP 非常满意:)

\n

解释

\n

在您的示例中,由于您已导入装饰函数(而不是在模块中定义它__main__),Hydra 会将参数解释config_path="conf"为相对于定义装饰函数的模块的父模块。在您的示例中,装饰函数在 中定义modules.module,其父级是modules,因此 Hydra 正在寻找一个名为的 python 包modules.conf。如果找到,将在该包中搜索 yaml 文件。

\n

上面的 Fix 2 采用了确保modules/conf/__init__.py存在的方法,因此它modules.conf实际上是一个 python 包。\n同时,Fix 1 采用了使用相对路径的方法config_path="../conf"。Hydra 然后查找名为 的顶级包conf。由于conf/__init__.py存在,因此会找到此顶级conf包并搜索 yaml 文件。为了发现这个包,Hydra 使用 python 导入机制。这意味着 Hydra 能够发现位于 Python 包中的 yaml 文件,这些包位于您的其他位置$PYTHONPATH或通过包管理器(例如pip.

\n

在 Fix 3 中,我们有module_function.__module__ == "__main__",这意味着 Hydra 不能依赖 python 的导入机制来发现module_function定义的位置。作为后备,Hydra 尝试查找目录 conf(而不是 conf);这就是__init__.pyFix 3 不需要文件的原因。以下是实现此行为的关键代码行。请注意,conf仍然被视为相对路径,相对于包含定义修饰函数的文件的目录(而不是相对于定义它的模块的父级)。是实现此相对路径计算的函数(对于模块情况和目录情况)。

\n