从 Python 子/子子目录模块引用 Hydra 的 'conf' 目录



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

hydra_config
├── conf
│   ├── api_key
│   │   ├── non_prod.yaml
│   │   └── prod.yaml
│   └── db
│       ├── mysql.yaml
│       └── postgresql.yaml
├── modules
│   └── module.py
└── my_app.py

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

问题是,如何添加

@hydra.main(config_path="conf")

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

import hydra
from omegaconf import DictConfig, OmegaConf
@hydra.main(config_path="conf")
def module_function(cfg: DictConfig):
print(OmegaConf.to_yaml(cfg))

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

from modules.module import module_function
def main():
module_function()
if __name__ == "__main__":
main()

当我尝试使用python my_app.py运行主 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数据库配置组的conf目录。

这里有人对此有任何经验并知道如何解决此错误吗?

首先,我将介绍一些可能的解决方案,然后我将给出一个解释。 您可以执行以下三件事来使示例正常工作:

修复1:创建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))
修复2:将conf移动到modules/conf并创建modules/conf/__init__.py
├── modules
│   ├── conf
│   │   ├── config.yaml
│   │   └── __init__.py
│   └── module.py
└── my_app.py
修复3:在模块中定义您的装饰函数,该函数将调用为__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"的方法。然后,九头蛇会寻找一个名为conf的顶级包。由于conf/__init__.py存在,因此将找到此顶级conf包并搜索 yaml 文件。为了发现这个包,Hydra 使用了 python 导入机制。这意味着 Hydra 能够发现位于 python 包中的 yaml 文件,这些文件位于$PYTHONPATH上的其他位置或通过包管理器(如pip)安装。

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

相关内容

最新更新