Pass hass instance when validating templates (#89242)
* Pass hass instance when validating templates * Update tests * Fix validating templates without hass * Update service tests
This commit is contained in:
parent
b0013247ff
commit
18cb53a35c
3 changed files with 97 additions and 14 deletions
|
@ -85,7 +85,12 @@ from homeassistant.const import (
|
||||||
WEEKDAYS,
|
WEEKDAYS,
|
||||||
UnitOfTemperature,
|
UnitOfTemperature,
|
||||||
)
|
)
|
||||||
from homeassistant.core import split_entity_id, valid_entity_id
|
from homeassistant.core import (
|
||||||
|
HomeAssistant,
|
||||||
|
async_get_hass,
|
||||||
|
split_entity_id,
|
||||||
|
valid_entity_id,
|
||||||
|
)
|
||||||
from homeassistant.exceptions import TemplateError
|
from homeassistant.exceptions import TemplateError
|
||||||
from homeassistant.generated import currencies
|
from homeassistant.generated import currencies
|
||||||
from homeassistant.generated.countries import COUNTRIES
|
from homeassistant.generated.countries import COUNTRIES
|
||||||
|
@ -597,7 +602,11 @@ def template(value: Any | None) -> template_helper.Template:
|
||||||
if isinstance(value, (list, dict, template_helper.Template)):
|
if isinstance(value, (list, dict, template_helper.Template)):
|
||||||
raise vol.Invalid("template value should be a string")
|
raise vol.Invalid("template value should be a string")
|
||||||
|
|
||||||
template_value = template_helper.Template(str(value))
|
hass: HomeAssistant | None = None
|
||||||
|
with contextlib.suppress(LookupError):
|
||||||
|
hass = async_get_hass()
|
||||||
|
|
||||||
|
template_value = template_helper.Template(str(value), hass)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
template_value.ensure_valid()
|
template_value.ensure_valid()
|
||||||
|
@ -615,7 +624,12 @@ def dynamic_template(value: Any | None) -> template_helper.Template:
|
||||||
if not template_helper.is_template_string(str(value)):
|
if not template_helper.is_template_string(str(value)):
|
||||||
raise vol.Invalid("template value does not contain a dynamic template")
|
raise vol.Invalid("template value does not contain a dynamic template")
|
||||||
|
|
||||||
template_value = template_helper.Template(str(value))
|
hass: HomeAssistant | None = None
|
||||||
|
with contextlib.suppress(LookupError):
|
||||||
|
hass = async_get_hass()
|
||||||
|
|
||||||
|
template_value = template_helper.Template(str(value), hass)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
template_value.ensure_valid()
|
template_value.ensure_valid()
|
||||||
return template_value
|
return template_value
|
||||||
|
|
|
@ -561,11 +561,16 @@ def test_x10_address() -> None:
|
||||||
schema("C11")
|
schema("C11")
|
||||||
|
|
||||||
|
|
||||||
def test_template() -> None:
|
def test_template(hass: HomeAssistant) -> None:
|
||||||
"""Test template validator."""
|
"""Test template validator."""
|
||||||
schema = vol.Schema(cv.template)
|
schema = vol.Schema(cv.template)
|
||||||
|
|
||||||
for value in (None, "{{ partial_print }", "{% if True %}Hello", ["test"]):
|
for value in (
|
||||||
|
None,
|
||||||
|
"{{ partial_print }",
|
||||||
|
"{% if True %}Hello",
|
||||||
|
["test"],
|
||||||
|
):
|
||||||
with pytest.raises(vol.Invalid):
|
with pytest.raises(vol.Invalid):
|
||||||
schema(value)
|
schema(value)
|
||||||
|
|
||||||
|
@ -574,12 +579,43 @@ def test_template() -> None:
|
||||||
"Hello",
|
"Hello",
|
||||||
"{{ beer }}",
|
"{{ beer }}",
|
||||||
"{% if 1 == 1 %}Hello{% else %}World{% endif %}",
|
"{% if 1 == 1 %}Hello{% else %}World{% endif %}",
|
||||||
|
# Function added as an extension by Home Assistant
|
||||||
|
"{{ expand('group.foo')|map(attribute='entity_id')|list }}",
|
||||||
|
# Filter added as an extension by Home Assistant
|
||||||
|
"{{ ['group.foo']|expand|map(attribute='entity_id')|list }}",
|
||||||
)
|
)
|
||||||
for value in options:
|
for value in options:
|
||||||
schema(value)
|
schema(value)
|
||||||
|
|
||||||
|
|
||||||
def test_dynamic_template() -> None:
|
async def test_template_no_hass(hass: HomeAssistant) -> None:
|
||||||
|
"""Test template validator."""
|
||||||
|
schema = vol.Schema(cv.template)
|
||||||
|
|
||||||
|
for value in (
|
||||||
|
None,
|
||||||
|
"{{ partial_print }",
|
||||||
|
"{% if True %}Hello",
|
||||||
|
["test"],
|
||||||
|
# Filter added as an extension by Home Assistant
|
||||||
|
"{{ ['group.foo']|expand|map(attribute='entity_id')|list }}",
|
||||||
|
):
|
||||||
|
with pytest.raises(vol.Invalid):
|
||||||
|
await hass.async_add_executor_job(schema, value)
|
||||||
|
|
||||||
|
options = (
|
||||||
|
1,
|
||||||
|
"Hello",
|
||||||
|
"{{ beer }}",
|
||||||
|
"{% if 1 == 1 %}Hello{% else %}World{% endif %}",
|
||||||
|
# Function added as an extension by Home Assistant
|
||||||
|
"{{ expand('group.foo')|map(attribute='entity_id')|list }}",
|
||||||
|
)
|
||||||
|
for value in options:
|
||||||
|
await hass.async_add_executor_job(schema, value)
|
||||||
|
|
||||||
|
|
||||||
|
def test_dynamic_template(hass: HomeAssistant) -> None:
|
||||||
"""Test dynamic template validator."""
|
"""Test dynamic template validator."""
|
||||||
schema = vol.Schema(cv.dynamic_template)
|
schema = vol.Schema(cv.dynamic_template)
|
||||||
|
|
||||||
|
@ -597,11 +633,42 @@ def test_dynamic_template() -> None:
|
||||||
options = (
|
options = (
|
||||||
"{{ beer }}",
|
"{{ beer }}",
|
||||||
"{% if 1 == 1 %}Hello{% else %}World{% endif %}",
|
"{% if 1 == 1 %}Hello{% else %}World{% endif %}",
|
||||||
|
# Function added as an extension by Home Assistant
|
||||||
|
"{{ expand('group.foo')|map(attribute='entity_id')|list }}",
|
||||||
|
# Filter added as an extension by Home Assistant
|
||||||
|
"{{ ['group.foo']|expand|map(attribute='entity_id')|list }}",
|
||||||
)
|
)
|
||||||
for value in options:
|
for value in options:
|
||||||
schema(value)
|
schema(value)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_dynamic_template_no_hass(hass: HomeAssistant) -> None:
|
||||||
|
"""Test dynamic template validator."""
|
||||||
|
schema = vol.Schema(cv.dynamic_template)
|
||||||
|
|
||||||
|
for value in (
|
||||||
|
None,
|
||||||
|
1,
|
||||||
|
"{{ partial_print }",
|
||||||
|
"{% if True %}Hello",
|
||||||
|
["test"],
|
||||||
|
"just a string",
|
||||||
|
# Filter added as an extension by Home Assistant
|
||||||
|
"{{ ['group.foo']|expand|map(attribute='entity_id')|list }}",
|
||||||
|
):
|
||||||
|
with pytest.raises(vol.Invalid):
|
||||||
|
await hass.async_add_executor_job(schema, value)
|
||||||
|
|
||||||
|
options = (
|
||||||
|
"{{ beer }}",
|
||||||
|
"{% if 1 == 1 %}Hello{% else %}World{% endif %}",
|
||||||
|
# Function added as an extension by Home Assistant
|
||||||
|
"{{ expand('group.foo')|map(attribute='entity_id')|list }}",
|
||||||
|
)
|
||||||
|
for value in options:
|
||||||
|
await hass.async_add_executor_job(schema, value)
|
||||||
|
|
||||||
|
|
||||||
def test_template_complex() -> None:
|
def test_template_complex() -> None:
|
||||||
"""Test template_complex validator."""
|
"""Test template_complex validator."""
|
||||||
schema = vol.Schema(cv.template_complex)
|
schema = vol.Schema(cv.template_complex)
|
||||||
|
|
|
@ -383,16 +383,18 @@ async def test_split_entity_string(hass: HomeAssistant):
|
||||||
async def test_not_mutate_input(hass: HomeAssistant):
|
async def test_not_mutate_input(hass: HomeAssistant):
|
||||||
"""Test for immutable input."""
|
"""Test for immutable input."""
|
||||||
async_mock_service(hass, "test_domain", "test_service")
|
async_mock_service(hass, "test_domain", "test_service")
|
||||||
config = cv.SERVICE_SCHEMA(
|
config = {
|
||||||
{
|
"service": "test_domain.test_service",
|
||||||
"service": "test_domain.test_service",
|
"entity_id": "hello.world, sensor.beer",
|
||||||
"entity_id": "hello.world, sensor.beer",
|
"data": {"hello": 1},
|
||||||
"data": {"hello": 1},
|
"data_template": {"nested": {"value": "{{ 1 + 1 }}"}},
|
||||||
"data_template": {"nested": {"value": "{{ 1 + 1 }}"}},
|
}
|
||||||
}
|
|
||||||
)
|
|
||||||
orig = deepcopy(config)
|
orig = deepcopy(config)
|
||||||
|
|
||||||
|
# Validate both the original and the copy
|
||||||
|
config = cv.SERVICE_SCHEMA(config)
|
||||||
|
orig = cv.SERVICE_SCHEMA(orig)
|
||||||
|
|
||||||
# Only change after call is each template getting hass attached
|
# Only change after call is each template getting hass attached
|
||||||
template.attach(hass, orig)
|
template.attach(hass, orig)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue