Dump the main.cpp config comment with sorted keys

voluptuous fills schema defaults in set-iteration order, so the
validated dict's key order changes with the process hash seed. The
unsorted dump churned the comment block in main.cpp and made every
backend (ESP-IDF, PlatformIO, nrf52) recompile main.cpp and relink the
firmware on every esphome run for any config using a defaults-heavy
action; logger.log in a button's on_press was enough.
This commit is contained in:
J. Nick Koston
2026-08-22 14:48:08 -05:00
parent d119ad6c60
commit a2bd8417d4
2 changed files with 29 additions and 1 deletions
+3 -1
View File
@@ -762,7 +762,9 @@ def _wrap_to_code(name, comp, yaml_util):
async def wrapped(conf):
cg.add(cg.LineComment(f"{name}:"))
if comp.config_schema is not None:
conf_str = yaml_util.dump(conf)
# sort_keys: voluptuous fills defaults in set order, so an
# unsorted dump would churn main.cpp and relink every run
conf_str = yaml_util.dump(conf, sort_keys=True)
conf_str = conf_str.replace("//", "")
# remove tailing \ to avoid multi-line comment warning
conf_str = conf_str.replace("\\\n", "\n")
+26
View File
@@ -7130,3 +7130,29 @@ def test_warn_source_tree_mismatch_falls_back_when_stat_fails(
# Same tree, so the path comparison still finds them equal and stays silent
assert not caplog.text
@pytest.mark.asyncio
async def test_wrap_to_code_comment_is_insertion_order_independent() -> None:
"""The config comment dumps with sorted keys: voluptuous fills schema
defaults in set-iteration order, so an unsorted dump would churn
main.cpp and relink the firmware on every run."""
from types import SimpleNamespace
from esphome import yaml_util
from esphome.__main__ import _wrap_to_code
comments: list[str] = []
async def to_code(conf):
pass
comp = SimpleNamespace(to_code=to_code, config_schema=object())
wrapped = _wrap_to_code("demo", comp, yaml_util)
with patch("esphome.codegen.add", side_effect=lambda st: comments.append(str(st))):
await wrapped({"beta": 1, "alpha": 2})
first = list(comments)
comments.clear()
await wrapped({"alpha": 2, "beta": 1})
assert first == comments
assert "alpha: 2" in comments[1]