Add native Python types support to templates (#41227)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
This commit is contained in:
parent
cbb4324c84
commit
ee914366a8
29 changed files with 349 additions and 282 deletions
|
@ -410,7 +410,7 @@ class APITemplateView(HomeAssistantView):
|
||||||
try:
|
try:
|
||||||
data = await request.json()
|
data = await request.json()
|
||||||
tpl = template.Template(data["template"], request.app["hass"])
|
tpl = template.Template(data["template"], request.app["hass"])
|
||||||
return tpl.async_render(data.get("variables"))
|
return str(tpl.async_render(data.get("variables")))
|
||||||
except (ValueError, TemplateError) as ex:
|
except (ValueError, TemplateError) as ex:
|
||||||
return self.json_message(
|
return self.json_message(
|
||||||
f"Error rendering template: {ex}", HTTP_BAD_REQUEST
|
f"Error rendering template: {ex}", HTTP_BAD_REQUEST
|
||||||
|
|
|
@ -271,7 +271,7 @@ class HistoryStatsSensor(Entity):
|
||||||
except (TemplateError, TypeError) as ex:
|
except (TemplateError, TypeError) as ex:
|
||||||
HistoryStatsHelper.handle_template_exception(ex, "start")
|
HistoryStatsHelper.handle_template_exception(ex, "start")
|
||||||
return
|
return
|
||||||
start = dt_util.parse_datetime(start_rendered)
|
start = dt_util.parse_datetime(str(start_rendered))
|
||||||
if start is None:
|
if start is None:
|
||||||
try:
|
try:
|
||||||
start = dt_util.as_local(
|
start = dt_util.as_local(
|
||||||
|
|
|
@ -258,7 +258,7 @@ class CoverTemplate(TemplateEntity, CoverEntity):
|
||||||
self._position = None
|
self._position = None
|
||||||
return
|
return
|
||||||
|
|
||||||
state = result.lower()
|
state = str(result).lower()
|
||||||
if state in _VALID_STATES:
|
if state in _VALID_STATES:
|
||||||
if state in ("true", STATE_OPEN):
|
if state in ("true", STATE_OPEN):
|
||||||
self._position = 100
|
self._position = 100
|
||||||
|
|
|
@ -367,6 +367,7 @@ class TemplateFan(TemplateEntity, FanEntity):
|
||||||
@callback
|
@callback
|
||||||
def _update_speed(self, speed):
|
def _update_speed(self, speed):
|
||||||
# Validate speed
|
# Validate speed
|
||||||
|
speed = str(speed)
|
||||||
if speed in self._speed_list:
|
if speed in self._speed_list:
|
||||||
self._speed = speed
|
self._speed = speed
|
||||||
elif speed in [STATE_UNAVAILABLE, STATE_UNKNOWN]:
|
elif speed in [STATE_UNAVAILABLE, STATE_UNKNOWN]:
|
||||||
|
|
|
@ -412,7 +412,7 @@ class LightTemplate(TemplateEntity, LightEntity):
|
||||||
self._available = True
|
self._available = True
|
||||||
return
|
return
|
||||||
|
|
||||||
state = result.lower()
|
state = str(result).lower()
|
||||||
if state in _VALID_STATES:
|
if state in _VALID_STATES:
|
||||||
self._state = state in ("true", STATE_ON)
|
self._state = state in ("true", STATE_ON)
|
||||||
else:
|
else:
|
||||||
|
@ -451,12 +451,17 @@ class LightTemplate(TemplateEntity, LightEntity):
|
||||||
@callback
|
@callback
|
||||||
def _update_color(self, render):
|
def _update_color(self, render):
|
||||||
"""Update the hs_color from the template."""
|
"""Update the hs_color from the template."""
|
||||||
if render in ("None", ""):
|
h_str = s_str = None
|
||||||
self._color = None
|
if isinstance(render, str):
|
||||||
return
|
if render in ("None", ""):
|
||||||
h_str, s_str = map(
|
self._color = None
|
||||||
float, render.replace("(", "").replace(")", "").split(",", 1)
|
return
|
||||||
)
|
h_str, s_str = map(
|
||||||
|
float, render.replace("(", "").replace(")", "").split(",", 1)
|
||||||
|
)
|
||||||
|
elif isinstance(render, (list, tuple)) and len(render) == 2:
|
||||||
|
h_str, s_str = render
|
||||||
|
|
||||||
if (
|
if (
|
||||||
h_str is not None
|
h_str is not None
|
||||||
and s_str is not None
|
and s_str is not None
|
||||||
|
|
|
@ -120,7 +120,16 @@ class TemplateLock(TemplateEntity, LockEntity):
|
||||||
if isinstance(result, TemplateError):
|
if isinstance(result, TemplateError):
|
||||||
self._state = None
|
self._state = None
|
||||||
return
|
return
|
||||||
self._state = result.lower() in ("true", STATE_ON, STATE_LOCKED)
|
|
||||||
|
if isinstance(result, bool):
|
||||||
|
self._state = result
|
||||||
|
return
|
||||||
|
|
||||||
|
if isinstance(result, str):
|
||||||
|
self._state = result.lower() in ("true", STATE_ON, STATE_LOCKED)
|
||||||
|
return
|
||||||
|
|
||||||
|
self._state = False
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
async def async_added_to_hass(self):
|
||||||
"""Register callbacks."""
|
"""Register callbacks."""
|
||||||
|
|
|
@ -136,7 +136,16 @@ class SwitchTemplate(TemplateEntity, SwitchEntity, RestoreEntity):
|
||||||
if isinstance(result, TemplateError):
|
if isinstance(result, TemplateError):
|
||||||
self._state = None
|
self._state = None
|
||||||
return
|
return
|
||||||
self._state = result.lower() in ("true", STATE_ON)
|
|
||||||
|
if isinstance(result, bool):
|
||||||
|
self._state = result
|
||||||
|
return
|
||||||
|
|
||||||
|
if isinstance(result, str):
|
||||||
|
self._state = result.lower() in ("true", STATE_ON)
|
||||||
|
return
|
||||||
|
|
||||||
|
self._state = False
|
||||||
|
|
||||||
async def async_added_to_hass(self):
|
async def async_added_to_hass(self):
|
||||||
"""Register callbacks."""
|
"""Register callbacks."""
|
||||||
|
|
|
@ -32,6 +32,7 @@ from homeassistant.const import (
|
||||||
CONF_ID,
|
CONF_ID,
|
||||||
CONF_INTERNAL_URL,
|
CONF_INTERNAL_URL,
|
||||||
CONF_LATITUDE,
|
CONF_LATITUDE,
|
||||||
|
CONF_LEGACY_TEMPLATES,
|
||||||
CONF_LONGITUDE,
|
CONF_LONGITUDE,
|
||||||
CONF_MEDIA_DIRS,
|
CONF_MEDIA_DIRS,
|
||||||
CONF_NAME,
|
CONF_NAME,
|
||||||
|
@ -224,6 +225,7 @@ CORE_CONFIG_SCHEMA = CUSTOMIZE_CONFIG_SCHEMA.extend(
|
||||||
),
|
),
|
||||||
# pylint: disable=no-value-for-parameter
|
# pylint: disable=no-value-for-parameter
|
||||||
vol.Optional(CONF_MEDIA_DIRS): cv.schema_with_slug_keys(vol.IsDir()),
|
vol.Optional(CONF_MEDIA_DIRS): cv.schema_with_slug_keys(vol.IsDir()),
|
||||||
|
vol.Optional(CONF_LEGACY_TEMPLATES): cv.boolean,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -500,6 +502,7 @@ async def async_process_ha_core_config(hass: HomeAssistant, config: Dict) -> Non
|
||||||
(CONF_INTERNAL_URL, "internal_url"),
|
(CONF_INTERNAL_URL, "internal_url"),
|
||||||
(CONF_EXTERNAL_URL, "external_url"),
|
(CONF_EXTERNAL_URL, "external_url"),
|
||||||
(CONF_MEDIA_DIRS, "media_dirs"),
|
(CONF_MEDIA_DIRS, "media_dirs"),
|
||||||
|
(CONF_LEGACY_TEMPLATES, "legacy_templates"),
|
||||||
):
|
):
|
||||||
if key in config:
|
if key in config:
|
||||||
setattr(hac, attr, config[key])
|
setattr(hac, attr, config[key])
|
||||||
|
|
|
@ -112,6 +112,7 @@ CONF_INCLUDE = "include"
|
||||||
CONF_INTERNAL_URL = "internal_url"
|
CONF_INTERNAL_URL = "internal_url"
|
||||||
CONF_IP_ADDRESS = "ip_address"
|
CONF_IP_ADDRESS = "ip_address"
|
||||||
CONF_LATITUDE = "latitude"
|
CONF_LATITUDE = "latitude"
|
||||||
|
CONF_LEGACY_TEMPLATES = "legacy_templates"
|
||||||
CONF_LIGHTS = "lights"
|
CONF_LIGHTS = "lights"
|
||||||
CONF_LONGITUDE = "longitude"
|
CONF_LONGITUDE = "longitude"
|
||||||
CONF_MAC = "mac"
|
CONF_MAC = "mac"
|
||||||
|
|
|
@ -1427,6 +1427,9 @@ class Config:
|
||||||
# If Home Assistant is running in safe mode
|
# If Home Assistant is running in safe mode
|
||||||
self.safe_mode: bool = False
|
self.safe_mode: bool = False
|
||||||
|
|
||||||
|
# Use legacy template behavior
|
||||||
|
self.legacy_templates: bool = False
|
||||||
|
|
||||||
def distance(self, lat: float, lon: float) -> Optional[float]:
|
def distance(self, lat: float, lon: float) -> Optional[float]:
|
||||||
"""Calculate distance from Home Assistant.
|
"""Calculate distance from Home Assistant.
|
||||||
|
|
||||||
|
|
|
@ -458,7 +458,10 @@ def async_template(
|
||||||
_LOGGER.error("Error during template condition: %s", ex)
|
_LOGGER.error("Error during template condition: %s", ex)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return value.lower() == "true"
|
if isinstance(value, bool):
|
||||||
|
return value
|
||||||
|
|
||||||
|
return str(value).lower() == "true"
|
||||||
|
|
||||||
|
|
||||||
def async_template_from_config(
|
def async_template_from_config(
|
||||||
|
|
|
@ -111,8 +111,8 @@ class TrackTemplateResult:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
template: Template
|
template: Template
|
||||||
last_result: Union[str, None, TemplateError]
|
last_result: Any
|
||||||
result: Union[str, TemplateError]
|
result: Any
|
||||||
|
|
||||||
|
|
||||||
def threaded_listener_factory(async_factory: Callable[..., Any]) -> CALLBACK_TYPE:
|
def threaded_listener_factory(async_factory: Callable[..., Any]) -> CALLBACK_TYPE:
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
"""Template helper methods for rendering strings with Home Assistant data."""
|
"""Template helper methods for rendering strings with Home Assistant data."""
|
||||||
|
from ast import literal_eval
|
||||||
import asyncio
|
import asyncio
|
||||||
import base64
|
import base64
|
||||||
import collections.abc
|
import collections.abc
|
||||||
|
@ -302,7 +303,7 @@ class Template:
|
||||||
|
|
||||||
return extract_entities(self.hass, self.template, variables)
|
return extract_entities(self.hass, self.template, variables)
|
||||||
|
|
||||||
def render(self, variables: TemplateVarsType = None, **kwargs: Any) -> str:
|
def render(self, variables: TemplateVarsType = None, **kwargs: Any) -> Any:
|
||||||
"""Render given template."""
|
"""Render given template."""
|
||||||
if self.is_static:
|
if self.is_static:
|
||||||
return self.template.strip()
|
return self.template.strip()
|
||||||
|
@ -315,7 +316,7 @@ class Template:
|
||||||
).result()
|
).result()
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_render(self, variables: TemplateVarsType = None, **kwargs: Any) -> str:
|
def async_render(self, variables: TemplateVarsType = None, **kwargs: Any) -> Any:
|
||||||
"""Render given template.
|
"""Render given template.
|
||||||
|
|
||||||
This method must be run in the event loop.
|
This method must be run in the event loop.
|
||||||
|
@ -329,10 +330,27 @@ class Template:
|
||||||
kwargs.update(variables)
|
kwargs.update(variables)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return compiled.render(kwargs).strip()
|
render_result = compiled.render(kwargs)
|
||||||
except jinja2.TemplateError as err:
|
except jinja2.TemplateError as err:
|
||||||
raise TemplateError(err) from err
|
raise TemplateError(err) from err
|
||||||
|
|
||||||
|
render_result = render_result.strip()
|
||||||
|
|
||||||
|
if not self.hass.config.legacy_templates:
|
||||||
|
try:
|
||||||
|
result = literal_eval(render_result)
|
||||||
|
|
||||||
|
# If the literal_eval result is a string, use the original
|
||||||
|
# render, by not returning right here. The evaluation of strings
|
||||||
|
# resulting in strings impacts quotes, to avoid unexpected
|
||||||
|
# output; use the original render instead of the evaluated one.
|
||||||
|
if not isinstance(result, str):
|
||||||
|
return result
|
||||||
|
except (ValueError, SyntaxError, MemoryError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
return render_result
|
||||||
|
|
||||||
async def async_render_will_timeout(
|
async def async_render_will_timeout(
|
||||||
self, timeout: float, variables: TemplateVarsType = None, **kwargs: Any
|
self, timeout: float, variables: TemplateVarsType = None, **kwargs: Any
|
||||||
) -> bool:
|
) -> bool:
|
||||||
|
|
|
@ -104,7 +104,7 @@ class TestNotifyDemo(unittest.TestCase):
|
||||||
self.hass.block_till_done()
|
self.hass.block_till_done()
|
||||||
last_event = self.events[-1]
|
last_event = self.events[-1]
|
||||||
assert last_event.data[notify.ATTR_TITLE] == "temperature"
|
assert last_event.data[notify.ATTR_TITLE] == "temperature"
|
||||||
assert last_event.data[notify.ATTR_MESSAGE] == "10"
|
assert last_event.data[notify.ATTR_MESSAGE] == 10
|
||||||
|
|
||||||
def test_method_forwards_correct_data(self):
|
def test_method_forwards_correct_data(self):
|
||||||
"""Test that all data from the service gets forwarded to service."""
|
"""Test that all data from the service gets forwarded to service."""
|
||||||
|
|
|
@ -65,7 +65,7 @@ DEFAULT_CONFIG_CODE = {
|
||||||
"name": "test",
|
"name": "test",
|
||||||
"state_topic": "alarm/state",
|
"state_topic": "alarm/state",
|
||||||
"command_topic": "alarm/command",
|
"command_topic": "alarm/command",
|
||||||
"code": "1234",
|
"code": "0123",
|
||||||
"code_arm_required": True,
|
"code_arm_required": True,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -396,7 +396,7 @@ async def test_disarm_publishes_mqtt_with_template(hass, mqtt_mock):
|
||||||
When command_template set to output json
|
When command_template set to output json
|
||||||
"""
|
"""
|
||||||
config = copy.deepcopy(DEFAULT_CONFIG_CODE)
|
config = copy.deepcopy(DEFAULT_CONFIG_CODE)
|
||||||
config[alarm_control_panel.DOMAIN]["code"] = "1234"
|
config[alarm_control_panel.DOMAIN]["code"] = "0123"
|
||||||
config[alarm_control_panel.DOMAIN]["command_template"] = (
|
config[alarm_control_panel.DOMAIN]["command_template"] = (
|
||||||
'{"action":"{{ action }}",' '"code":"{{ code }}"}'
|
'{"action":"{{ action }}",' '"code":"{{ code }}"}'
|
||||||
)
|
)
|
||||||
|
@ -407,9 +407,9 @@ async def test_disarm_publishes_mqtt_with_template(hass, mqtt_mock):
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
await common.async_alarm_disarm(hass, 1234)
|
await common.async_alarm_disarm(hass, "0123")
|
||||||
mqtt_mock.async_publish.assert_called_once_with(
|
mqtt_mock.async_publish.assert_called_once_with(
|
||||||
"alarm/command", '{"action":"DISARM","code":"1234"}', 0, False
|
"alarm/command", {"action": "DISARM", "code": "0123"}, 0, False
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -702,9 +702,7 @@ async def test_set_position_templated(hass, mqtt_mock):
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
mqtt_mock.async_publish.assert_called_once_with(
|
mqtt_mock.async_publish.assert_called_once_with("set-position-topic", 38, 0, False)
|
||||||
"set-position-topic", "38", 0, False
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def test_set_position_untemplated(hass, mqtt_mock):
|
async def test_set_position_untemplated(hass, mqtt_mock):
|
||||||
|
|
|
@ -123,7 +123,7 @@ async def test_service_call_with_template_payload_renders_template(hass, mqtt_mo
|
||||||
mqtt.async_publish_template(hass, "test/topic", "{{ 1+1 }}")
|
mqtt.async_publish_template(hass, "test/topic", "{{ 1+1 }}")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert mqtt_mock.async_publish.called
|
assert mqtt_mock.async_publish.called
|
||||||
assert mqtt_mock.async_publish.call_args[0][1] == "2"
|
assert mqtt_mock.async_publish.call_args[0][1] == 2
|
||||||
|
|
||||||
|
|
||||||
async def test_service_call_with_payload_doesnt_render_template(hass, mqtt_mock):
|
async def test_service_call_with_payload_doesnt_render_template(hass, mqtt_mock):
|
||||||
|
|
|
@ -837,7 +837,7 @@ async def test_sending_mqtt_color_temp_command_with_template(hass, mqtt_mock):
|
||||||
mqtt_mock.async_publish.assert_has_calls(
|
mqtt_mock.async_publish.assert_has_calls(
|
||||||
[
|
[
|
||||||
call("test_light_color_temp/set", "on", 0, False),
|
call("test_light_color_temp/set", "on", 0, False),
|
||||||
call("test_light_color_temp/color_temp/set", "10", 0, False),
|
call("test_light_color_temp/color_temp/set", 10, 0, False),
|
||||||
],
|
],
|
||||||
any_order=True,
|
any_order=True,
|
||||||
)
|
)
|
||||||
|
|
|
@ -705,4 +705,4 @@ async def test_script_variables(hass, caplog):
|
||||||
await hass.services.async_call("script", "script3", {"break": 0}, blocking=True)
|
await hass.services.async_call("script", "script3", {"break": 0}, blocking=True)
|
||||||
|
|
||||||
assert len(mock_calls) == 4
|
assert len(mock_calls) == 4
|
||||||
assert mock_calls[3].data["value"] == "1"
|
assert mock_calls[3].data["value"] == 1
|
||||||
|
|
|
@ -402,7 +402,7 @@ async def test_intent_special_slots(hass, mqtt_mock):
|
||||||
assert len(calls) == 1
|
assert len(calls) == 1
|
||||||
assert calls[0].domain == "light"
|
assert calls[0].domain == "light"
|
||||||
assert calls[0].service == "turn_on"
|
assert calls[0].service == "turn_on"
|
||||||
assert calls[0].data["confidenceScore"] == "0.85"
|
assert calls[0].data["confidenceScore"] == 0.85
|
||||||
assert calls[0].data["site_id"] == "default"
|
assert calls[0].data["site_id"] == "default"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -662,7 +662,7 @@ def _verify(
|
||||||
"""Verify fan's state, speed and osc."""
|
"""Verify fan's state, speed and osc."""
|
||||||
state = hass.states.get(_TEST_FAN)
|
state = hass.states.get(_TEST_FAN)
|
||||||
attributes = state.attributes
|
attributes = state.attributes
|
||||||
assert state.state == expected_state
|
assert state.state == str(expected_state)
|
||||||
assert attributes.get(ATTR_SPEED) == expected_speed
|
assert attributes.get(ATTR_SPEED) == expected_speed
|
||||||
assert attributes.get(ATTR_OSCILLATING) == expected_oscillating
|
assert attributes.get(ATTR_OSCILLATING) == expected_oscillating
|
||||||
assert attributes.get(ATTR_DIRECTION) == expected_direction
|
assert attributes.get(ATTR_DIRECTION) == expected_direction
|
||||||
|
|
|
@ -550,7 +550,7 @@ class TestTemplateLight:
|
||||||
)
|
)
|
||||||
self.hass.block_till_done()
|
self.hass.block_till_done()
|
||||||
assert len(self.calls) == 1
|
assert len(self.calls) == 1
|
||||||
assert self.calls[0].data["white_value"] == "124"
|
assert self.calls[0].data["white_value"] == 124
|
||||||
|
|
||||||
state = self.hass.states.get("light.test_template_light")
|
state = self.hass.states.get("light.test_template_light")
|
||||||
assert state is not None
|
assert state is not None
|
||||||
|
@ -649,7 +649,7 @@ class TestTemplateLight:
|
||||||
common.turn_on(self.hass, "light.test_template_light", **{ATTR_BRIGHTNESS: 124})
|
common.turn_on(self.hass, "light.test_template_light", **{ATTR_BRIGHTNESS: 124})
|
||||||
self.hass.block_till_done()
|
self.hass.block_till_done()
|
||||||
assert len(self.calls) == 1
|
assert len(self.calls) == 1
|
||||||
assert self.calls[0].data["brightness"] == "124"
|
assert self.calls[0].data["brightness"] == 124
|
||||||
|
|
||||||
state = self.hass.states.get("light.test_template_light")
|
state = self.hass.states.get("light.test_template_light")
|
||||||
_LOGGER.info(str(state.attributes))
|
_LOGGER.info(str(state.attributes))
|
||||||
|
@ -802,7 +802,7 @@ class TestTemplateLight:
|
||||||
common.turn_on(self.hass, "light.test_template_light", **{ATTR_COLOR_TEMP: 345})
|
common.turn_on(self.hass, "light.test_template_light", **{ATTR_COLOR_TEMP: 345})
|
||||||
self.hass.block_till_done()
|
self.hass.block_till_done()
|
||||||
assert len(self.calls) == 1
|
assert len(self.calls) == 1
|
||||||
assert self.calls[0].data["color_temp"] == "345"
|
assert self.calls[0].data["color_temp"] == 345
|
||||||
|
|
||||||
state = self.hass.states.get("light.test_template_light")
|
state = self.hass.states.get("light.test_template_light")
|
||||||
_LOGGER.info(str(state.attributes))
|
_LOGGER.info(str(state.attributes))
|
||||||
|
@ -1008,18 +1008,18 @@ class TestTemplateLight:
|
||||||
)
|
)
|
||||||
self.hass.block_till_done()
|
self.hass.block_till_done()
|
||||||
assert len(self.calls) == 2
|
assert len(self.calls) == 2
|
||||||
assert self.calls[0].data["h"] == "40"
|
assert self.calls[0].data["h"] == 40
|
||||||
assert self.calls[0].data["s"] == "50"
|
assert self.calls[0].data["s"] == 50
|
||||||
assert self.calls[1].data["h"] == "40"
|
assert self.calls[1].data["h"] == 40
|
||||||
assert self.calls[1].data["s"] == "50"
|
assert self.calls[1].data["s"] == 50
|
||||||
|
|
||||||
state = self.hass.states.get("light.test_template_light")
|
state = self.hass.states.get("light.test_template_light")
|
||||||
_LOGGER.info(str(state.attributes))
|
_LOGGER.info(str(state.attributes))
|
||||||
assert state is not None
|
assert state is not None
|
||||||
assert self.calls[0].data["h"] == "40"
|
assert self.calls[0].data["h"] == 40
|
||||||
assert self.calls[0].data["s"] == "50"
|
assert self.calls[0].data["s"] == 50
|
||||||
assert self.calls[1].data["h"] == "40"
|
assert self.calls[1].data["h"] == 40
|
||||||
assert self.calls[1].data["s"] == "50"
|
assert self.calls[1].data["s"] == 50
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"expected_hs,template",
|
"expected_hs,template",
|
||||||
|
|
|
@ -867,7 +867,7 @@ async def test_self_referencing_entity_picture_loop(hass, caplog):
|
||||||
|
|
||||||
state = hass.states.get("sensor.test")
|
state = hass.states.get("sensor.test")
|
||||||
assert int(state.state) == 1
|
assert int(state.state) == 1
|
||||||
assert state.attributes[ATTR_ENTITY_PICTURE] == "2"
|
assert state.attributes[ATTR_ENTITY_PICTURE] == 2
|
||||||
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert int(state.state) == 1
|
assert int(state.state) == 1
|
||||||
|
|
|
@ -5,7 +5,7 @@ from homeassistant import config_entries, data_entry_flow, setup
|
||||||
from homeassistant.components.vilfo.const import DOMAIN
|
from homeassistant.components.vilfo.const import DOMAIN
|
||||||
from homeassistant.const import CONF_ACCESS_TOKEN, CONF_HOST, CONF_ID, CONF_MAC
|
from homeassistant.const import CONF_ACCESS_TOKEN, CONF_HOST, CONF_ID, CONF_MAC
|
||||||
|
|
||||||
from tests.async_mock import patch
|
from tests.async_mock import Mock, patch
|
||||||
|
|
||||||
|
|
||||||
async def test_form(hass):
|
async def test_form(hass):
|
||||||
|
@ -29,6 +29,7 @@ async def test_form(hass):
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
{CONF_HOST: "testadmin.vilfo.com", CONF_ACCESS_TOKEN: "test-token"},
|
{CONF_HOST: "testadmin.vilfo.com", CONF_ACCESS_TOKEN: "test-token"},
|
||||||
)
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||||
assert result2["title"] == "testadmin.vilfo.com"
|
assert result2["title"] == "testadmin.vilfo.com"
|
||||||
|
@ -142,7 +143,10 @@ async def test_form_unexpected_exception(hass):
|
||||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||||
)
|
)
|
||||||
|
|
||||||
with patch("vilfo.Client.ping", side_effect=Exception):
|
with patch(
|
||||||
|
"homeassistant.components.vilfo.config_flow.VilfoClient",
|
||||||
|
) as mock_client:
|
||||||
|
mock_client.return_value.ping = Mock(side_effect=Exception)
|
||||||
result2 = await hass.config_entries.flow.async_configure(
|
result2 = await hass.config_entries.flow.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
{"host": "testadmin.vilfo.com", "access_token": "test-token"},
|
{"host": "testadmin.vilfo.com", "access_token": "test-token"},
|
||||||
|
|
|
@ -958,7 +958,7 @@ async def test_track_template_result_complex(hass):
|
||||||
hass.states.async_set("sensor.domain", "light")
|
hass.states.async_set("sensor.domain", "light")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert len(specific_runs) == 1
|
assert len(specific_runs) == 1
|
||||||
assert specific_runs[0].strip() == "['light.one']"
|
assert specific_runs[0] == ["light.one"]
|
||||||
|
|
||||||
assert info.listeners == {
|
assert info.listeners == {
|
||||||
"all": False,
|
"all": False,
|
||||||
|
@ -969,7 +969,7 @@ async def test_track_template_result_complex(hass):
|
||||||
hass.states.async_set("sensor.domain", "lock")
|
hass.states.async_set("sensor.domain", "lock")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert len(specific_runs) == 2
|
assert len(specific_runs) == 2
|
||||||
assert specific_runs[1].strip() == "['lock.one']"
|
assert specific_runs[1] == ["lock.one"]
|
||||||
assert info.listeners == {
|
assert info.listeners == {
|
||||||
"all": False,
|
"all": False,
|
||||||
"domains": {"lock"},
|
"domains": {"lock"},
|
||||||
|
@ -987,7 +987,7 @@ async def test_track_template_result_complex(hass):
|
||||||
hass.states.async_set("sensor.domain", "light")
|
hass.states.async_set("sensor.domain", "light")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert len(specific_runs) == 4
|
assert len(specific_runs) == 4
|
||||||
assert specific_runs[3].strip() == "['light.one']"
|
assert specific_runs[3] == ["light.one"]
|
||||||
assert info.listeners == {
|
assert info.listeners == {
|
||||||
"all": False,
|
"all": False,
|
||||||
"domains": {"light"},
|
"domains": {"light"},
|
||||||
|
@ -1022,7 +1022,7 @@ async def test_track_template_result_complex(hass):
|
||||||
hass.states.async_set("sensor.domain", "lock")
|
hass.states.async_set("sensor.domain", "lock")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert len(specific_runs) == 7
|
assert len(specific_runs) == 7
|
||||||
assert specific_runs[6].strip() == "['lock.one']"
|
assert specific_runs[6] == ["lock.one"]
|
||||||
assert info.listeners == {
|
assert info.listeners == {
|
||||||
"all": False,
|
"all": False,
|
||||||
"domains": {"lock"},
|
"domains": {"lock"},
|
||||||
|
@ -1032,7 +1032,7 @@ async def test_track_template_result_complex(hass):
|
||||||
hass.states.async_set("sensor.domain", "single_binary_sensor")
|
hass.states.async_set("sensor.domain", "single_binary_sensor")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert len(specific_runs) == 8
|
assert len(specific_runs) == 8
|
||||||
assert specific_runs[7].strip() == "unknown"
|
assert specific_runs[7] == "unknown"
|
||||||
assert info.listeners == {
|
assert info.listeners == {
|
||||||
"all": False,
|
"all": False,
|
||||||
"domains": set(),
|
"domains": set(),
|
||||||
|
@ -1042,7 +1042,7 @@ async def test_track_template_result_complex(hass):
|
||||||
hass.states.async_set("binary_sensor.single", "binary_sensor_on")
|
hass.states.async_set("binary_sensor.single", "binary_sensor_on")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert len(specific_runs) == 9
|
assert len(specific_runs) == 9
|
||||||
assert specific_runs[8].strip() == "binary_sensor_on"
|
assert specific_runs[8] == "binary_sensor_on"
|
||||||
assert info.listeners == {
|
assert info.listeners == {
|
||||||
"all": False,
|
"all": False,
|
||||||
"domains": set(),
|
"domains": set(),
|
||||||
|
@ -1052,7 +1052,7 @@ async def test_track_template_result_complex(hass):
|
||||||
hass.states.async_set("sensor.domain", "lock")
|
hass.states.async_set("sensor.domain", "lock")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert len(specific_runs) == 10
|
assert len(specific_runs) == 10
|
||||||
assert specific_runs[9].strip() == "['lock.one']"
|
assert specific_runs[9] == ["lock.one"]
|
||||||
assert info.listeners == {
|
assert info.listeners == {
|
||||||
"all": False,
|
"all": False,
|
||||||
"domains": {"lock"},
|
"domains": {"lock"},
|
||||||
|
@ -1144,13 +1144,13 @@ async def test_track_template_result_with_group(hass):
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert len(specific_runs) == 1
|
assert len(specific_runs) == 1
|
||||||
|
|
||||||
assert specific_runs[0] == str(100.1 + 200.2 + 400.4)
|
assert specific_runs[0] == 100.1 + 200.2 + 400.4
|
||||||
|
|
||||||
hass.states.async_set("sensor.power_3", 0)
|
hass.states.async_set("sensor.power_3", 0)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert len(specific_runs) == 2
|
assert len(specific_runs) == 2
|
||||||
|
|
||||||
assert specific_runs[1] == str(100.1 + 200.2 + 0)
|
assert specific_runs[1] == 100.1 + 200.2 + 0
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.config.load_yaml_config_file",
|
"homeassistant.config.load_yaml_config_file",
|
||||||
|
@ -1165,7 +1165,7 @@ async def test_track_template_result_with_group(hass):
|
||||||
|
|
||||||
info.async_refresh()
|
info.async_refresh()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert specific_runs[-1] == str(100.1 + 200.2 + 0 + 800.8)
|
assert specific_runs[-1] == 100.1 + 200.2 + 0 + 800.8
|
||||||
|
|
||||||
|
|
||||||
async def test_track_template_result_and_conditional(hass):
|
async def test_track_template_result_and_conditional(hass):
|
||||||
|
@ -1421,38 +1421,38 @@ async def test_track_template_rate_limit(hass):
|
||||||
info.async_refresh()
|
info.async_refresh()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert refresh_runs == ["0"]
|
assert refresh_runs == [0]
|
||||||
hass.states.async_set("sensor.one", "any")
|
hass.states.async_set("sensor.one", "any")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert refresh_runs == ["0"]
|
assert refresh_runs == [0]
|
||||||
info.async_refresh()
|
info.async_refresh()
|
||||||
assert refresh_runs == ["0", "1"]
|
assert refresh_runs == [0, 1]
|
||||||
hass.states.async_set("sensor.two", "any")
|
hass.states.async_set("sensor.two", "any")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert refresh_runs == ["0", "1"]
|
assert refresh_runs == [0, 1]
|
||||||
next_time = dt_util.utcnow() + timedelta(seconds=0.125)
|
next_time = dt_util.utcnow() + timedelta(seconds=0.125)
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.helpers.ratelimit.dt_util.utcnow", return_value=next_time
|
"homeassistant.helpers.ratelimit.dt_util.utcnow", return_value=next_time
|
||||||
):
|
):
|
||||||
async_fire_time_changed(hass, next_time)
|
async_fire_time_changed(hass, next_time)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert refresh_runs == ["0", "1", "2"]
|
assert refresh_runs == [0, 1, 2]
|
||||||
hass.states.async_set("sensor.three", "any")
|
hass.states.async_set("sensor.three", "any")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert refresh_runs == ["0", "1", "2"]
|
assert refresh_runs == [0, 1, 2]
|
||||||
hass.states.async_set("sensor.four", "any")
|
hass.states.async_set("sensor.four", "any")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert refresh_runs == ["0", "1", "2"]
|
assert refresh_runs == [0, 1, 2]
|
||||||
next_time = dt_util.utcnow() + timedelta(seconds=0.125 * 2)
|
next_time = dt_util.utcnow() + timedelta(seconds=0.125 * 2)
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.helpers.ratelimit.dt_util.utcnow", return_value=next_time
|
"homeassistant.helpers.ratelimit.dt_util.utcnow", return_value=next_time
|
||||||
):
|
):
|
||||||
async_fire_time_changed(hass, next_time)
|
async_fire_time_changed(hass, next_time)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert refresh_runs == ["0", "1", "2", "4"]
|
assert refresh_runs == [0, 1, 2, 4]
|
||||||
hass.states.async_set("sensor.five", "any")
|
hass.states.async_set("sensor.five", "any")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert refresh_runs == ["0", "1", "2", "4"]
|
assert refresh_runs == [0, 1, 2, 4]
|
||||||
|
|
||||||
|
|
||||||
async def test_track_template_rate_limit_five(hass):
|
async def test_track_template_rate_limit_five(hass):
|
||||||
|
@ -1474,18 +1474,18 @@ async def test_track_template_rate_limit_five(hass):
|
||||||
info.async_refresh()
|
info.async_refresh()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert refresh_runs == ["0"]
|
assert refresh_runs == [0]
|
||||||
hass.states.async_set("sensor.one", "any")
|
hass.states.async_set("sensor.one", "any")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert refresh_runs == ["0"]
|
assert refresh_runs == [0]
|
||||||
info.async_refresh()
|
info.async_refresh()
|
||||||
assert refresh_runs == ["0", "1"]
|
assert refresh_runs == [0, 1]
|
||||||
hass.states.async_set("sensor.two", "any")
|
hass.states.async_set("sensor.two", "any")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert refresh_runs == ["0", "1"]
|
assert refresh_runs == [0, 1]
|
||||||
hass.states.async_set("sensor.three", "any")
|
hass.states.async_set("sensor.three", "any")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert refresh_runs == ["0", "1"]
|
assert refresh_runs == [0, 1]
|
||||||
|
|
||||||
|
|
||||||
async def test_track_template_has_default_rate_limit(hass):
|
async def test_track_template_has_default_rate_limit(hass):
|
||||||
|
@ -1508,18 +1508,18 @@ async def test_track_template_has_default_rate_limit(hass):
|
||||||
info.async_refresh()
|
info.async_refresh()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert refresh_runs == ["1"]
|
assert refresh_runs == [1]
|
||||||
hass.states.async_set("sensor.one", "any")
|
hass.states.async_set("sensor.one", "any")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert refresh_runs == ["1"]
|
assert refresh_runs == [1]
|
||||||
info.async_refresh()
|
info.async_refresh()
|
||||||
assert refresh_runs == ["1", "2"]
|
assert refresh_runs == [1, 2]
|
||||||
hass.states.async_set("sensor.two", "any")
|
hass.states.async_set("sensor.two", "any")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert refresh_runs == ["1", "2"]
|
assert refresh_runs == [1, 2]
|
||||||
hass.states.async_set("sensor.three", "any")
|
hass.states.async_set("sensor.three", "any")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert refresh_runs == ["1", "2"]
|
assert refresh_runs == [1, 2]
|
||||||
|
|
||||||
|
|
||||||
async def test_track_template_unavailable_sates_has_default_rate_limit(hass):
|
async def test_track_template_unavailable_sates_has_default_rate_limit(hass):
|
||||||
|
@ -1545,21 +1545,21 @@ async def test_track_template_unavailable_sates_has_default_rate_limit(hass):
|
||||||
info.async_refresh()
|
info.async_refresh()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert refresh_runs == ["1"]
|
assert refresh_runs == [1]
|
||||||
hass.states.async_set("sensor.one", "unknown")
|
hass.states.async_set("sensor.one", "unknown")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert refresh_runs == ["1"]
|
assert refresh_runs == [1]
|
||||||
info.async_refresh()
|
info.async_refresh()
|
||||||
assert refresh_runs == ["1", "2"]
|
assert refresh_runs == [1, 2]
|
||||||
hass.states.async_set("sensor.two", "any")
|
hass.states.async_set("sensor.two", "any")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert refresh_runs == ["1", "2"]
|
assert refresh_runs == [1, 2]
|
||||||
hass.states.async_set("sensor.three", "unknown")
|
hass.states.async_set("sensor.three", "unknown")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert refresh_runs == ["1", "2"]
|
assert refresh_runs == [1, 2]
|
||||||
info.async_refresh()
|
info.async_refresh()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert refresh_runs == ["1", "2", "3"]
|
assert refresh_runs == [1, 2, 3]
|
||||||
|
|
||||||
|
|
||||||
async def test_specifically_referenced_entity_is_not_rate_limited(hass):
|
async def test_specifically_referenced_entity_is_not_rate_limited(hass):
|
||||||
|
@ -1628,19 +1628,19 @@ async def test_track_two_templates_with_different_rate_limits(hass):
|
||||||
info.async_refresh()
|
info.async_refresh()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert refresh_runs[template_one] == ["0"]
|
assert refresh_runs[template_one] == [0]
|
||||||
assert refresh_runs[template_five] == ["0"]
|
assert refresh_runs[template_five] == [0]
|
||||||
hass.states.async_set("sensor.one", "any")
|
hass.states.async_set("sensor.one", "any")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert refresh_runs[template_one] == ["0"]
|
assert refresh_runs[template_one] == [0]
|
||||||
assert refresh_runs[template_five] == ["0"]
|
assert refresh_runs[template_five] == [0]
|
||||||
info.async_refresh()
|
info.async_refresh()
|
||||||
assert refresh_runs[template_one] == ["0", "1"]
|
assert refresh_runs[template_one] == [0, 1]
|
||||||
assert refresh_runs[template_five] == ["0", "1"]
|
assert refresh_runs[template_five] == [0, 1]
|
||||||
hass.states.async_set("sensor.two", "any")
|
hass.states.async_set("sensor.two", "any")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert refresh_runs[template_one] == ["0", "1"]
|
assert refresh_runs[template_one] == [0, 1]
|
||||||
assert refresh_runs[template_five] == ["0", "1"]
|
assert refresh_runs[template_five] == [0, 1]
|
||||||
next_time = dt_util.utcnow() + timedelta(seconds=0.125 * 1)
|
next_time = dt_util.utcnow() + timedelta(seconds=0.125 * 1)
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.helpers.ratelimit.dt_util.utcnow", return_value=next_time
|
"homeassistant.helpers.ratelimit.dt_util.utcnow", return_value=next_time
|
||||||
|
@ -1648,20 +1648,20 @@ async def test_track_two_templates_with_different_rate_limits(hass):
|
||||||
async_fire_time_changed(hass, next_time)
|
async_fire_time_changed(hass, next_time)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert refresh_runs[template_one] == ["0", "1", "2"]
|
assert refresh_runs[template_one] == [0, 1, 2]
|
||||||
assert refresh_runs[template_five] == ["0", "1"]
|
assert refresh_runs[template_five] == [0, 1]
|
||||||
hass.states.async_set("sensor.three", "any")
|
hass.states.async_set("sensor.three", "any")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert refresh_runs[template_one] == ["0", "1", "2"]
|
assert refresh_runs[template_one] == [0, 1, 2]
|
||||||
assert refresh_runs[template_five] == ["0", "1"]
|
assert refresh_runs[template_five] == [0, 1]
|
||||||
hass.states.async_set("sensor.four", "any")
|
hass.states.async_set("sensor.four", "any")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert refresh_runs[template_one] == ["0", "1", "2"]
|
assert refresh_runs[template_one] == [0, 1, 2]
|
||||||
assert refresh_runs[template_five] == ["0", "1"]
|
assert refresh_runs[template_five] == [0, 1]
|
||||||
hass.states.async_set("sensor.five", "any")
|
hass.states.async_set("sensor.five", "any")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
assert refresh_runs[template_one] == ["0", "1", "2"]
|
assert refresh_runs[template_one] == [0, 1, 2]
|
||||||
assert refresh_runs[template_five] == ["0", "1"]
|
assert refresh_runs[template_five] == [0, 1]
|
||||||
|
|
||||||
|
|
||||||
async def test_string(hass):
|
async def test_string(hass):
|
||||||
|
@ -1702,7 +1702,7 @@ async def test_track_template_result_refresh_cancel(hass):
|
||||||
hass.states.async_set("switch.test", "off")
|
hass.states.async_set("switch.test", "off")
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert refresh_runs == ["False"]
|
assert refresh_runs == [False]
|
||||||
|
|
||||||
assert len(refresh_runs) == 1
|
assert len(refresh_runs) == 1
|
||||||
|
|
||||||
|
@ -1770,9 +1770,9 @@ async def test_async_track_template_result_multiple_templates(hass):
|
||||||
|
|
||||||
assert refresh_runs == [
|
assert refresh_runs == [
|
||||||
[
|
[
|
||||||
TrackTemplateResult(template_1, None, "True"),
|
TrackTemplateResult(template_1, None, True),
|
||||||
TrackTemplateResult(template_2, None, "True"),
|
TrackTemplateResult(template_2, None, True),
|
||||||
TrackTemplateResult(template_3, None, "False"),
|
TrackTemplateResult(template_3, None, False),
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1782,9 +1782,9 @@ async def test_async_track_template_result_multiple_templates(hass):
|
||||||
|
|
||||||
assert refresh_runs == [
|
assert refresh_runs == [
|
||||||
[
|
[
|
||||||
TrackTemplateResult(template_1, "True", "False"),
|
TrackTemplateResult(template_1, True, False),
|
||||||
TrackTemplateResult(template_2, "True", "False"),
|
TrackTemplateResult(template_2, True, False),
|
||||||
TrackTemplateResult(template_3, "False", "True"),
|
TrackTemplateResult(template_3, False, True),
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1793,7 +1793,7 @@ async def test_async_track_template_result_multiple_templates(hass):
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert refresh_runs == [
|
assert refresh_runs == [
|
||||||
[TrackTemplateResult(template_4, None, "['binary_sensor.test']")]
|
[TrackTemplateResult(template_4, None, ["binary_sensor.test"])]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -1827,10 +1827,10 @@ async def test_async_track_template_result_multiple_templates_mixing_domain(hass
|
||||||
|
|
||||||
assert refresh_runs == [
|
assert refresh_runs == [
|
||||||
[
|
[
|
||||||
TrackTemplateResult(template_1, None, "True"),
|
TrackTemplateResult(template_1, None, True),
|
||||||
TrackTemplateResult(template_2, None, "True"),
|
TrackTemplateResult(template_2, None, True),
|
||||||
TrackTemplateResult(template_3, None, "False"),
|
TrackTemplateResult(template_3, None, False),
|
||||||
TrackTemplateResult(template_4, None, "['switch.test']"),
|
TrackTemplateResult(template_4, None, ["switch.test"]),
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1840,9 +1840,9 @@ async def test_async_track_template_result_multiple_templates_mixing_domain(hass
|
||||||
|
|
||||||
assert refresh_runs == [
|
assert refresh_runs == [
|
||||||
[
|
[
|
||||||
TrackTemplateResult(template_1, "True", "False"),
|
TrackTemplateResult(template_1, True, False),
|
||||||
TrackTemplateResult(template_2, "True", "False"),
|
TrackTemplateResult(template_2, True, False),
|
||||||
TrackTemplateResult(template_3, "False", "True"),
|
TrackTemplateResult(template_3, False, True),
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1859,7 +1859,7 @@ async def test_async_track_template_result_multiple_templates_mixing_domain(hass
|
||||||
assert refresh_runs == [
|
assert refresh_runs == [
|
||||||
[
|
[
|
||||||
TrackTemplateResult(
|
TrackTemplateResult(
|
||||||
template_4, "['switch.test']", "['switch.new', 'switch.test']"
|
template_4, ["switch.test"], ["switch.new", "switch.test"]
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
|
@ -194,8 +194,8 @@ async def test_multiple_runs_no_wait(hass):
|
||||||
|
|
||||||
calls.append(service)
|
calls.append(service)
|
||||||
logger.debug("simulated service (%s:%s) started", fire, listen)
|
logger.debug("simulated service (%s:%s) started", fire, listen)
|
||||||
unsub = hass.bus.async_listen(listen, service_done_cb)
|
unsub = hass.bus.async_listen(str(listen), service_done_cb)
|
||||||
hass.bus.async_fire(fire)
|
hass.bus.async_fire(str(fire))
|
||||||
await service_done.wait()
|
await service_done.wait()
|
||||||
unsub()
|
unsub()
|
||||||
|
|
||||||
|
@ -834,14 +834,14 @@ async def test_wait_variables_out(hass, mode, action_type):
|
||||||
assert not script_obj.is_running
|
assert not script_obj.is_running
|
||||||
assert len(events) == 1
|
assert len(events) == 1
|
||||||
if action_type == "template":
|
if action_type == "template":
|
||||||
assert events[0].data["completed"] == str(mode != "timeout_not_finish")
|
assert events[0].data["completed"] == (mode != "timeout_not_finish")
|
||||||
elif mode != "timeout_not_finish":
|
elif mode != "timeout_not_finish":
|
||||||
assert "'to_state': <state switch.test=off" in events[0].data["trigger"]
|
assert "'to_state': <state switch.test=off" in events[0].data["trigger"]
|
||||||
else:
|
else:
|
||||||
assert events[0].data["trigger"] == "None"
|
assert events[0].data["trigger"] is None
|
||||||
remaining = events[0].data["remaining"]
|
remaining = events[0].data["remaining"]
|
||||||
if mode == "no_timeout":
|
if mode == "no_timeout":
|
||||||
assert remaining == "None"
|
assert remaining is None
|
||||||
elif mode == "timeout_finish":
|
elif mode == "timeout_finish":
|
||||||
assert 0.0 < float(remaining) < 5
|
assert 0.0 < float(remaining) < 5
|
||||||
else:
|
else:
|
||||||
|
@ -977,9 +977,9 @@ async def test_repeat_count(hass):
|
||||||
|
|
||||||
assert len(events) == count
|
assert len(events) == count
|
||||||
for index, event in enumerate(events):
|
for index, event in enumerate(events):
|
||||||
assert event.data.get("first") == str(index == 0)
|
assert event.data.get("first") == (index == 0)
|
||||||
assert event.data.get("index") == str(index + 1)
|
assert event.data.get("index") == index + 1
|
||||||
assert event.data.get("last") == str(index == count - 1)
|
assert event.data.get("last") == (index == count - 1)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("condition", ["while", "until"])
|
@pytest.mark.parametrize("condition", ["while", "until"])
|
||||||
|
@ -1052,8 +1052,8 @@ async def test_repeat_conditional(hass, condition, direct_template):
|
||||||
|
|
||||||
assert len(events) == count
|
assert len(events) == count
|
||||||
for index, event in enumerate(events):
|
for index, event in enumerate(events):
|
||||||
assert event.data.get("first") == str(index == 0)
|
assert event.data.get("first") == (index == 0)
|
||||||
assert event.data.get("index") == str(index + 1)
|
assert event.data.get("index") == index + 1
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("condition", ["while", "until"])
|
@pytest.mark.parametrize("condition", ["while", "until"])
|
||||||
|
@ -1089,8 +1089,8 @@ async def test_repeat_var_in_condition(hass, condition):
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"variables,first_last,inside_x",
|
"variables,first_last,inside_x",
|
||||||
[
|
[
|
||||||
(None, {"repeat": "None", "x": "None"}, "None"),
|
(None, {"repeat": None, "x": None}, None),
|
||||||
(MappingProxyType({"x": 1}), {"repeat": "None", "x": "1"}, "1"),
|
(MappingProxyType({"x": 1}), {"repeat": None, "x": 1}, 1),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
async def test_repeat_nested(hass, variables, first_last, inside_x):
|
async def test_repeat_nested(hass, variables, first_last, inside_x):
|
||||||
|
@ -1168,14 +1168,14 @@ async def test_repeat_nested(hass, variables, first_last, inside_x):
|
||||||
assert events[-1].data == first_last
|
assert events[-1].data == first_last
|
||||||
for index, result in enumerate(
|
for index, result in enumerate(
|
||||||
(
|
(
|
||||||
("True", "1", "False", inside_x),
|
(True, 1, False, inside_x),
|
||||||
("True", "1", "False", inside_x),
|
(True, 1, False, inside_x),
|
||||||
("False", "2", "True", inside_x),
|
(False, 2, True, inside_x),
|
||||||
("True", "1", "False", inside_x),
|
(True, 1, False, inside_x),
|
||||||
("False", "2", "True", inside_x),
|
(False, 2, True, inside_x),
|
||||||
("True", "1", "False", inside_x),
|
(True, 1, False, inside_x),
|
||||||
("False", "2", "True", inside_x),
|
(False, 2, True, inside_x),
|
||||||
("False", "2", "True", inside_x),
|
(False, 2, True, inside_x),
|
||||||
),
|
),
|
||||||
1,
|
1,
|
||||||
):
|
):
|
||||||
|
@ -1827,8 +1827,8 @@ async def test_set_redefines_variable(hass, caplog):
|
||||||
await script_obj.async_run(context=Context())
|
await script_obj.async_run(context=Context())
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert mock_calls[0].data["value"] == "1"
|
assert mock_calls[0].data["value"] == 1
|
||||||
assert mock_calls[1].data["value"] == "2"
|
assert mock_calls[1].data["value"] == 2
|
||||||
|
|
||||||
|
|
||||||
async def test_validate_action_config(hass):
|
async def test_validate_action_config(hass):
|
||||||
|
|
|
@ -50,7 +50,7 @@ async def test_template_vars(hass):
|
||||||
"""Test template vars."""
|
"""Test template vars."""
|
||||||
var = cv.SCRIPT_VARIABLES_SCHEMA({"hello": "{{ 1 + 1 }}"})
|
var = cv.SCRIPT_VARIABLES_SCHEMA({"hello": "{{ 1 + 1 }}"})
|
||||||
rendered = var.async_render(hass, None)
|
rendered = var.async_render(hass, None)
|
||||||
assert rendered == {"hello": "2"}
|
assert rendered == {"hello": 2}
|
||||||
|
|
||||||
|
|
||||||
async def test_template_vars_run_args(hass):
|
async def test_template_vars_run_args(hass):
|
||||||
|
@ -70,7 +70,7 @@ async def test_template_vars_run_args(hass):
|
||||||
)
|
)
|
||||||
assert rendered == {
|
assert rendered == {
|
||||||
"run_var_ex": 5,
|
"run_var_ex": 5,
|
||||||
"something": "6",
|
"something": 6,
|
||||||
"something_2": 1,
|
"something_2": 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ async def test_template_vars_no_default(hass):
|
||||||
"""Test template vars."""
|
"""Test template vars."""
|
||||||
var = cv.SCRIPT_VARIABLES_SCHEMA({"hello": "{{ 1 + 1 }}"})
|
var = cv.SCRIPT_VARIABLES_SCHEMA({"hello": "{{ 1 + 1 }}"})
|
||||||
rendered = var.async_render(hass, None, render_as_defaults=False)
|
rendered = var.async_render(hass, None, render_as_defaults=False)
|
||||||
assert rendered == {"hello": "2"}
|
assert rendered == {"hello": 2}
|
||||||
|
|
||||||
|
|
||||||
async def test_template_vars_run_args_no_default(hass):
|
async def test_template_vars_run_args_no_default(hass):
|
||||||
|
@ -100,8 +100,8 @@ async def test_template_vars_run_args_no_default(hass):
|
||||||
)
|
)
|
||||||
assert rendered == {
|
assert rendered == {
|
||||||
"run_var_ex": 5,
|
"run_var_ex": 5,
|
||||||
"something": "6",
|
"something": 6,
|
||||||
"something_2": "6",
|
"something_2": 6,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import pytest
|
||||||
import pytz
|
import pytz
|
||||||
|
|
||||||
from homeassistant.components import group
|
from homeassistant.components import group
|
||||||
|
from homeassistant.config import async_process_ha_core_config
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_UNIT_OF_MEASUREMENT,
|
ATTR_UNIT_OF_MEASUREMENT,
|
||||||
LENGTH_METERS,
|
LENGTH_METERS,
|
||||||
|
@ -173,7 +174,7 @@ def test_iterating_all_states_unavailable(hass):
|
||||||
hass.states.async_set("sensor.temperature", 10)
|
hass.states.async_set("sensor.temperature", 10)
|
||||||
|
|
||||||
info = render_to_info(hass, tmpl_str)
|
info = render_to_info(hass, tmpl_str)
|
||||||
assert_result_info(info, "1", entities=[], all_states=True)
|
assert_result_info(info, 1, entities=[], all_states=True)
|
||||||
|
|
||||||
|
|
||||||
def test_iterating_domain_states(hass):
|
def test_iterating_domain_states(hass):
|
||||||
|
@ -205,14 +206,14 @@ def test_float(hass):
|
||||||
template.Template(
|
template.Template(
|
||||||
"{{ float(states.sensor.temperature.state) }}", hass
|
"{{ float(states.sensor.temperature.state) }}", hass
|
||||||
).async_render()
|
).async_render()
|
||||||
== "12.0"
|
== 12.0
|
||||||
)
|
)
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
template.Template(
|
template.Template(
|
||||||
"{{ float(states.sensor.temperature.state) > 11 }}", hass
|
"{{ float(states.sensor.temperature.state) > 11 }}", hass
|
||||||
).async_render()
|
).async_render()
|
||||||
== "True"
|
is True
|
||||||
)
|
)
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
|
@ -229,41 +230,41 @@ def test_rounding_value(hass):
|
||||||
template.Template(
|
template.Template(
|
||||||
"{{ states.sensor.temperature.state | round(1) }}", hass
|
"{{ states.sensor.temperature.state | round(1) }}", hass
|
||||||
).async_render()
|
).async_render()
|
||||||
== "12.8"
|
== 12.8
|
||||||
)
|
)
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
template.Template(
|
template.Template(
|
||||||
"{{ states.sensor.temperature.state | multiply(10) | round }}", hass
|
"{{ states.sensor.temperature.state | multiply(10) | round }}", hass
|
||||||
).async_render()
|
).async_render()
|
||||||
== "128"
|
== 128
|
||||||
)
|
)
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
template.Template(
|
template.Template(
|
||||||
'{{ states.sensor.temperature.state | round(1, "floor") }}', hass
|
'{{ states.sensor.temperature.state | round(1, "floor") }}', hass
|
||||||
).async_render()
|
).async_render()
|
||||||
== "12.7"
|
== 12.7
|
||||||
)
|
)
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
template.Template(
|
template.Template(
|
||||||
'{{ states.sensor.temperature.state | round(1, "ceil") }}', hass
|
'{{ states.sensor.temperature.state | round(1, "ceil") }}', hass
|
||||||
).async_render()
|
).async_render()
|
||||||
== "12.8"
|
== 12.8
|
||||||
)
|
)
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
template.Template(
|
template.Template(
|
||||||
'{{ states.sensor.temperature.state | round(1, "half") }}', hass
|
'{{ states.sensor.temperature.state | round(1, "half") }}', hass
|
||||||
).async_render()
|
).async_render()
|
||||||
== "13.0"
|
== 13.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_rounding_value_get_original_value_on_error(hass):
|
def test_rounding_value_get_original_value_on_error(hass):
|
||||||
"""Test rounding value get original value on error."""
|
"""Test rounding value get original value on error."""
|
||||||
assert template.Template("{{ None | round }}", hass).async_render() == "None"
|
assert template.Template("{{ None | round }}", hass).async_render() is None
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
template.Template('{{ "no_number" | round }}', hass).async_render()
|
template.Template('{{ "no_number" | round }}', hass).async_render()
|
||||||
|
@ -273,7 +274,7 @@ def test_rounding_value_get_original_value_on_error(hass):
|
||||||
|
|
||||||
def test_multiply(hass):
|
def test_multiply(hass):
|
||||||
"""Test multiply."""
|
"""Test multiply."""
|
||||||
tests = {None: "None", 10: "100", '"abcd"': "abcd"}
|
tests = {None: None, 10: 100, '"abcd"': "abcd"}
|
||||||
|
|
||||||
for inp, out in tests.items():
|
for inp, out in tests.items():
|
||||||
assert (
|
assert (
|
||||||
|
@ -287,11 +288,11 @@ def test_multiply(hass):
|
||||||
def test_logarithm(hass):
|
def test_logarithm(hass):
|
||||||
"""Test logarithm."""
|
"""Test logarithm."""
|
||||||
tests = [
|
tests = [
|
||||||
(4, 2, "2.0"),
|
(4, 2, 2.0),
|
||||||
(1000, 10, "3.0"),
|
(1000, 10, 3.0),
|
||||||
(math.e, "", "1.0"),
|
(math.e, "", 1.0),
|
||||||
('"invalid"', "_", "invalid"),
|
('"invalid"', "_", "invalid"),
|
||||||
(10, '"invalid"', "10.0"),
|
(10, '"invalid"', 10.0),
|
||||||
]
|
]
|
||||||
|
|
||||||
for value, base, expected in tests:
|
for value, base, expected in tests:
|
||||||
|
@ -313,11 +314,11 @@ def test_logarithm(hass):
|
||||||
def test_sine(hass):
|
def test_sine(hass):
|
||||||
"""Test sine."""
|
"""Test sine."""
|
||||||
tests = [
|
tests = [
|
||||||
(0, "0.0"),
|
(0, 0.0),
|
||||||
(math.pi / 2, "1.0"),
|
(math.pi / 2, 1.0),
|
||||||
(math.pi, "0.0"),
|
(math.pi, 0.0),
|
||||||
(math.pi * 1.5, "-1.0"),
|
(math.pi * 1.5, -1.0),
|
||||||
(math.pi / 10, "0.309"),
|
(math.pi / 10, 0.309),
|
||||||
('"duck"', "duck"),
|
('"duck"', "duck"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -331,11 +332,11 @@ def test_sine(hass):
|
||||||
def test_cos(hass):
|
def test_cos(hass):
|
||||||
"""Test cosine."""
|
"""Test cosine."""
|
||||||
tests = [
|
tests = [
|
||||||
(0, "1.0"),
|
(0, 1.0),
|
||||||
(math.pi / 2, "0.0"),
|
(math.pi / 2, 0.0),
|
||||||
(math.pi, "-1.0"),
|
(math.pi, -1.0),
|
||||||
(math.pi * 1.5, "-0.0"),
|
(math.pi * 1.5, -0.0),
|
||||||
(math.pi / 10, "0.951"),
|
(math.pi / 10, 0.951),
|
||||||
("'error'", "error"),
|
("'error'", "error"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -349,11 +350,11 @@ def test_cos(hass):
|
||||||
def test_tan(hass):
|
def test_tan(hass):
|
||||||
"""Test tangent."""
|
"""Test tangent."""
|
||||||
tests = [
|
tests = [
|
||||||
(0, "0.0"),
|
(0, 0.0),
|
||||||
(math.pi, "-0.0"),
|
(math.pi, -0.0),
|
||||||
(math.pi / 180 * 45, "1.0"),
|
(math.pi / 180 * 45, 1.0),
|
||||||
(math.pi / 180 * 90, "1.633123935319537e+16"),
|
(math.pi / 180 * 90, 1.633123935319537e16),
|
||||||
(math.pi / 180 * 135, "-1.0"),
|
(math.pi / 180 * 135, -1.0),
|
||||||
("'error'", "error"),
|
("'error'", "error"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -367,11 +368,11 @@ def test_tan(hass):
|
||||||
def test_sqrt(hass):
|
def test_sqrt(hass):
|
||||||
"""Test square root."""
|
"""Test square root."""
|
||||||
tests = [
|
tests = [
|
||||||
(0, "0.0"),
|
(0, 0.0),
|
||||||
(1, "1.0"),
|
(1, 1.0),
|
||||||
(2, "1.414"),
|
(2, 1.414),
|
||||||
(10, "3.162"),
|
(10, 3.162),
|
||||||
(100, "10.0"),
|
(100, 10.0),
|
||||||
("'error'", "error"),
|
("'error'", "error"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -385,13 +386,13 @@ def test_sqrt(hass):
|
||||||
def test_arc_sine(hass):
|
def test_arc_sine(hass):
|
||||||
"""Test arcus sine."""
|
"""Test arcus sine."""
|
||||||
tests = [
|
tests = [
|
||||||
(-2.0, "-2.0"), # value error
|
(-2.0, -2.0), # value error
|
||||||
(-1.0, "-1.571"),
|
(-1.0, -1.571),
|
||||||
(-0.5, "-0.524"),
|
(-0.5, -0.524),
|
||||||
(0.0, "0.0"),
|
(0.0, 0.0),
|
||||||
(0.5, "0.524"),
|
(0.5, 0.524),
|
||||||
(1.0, "1.571"),
|
(1.0, 1.571),
|
||||||
(2.0, "2.0"), # value error
|
(2.0, 2.0), # value error
|
||||||
('"error"', "error"),
|
('"error"', "error"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -405,13 +406,13 @@ def test_arc_sine(hass):
|
||||||
def test_arc_cos(hass):
|
def test_arc_cos(hass):
|
||||||
"""Test arcus cosine."""
|
"""Test arcus cosine."""
|
||||||
tests = [
|
tests = [
|
||||||
(-2.0, "-2.0"), # value error
|
(-2.0, -2.0), # value error
|
||||||
(-1.0, "3.142"),
|
(-1.0, 3.142),
|
||||||
(-0.5, "2.094"),
|
(-0.5, 2.094),
|
||||||
(0.0, "1.571"),
|
(0.0, 1.571),
|
||||||
(0.5, "1.047"),
|
(0.5, 1.047),
|
||||||
(1.0, "0.0"),
|
(1.0, 0.0),
|
||||||
(2.0, "2.0"), # value error
|
(2.0, 2.0), # value error
|
||||||
('"error"', "error"),
|
('"error"', "error"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -425,15 +426,15 @@ def test_arc_cos(hass):
|
||||||
def test_arc_tan(hass):
|
def test_arc_tan(hass):
|
||||||
"""Test arcus tangent."""
|
"""Test arcus tangent."""
|
||||||
tests = [
|
tests = [
|
||||||
(-10.0, "-1.471"),
|
(-10.0, -1.471),
|
||||||
(-2.0, "-1.107"),
|
(-2.0, -1.107),
|
||||||
(-1.0, "-0.785"),
|
(-1.0, -0.785),
|
||||||
(-0.5, "-0.464"),
|
(-0.5, -0.464),
|
||||||
(0.0, "0.0"),
|
(0.0, 0.0),
|
||||||
(0.5, "0.464"),
|
(0.5, 0.464),
|
||||||
(1.0, "0.785"),
|
(1.0, 0.785),
|
||||||
(2.0, "1.107"),
|
(2.0, 1.107),
|
||||||
(10.0, "1.471"),
|
(10.0, 1.471),
|
||||||
('"error"', "error"),
|
('"error"', "error"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -447,19 +448,19 @@ def test_arc_tan(hass):
|
||||||
def test_arc_tan2(hass):
|
def test_arc_tan2(hass):
|
||||||
"""Test two parameter version of arcus tangent."""
|
"""Test two parameter version of arcus tangent."""
|
||||||
tests = [
|
tests = [
|
||||||
(-10.0, -10.0, "-2.356"),
|
(-10.0, -10.0, -2.356),
|
||||||
(-10.0, 0.0, "-1.571"),
|
(-10.0, 0.0, -1.571),
|
||||||
(-10.0, 10.0, "-0.785"),
|
(-10.0, 10.0, -0.785),
|
||||||
(0.0, -10.0, "3.142"),
|
(0.0, -10.0, 3.142),
|
||||||
(0.0, 0.0, "0.0"),
|
(0.0, 0.0, 0.0),
|
||||||
(0.0, 10.0, "0.0"),
|
(0.0, 10.0, 0.0),
|
||||||
(10.0, -10.0, "2.356"),
|
(10.0, -10.0, 2.356),
|
||||||
(10.0, 0.0, "1.571"),
|
(10.0, 0.0, 1.571),
|
||||||
(10.0, 10.0, "0.785"),
|
(10.0, 10.0, 0.785),
|
||||||
(-4.0, 3.0, "-0.927"),
|
(-4.0, 3.0, -0.927),
|
||||||
(-1.0, 2.0, "-0.464"),
|
(-1.0, 2.0, -0.464),
|
||||||
(2.0, 1.0, "1.107"),
|
(2.0, 1.0, 1.107),
|
||||||
('"duck"', '"goose"', "('duck', 'goose')"),
|
('"duck"', '"goose"', ("duck", "goose")),
|
||||||
]
|
]
|
||||||
|
|
||||||
for y, x, expected in tests:
|
for y, x, expected in tests:
|
||||||
|
@ -486,26 +487,26 @@ def test_strptime(hass):
|
||||||
("2016-10-19", "%Y-%m-%d", None),
|
("2016-10-19", "%Y-%m-%d", None),
|
||||||
("2016", "%Y", None),
|
("2016", "%Y", None),
|
||||||
("15:22:05", "%H:%M:%S", None),
|
("15:22:05", "%H:%M:%S", None),
|
||||||
("1469119144", "%Y", "1469119144"),
|
("1469119144", "%Y", 1469119144),
|
||||||
("invalid", "%Y", "invalid"),
|
("invalid", "%Y", "invalid"),
|
||||||
]
|
]
|
||||||
|
|
||||||
for inp, fmt, expected in tests:
|
for inp, fmt, expected in tests:
|
||||||
if expected is None:
|
if expected is None:
|
||||||
expected = datetime.strptime(inp, fmt)
|
expected = str(datetime.strptime(inp, fmt))
|
||||||
|
|
||||||
temp = f"{{{{ strptime('{inp}', '{fmt}') }}}}"
|
temp = f"{{{{ strptime('{inp}', '{fmt}') }}}}"
|
||||||
|
|
||||||
assert template.Template(temp, hass).async_render() == str(expected)
|
assert template.Template(temp, hass).async_render() == expected
|
||||||
|
|
||||||
|
|
||||||
def test_timestamp_custom(hass):
|
def test_timestamp_custom(hass):
|
||||||
"""Test the timestamps to custom filter."""
|
"""Test the timestamps to custom filter."""
|
||||||
now = dt_util.utcnow()
|
now = dt_util.utcnow()
|
||||||
tests = [
|
tests = [
|
||||||
(None, None, None, "None"),
|
(None, None, None, None),
|
||||||
(1469119144, None, True, "2016-07-21 16:39:04"),
|
(1469119144, None, True, "2016-07-21 16:39:04"),
|
||||||
(1469119144, "%Y", True, "2016"),
|
(1469119144, "%Y", True, 2016),
|
||||||
(1469119144, "invalid", True, "invalid"),
|
(1469119144, "invalid", True, "invalid"),
|
||||||
(dt_util.as_timestamp(now), None, False, now.strftime("%Y-%m-%d %H:%M:%S")),
|
(dt_util.as_timestamp(now), None, False, now.strftime("%Y-%m-%d %H:%M:%S")),
|
||||||
]
|
]
|
||||||
|
@ -523,7 +524,7 @@ def test_timestamp_custom(hass):
|
||||||
|
|
||||||
def test_timestamp_local(hass):
|
def test_timestamp_local(hass):
|
||||||
"""Test the timestamps to local filter."""
|
"""Test the timestamps to local filter."""
|
||||||
tests = {None: "None", 1469119144: "2016-07-21 16:39:04"}
|
tests = {None: None, 1469119144: "2016-07-21 16:39:04"}
|
||||||
|
|
||||||
for inp, out in tests.items():
|
for inp, out in tests.items():
|
||||||
assert (
|
assert (
|
||||||
|
@ -550,7 +551,7 @@ def test_to_json(hass):
|
||||||
|
|
||||||
# Note that we're not testing the actual json.loads and json.dumps methods,
|
# Note that we're not testing the actual json.loads and json.dumps methods,
|
||||||
# only the filters, so we don't need to be exhaustive with our sample JSON.
|
# only the filters, so we don't need to be exhaustive with our sample JSON.
|
||||||
expected_result = '{"Foo": "Bar"}'
|
expected_result = {"Foo": "Bar"}
|
||||||
actual_result = template.Template(
|
actual_result = template.Template(
|
||||||
"{{ {'Foo': 'Bar'} | to_json }}", hass
|
"{{ {'Foo': 'Bar'} | to_json }}", hass
|
||||||
).async_render()
|
).async_render()
|
||||||
|
@ -571,17 +572,17 @@ def test_from_json(hass):
|
||||||
|
|
||||||
def test_min(hass):
|
def test_min(hass):
|
||||||
"""Test the min filter."""
|
"""Test the min filter."""
|
||||||
assert template.Template("{{ [1, 2, 3] | min }}", hass).async_render() == "1"
|
assert template.Template("{{ [1, 2, 3] | min }}", hass).async_render() == 1
|
||||||
|
|
||||||
|
|
||||||
def test_max(hass):
|
def test_max(hass):
|
||||||
"""Test the max filter."""
|
"""Test the max filter."""
|
||||||
assert template.Template("{{ [1, 2, 3] | max }}", hass).async_render() == "3"
|
assert template.Template("{{ [1, 2, 3] | max }}", hass).async_render() == 3
|
||||||
|
|
||||||
|
|
||||||
def test_ord(hass):
|
def test_ord(hass):
|
||||||
"""Test the ord filter."""
|
"""Test the ord filter."""
|
||||||
assert template.Template('{{ "d" | ord }}', hass).async_render() == "100"
|
assert template.Template('{{ "d" | ord }}', hass).async_render() == 100
|
||||||
|
|
||||||
|
|
||||||
def test_base64_encode(hass):
|
def test_base64_encode(hass):
|
||||||
|
@ -626,7 +627,7 @@ def test_timestamp_utc(hass):
|
||||||
"""Test the timestamps to local filter."""
|
"""Test the timestamps to local filter."""
|
||||||
now = dt_util.utcnow()
|
now = dt_util.utcnow()
|
||||||
tests = {
|
tests = {
|
||||||
None: "None",
|
None: None,
|
||||||
1469119144: "2016-07-21 16:39:04",
|
1469119144: "2016-07-21 16:39:04",
|
||||||
dt_util.as_timestamp(now): now.strftime("%Y-%m-%d %H:%M:%S"),
|
dt_util.as_timestamp(now): now.strftime("%Y-%m-%d %H:%M:%S"),
|
||||||
}
|
}
|
||||||
|
@ -641,20 +642,19 @@ def test_timestamp_utc(hass):
|
||||||
def test_as_timestamp(hass):
|
def test_as_timestamp(hass):
|
||||||
"""Test the as_timestamp function."""
|
"""Test the as_timestamp function."""
|
||||||
assert (
|
assert (
|
||||||
template.Template('{{ as_timestamp("invalid") }}', hass).async_render()
|
template.Template('{{ as_timestamp("invalid") }}', hass).async_render() is None
|
||||||
== "None"
|
|
||||||
)
|
)
|
||||||
hass.mock = None
|
hass.mock = None
|
||||||
assert (
|
assert (
|
||||||
template.Template("{{ as_timestamp(states.mock) }}", hass).async_render()
|
template.Template("{{ as_timestamp(states.mock) }}", hass).async_render()
|
||||||
== "None"
|
is None
|
||||||
)
|
)
|
||||||
|
|
||||||
tpl = (
|
tpl = (
|
||||||
'{{ as_timestamp(strptime("2024-02-03T09:10:24+0000", '
|
'{{ as_timestamp(strptime("2024-02-03T09:10:24+0000", '
|
||||||
'"%Y-%m-%dT%H:%M:%S%z")) }}'
|
'"%Y-%m-%dT%H:%M:%S%z")) }}'
|
||||||
)
|
)
|
||||||
assert template.Template(tpl, hass).async_render() == "1706951424.0"
|
assert template.Template(tpl, hass).async_render() == 1706951424.0
|
||||||
|
|
||||||
|
|
||||||
@patch.object(random, "choice")
|
@patch.object(random, "choice")
|
||||||
|
@ -669,22 +669,19 @@ def test_random_every_time(test_choice, hass):
|
||||||
|
|
||||||
def test_passing_vars_as_keywords(hass):
|
def test_passing_vars_as_keywords(hass):
|
||||||
"""Test passing variables as keywords."""
|
"""Test passing variables as keywords."""
|
||||||
assert template.Template("{{ hello }}", hass).async_render(hello=127) == "127"
|
assert template.Template("{{ hello }}", hass).async_render(hello=127) == 127
|
||||||
|
|
||||||
|
|
||||||
def test_passing_vars_as_vars(hass):
|
def test_passing_vars_as_vars(hass):
|
||||||
"""Test passing variables as variables."""
|
"""Test passing variables as variables."""
|
||||||
assert template.Template("{{ hello }}", hass).async_render({"hello": 127}) == "127"
|
assert template.Template("{{ hello }}", hass).async_render({"hello": 127}) == 127
|
||||||
|
|
||||||
|
|
||||||
def test_passing_vars_as_list(hass):
|
def test_passing_vars_as_list(hass):
|
||||||
"""Test passing variables as list."""
|
"""Test passing variables as list."""
|
||||||
assert (
|
assert template.render_complex(
|
||||||
template.render_complex(
|
template.Template("{{ hello }}", hass), {"hello": ["foo", "bar"]}
|
||||||
template.Template("{{ hello }}", hass), {"hello": ["foo", "bar"]}
|
) == ["foo", "bar"]
|
||||||
)
|
|
||||||
== "['foo', 'bar']"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_passing_vars_as_list_element(hass):
|
def test_passing_vars_as_list_element(hass):
|
||||||
|
@ -709,12 +706,9 @@ def test_passing_vars_as_dict_element(hass):
|
||||||
|
|
||||||
def test_passing_vars_as_dict(hass):
|
def test_passing_vars_as_dict(hass):
|
||||||
"""Test passing variables as list."""
|
"""Test passing variables as list."""
|
||||||
assert (
|
assert template.render_complex(
|
||||||
template.render_complex(
|
template.Template("{{ hello }}", hass), {"hello": {"foo": "bar"}}
|
||||||
template.Template("{{ hello }}", hass), {"hello": {"foo": "bar"}}
|
) == {"foo": "bar"}
|
||||||
)
|
|
||||||
== "{'foo': 'bar'}"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_render_with_possible_json_value_with_valid_json(hass):
|
def test_render_with_possible_json_value_with_valid_json(hass):
|
||||||
|
@ -801,7 +795,7 @@ def test_is_state(hass):
|
||||||
""",
|
""",
|
||||||
hass,
|
hass,
|
||||||
)
|
)
|
||||||
assert tpl.async_render() == "False"
|
assert tpl.async_render() is False
|
||||||
|
|
||||||
|
|
||||||
def test_is_state_attr(hass):
|
def test_is_state_attr(hass):
|
||||||
|
@ -821,7 +815,7 @@ def test_is_state_attr(hass):
|
||||||
""",
|
""",
|
||||||
hass,
|
hass,
|
||||||
)
|
)
|
||||||
assert tpl.async_render() == "False"
|
assert tpl.async_render() is False
|
||||||
|
|
||||||
|
|
||||||
def test_state_attr(hass):
|
def test_state_attr(hass):
|
||||||
|
@ -841,7 +835,7 @@ def test_state_attr(hass):
|
||||||
""",
|
""",
|
||||||
hass,
|
hass,
|
||||||
)
|
)
|
||||||
assert tpl.async_render() == "True"
|
assert tpl.async_render() is True
|
||||||
|
|
||||||
|
|
||||||
def test_states_function(hass):
|
def test_states_function(hass):
|
||||||
|
@ -994,7 +988,7 @@ def test_regex_match(hass):
|
||||||
""",
|
""",
|
||||||
hass,
|
hass,
|
||||||
)
|
)
|
||||||
assert tpl.async_render() == "True"
|
assert tpl.async_render() is True
|
||||||
|
|
||||||
tpl = template.Template(
|
tpl = template.Template(
|
||||||
"""
|
"""
|
||||||
|
@ -1002,7 +996,7 @@ def test_regex_match(hass):
|
||||||
""",
|
""",
|
||||||
hass,
|
hass,
|
||||||
)
|
)
|
||||||
assert tpl.async_render() == "True"
|
assert tpl.async_render() is True
|
||||||
|
|
||||||
tpl = template.Template(
|
tpl = template.Template(
|
||||||
"""
|
"""
|
||||||
|
@ -1010,7 +1004,7 @@ def test_regex_match(hass):
|
||||||
""",
|
""",
|
||||||
hass,
|
hass,
|
||||||
)
|
)
|
||||||
assert tpl.async_render() == "False"
|
assert tpl.async_render() is False
|
||||||
|
|
||||||
tpl = template.Template(
|
tpl = template.Template(
|
||||||
"""
|
"""
|
||||||
|
@ -1018,7 +1012,7 @@ def test_regex_match(hass):
|
||||||
""",
|
""",
|
||||||
hass,
|
hass,
|
||||||
)
|
)
|
||||||
assert tpl.async_render() == "True"
|
assert tpl.async_render() is True
|
||||||
|
|
||||||
|
|
||||||
def test_regex_search(hass):
|
def test_regex_search(hass):
|
||||||
|
@ -1029,7 +1023,7 @@ def test_regex_search(hass):
|
||||||
""",
|
""",
|
||||||
hass,
|
hass,
|
||||||
)
|
)
|
||||||
assert tpl.async_render() == "True"
|
assert tpl.async_render() is True
|
||||||
|
|
||||||
tpl = template.Template(
|
tpl = template.Template(
|
||||||
"""
|
"""
|
||||||
|
@ -1037,7 +1031,7 @@ def test_regex_search(hass):
|
||||||
""",
|
""",
|
||||||
hass,
|
hass,
|
||||||
)
|
)
|
||||||
assert tpl.async_render() == "True"
|
assert tpl.async_render() is True
|
||||||
|
|
||||||
tpl = template.Template(
|
tpl = template.Template(
|
||||||
"""
|
"""
|
||||||
|
@ -1045,7 +1039,7 @@ def test_regex_search(hass):
|
||||||
""",
|
""",
|
||||||
hass,
|
hass,
|
||||||
)
|
)
|
||||||
assert tpl.async_render() == "True"
|
assert tpl.async_render() is True
|
||||||
|
|
||||||
tpl = template.Template(
|
tpl = template.Template(
|
||||||
"""
|
"""
|
||||||
|
@ -1053,7 +1047,7 @@ def test_regex_search(hass):
|
||||||
""",
|
""",
|
||||||
hass,
|
hass,
|
||||||
)
|
)
|
||||||
assert tpl.async_render() == "True"
|
assert tpl.async_render() is True
|
||||||
|
|
||||||
|
|
||||||
def test_regex_replace(hass):
|
def test_regex_replace(hass):
|
||||||
|
@ -1072,7 +1066,7 @@ def test_regex_replace(hass):
|
||||||
""",
|
""",
|
||||||
hass,
|
hass,
|
||||||
)
|
)
|
||||||
assert tpl.async_render() == "['Home Assistant test']"
|
assert tpl.async_render() == ["Home Assistant test"]
|
||||||
|
|
||||||
|
|
||||||
def test_regex_findall_index(hass):
|
def test_regex_findall_index(hass):
|
||||||
|
@ -1110,21 +1104,21 @@ def test_bitwise_and(hass):
|
||||||
""",
|
""",
|
||||||
hass,
|
hass,
|
||||||
)
|
)
|
||||||
assert tpl.async_render() == str(8 & 8)
|
assert tpl.async_render() == 8 & 8
|
||||||
tpl = template.Template(
|
tpl = template.Template(
|
||||||
"""
|
"""
|
||||||
{{ 10 | bitwise_and(2) }}
|
{{ 10 | bitwise_and(2) }}
|
||||||
""",
|
""",
|
||||||
hass,
|
hass,
|
||||||
)
|
)
|
||||||
assert tpl.async_render() == str(10 & 2)
|
assert tpl.async_render() == 10 & 2
|
||||||
tpl = template.Template(
|
tpl = template.Template(
|
||||||
"""
|
"""
|
||||||
{{ 8 | bitwise_and(2) }}
|
{{ 8 | bitwise_and(2) }}
|
||||||
""",
|
""",
|
||||||
hass,
|
hass,
|
||||||
)
|
)
|
||||||
assert tpl.async_render() == str(8 & 2)
|
assert tpl.async_render() == 8 & 2
|
||||||
|
|
||||||
|
|
||||||
def test_bitwise_or(hass):
|
def test_bitwise_or(hass):
|
||||||
|
@ -1135,21 +1129,21 @@ def test_bitwise_or(hass):
|
||||||
""",
|
""",
|
||||||
hass,
|
hass,
|
||||||
)
|
)
|
||||||
assert tpl.async_render() == str(8 | 8)
|
assert tpl.async_render() == 8 | 8
|
||||||
tpl = template.Template(
|
tpl = template.Template(
|
||||||
"""
|
"""
|
||||||
{{ 10 | bitwise_or(2) }}
|
{{ 10 | bitwise_or(2) }}
|
||||||
""",
|
""",
|
||||||
hass,
|
hass,
|
||||||
)
|
)
|
||||||
assert tpl.async_render() == str(10 | 2)
|
assert tpl.async_render() == 10 | 2
|
||||||
tpl = template.Template(
|
tpl = template.Template(
|
||||||
"""
|
"""
|
||||||
{{ 8 | bitwise_or(2) }}
|
{{ 8 | bitwise_or(2) }}
|
||||||
""",
|
""",
|
||||||
hass,
|
hass,
|
||||||
)
|
)
|
||||||
assert tpl.async_render() == str(8 | 2)
|
assert tpl.async_render() == 8 | 2
|
||||||
|
|
||||||
|
|
||||||
def test_distance_function_with_1_state(hass):
|
def test_distance_function_with_1_state(hass):
|
||||||
|
@ -1159,7 +1153,7 @@ def test_distance_function_with_1_state(hass):
|
||||||
"test.object", "happy", {"latitude": 32.87336, "longitude": -117.22943}
|
"test.object", "happy", {"latitude": 32.87336, "longitude": -117.22943}
|
||||||
)
|
)
|
||||||
tpl = template.Template("{{ distance(states.test.object) | round }}", hass)
|
tpl = template.Template("{{ distance(states.test.object) | round }}", hass)
|
||||||
assert tpl.async_render() == "187"
|
assert tpl.async_render() == 187
|
||||||
|
|
||||||
|
|
||||||
def test_distance_function_with_2_states(hass):
|
def test_distance_function_with_2_states(hass):
|
||||||
|
@ -1176,14 +1170,14 @@ def test_distance_function_with_2_states(hass):
|
||||||
tpl = template.Template(
|
tpl = template.Template(
|
||||||
"{{ distance(states.test.object, states.test.object_2) | round }}", hass
|
"{{ distance(states.test.object, states.test.object_2) | round }}", hass
|
||||||
)
|
)
|
||||||
assert tpl.async_render() == "187"
|
assert tpl.async_render() == 187
|
||||||
|
|
||||||
|
|
||||||
def test_distance_function_with_1_coord(hass):
|
def test_distance_function_with_1_coord(hass):
|
||||||
"""Test distance function with 1 coord."""
|
"""Test distance function with 1 coord."""
|
||||||
_set_up_units(hass)
|
_set_up_units(hass)
|
||||||
tpl = template.Template('{{ distance("32.87336", "-117.22943") | round }}', hass)
|
tpl = template.Template('{{ distance("32.87336", "-117.22943") | round }}', hass)
|
||||||
assert tpl.async_render() == "187"
|
assert tpl.async_render() == 187
|
||||||
|
|
||||||
|
|
||||||
def test_distance_function_with_2_coords(hass):
|
def test_distance_function_with_2_coords(hass):
|
||||||
|
@ -1195,7 +1189,7 @@ def test_distance_function_with_2_coords(hass):
|
||||||
% (hass.config.latitude, hass.config.longitude),
|
% (hass.config.latitude, hass.config.longitude),
|
||||||
hass,
|
hass,
|
||||||
).async_render()
|
).async_render()
|
||||||
== "187"
|
== 187
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1211,29 +1205,29 @@ def test_distance_function_with_1_state_1_coord(hass):
|
||||||
'{{ distance("32.87336", "-117.22943", states.test.object_2) ' "| round }}",
|
'{{ distance("32.87336", "-117.22943", states.test.object_2) ' "| round }}",
|
||||||
hass,
|
hass,
|
||||||
)
|
)
|
||||||
assert tpl.async_render() == "187"
|
assert tpl.async_render() == 187
|
||||||
|
|
||||||
tpl2 = template.Template(
|
tpl2 = template.Template(
|
||||||
'{{ distance(states.test.object_2, "32.87336", "-117.22943") ' "| round }}",
|
'{{ distance(states.test.object_2, "32.87336", "-117.22943") ' "| round }}",
|
||||||
hass,
|
hass,
|
||||||
)
|
)
|
||||||
assert tpl2.async_render() == "187"
|
assert tpl2.async_render() == 187
|
||||||
|
|
||||||
|
|
||||||
def test_distance_function_return_none_if_invalid_state(hass):
|
def test_distance_function_return_none_if_invalid_state(hass):
|
||||||
"""Test distance function return None if invalid state."""
|
"""Test distance function return None if invalid state."""
|
||||||
hass.states.async_set("test.object_2", "happy", {"latitude": 10})
|
hass.states.async_set("test.object_2", "happy", {"latitude": 10})
|
||||||
tpl = template.Template("{{ distance(states.test.object_2) | round }}", hass)
|
tpl = template.Template("{{ distance(states.test.object_2) | round }}", hass)
|
||||||
assert tpl.async_render() == "None"
|
assert tpl.async_render() is None
|
||||||
|
|
||||||
|
|
||||||
def test_distance_function_return_none_if_invalid_coord(hass):
|
def test_distance_function_return_none_if_invalid_coord(hass):
|
||||||
"""Test distance function return None if invalid coord."""
|
"""Test distance function return None if invalid coord."""
|
||||||
assert (
|
assert (
|
||||||
template.Template('{{ distance("123", "abc") }}', hass).async_render() == "None"
|
template.Template('{{ distance("123", "abc") }}', hass).async_render() is None
|
||||||
)
|
)
|
||||||
|
|
||||||
assert template.Template('{{ distance("123") }}', hass).async_render() == "None"
|
assert template.Template('{{ distance("123") }}', hass).async_render() is None
|
||||||
|
|
||||||
hass.states.async_set(
|
hass.states.async_set(
|
||||||
"test.object_2",
|
"test.object_2",
|
||||||
|
@ -1241,7 +1235,7 @@ def test_distance_function_return_none_if_invalid_coord(hass):
|
||||||
{"latitude": hass.config.latitude, "longitude": hass.config.longitude},
|
{"latitude": hass.config.latitude, "longitude": hass.config.longitude},
|
||||||
)
|
)
|
||||||
tpl = template.Template('{{ distance("123", states.test_object_2) }}', hass)
|
tpl = template.Template('{{ distance("123", states.test_object_2) }}', hass)
|
||||||
assert tpl.async_render() == "None"
|
assert tpl.async_render() is None
|
||||||
|
|
||||||
|
|
||||||
def test_distance_function_with_2_entity_ids(hass):
|
def test_distance_function_with_2_entity_ids(hass):
|
||||||
|
@ -1258,7 +1252,7 @@ def test_distance_function_with_2_entity_ids(hass):
|
||||||
tpl = template.Template(
|
tpl = template.Template(
|
||||||
'{{ distance("test.object", "test.object_2") | round }}', hass
|
'{{ distance("test.object", "test.object_2") | round }}', hass
|
||||||
)
|
)
|
||||||
assert tpl.async_render() == "187"
|
assert tpl.async_render() == 187
|
||||||
|
|
||||||
|
|
||||||
def test_distance_function_with_1_entity_1_coord(hass):
|
def test_distance_function_with_1_entity_1_coord(hass):
|
||||||
|
@ -1272,7 +1266,7 @@ def test_distance_function_with_1_entity_1_coord(hass):
|
||||||
tpl = template.Template(
|
tpl = template.Template(
|
||||||
'{{ distance("test.object", "32.87336", "-117.22943") | round }}', hass
|
'{{ distance("test.object", "32.87336", "-117.22943") | round }}', hass
|
||||||
)
|
)
|
||||||
assert tpl.async_render() == "187"
|
assert tpl.async_render() == 187
|
||||||
|
|
||||||
|
|
||||||
def test_closest_function_home_vs_domain(hass):
|
def test_closest_function_home_vs_domain(hass):
|
||||||
|
@ -1400,11 +1394,11 @@ async def test_closest_function_home_vs_group_state(hass):
|
||||||
async def test_expand(hass):
|
async def test_expand(hass):
|
||||||
"""Test expand function."""
|
"""Test expand function."""
|
||||||
info = render_to_info(hass, "{{ expand('test.object') }}")
|
info = render_to_info(hass, "{{ expand('test.object') }}")
|
||||||
assert_result_info(info, "[]", ["test.object"])
|
assert_result_info(info, [], ["test.object"])
|
||||||
assert info.rate_limit is None
|
assert info.rate_limit is None
|
||||||
|
|
||||||
info = render_to_info(hass, "{{ expand(56) }}")
|
info = render_to_info(hass, "{{ expand(56) }}")
|
||||||
assert_result_info(info, "[]")
|
assert_result_info(info, [])
|
||||||
assert info.rate_limit is None
|
assert info.rate_limit is None
|
||||||
|
|
||||||
hass.states.async_set("test.object", "happy")
|
hass.states.async_set("test.object", "happy")
|
||||||
|
@ -1476,7 +1470,7 @@ async def test_expand(hass):
|
||||||
)
|
)
|
||||||
assert_result_info(
|
assert_result_info(
|
||||||
info,
|
info,
|
||||||
str(200.2 + 400.4),
|
200.2 + 400.4,
|
||||||
{"group.power_sensors", "sensor.power_1", "sensor.power_2", "sensor.power_3"},
|
{"group.power_sensors", "sensor.power_1", "sensor.power_2", "sensor.power_3"},
|
||||||
)
|
)
|
||||||
assert info.rate_limit is None
|
assert info.rate_limit is None
|
||||||
|
@ -1593,7 +1587,7 @@ def test_async_render_to_info_with_complex_branching(hass):
|
||||||
{"otherdomain": "sensor"},
|
{"otherdomain": "sensor"},
|
||||||
)
|
)
|
||||||
|
|
||||||
assert_result_info(info, "['sensor.a']", {"light.a", "light.b"}, {"sensor"})
|
assert_result_info(info, ["sensor.a"], {"light.a", "light.b"}, {"sensor"})
|
||||||
assert info.rate_limit == template.DEFAULT_RATE_LIMIT
|
assert info.rate_limit == template.DEFAULT_RATE_LIMIT
|
||||||
|
|
||||||
|
|
||||||
|
@ -1820,7 +1814,7 @@ def test_closest_function_invalid_state(hass):
|
||||||
for state in ("states.zone.non_existing", '"zone.non_existing"'):
|
for state in ("states.zone.non_existing", '"zone.non_existing"'):
|
||||||
assert (
|
assert (
|
||||||
template.Template("{{ closest(%s, states) }}" % state, hass).async_render()
|
template.Template("{{ closest(%s, states) }}" % state, hass).async_render()
|
||||||
== "None"
|
is None
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1836,7 +1830,7 @@ def test_closest_function_state_with_invalid_location(hass):
|
||||||
template.Template(
|
template.Template(
|
||||||
"{{ closest(states.test_domain.closest_home, states) }}", hass
|
"{{ closest(states.test_domain.closest_home, states) }}", hass
|
||||||
).async_render()
|
).async_render()
|
||||||
== "None"
|
is None
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1855,13 +1849,13 @@ def test_closest_function_invalid_coordinates(hass):
|
||||||
template.Template(
|
template.Template(
|
||||||
'{{ closest("invalid", "coord", states) }}', hass
|
'{{ closest("invalid", "coord", states) }}', hass
|
||||||
).async_render()
|
).async_render()
|
||||||
== "None"
|
is None
|
||||||
)
|
)
|
||||||
assert (
|
assert (
|
||||||
template.Template(
|
template.Template(
|
||||||
'{{ states | closest("invalid", "coord") }}', hass
|
'{{ states | closest("invalid", "coord") }}', hass
|
||||||
).async_render()
|
).async_render()
|
||||||
== "None"
|
is None
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -2004,7 +1998,7 @@ async def test_async_render_to_info_in_conditional(hass):
|
||||||
|
|
||||||
tmp = template.Template(template_str, hass)
|
tmp = template.Template(template_str, hass)
|
||||||
info = tmp.async_render_to_info()
|
info = tmp.async_render_to_info()
|
||||||
assert_result_info(info, "False", ["sensor.xyz"], [])
|
assert_result_info(info, False, ["sensor.xyz"], [])
|
||||||
|
|
||||||
hass.states.async_set("sensor.xyz", "dog")
|
hass.states.async_set("sensor.xyz", "dog")
|
||||||
hass.states.async_set("sensor.cow", "True")
|
hass.states.async_set("sensor.cow", "True")
|
||||||
|
@ -2020,7 +2014,7 @@ async def test_async_render_to_info_in_conditional(hass):
|
||||||
|
|
||||||
tmp = template.Template(template_str, hass)
|
tmp = template.Template(template_str, hass)
|
||||||
info = tmp.async_render_to_info()
|
info = tmp.async_render_to_info()
|
||||||
assert_result_info(info, "True", ["sensor.xyz", "sensor.cow"], [])
|
assert_result_info(info, True, ["sensor.xyz", "sensor.cow"], [])
|
||||||
|
|
||||||
hass.states.async_set("sensor.xyz", "sheep")
|
hass.states.async_set("sensor.xyz", "sheep")
|
||||||
hass.states.async_set("sensor.pig", "oink")
|
hass.states.async_set("sensor.pig", "oink")
|
||||||
|
@ -2327,17 +2321,17 @@ def test_length_of_states(hass):
|
||||||
hass.states.async_set("climate.test2", "cooling")
|
hass.states.async_set("climate.test2", "cooling")
|
||||||
|
|
||||||
tpl = template.Template("{{ states | length }}", hass)
|
tpl = template.Template("{{ states | length }}", hass)
|
||||||
assert tpl.async_render() == "3"
|
assert tpl.async_render() == 3
|
||||||
|
|
||||||
tpl = template.Template("{{ states.sensor | length }}", hass)
|
tpl = template.Template("{{ states.sensor | length }}", hass)
|
||||||
assert tpl.async_render() == "2"
|
assert tpl.async_render() == 2
|
||||||
|
|
||||||
|
|
||||||
def test_render_complex_handling_non_template_values(hass):
|
def test_render_complex_handling_non_template_values(hass):
|
||||||
"""Test that we can render non-template fields."""
|
"""Test that we can render non-template fields."""
|
||||||
assert template.render_complex(
|
assert template.render_complex(
|
||||||
{True: 1, False: template.Template("{{ hello }}", hass)}, {"hello": 2}
|
{True: 1, False: template.Template("{{ hello }}", hass)}, {"hello": 2}
|
||||||
) == {True: 1, False: "2"}
|
) == {True: 1, False: 2}
|
||||||
|
|
||||||
|
|
||||||
def test_urlencode(hass):
|
def test_urlencode(hass):
|
||||||
|
@ -2571,7 +2565,7 @@ async def test_state_attributes(hass):
|
||||||
"{{ states.sensor.test.state_with_unit }}",
|
"{{ states.sensor.test.state_with_unit }}",
|
||||||
hass,
|
hass,
|
||||||
)
|
)
|
||||||
assert tpl.async_render() == "23"
|
assert tpl.async_render() == 23
|
||||||
|
|
||||||
tpl = template.Template(
|
tpl = template.Template(
|
||||||
"{{ states.sensor.test.invalid_prop }}",
|
"{{ states.sensor.test.invalid_prop }}",
|
||||||
|
@ -2608,3 +2602,20 @@ async def test_unavailable_states(hass):
|
||||||
hass,
|
hass,
|
||||||
)
|
)
|
||||||
assert tpl.async_render() == "light.none, light.unavailable, light.unknown"
|
assert tpl.async_render() == "light.none, light.unavailable, light.unknown"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_legacy_templates(hass):
|
||||||
|
"""Test if old template behavior works when legacy templates are enabled."""
|
||||||
|
hass.states.async_set("sensor.temperature", "12")
|
||||||
|
|
||||||
|
assert (
|
||||||
|
template.Template("{{ states.sensor.temperature.state }}", hass).async_render()
|
||||||
|
== 12
|
||||||
|
)
|
||||||
|
|
||||||
|
await async_process_ha_core_config(hass, {"legacy_templates": True})
|
||||||
|
|
||||||
|
assert (
|
||||||
|
template.Template("{{ states.sensor.temperature.state }}", hass).async_render()
|
||||||
|
== "12"
|
||||||
|
)
|
||||||
|
|
|
@ -471,6 +471,7 @@ async def test_loading_configuration(hass):
|
||||||
"external_url": "https://www.example.com",
|
"external_url": "https://www.example.com",
|
||||||
"internal_url": "http://example.local",
|
"internal_url": "http://example.local",
|
||||||
"media_dirs": {"mymedia": "/usr"},
|
"media_dirs": {"mymedia": "/usr"},
|
||||||
|
"legacy_templates": True,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -487,6 +488,7 @@ async def test_loading_configuration(hass):
|
||||||
assert "/usr" in hass.config.allowlist_external_dirs
|
assert "/usr" in hass.config.allowlist_external_dirs
|
||||||
assert hass.config.media_dirs == {"mymedia": "/usr"}
|
assert hass.config.media_dirs == {"mymedia": "/usr"}
|
||||||
assert hass.config.config_source == config_util.SOURCE_YAML
|
assert hass.config.config_source == config_util.SOURCE_YAML
|
||||||
|
assert hass.config.legacy_templates is True
|
||||||
|
|
||||||
|
|
||||||
async def test_loading_configuration_temperature_unit(hass):
|
async def test_loading_configuration_temperature_unit(hass):
|
||||||
|
|
Loading…
Add table
Reference in a new issue