一起使用 Typer 和 Hydra
Using Typer and Hydra together
我有一个简单的Typer应用程序:
import typer
app = typer.Typer()
@app.command()
def say_hi():
print("Hi")
@app.callback()
def main():
pass
if __name__ == "__main__":
app()
我想使用 Hydra 来管理应用程序的配置,但是我不确定如何在不失去覆盖配置的能力的情况下做到这一点来自 CLI。
我的第一次尝试是:
import hydra
import typer
from omegaconf import DictConfig, OmegaConf
app = typer.Typer()
@app.command()
def say_hi():
print("Hi")
@app.callback()
@hydra.main(config_path="conf", config_name="config")
def main(cfg: DictConfig) -> None:
print(OmegaConf.to_yaml(cfg))
if __name__ == "__main__":
app()
但我收到一条错误消息:
RuntimeError: Type not yet supported: <class 'omegaconf.dictconfig.DictConfig'>
如果我删除 DictConfig
类型注释,我会收到一条错误消息,指出缺少 cfg
。
我在 Hydra 文档中看到 Compose API 允许在没有装饰器的情况下初始化配置:
@app.callback()
def main() -> None:
with initialize(config_path="conf", job_name="test_app"):
cfg = compose(config_name="config")
print(OmegaConf.to_yaml(cfg))
但在这种情况下,我似乎无法从命令行覆盖配置,因为 Typer 应用无法识别这些值。
有什么解决方法的建议吗?
compose
函数接受覆盖字符串的可选列表:
with initialize(config_path="conf", job_name="test_app"):
cfg = compose(config_name="config", overrides=["db=mysql", "db.user=me"])
您需要从命令行获取覆盖字符串列表,然后将该列表传递给 compose
。
这是一个使用 Typer 的例子;类似的模式可以适用于例如argparse 或点击。
(免责声明:我不是 Typer 专家)
from typing import List, Optional
import typer
from omegaconf import OmegaConf, DictConfig
from hydra import compose, initialize
app = typer.Typer()
def my_compose(overrides: Optional[List[str]]) -> DictConfig:
with initialize(config_path="conf", job_name="test_app"):
return compose(config_name="config", overrides=overrides)
@app.command()
def say_hi(overrides: Optional[List[str]] = typer.Argument(None)):
print("HI!")
print(f"Got {overrides=}")
cfg = my_compose(overrides)
print("\nHydra config:")
print(OmegaConf.to_yaml(cfg))
@app.command()
def say_bye(overrides: Optional[List[str]] = typer.Argument(None)):
cfg = my_compose(overrides)
...
print("BYE!")
if __name__ == "__main__":
app()
$ python my_app.py say-hi +foo=bar +baz=qux
HI!
Got overrides=('+foo=bar', '+baz=qux')
Hydra config:
foo: bar
baz: qux
$ python my_app.py say-bye
BYE!
我有一个简单的Typer应用程序:
import typer
app = typer.Typer()
@app.command()
def say_hi():
print("Hi")
@app.callback()
def main():
pass
if __name__ == "__main__":
app()
我想使用 Hydra 来管理应用程序的配置,但是我不确定如何在不失去覆盖配置的能力的情况下做到这一点来自 CLI。
我的第一次尝试是:
import hydra
import typer
from omegaconf import DictConfig, OmegaConf
app = typer.Typer()
@app.command()
def say_hi():
print("Hi")
@app.callback()
@hydra.main(config_path="conf", config_name="config")
def main(cfg: DictConfig) -> None:
print(OmegaConf.to_yaml(cfg))
if __name__ == "__main__":
app()
但我收到一条错误消息:
RuntimeError: Type not yet supported: <class 'omegaconf.dictconfig.DictConfig'>
如果我删除 DictConfig
类型注释,我会收到一条错误消息,指出缺少 cfg
。
我在 Hydra 文档中看到 Compose API 允许在没有装饰器的情况下初始化配置:
@app.callback()
def main() -> None:
with initialize(config_path="conf", job_name="test_app"):
cfg = compose(config_name="config")
print(OmegaConf.to_yaml(cfg))
但在这种情况下,我似乎无法从命令行覆盖配置,因为 Typer 应用无法识别这些值。
有什么解决方法的建议吗?
compose
函数接受覆盖字符串的可选列表:
with initialize(config_path="conf", job_name="test_app"):
cfg = compose(config_name="config", overrides=["db=mysql", "db.user=me"])
您需要从命令行获取覆盖字符串列表,然后将该列表传递给 compose
。
这是一个使用 Typer 的例子;类似的模式可以适用于例如argparse 或点击。
(免责声明:我不是 Typer 专家)
from typing import List, Optional
import typer
from omegaconf import OmegaConf, DictConfig
from hydra import compose, initialize
app = typer.Typer()
def my_compose(overrides: Optional[List[str]]) -> DictConfig:
with initialize(config_path="conf", job_name="test_app"):
return compose(config_name="config", overrides=overrides)
@app.command()
def say_hi(overrides: Optional[List[str]] = typer.Argument(None)):
print("HI!")
print(f"Got {overrides=}")
cfg = my_compose(overrides)
print("\nHydra config:")
print(OmegaConf.to_yaml(cfg))
@app.command()
def say_bye(overrides: Optional[List[str]] = typer.Argument(None)):
cfg = my_compose(overrides)
...
print("BYE!")
if __name__ == "__main__":
app()
$ python my_app.py say-hi +foo=bar +baz=qux
HI!
Got overrides=('+foo=bar', '+baz=qux')
Hydra config:
foo: bar
baz: qux
$ python my_app.py say-bye
BYE!