mirror of
https://github.com/esphome/esphome.git
synced 2026-09-11 15:27:33 +00:00
[core] Fix area saved as null in storage.json (#17219)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
This commit is contained in:
co-authored by
Jonathan Swoboda
parent
f78cbf9200
commit
84d1c34c28
+11
-1
@@ -407,6 +407,17 @@ def preload_core_config(config, result) -> str:
|
||||
|
||||
CORE.name = conf[CONF_NAME]
|
||||
CORE.friendly_name = conf.get(CONF_FRIENDLY_NAME)
|
||||
# Record the node's area name now (substitutions are already resolved at this
|
||||
# point). storage.json is written before to_code() runs, so deferring this to
|
||||
# to_code() left the area as null in storage.json. The value here is the raw
|
||||
# post-substitution form (a plain string or a {name: ...} mapping). Assign
|
||||
# unconditionally (like friendly_name) so a config without an area never
|
||||
# inherits a stale value from a previous load in a long-running process, and
|
||||
# use .get() so a malformed mapping surfaces later as a proper validation
|
||||
# error rather than a KeyError here. to_code() sets it again from the
|
||||
# validated config, which yields the same name.
|
||||
area = conf.get(CONF_AREA)
|
||||
CORE.area = area.get(CONF_NAME) if isinstance(area, dict) else area
|
||||
CORE.data[KEY_CORE] = {}
|
||||
|
||||
if CONF_BUILD_PATH not in conf:
|
||||
@@ -760,7 +771,6 @@ async def to_code(config: ConfigType) -> None:
|
||||
# Process areas
|
||||
all_areas: list[dict[str, str | core.ID]] = []
|
||||
if CONF_AREA in config:
|
||||
CORE.area = config[CONF_AREA][CONF_NAME]
|
||||
all_areas.append(config[CONF_AREA])
|
||||
all_areas.extend(config[CONF_AREAS])
|
||||
|
||||
|
||||
@@ -152,15 +152,21 @@ def test_multiple_areas_and_devices(yaml_file: Callable[[str], str]) -> None:
|
||||
("multiple_areas_devices.yaml", "Main Area"),
|
||||
],
|
||||
)
|
||||
async def test_to_code_records_core_area(
|
||||
async def test_core_area_recorded_at_config_load(
|
||||
yaml_file: Callable[[str], Path],
|
||||
fixture: str,
|
||||
expected_area: str,
|
||||
) -> None:
|
||||
"""``to_code`` records the node's area name on CORE for StorageJSON."""
|
||||
"""The node's area name is recorded on CORE for StorageJSON.
|
||||
|
||||
It must be set during config load (preload_core_config), not deferred to
|
||||
to_code(): storage.json is written before to_code() runs, so a late
|
||||
assignment left the area as null in storage.json (regression #17218).
|
||||
"""
|
||||
result = load_config_from_fixture(yaml_file, fixture, FIXTURES_DIR)
|
||||
assert result is not None
|
||||
assert CORE.area is None
|
||||
# Recorded already at config-load time, before any code generation.
|
||||
assert CORE.area == expected_area
|
||||
|
||||
with patch("esphome.core.config.cg") as mock_cg:
|
||||
mock_cg.RawStatement.side_effect = lambda *args, **kwargs: MagicMock()
|
||||
@@ -170,6 +176,23 @@ async def test_to_code_records_core_area(
|
||||
assert CORE.area == expected_area
|
||||
|
||||
|
||||
def test_config_load_without_area_clears_stale_core_area(
|
||||
yaml_file: Callable[[str], Path],
|
||||
) -> None:
|
||||
"""A config without an area must not inherit a stale CORE.area.
|
||||
|
||||
preload_core_config assigns CORE.area unconditionally, so the area from a
|
||||
previous load in a long-running process cannot leak into a config that
|
||||
omits it.
|
||||
"""
|
||||
CORE.area = "Stale Area From Previous Load"
|
||||
result = load_config_from_fixture(
|
||||
yaml_file, "device_without_area.yaml", FIXTURES_DIR
|
||||
)
|
||||
assert result is not None
|
||||
assert CORE.area is None
|
||||
|
||||
|
||||
def test_legacy_string_area(
|
||||
yaml_file: Callable[[str], str], caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
|
||||
Reference in New Issue
Block a user