[core] Add final_validate.get_declaring_config (#20912)

This commit is contained in:
J. Nick Koston
2026-10-18 14:46:57 -10:00
committed by GitHub
parent 704dd4b445
commit 5575dd8928
2 changed files with 63 additions and 1 deletions
+16 -1
View File
@@ -3,7 +3,7 @@ import contextvars
from typing import Any
import esphome.config_validation as cv
from esphome.types import ID, ConfigFragmentType, ConfigPathType
from esphome.types import ID, ConfigFragmentType, ConfigPathType, ConfigType
class FinalValidateConfig(ABC):
@@ -39,6 +39,21 @@ full_config: contextvars.ContextVar[FinalValidateConfig] = contextvars.ContextVa
)
def get_declaring_config(
id_: ID, config: FinalValidateConfig | None = None
) -> ConfigType:
"""Return the config block that declares id_, such as a hub's own config.
Uses the full config being validated unless config is given.
Raises KeyError if the id was not declared, TypeError if its parent is not a dict.
"""
fconf = full_config.get() if config is None else config
declaring = fconf.get_config_for_path(fconf.get_path_for_id(id_)[:-1])
if not isinstance(declaring, dict):
raise TypeError(f"ID {id_} is not declared in a config block")
return declaring
def id_declaration_match_schema(schema):
"""A final-validation schema function that applies a schema to the outer config fragment of an
ID declaration.
+47
View File
@@ -0,0 +1,47 @@
"""Tests for esphome.final_validate helpers."""
import pytest
from esphome import final_validate as fv
from esphome.config import Config
from esphome.const import CONF_ID
from esphome.core import ID
def _config() -> tuple[Config, ID, dict]:
hub_id = ID("my_hub", is_declaration=True)
hub = {CONF_ID: hub_id, "mode": "fast"}
config = Config()
config["other"] = {"x": 1}
config["my_comp"] = [{"y": 2}, hub]
config.declare_ids.append((hub_id, ["my_comp", 1, CONF_ID]))
return config, hub_id, hub
def test_returns_the_declaring_block_from_the_full_config() -> None:
config, hub_id, hub = _config()
token = fv.full_config.set(config)
try:
assert fv.get_declaring_config(hub_id) is hub
finally:
fv.full_config.reset(token)
def test_uses_the_given_config() -> None:
config, hub_id, hub = _config()
assert fv.get_declaring_config(ID("my_hub"), config) is hub
def test_unknown_id_raises_key_error() -> None:
config, _, _ = _config()
with pytest.raises(KeyError):
fv.get_declaring_config(ID("missing"), config)
def test_non_dict_parent_raises_type_error() -> None:
config, _, _ = _config()
list_id = ID("in_list", is_declaration=True)
config["listed"] = [list_id]
config.declare_ids.append((list_id, ["listed", 0]))
with pytest.raises(TypeError):
fv.get_declaring_config(ID("in_list"), config)