mirror of
https://github.com/home-assistant/core.git
synced 2025-07-16 09:47:13 +00:00
Cache transient templates compiles provided via api (#89065)
* Cache transient templates compiles provided via api partially fixes #89047 (there is more going on here) * add a bit more coverage just to be sure * switch method * Revert "switch method" This reverts commit 0e9e1c8cbe8753159f4fd6775cdc9cf217d66f0e. * tweak * hold hass * empty for github flakey
This commit is contained in:
parent
322eb4bd83
commit
d4c28a1f4a
@ -1,5 +1,6 @@
|
|||||||
"""Rest API for Home Assistant."""
|
"""Rest API for Home Assistant."""
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from functools import lru_cache
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
@ -350,6 +351,12 @@ class APIComponentsView(HomeAssistantView):
|
|||||||
return self.json(request.app["hass"].config.components)
|
return self.json(request.app["hass"].config.components)
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache
|
||||||
|
def _cached_template(template_str: str, hass: ha.HomeAssistant) -> template.Template:
|
||||||
|
"""Return a cached template."""
|
||||||
|
return template.Template(template_str, hass)
|
||||||
|
|
||||||
|
|
||||||
class APITemplateView(HomeAssistantView):
|
class APITemplateView(HomeAssistantView):
|
||||||
"""View to handle Template requests."""
|
"""View to handle Template requests."""
|
||||||
|
|
||||||
@ -362,7 +369,7 @@ class APITemplateView(HomeAssistantView):
|
|||||||
raise Unauthorized()
|
raise Unauthorized()
|
||||||
try:
|
try:
|
||||||
data = await request.json()
|
data = await request.json()
|
||||||
tpl = template.Template(data["template"], request.app["hass"])
|
tpl = _cached_template(data["template"], request.app["hass"])
|
||||||
return tpl.async_render(variables=data.get("variables"), parse_result=False)
|
return tpl.async_render(variables=data.get("variables"), parse_result=False)
|
||||||
except (ValueError, TemplateError) as ex:
|
except (ValueError, TemplateError) as ex:
|
||||||
return self.json_message(
|
return self.json_message(
|
||||||
|
@ -4,7 +4,7 @@ from __future__ import annotations
|
|||||||
import asyncio
|
import asyncio
|
||||||
from collections.abc import Callable, Coroutine
|
from collections.abc import Callable, Coroutine
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
from functools import wraps
|
from functools import lru_cache, wraps
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
import logging
|
import logging
|
||||||
import secrets
|
import secrets
|
||||||
@ -365,6 +365,12 @@ async def webhook_stream_camera(
|
|||||||
return webhook_response(resp, registration=config_entry.data)
|
return webhook_response(resp, registration=config_entry.data)
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache
|
||||||
|
def _cached_template(template_str: str, hass: HomeAssistant) -> template.Template:
|
||||||
|
"""Return a cached template."""
|
||||||
|
return template.Template(template_str, hass)
|
||||||
|
|
||||||
|
|
||||||
@WEBHOOK_COMMANDS.register("render_template")
|
@WEBHOOK_COMMANDS.register("render_template")
|
||||||
@validate_schema(
|
@validate_schema(
|
||||||
{
|
{
|
||||||
@ -381,7 +387,7 @@ async def webhook_render_template(
|
|||||||
resp = {}
|
resp = {}
|
||||||
for key, item in data.items():
|
for key, item in data.items():
|
||||||
try:
|
try:
|
||||||
tpl = template.Template(item[ATTR_TEMPLATE], hass)
|
tpl = _cached_template(item[ATTR_TEMPLATE], hass)
|
||||||
resp[key] = tpl.async_render(item.get(ATTR_TEMPLATE_VARIABLES))
|
resp[key] = tpl.async_render(item.get(ATTR_TEMPLATE_VARIABLES))
|
||||||
except TemplateError as ex:
|
except TemplateError as ex:
|
||||||
resp[key] = {"error": str(ex)}
|
resp[key] = {"error": str(ex)}
|
||||||
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
|||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
import datetime as dt
|
import datetime as dt
|
||||||
|
from functools import lru_cache
|
||||||
import json
|
import json
|
||||||
from typing import Any, cast
|
from typing import Any, cast
|
||||||
|
|
||||||
@ -424,6 +425,12 @@ def handle_ping(
|
|||||||
connection.send_message(pong_message(msg["id"]))
|
connection.send_message(pong_message(msg["id"]))
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache
|
||||||
|
def _cached_template(template_str: str, hass: HomeAssistant) -> template.Template:
|
||||||
|
"""Return a cached template."""
|
||||||
|
return template.Template(template_str, hass)
|
||||||
|
|
||||||
|
|
||||||
@decorators.websocket_command(
|
@decorators.websocket_command(
|
||||||
{
|
{
|
||||||
vol.Required("type"): "render_template",
|
vol.Required("type"): "render_template",
|
||||||
@ -440,7 +447,7 @@ async def handle_render_template(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Handle render_template command."""
|
"""Handle render_template command."""
|
||||||
template_str = msg["template"]
|
template_str = msg["template"]
|
||||||
template_obj = template.Template(template_str, hass)
|
template_obj = _cached_template(template_str, hass)
|
||||||
variables = msg.get("variables")
|
variables = msg.get("variables")
|
||||||
timeout = msg.get("timeout")
|
timeout = msg.get("timeout")
|
||||||
info = None
|
info = None
|
||||||
|
@ -349,6 +349,52 @@ async def test_api_template(hass: HomeAssistant, mock_api_client: TestClient) ->
|
|||||||
|
|
||||||
assert body == "10"
|
assert body == "10"
|
||||||
|
|
||||||
|
hass.states.async_set("sensor.temperature", 20)
|
||||||
|
resp = await mock_api_client.post(
|
||||||
|
const.URL_API_TEMPLATE,
|
||||||
|
json={"template": "{{ states.sensor.temperature.state }}"},
|
||||||
|
)
|
||||||
|
|
||||||
|
body = await resp.text()
|
||||||
|
|
||||||
|
assert body == "20"
|
||||||
|
|
||||||
|
hass.states.async_remove("sensor.temperature")
|
||||||
|
resp = await mock_api_client.post(
|
||||||
|
const.URL_API_TEMPLATE,
|
||||||
|
json={"template": "{{ states.sensor.temperature.state }}"},
|
||||||
|
)
|
||||||
|
|
||||||
|
body = await resp.text()
|
||||||
|
|
||||||
|
assert body == ""
|
||||||
|
|
||||||
|
|
||||||
|
async def test_api_template_cached(
|
||||||
|
hass: HomeAssistant, mock_api_client: TestClient
|
||||||
|
) -> None:
|
||||||
|
"""Test the template API uses the cache."""
|
||||||
|
hass.states.async_set("sensor.temperature", 30)
|
||||||
|
|
||||||
|
resp = await mock_api_client.post(
|
||||||
|
const.URL_API_TEMPLATE,
|
||||||
|
json={"template": "{{ states.sensor.temperature.state }}"},
|
||||||
|
)
|
||||||
|
|
||||||
|
body = await resp.text()
|
||||||
|
|
||||||
|
assert body == "30"
|
||||||
|
|
||||||
|
hass.states.async_set("sensor.temperature", 40)
|
||||||
|
resp = await mock_api_client.post(
|
||||||
|
const.URL_API_TEMPLATE,
|
||||||
|
json={"template": "{{ states.sensor.temperature.state }}"},
|
||||||
|
)
|
||||||
|
|
||||||
|
body = await resp.text()
|
||||||
|
|
||||||
|
assert body == "40"
|
||||||
|
|
||||||
|
|
||||||
async def test_api_template_error(
|
async def test_api_template_error(
|
||||||
hass: HomeAssistant, mock_api_client: TestClient
|
hass: HomeAssistant, mock_api_client: TestClient
|
||||||
|
Loading…
x
Reference in New Issue
Block a user