sort so config hash does not change

This commit is contained in:
J. Nick Koston
2025-12-13 09:40:26 -06:00
parent cf8708b888
commit b4a54f2df1
3 changed files with 40 additions and 3 deletions
+2 -1
View File
@@ -693,12 +693,13 @@ class EsphomeCore:
"""Get the FNV-1a 32-bit hash of the config.
The hash is computed lazily and cached for performance.
Uses sort_keys=True to ensure deterministic ordering.
"""
if self._config_hash is None:
from esphome import yaml_util
from esphome.helpers import fnv1a_32bit_hash
config_str = yaml_util.dump(self.config, show_secrets=True)
config_str = yaml_util.dump(self.config, show_secrets=True, sort_keys=True)
self._config_hash = fnv1a_32bit_hash(config_str)
return self._config_hash
+10 -2
View File
@@ -1,6 +1,7 @@
from __future__ import annotations
from collections.abc import Callable
from contextlib import suppress
import functools
import inspect
from io import BytesIO, TextIOBase, TextIOWrapper
@@ -501,13 +502,17 @@ def _load_yaml_internal_with_type(
loader.dispose()
def dump(dict_, show_secrets=False):
def dump(dict_, show_secrets=False, sort_keys=False):
"""Dump YAML to a string and remove null."""
if show_secrets:
_SECRET_VALUES.clear()
_SECRET_CACHE.clear()
return yaml.dump(
dict_, default_flow_style=False, allow_unicode=True, Dumper=ESPHomeDumper
dict_,
default_flow_style=False,
allow_unicode=True,
Dumper=ESPHomeDumper,
sort_keys=sort_keys,
)
@@ -543,6 +548,9 @@ class ESPHomeDumper(yaml.SafeDumper):
best_style = True
if hasattr(mapping, "items"):
mapping = list(mapping.items())
if self.sort_keys:
with suppress(TypeError):
mapping = sorted(mapping)
for item_key, item_value in mapping:
node_key = self.represent_data(item_key)
node_value = self.represent_data(item_value)
+28
View File
@@ -278,3 +278,31 @@ def test_secret_values_tracking(fixture_path: Path) -> None:
assert yaml_util._SECRET_VALUES["super_secret_wifi"] == "wifi_password"
assert "0123456789abcdef" in yaml_util._SECRET_VALUES
assert yaml_util._SECRET_VALUES["0123456789abcdef"] == "api_key"
def test_dump_sort_keys() -> None:
"""Test that dump with sort_keys=True produces sorted output."""
# Create a dict with unsorted keys
data = {
"zebra": 1,
"alpha": 2,
"nested": {
"z_key": "z_value",
"a_key": "a_value",
},
}
# Without sort_keys, keys are in insertion order
unsorted = yaml_util.dump(data, sort_keys=False)
lines_unsorted = unsorted.strip().split("\n")
# First key should be "zebra" (insertion order)
assert lines_unsorted[0].startswith("zebra:")
# With sort_keys, keys are alphabetically sorted
sorted_dump = yaml_util.dump(data, sort_keys=True)
lines_sorted = sorted_dump.strip().split("\n")
# First key should be "alpha" (alphabetical order)
assert lines_sorted[0].startswith("alpha:")
# nested keys should also be sorted
assert "a_key:" in sorted_dump
assert sorted_dump.index("a_key:") < sorted_dump.index("z_key:")