假设我们有一个具有以下结构的Python项目:
hydra_config
├── conf
│ ├── api_key
│ │ ├── non_prod.yaml
│ │ └── prod.yaml
│ └── db
│ ├── mysql.yaml
│ └── postgresql.yaml
├── modules
│ └── module.py
└── my_app.py
Hydra 的配置文档指出,我们需要在我们想要访问配置文件的函数之上添加一个
@hydra.main
装饰器。然而,文档仅展示了如何对项目主模块 my_app.py
中的函数执行此操作。但是我如何将这个装饰器应用到 modules/module.py
中的函数?
以下是文件内容:
# modules/module.py
import hydra
from omegaconf import DictConfig, OmegaConf
@hydra.main(config_path="conf")
def module_function(cfg: DictConfig):
print(OmegaConf.to_yaml(cfg))
# my_app.py
from modules.module import module_function
def main():
module_function()
if __name__ == "__main__":
main()
但是当我运行
python my_app.py
时,我得到了一个错误:
Primary config module 'modules.conf' not found.
Check that it's correct and contains an __init__.py file
Set the environment variable HYDRA_FULL_ERROR=1 for a complete stack trace.
我理解这意味着添加到
module_function
内的module.py
的装饰器找不到包含api_key和db配置组的
conf
目录。
这里有人有这方面的经验并知道如何修复这个错误吗?
首先我将讨论一些可能的解决方案,然后我将给出解释。 您可以执行以下三件事来使示例正常工作:
conf/__init__.py
并将 config_path="conf"
更改为 config_path="../conf"
:├── conf
│ ├── config.yaml
│ └── __init__.py
├── modules
│ └── module.py
└── my_app.py
# modules/module.py
import hydra
from omegaconf import DictConfig, OmegaConf
@hydra.main(config_path="../conf", config_name="config") # relative path
def module_function(cfg: DictConfig):
print(OmegaConf.to_yaml(cfg))
conf
移动到 modules/conf
并创建 modules/conf/__init__.py
:├── modules
│ ├── conf
│ │ ├── config.yaml
│ │ └── __init__.py
│ └── module.py
└── my_app.py
__main__
:├── conf
│ └── config.yaml
└── my_app.py
# my_app.py
import hydra
from omegaconf import DictConfig, OmegaConf
@hydra.main(config_path="conf", config_name="config")
def module_function(cfg: DictConfig):
print(OmegaConf.to_yaml(cfg))
if __name__ == "__main__":
module_function()
修复 3 不会让 OP 非常满意:)
在您的示例中,由于您已导入装饰函数(而不是在
__main__
模块中定义它),Hydra 会将参数 config_path="conf"
解释为相对于定义装饰函数的模块的父级。在您的示例中,装饰函数在 modules.module
中定义,其父级是 modules
,因此 Hydra 正在寻找名为 modules.conf
的 python 包。如果找到,将在该包中搜索 yaml 文件。
上面的 Fix 2 采用确保
modules/conf/__init__.py
存在的方法,以便 modules.conf
实际上是一个 python 包。
同时,Fix 1 采用了使用相对路径config_path="../conf"
的方法。 Hydra 然后查找名为 conf
的顶级包。由于 conf/__init__.py
存在,因此会找到此顶级 conf
包并搜索 yaml 文件。为了发现这个包,Hydra 使用 python 导入机制。这意味着 Hydra 能够发现位于 $PYTHONPATH
上其他位置的 Python 包中的 yaml 文件,或者通过包管理器(例如 pip
)安装的 yaml 文件。
在 Fix 3 中,我们有
module_function.__module__ == "__main__"
,这意味着 Hydra 不能依赖 python 的导入机制来发现 module_function
的定义位置。作为后备,Hydra 尝试找到一个 directory conf
(而不是 package conf
);这就是 Fix 3 不需要 __init__.py
文件的原因。Here 是实现此行为的关键代码行。请注意,conf
仍被视为相对路径,相对于包含定义修饰函数的file的目录(而不是相对于定义它的module的父级)。 这里是实现相对路径计算的函数(对于模块情况和目录情况)。