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

问题描述 投票:0回答:1

假设我们有一个具有以下结构的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目录。

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

python path config fb-hydra
1个回答
8
投票

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

修复 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"
的方法。 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的父级)。 这里是实现相对路径计算的函数(对于模块情况和目录情况)。

© www.soinside.com 2019 - 2024. All rights reserved.