[substitutions] refactor substitute() as a pure function (package refactor part 3) (#15031)

Co-authored-by: J. Nick Koston <nick@home-assistant.io>
This commit is contained in:
Javier Peletier
2026-03-23 14:28:04 -10:00
committed by GitHub
co-authored by J. Nick Koston
parent 69911c3db1
commit df4318505f
3 changed files with 82 additions and 66 deletions
+40 -6
View File
@@ -550,8 +550,8 @@ def test_lambda_substitution() -> None:
"lambda": lam,
}
)
substitutions.do_substitution_pass(config)
assert lam.value == "return 42;"
config = substitutions.do_substitution_pass(config)
assert config["lambda"].value == "return 42;"
def test_lambda_no_substitution_unchanged() -> None:
@@ -564,8 +564,8 @@ def test_lambda_no_substitution_unchanged() -> None:
"lambda": lam,
}
)
substitutions.do_substitution_pass(config)
assert lam.value is original_value
config = substitutions.do_substitution_pass(config)
assert config["lambda"].value is original_value
def test_extend_substitution() -> None:
@@ -577,8 +577,42 @@ def test_extend_substitution() -> None:
"sensor": ext,
}
)
substitutions.do_substitution_pass(config)
assert ext.value == "my_sensor"
config = substitutions.do_substitution_pass(config)
assert config["sensor"].value == "my_sensor"
def test_substitute_does_not_mutate_input() -> None:
"""substitute() must return a new tree without modifying the original."""
inner_list = ["${var}", "static"]
inner_dict = OrderedDict({"key": "${var}"})
lam = Lambda("return ${var};")
config = OrderedDict(
{
"a_list": inner_list,
"a_dict": inner_dict,
"a_lambda": lam,
"plain": "${var}",
}
)
context = substitutions.ContextVars({"var": "replaced"})
result = substitutions.substitute(config, [], context, strict_undefined=True)
# Result has substitutions applied
assert result["plain"] == "replaced"
assert result["a_list"] == ["replaced", "static"]
assert result["a_dict"]["key"] == "replaced"
assert result["a_lambda"].value == "return replaced;"
# Original input is untouched
assert config["plain"] == "${var}"
assert inner_list == ["${var}", "static"]
assert inner_dict["key"] == "${var}"
assert lam.value == "return ${var};"
# Containers are new objects, not the originals
assert result["a_list"] is not inner_list
assert result["a_dict"] is not inner_dict
assert result["a_lambda"] is not lam
def test_do_substitution_pass_substitutions_must_be_mapping_from_config() -> None: