【问题标题】:Referring to Hydra's `conf` directory from a Python sub/sub-sub-directory module从 Python 子/子子目录模块引用 Hydra\ 的 `conf` 目录
【发布时间】:2022-08-03 02:10:23
【问题描述】:

假设我们有一个具有这种结构的 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.pymodule.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.pypython 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_functionmodule.py 的装饰器找不到包含的 conf 目录api_keyD b配置组。

这里有没有人有这方面的经验并且知道如何解决这个错误?

    标签: python path config fb-hydra hydra-python


    【解决方案1】:

    首先我会介绍一些可能的解决方案,然后我会给出解释。 以下是您可以做的三件事来使您的示例工作:

    修复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 文件。

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

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

    【讨论】:

      猜你喜欢
      • 2015-07-23
      • 1970-01-01
      • 2017-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多