我有一个带有 yaml 文件的现有 Hydra 设置,并且正在尝试将其迁移以使用结构化配置来获得类型注释和继承优势。我遇到的一个症结是,我当前的 yaml 设置的一部分遵循 Hydra 文档中的 从配置组中选择多个配置 模式。我正在努力将该模式转换为使用结构化配置类而不是 yaml 文件。这是我尝试将文档中的确切示例转换为结构化配置:
from dataclasses import dataclass, field
from typing import Any
import hydra
from hydra.core.config_store import ConfigStore
from omegaconf import OmegaConf
@dataclass
class Amazon:
domain: str = "amazon.com"
@dataclass
class Facebook:
domain: str = "facebook.com"
@dataclass
class Google:
domain: str = "google.com"
@dataclass
class Apache:
host: str = "localhost"
port: int = 443
@dataclass
class Server:
site: list[Any] = field(default_factory=lambda: [Amazon, Facebook, Google])
tech: Any = field(default_factory=Apache)
DEFAULTS = [{"server/site": ["facebook", "google"]}]
@dataclass
class Config:
server: Any = field(default_factory=Server)
defaults: list[Any] = field(default_factory=lambda: DEFAULTS)
@hydra.main(version_base=None, config_name="config")
def my_app(cfg: Config) -> None:
print(OmegaConf.to_yaml(cfg))
if __name__ == "__main__":
cs = ConfigStore.instance()
cs.store(group="server/site", name="facebook", node=Facebook)
cs.store(group="server/site", name="amazon", node=Amazon)
cs.store(group="server/site", name="google", node=Google)
cs.store(name="config", node=Config)
my_app()
但是,当我运行时,出现错误:
hydra.errors.ConfigCompositionException: In 'server/site/google': ValidationError raised while composing config:
Merge error: Google is not a subclass of Facebook. value: {'domain': 'google.com'}
full_key:
object_type=dict
看起来默认的
server/site
是一个列表,这使得 Hydra 尝试合并 facebook 和 google 的配置,而不是使用字典列表作为配置。我做错了什么?
您的端口存在几个问题。 如果您查看示例页面中的结果配置,您会注意到该站点不是列表而是字典。 每个不同的站点都有一个不同的硬编码密钥,以避免它们填充相同的节点。
下面的示例创建了一个 Site 类,其中包含每个配置的可选字段。这与您正在移植的示例更加一致(除了不支持列表组合的事实)。
此外,如果在 ConfigStore 中存储配置时站点配置位于正确的包中,它会覆盖这些包。
from dataclasses import dataclass, field
from typing import Any, Optional
import hydra
from hydra.core.config_store import ConfigStore
from omegaconf import OmegaConf
@dataclass
class Amazon:
domain: str = "amazon.com"
@dataclass
class Facebook:
domain: str = "facebook.com"
@dataclass
class Google:
domain: str = "google.com"
@dataclass
class Apache:
host: str = "localhost"
port: int = 443
@dataclass
class Site:
facebook: Optional[Facebook] = None
google: Optional[Google] = None
amazon: Optional[Apache] = None
@dataclass
class Server:
site: Site = field(default_factory=Site)
tech: Any = field(default_factory=Apache)
DEFAULTS = ["_self_", {"server/site": ["facebook", "google"]}]
@dataclass
class Config:
server: Any = field(default_factory=Server)
defaults: list[Any] = field(default_factory=lambda: DEFAULTS)
@hydra.main(version_base=None, config_name="config")
def my_app(cfg: Config) -> None:
print(OmegaConf.to_yaml(cfg))
if __name__ == "__main__":
cs = ConfigStore.instance()
cs.store(group="server/site", name="facebook", node=Facebook, package="server.site.facebook")
cs.store(group="server/site", name="amazon", node=Amazon, package="server.site.amazon")
cs.store(group="server/site", name="google", node=Google, package="server.site.google")
cs.store(name="config", node=Config)
my_app()