1
0
mirror of https://github.com/home-assistant/core.git synced 2026-05-19 06:50:15 +01:00

Fix line length violations in tests/components t-z (#170994)

This commit is contained in:
Franck Nijhof
2026-05-17 23:12:29 +02:00
committed by GitHub
parent d8cb3ab4b8
commit 833ff982d0
196 changed files with 1316 additions and 665 deletions
+1 -1
View File
@@ -124,7 +124,7 @@ async def test_duration_enabled_without_tado_default(
async def test_duration_enabled_with_tado_default(
hass: HomeAssistant, entry: ConfigEntry, tado: Tado
) -> None:
"""Test overlay method selection when ended up with timer overlay and None duration."""
"""Test overlay method selection with timer overlay and None duration."""
zone_fallback = CONST_OVERLAY_TIMER
expected_duration = 45000
tado = dummy_tado_connector(
+2 -2
View File
@@ -59,7 +59,7 @@ DEFAULT_CONFIG = {
"20": 0, # Update of Dimmer/Color/CT without turning power on
"30": 0, # Enforce Home Assistant auto-discovery as light
"68": 0, # Multi-channel PWM instead of a single light
"73": 0, # Enable Buttons decoupling and send multi-press and hold MQTT messages
"73": 0, # Enable Buttons decoupling and send multi-press
"82": 0, # Reduce the CT range from 153..500 to 200.380
"114": 0, # Enable sending switch MQTT messages
},
@@ -94,7 +94,7 @@ DEFAULT_CONFIG_9_0_0_3 = {
"20": 0, # Update of Dimmer/Color/CT without turning power on
"30": 0, # Enforce Home Assistant auto-discovery as light
"68": 0, # Multi-channel PWM instead of a single light
"73": 0, # Enable Buttons decoupling and send multi-press and hold MQTT messages
"73": 0, # Enable Buttons decoupling and send multi-press
"80": 0, # Blinds and shutters support
"82": 0, # Reduce the CT range from 153..500 to 200.380
},
+12 -6
View File
@@ -30,8 +30,10 @@ async def test_mqtt_abort_invalid_topic(
discovery_info = MqttServiceInfo(
topic="tasmota/discovery/DC4F220848A2/bla",
payload=(
'{"ip":"192.168.0.136","dn":"Tasmota","fn":["Tasmota",null,null,null,null,'
'null,null,null],"hn":"tasmota_0848A2","mac":"DC4F220848A2","md":"Sonoff Basic",'
'{"ip":"192.168.0.136","dn":"Tasmota",'
'"fn":["Tasmota",null,null,null,null,'
'null,null,null],"hn":"tasmota_0848A2",'
'"mac":"DC4F220848A2","md":"Sonoff Basic",'
'"ty":0,"if":0,"ofln":"Offline","onln":"Online","state":["OFF","ON",'
'"TOGGLE","HOLD"],"sw":"9.4.0.4","t":"tasmota_0848A2","ft":"%topic%/%prefix%/",'
'"tp":["cmnd","stat","tele"],"rl":[1,0,0,0,0,0,0,0],"swc":[-1,-1,-1,-1,-1,-1,-1,-1],'
@@ -67,8 +69,10 @@ async def test_mqtt_abort_invalid_topic(
discovery_info = MqttServiceInfo(
topic="tasmota/discovery/DC4F220848A2/config",
payload=(
'{"ip":"192.168.0.136","dn":"Tasmota","fn":["Tasmota",null,null,null,null,'
'null,null,null],"hn":"tasmota_0848A2","mac":"DC4F220848A2","md":"Sonoff Basic",'
'{"ip":"192.168.0.136","dn":"Tasmota",'
'"fn":["Tasmota",null,null,null,null,'
'null,null,null],"hn":"tasmota_0848A2",'
'"mac":"DC4F220848A2","md":"Sonoff Basic",'
'"ty":0,"if":0,"ofln":"Offline","onln":"Online","state":["OFF","ON",'
'"TOGGLE","HOLD"],"sw":"9.4.0.4","t":"tasmota_0848A2","ft":"%topic%/%prefix%/",'
'"tp":["cmnd","stat","tele"],"rl":[1,0,0,0,0,0,0,0],"swc":[-1,-1,-1,-1,-1,-1,-1,-1],'
@@ -92,8 +96,10 @@ async def test_mqtt_setup(hass: HomeAssistant, mqtt_mock: MqttMockHAClient) -> N
discovery_info = MqttServiceInfo(
topic="tasmota/discovery/DC4F220848A2/config",
payload=(
'{"ip":"192.168.0.136","dn":"Tasmota","fn":["Tasmota",null,null,null,null,'
'null,null,null],"hn":"tasmota_0848A2","mac":"DC4F220848A2","md":"Sonoff Basic",'
'{"ip":"192.168.0.136","dn":"Tasmota",'
'"fn":["Tasmota",null,null,null,null,'
'null,null,null],"hn":"tasmota_0848A2",'
'"mac":"DC4F220848A2","md":"Sonoff Basic",'
'"ty":0,"if":0,"ofln":"Offline","onln":"Online","state":["OFF","ON",'
'"TOGGLE","HOLD"],"sw":"9.4.0.4","t":"tasmota_0848A2","ft":"%topic%/%prefix%/",'
'"tp":["cmnd","stat","tele"],"rl":[1,0,0,0,0,0,0,0],"swc":[-1,-1,-1,-1,-1,-1,-1,-1],'
+2 -1
View File
@@ -400,7 +400,8 @@ async def test_device_remove_multiple_config_entries_2(
assert device_entry.config_entries == {tasmota_entry.entry_id}
mqtt_mock.async_publish.assert_not_called()
# Remove other config entry from the other device - Tasmota should not do any cleanup
# Remove other config entry from the other device
# Tasmota should not do any cleanup
device_registry.async_update_device(
other_device_entry.id, remove_config_entry_id=mock_entry.entry_id
)
+2 -1
View File
@@ -188,7 +188,8 @@ async def test_sending_mqtt_commands(
assert state.attributes["percentage"] == 0
mqtt_mock.async_publish.reset_mock()
# Finally, turn the fan on again and verify MQTT message is sent with last known speed
# Finally, turn the fan on again and verify MQTT message is sent
# with last known speed
await common.async_turn_on(hass, "fan.tasmota")
mqtt_mock.async_publish.assert_called_once_with(
"tasmota_49A3BC/cmnd/FanSpeed", "3", 0, False, message_expiry_interval=None
+13 -6
View File
@@ -201,7 +201,8 @@ TEMPERATURE_SENSOR_CONFIG = {
["sensor.tasmota_tx23_speed_act", "sensor.tasmota_tx23_dir_card"],
(
'{"TX23":{"Speed":{"Act":"12.3"},"Dir": {"Card": "WSW"}}}',
'{"StatusSNS":{"TX23":{"Speed":{"Act":"23.4"},"Dir": {"Card": "ESE"}}}}',
'{"StatusSNS":{"TX23":{"Speed":{"Act":"23.4"},'
'"Dir": {"Card": "ESE"}}}}',
),
),
(
@@ -239,8 +240,10 @@ TEMPERATURE_SENSOR_CONFIG = {
LIST_SENSOR_CONFIG_2,
["sensor.tasmota_energy_total_0", "sensor.tasmota_energy_total_1"],
(
'{"ENERGY":{"Total":[1.2, 3.4],"TotalStartTime":"2018-11-23T15:33:47"}}',
'{"StatusSNS":{"ENERGY":{"Total":[5.6, 7.8],"TotalStartTime":"2018-11-23T16:33:47"}}}',
'{"ENERGY":{"Total":[1.2, 3.4],'
'"TotalStartTime":"2018-11-23T15:33:47"}}',
'{"StatusSNS":{"ENERGY":{"Total":[5.6, 7.8],'
'"TotalStartTime":"2018-11-23T16:33:47"}}}',
),
),
# Test dict Total sensors
@@ -251,8 +254,11 @@ TEMPERATURE_SENSOR_CONFIG = {
"sensor.tasmota_energy_total_phase2",
],
(
'{"ENERGY":{"Total":{"Phase1":1.2, "Phase2":3.4},"TotalStartTime":"2018-11-23T15:33:47"}}',
'{"StatusSNS":{"ENERGY":{"Total":{"Phase1":5.6, "Phase2":7.8},"TotalStartTime":"2018-11-23T15:33:47"}}}',
'{"ENERGY":{"Total":{"Phase1":1.2, "Phase2":3.4},'
'"TotalStartTime":"2018-11-23T15:33:47"}}',
'{"StatusSNS":{"ENERGY":'
'{"Total":{"Phase1":5.6, "Phase2":7.8},'
'"TotalStartTime":"2018-11-23T15:33:47"}}}',
),
),
(
@@ -292,7 +298,8 @@ TEMPERATURE_SENSOR_CONFIG = {
),
),
),
# Test we automatically set state class to measurement on unknown numerical sensors
# Test we automatically set state class to measurement on
# unknown numerical sensors
(
DEFAULT_SENSOR_CONFIG_UNKNOWN,
[
@@ -75,7 +75,7 @@ async def test_connection_error(hass: HomeAssistant, mock_technove: MagicMock) -
async def test_full_user_flow_with_error(
hass: HomeAssistant, mock_technove: MagicMock
) -> None:
"""Test the full manual user flow from start to finish with some errors in the middle."""
"""Test the full manual user flow with some errors in the middle."""
mock_technove.update.side_effect = TechnoVEConnectionError
result = await hass.config_entries.flow.async_init(
DOMAIN,
+4 -1
View File
@@ -134,7 +134,10 @@ async def test_lock_without_pullspring(
with pytest.raises(
ServiceNotSupported,
match=f"Entity lock.lock_2c3d does not support action {LOCK_DOMAIN}.{SERVICE_OPEN}",
match=(
"Entity lock.lock_2c3d does not support action"
f" {LOCK_DOMAIN}.{SERVICE_OPEN}"
),
):
await hass.services.async_call(
LOCK_DOMAIN,
+3 -3
View File
@@ -255,7 +255,7 @@ def update_message_text():
@pytest.fixture
def unauthorized_update_message_text(update_message_text):
"""Fixture for mocking an incoming update of type message/text that is not in our `allowed_chat_ids`."""
"""Fixture for mocking an incoming unauthorized message/text."""
update_message_text["message"]["from"]["id"] = 1234
update_message_text["message"]["chat"]["id"] = 1234
return update_message_text
@@ -285,7 +285,7 @@ def update_callback_query():
@pytest.fixture
def update_callback_inline_keyboard():
"""Fixture for mocking an incoming update of type callback_query from inline keyboard button."""
"""Fixture for mocking a callback_query from inline keyboard."""
return {
"update_id": 1,
"callback_query": {
@@ -382,7 +382,7 @@ async def webhook_bot(
@pytest.fixture
def mock_polling_calls() -> Generator[None]:
"""Fixture for setting up the polling platform using appropriate config and mocks."""
"""Fixture for setting up the polling platform with config and mocks."""
with patch(
"homeassistant.components.telegram_bot.polling.ApplicationBuilder"
) as application_builder_class:
@@ -743,7 +743,7 @@ async def test_subentry_flow_broadcast_update_error(
mock_broadcast_config_entry: MockConfigEntry,
mock_external_calls: None,
) -> None:
"""Test subentry flow where broadcast bot encounter error while receiving messages."""
"""Test subentry flow where broadcast bot errors receiving messages."""
mock_broadcast_config_entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(mock_broadcast_config_entry.entry_id)
@@ -205,7 +205,7 @@ async def test_polling_platform_init_failed(
async def test_send_message(
hass: HomeAssistant, webhook_bot, service: str, input: dict[str, Any]
) -> None:
"""Test the send_message service. Tests any service that does not require files to be sent."""
"""Test services that do not require files to be sent."""
context = Context()
events = async_capture_events(hass, "telegram_sent")
@@ -375,7 +375,12 @@ async def test_send_sticker_partial_error(
assert mock_send_sticker.call_count == 2
assert err.value.translation_key == "multiple_errors"
assert err.value.translation_placeholders == {
"errors": "`entity_id` notify.mock_title_mock_chat_1: mock network error\n`entity_id` notify.mock_title_mock_chat_2: mock network error"
"errors": (
"`entity_id` notify.mock_title_mock_chat_1:"
" mock network error\n"
"`entity_id` notify.mock_title_mock_chat_2:"
" mock network error"
)
}
@@ -623,7 +628,7 @@ async def test_webhook_endpoint_generates_telegram_text_event(
update_message_text,
mock_generate_secret_token,
) -> None:
"""POST to the configured webhook endpoint and assert fired `telegram_text` event."""
"""POST to webhook endpoint and assert fired telegram_text event."""
client = await hass_client()
events = async_capture_events(hass, "telegram_text")
@@ -650,7 +655,7 @@ async def test_webhook_endpoint_generates_telegram_command_event(
update_message_command,
mock_generate_secret_token,
) -> None:
"""POST to the configured webhook endpoint and assert fired `telegram_command` event."""
"""POST to webhook endpoint and assert fired telegram_command event."""
client = await hass_client()
events = async_capture_events(hass, "telegram_command")
@@ -752,7 +757,7 @@ async def test_webhook_endpoint_generates_telegram_attachment_event(
mock_generate_secret_token: str,
attachment_type: str,
) -> None:
"""POST to the configured webhook endpoint and assert fired `telegram_attachment` event for photo and document."""
"""POST to webhook and assert fired telegram_attachment event."""
client = await hass_client()
events = async_capture_events(hass, "telegram_attachment")
update_message_attachment = await async_load_fixture(
@@ -790,13 +795,14 @@ async def test_polling_platform_message_text_update(
update_message_text,
mock_external_calls: None,
) -> None:
"""Provide the `BaseTelegramBot.update_handler` with an `Update` and assert fired `telegram_text` event."""
"""Test update_handler with an Update fires telegram_text event."""
events = async_capture_events(hass, "telegram_text")
with patch(
"homeassistant.components.telegram_bot.polling.ApplicationBuilder"
) as application_builder_class:
# Set up the integration with the polling platform inside the patch context manager.
# Set up the integration with the polling platform inside
# the patch context manager.
application = (
application_builder_class.return_value.bot.return_value.build.return_value
)
@@ -1941,10 +1947,24 @@ async def test_migrate_chat_id(
"action": "telegram_bot.send_message",
"action_origin": expected_action_origin,
"chat_ids": "654321",
"telegram_bot_entities_url": "/config/entities?domain=telegram_bot",
"example_old": "```yaml\naction: send_message\ndata:\n target: # to be updated\n - 1234567890\n...\n```",
"example_new_entity_id": "```yaml\naction: send_message\ndata:\n entity_id:\n - notify.telegram_bot_1234567890_1234567890 # replace with your notify entity\n...\n```",
"example_new_chat_id": "```yaml\naction: send_message\ndata:\n chat_id:\n - 1234567890 # replace with your chat_id\n...\n```",
"telegram_bot_entities_url": ("/config/entities?domain=telegram_bot"),
"example_old": (
"```yaml\naction: send_message\ndata:\n"
" target: # to be updated\n"
" - 1234567890\n...\n```"
),
"example_new_entity_id": (
"```yaml\naction: send_message\ndata:\n"
" entity_id:\n"
" - notify.telegram_bot_1234567890_1234567890"
" # replace with your notify entity\n...\n```"
),
"example_new_chat_id": (
"```yaml\naction: send_message\ndata:\n"
" chat_id:\n"
" - 1234567890"
" # replace with your chat_id\n...\n```"
),
}
# fix the issue via repair flow
@@ -1972,9 +1992,23 @@ async def test_migrate_chat_id(
"action_origin": expected_action_origin,
"chat_ids": "654321",
"telegram_bot_entities_url": "/config/entities?domain=telegram_bot",
"example_old": "```yaml\naction: send_message\ndata:\n target: # to be updated\n - 1234567890\n...\n```",
"example_new_entity_id": "```yaml\naction: send_message\ndata:\n entity_id:\n - notify.telegram_bot_1234567890_1234567890 # replace with your notify entity\n...\n```",
"example_new_chat_id": "```yaml\naction: send_message\ndata:\n chat_id:\n - 1234567890 # replace with your chat_id\n...\n```",
"example_old": (
"```yaml\naction: send_message\ndata:\n"
" target: # to be updated\n"
" - 1234567890\n...\n```"
),
"example_new_entity_id": (
"```yaml\naction: send_message\ndata:\n"
" entity_id:\n"
" - notify.telegram_bot_1234567890_1234567890"
" # replace with your notify entity\n...\n```"
),
"example_new_chat_id": (
"```yaml\naction: send_message\ndata:\n"
" chat_id:\n"
" - 1234567890"
" # replace with your chat_id\n...\n```"
),
},
"last_step": None,
"preview": None,
@@ -45,7 +45,8 @@ async def test_set_webhooks_failed(
# first fail with exception, second fail with False
assert mock_set_webhook.call_count == 2
# SETUP_ERROR is result of RuntimeError("Failed to register webhook with Telegram") in webhooks.py
# SETUP_ERROR is result of RuntimeError(
# "Failed to register webhook with Telegram") in webhooks.py
assert mock_webhooks_config_entry.state is ConfigEntryState.SETUP_ERROR
# test fail after retries
@@ -180,7 +180,7 @@ async def test_step_import_load_json(hass: HomeAssistant, mock_tellduslive) -> N
@pytest.mark.parametrize("supports_local_api", [False])
async def test_step_disco_no_local_api(hass: HomeAssistant, mock_tellduslive) -> None:
"""Test that we trigger when configuring from discovery, not supporting local api."""
"""Test configuring from discovery, not supporting local api."""
flow = init_config_flow(hass)
flow.context = {"source": SOURCE_DISCOVERY}
@@ -560,7 +560,7 @@ async def test_form_user_flow_rut240(
mock_teltasync_client: MagicMock,
rut240_device_info: UnauthorizedStatusData,
) -> None:
"""RUT240 firmware omits device_identifier; the flow falls back to mnf_info.serial."""
"""RUT240 firmware omits device_identifier; falls back to serial."""
mock_teltasync_client.get_device_info.return_value = rut240_device_info
mock_teltasync_client.validate_credentials.return_value = True
@@ -695,7 +695,7 @@ async def test_dhcp_discovery_apiv1_already_configured_aborts(
mock_config_entry: MockConfigEntry,
rut240_device_info: UnauthorizedStatusData,
) -> None:
"""An API v1.0 (e.g. RUT240) known to the device registry by MAC aborts before dhcp_confirm."""
"""API v1.0 RUT240 known by MAC aborts before dhcp_confirm."""
mock_config_entry.add_to_hass(hass)
device_registry.async_get_or_create(
config_entry_id=mock_config_entry.entry_id,
+15 -13
View File
@@ -156,7 +156,7 @@ async def test_temperature_trigger_sensor_behavior_any(
trigger_options: dict[str, Any],
states: list[TriggerStateDescription],
) -> None:
"""Test temperature trigger fires for sensor entities with device_class temperature."""
"""Test trigger fires for sensor entities with device_class temperature."""
await assert_trigger_behavior_any(
hass,
target_entities=target_sensors,
@@ -195,7 +195,7 @@ async def test_temperature_trigger_sensor_crossed_threshold_behavior_first(
trigger_options: dict[str, Any],
states: list[TriggerStateDescription],
) -> None:
"""Test temperature crossed_threshold trigger fires on the first sensor state change."""
"""Test crossed_threshold trigger fires on first sensor state change."""
await assert_trigger_behavior_first(
hass,
target_entities=target_sensors,
@@ -234,7 +234,7 @@ async def test_temperature_trigger_sensor_crossed_threshold_behavior_last(
trigger_options: dict[str, Any],
states: list[TriggerStateDescription],
) -> None:
"""Test temperature crossed_threshold trigger fires when the last sensor changes state."""
"""Test crossed_threshold trigger fires on last sensor state change."""
await assert_trigger_behavior_last(
hass,
target_entities=target_sensors,
@@ -324,7 +324,7 @@ async def test_temperature_trigger_climate_crossed_threshold_behavior_first(
trigger_options: dict[str, Any],
states: list[TriggerStateDescription],
) -> None:
"""Test temperature crossed_threshold trigger fires on the first climate state change."""
"""Test crossed_threshold trigger fires on first climate state change."""
await assert_trigger_behavior_first(
hass,
target_entities=target_climates,
@@ -364,7 +364,7 @@ async def test_temperature_trigger_climate_crossed_threshold_behavior_last(
trigger_options: dict[str, Any],
states: list[TriggerStateDescription],
) -> None:
"""Test temperature crossed_threshold trigger fires when the last climate changes state."""
"""Test crossed_threshold trigger fires on last climate state change."""
await assert_trigger_behavior_last(
hass,
target_entities=target_climates,
@@ -454,7 +454,7 @@ async def test_temperature_trigger_water_heater_crossed_threshold_behavior_first
trigger_options: dict[str, Any],
states: list[TriggerStateDescription],
) -> None:
"""Test temperature crossed_threshold trigger fires on the first water_heater state change."""
"""Test crossed_threshold fires on first water_heater state change."""
await assert_trigger_behavior_first(
hass,
target_entities=target_water_heaters,
@@ -494,7 +494,7 @@ async def test_temperature_trigger_water_heater_crossed_threshold_behavior_last(
trigger_options: dict[str, Any],
states: list[TriggerStateDescription],
) -> None:
"""Test temperature crossed_threshold trigger fires when the last water_heater changes state."""
"""Test crossed_threshold fires on last water_heater state change."""
await assert_trigger_behavior_last(
hass,
target_entities=target_water_heaters,
@@ -587,7 +587,7 @@ async def test_temperature_trigger_weather_crossed_threshold_behavior_first(
trigger_options: dict[str, Any],
states: list[TriggerStateDescription],
) -> None:
"""Test temperature crossed_threshold trigger fires on the first weather state change."""
"""Test crossed_threshold trigger fires on first weather state change."""
await assert_trigger_behavior_first(
hass,
target_entities=target_weathers,
@@ -628,7 +628,7 @@ async def test_temperature_trigger_weather_crossed_threshold_behavior_last(
trigger_options: dict[str, Any],
states: list[TriggerStateDescription],
) -> None:
"""Test temperature crossed_threshold trigger fires when the last weather changes state."""
"""Test crossed_threshold fires on last weather state change."""
await assert_trigger_behavior_last(
hass,
target_entities=target_weathers,
@@ -648,7 +648,7 @@ async def test_temperature_trigger_weather_crossed_threshold_behavior_last(
async def test_temperature_trigger_unit_conversion_sensor_celsius_to_fahrenheit(
hass: HomeAssistant,
) -> None:
"""Test temperature trigger converts sensor value from °C to °F for threshold comparison."""
"""Test trigger converts sensor value from C to F for comparison."""
calls: list[str] = []
entity_id = "sensor.test_temp"
@@ -706,7 +706,7 @@ async def test_temperature_trigger_unit_conversion_sensor_celsius_to_fahrenheit(
async def test_temperature_trigger_unit_conversion_sensor_fahrenheit_to_celsius(
hass: HomeAssistant,
) -> None:
"""Test temperature trigger converts sensor value from °F to °C for threshold comparison."""
"""Test trigger converts sensor value from F to C for comparison."""
calls: list[str] = []
entity_id = "sensor.test_temp"
@@ -768,7 +768,8 @@ async def test_temperature_trigger_unit_conversion_changed(
calls: list[str] = []
entity_id = "sensor.test_temp"
# Sensor reports in °C, trigger configured in °F: above 68°F (20°C), below 77°F (25°C)
# Sensor reports in C, trigger configured in F:
# above 68F (20C), below 77F (25C)
hass.states.async_set(
entity_id,
"18",
@@ -839,7 +840,8 @@ async def test_temperature_trigger_unit_conversion_weather(
calls: list[str] = []
entity_id = "weather.test"
# Weather reports temperature in °F, trigger configured in °C with threshold above 25°C
# Weather reports in F, trigger configured in C with threshold
# above 25C
hass.states.async_set(
entity_id,
"sunny",
+6 -5
View File
@@ -96,7 +96,7 @@ async def async_setup_legacy_platforms(
count: int,
config: ConfigType | list[ConfigType],
) -> None:
"""Do setup of any legacy platform that supports a keyed dictionary of template entities."""
"""Do setup of any legacy platform with keyed template entities."""
if slug is None:
# Lock and Weather platforms do not use a slug
if isinstance(config, list):
@@ -301,12 +301,13 @@ async def setup_and_test_nested_unique_id(
entity_config: ConfigType | None,
state_template: str | None = None,
) -> None:
"""Setup 2 entities with unique unique_ids in a template section that contains a unique_id.
"""Setup 2 entities with unique_ids in a template section with a unique_id.
The test will verify that 2 entities are created where the unique_id appends the
section unique_id to each entity unique_id.
The test will verify that 2 entities are created where the unique_id
appends the section unique_id to each entity unique_id.
The entity_config should not provide name or unique_id, those are added automatically.
The entity_config should not provide name or unique_id, those are
added automatically.
"""
state_config = {"state": state_template} if state_template else {}
entities = [
@@ -1186,7 +1186,7 @@ async def test_trigger_with_negative_time_periods(
async def test_trigger_template_delay_with_multiple_triggers(
hass: HomeAssistant, delay_state: str, freezer: FrozenDateTimeFactory
) -> None:
"""Test trigger based binary sensor with multiple triggers occurring during the delay."""
"""Test trigger based binary sensor with multiple triggers during delay."""
for _ in range(10):
# State should still be unknown
state = hass.states.get(TEST_BINARY_SENSOR.entity_id)
+1 -1
View File
@@ -229,7 +229,7 @@ async def test_reload_template_when_blueprint_changes(hass: HomeAssistant) -> No
async def test_init_attribute_variables_from_blueprint(hass: HomeAssistant) -> None:
"""Test a state based blueprint initializes icon, name, and picture with variables."""
"""Test blueprint initializes icon, name, and picture with variables."""
blueprint = "test_init_attribute_variables.yaml"
source = "switch.foo"
entity_id = "sensor.foo"
+28 -8
View File
@@ -131,7 +131,8 @@ async def test_invalid_default_entity_id(
"auto_off": "00:00:01",
},
},
"The auto_off option for template binary sensor: name: Template Binary Sensor",
"The auto_off option for template binary sensor:"
" name: Template Binary Sensor",
),
(
{
@@ -172,7 +173,8 @@ async def test_invalid_default_entity_id(
"auto_off": "00:00:01",
},
},
"The auto_off option for template binary sensor: default_entity_id: binary_sensor.test_entity_id",
"The auto_off option for template binary sensor:"
" default_entity_id: binary_sensor.test_entity_id",
),
(
{
@@ -195,7 +197,8 @@ async def test_invalid_default_entity_id(
"auto_off": "00:00:01",
},
},
"The auto_off option for template binary sensor: default_entity_id: binary_sensor.test_entity_id",
"The auto_off option for template binary sensor:"
" default_entity_id: binary_sensor.test_entity_id",
),
],
)
@@ -376,7 +379,7 @@ async def test_combined_trigger_variables(
async def test_state_init_attribute_variables(
hass: HomeAssistant,
) -> None:
"""Test a state based template entity initializes icon, name, and picture with variables."""
"""Test state based template entity initializes attributes with variables."""
source = "switch.foo"
entity_id = "sensor.foo"
@@ -396,7 +399,9 @@ async def test_state_init_attribute_variables(
},
"name": "{{ state_attr(switch, 'friendly_name') }}",
"icon": "{{ on_icon if is_state(switch, 'on') else off_icon }}",
"picture": "{{ on_picture if is_state(switch, 'on') else off_picture }}",
"picture": (
"{{ on_picture if is_state(switch, 'on') else off_picture }}"
),
"state": "{{ is_state(switch, 'on') }}",
},
}
@@ -436,7 +441,8 @@ async def test_state_init_attribute_variables(
{
"trigger": {"trigger": "event", "event_type": "my_event"},
},
"Invalid template configuration found, trigger option is missing matching domain",
"Invalid template configuration found, trigger option is"
" missing matching domain",
),
(
{
@@ -520,10 +526,24 @@ async def test_multiple_configuration_keys(
"action": "cover.stop_cover",
},
"default_entity_id": "cover.shades_reversed",
"icon": "{% set s = states('cover.shades_curtain') %}\n{% if s == 'open' %}\n mdi:curtains-closed\n{% else %}\n mdi:curtains\n{% endif %}",
"icon": (
"{% set s = states('cover.shades_curtain') %}\n"
"{% if s == 'open' %}\n"
" mdi:curtains-closed\n"
"{% else %}\n"
" mdi:curtains\n"
"{% endif %}"
),
"name": "Shades Reversed",
"unique_id": "c0223bcb-32c6-430e-a2c1-3545f8031796",
"state": "{% set s = states('cover.shades_curtain') %}\n{% if s == 'open' %}\n closed\n{% elif s == 'closed' %}\n open\n{% elif s == 'opening' %}\n closing\n{% elif s == 'closing' %}\n opening\n{% else %}\n unknown\n{% endif %}",
"state": (
"{% set s = states('cover.shades_curtain') %}\n"
"{% if s == 'open' %}\n closed\n"
"{% elif s == 'closed' %}\n open\n"
"{% elif s == 'opening' %}\n closing\n"
"{% elif s == 'closing' %}\n opening\n"
"{% else %}\n unknown\n{% endif %}"
),
}
]
},
+44 -12
View File
@@ -73,7 +73,10 @@ BINARY_SENSOR_OPTIONS = {
(
"binary_sensor",
{
"state": "{{ states('binary_sensor.one') == 'on' or states('binary_sensor.two') == 'on' }}"
"state": (
"{{ states('binary_sensor.one') == 'on'"
" or states('binary_sensor.two') == 'on' }}"
)
},
"on",
{"one": "on", "two": "off"},
@@ -85,7 +88,9 @@ BINARY_SENSOR_OPTIONS = {
(
"sensor",
{
"state": "{{ float(states('sensor.one')) + float(states('sensor.two')) }}"
"state": (
"{{ float(states('sensor.one')) + float(states('sensor.two')) }}"
)
},
"50.0",
{"one": "30.0", "two": "20.0"},
@@ -570,10 +575,16 @@ async def test_config_flow_device(
(
"binary_sensor",
{
"state": "{{ states('binary_sensor.one') == 'on' or states('binary_sensor.two') == 'on' }}"
"state": (
"{{ states('binary_sensor.one') == 'on'"
" or states('binary_sensor.two') == 'on' }}"
)
},
{
"state": "{{ states('binary_sensor.one') == 'on' and states('binary_sensor.two') == 'on' }}"
"state": (
"{{ states('binary_sensor.one') == 'on'"
" and states('binary_sensor.two') == 'on' }}"
)
},
["on", "off"],
{"one": "on", "two": "off"},
@@ -585,10 +596,14 @@ async def test_config_flow_device(
(
"sensor",
{
"state": "{{ float(states('sensor.one')) + float(states('sensor.two')) }}"
"state": (
"{{ float(states('sensor.one')) + float(states('sensor.two')) }}"
)
},
{
"state": "{{ float(states('sensor.one')) - float(states('sensor.two')) }}"
"state": (
"{{ float(states('sensor.one')) - float(states('sensor.two')) }}"
)
},
["50.0", "10.0"],
{"one": "30.0", "two": "20.0"},
@@ -916,10 +931,16 @@ async def test_options(
(
"binary_sensor",
{
"state": "{{ states('binary_sensor.one') == 'on' or states('binary_sensor.two') == 'on' }}"
"state": (
"{{ states('binary_sensor.one') == 'on'"
" or states('binary_sensor.two') == 'on' }}"
)
},
{
"state": "{{ states('binary_sensor.one') == 'on' and states('binary_sensor.two') == 'on' }}"
"state": (
"{{ states('binary_sensor.one') == 'on'"
" and states('binary_sensor.two') == 'on' }}"
)
},
{"one": "on", "two": "off"},
{"device_class": "motion"},
@@ -1026,7 +1047,10 @@ async def test_options_remove_device_class(
[
(
"binary_sensor",
"{{ states.binary_sensor.one.state == 'on' or states.binary_sensor.two.state == 'on' }}",
(
"{{ states.binary_sensor.one.state == 'on'"
" or states.binary_sensor.two.state == 'on' }}"
),
{},
{"one": "on", "two": "off"},
["off", "on"],
@@ -1225,7 +1249,9 @@ EARLY_END_ERROR = "invalid template (TemplateSyntaxError: unexpected 'end of tem
),
"unit_of_measurement": (
"'None' is not a valid unit for device class 'energy'; "
"expected one of 'cal', 'Gcal', 'GJ', 'GWh', 'J', 'kcal', 'kJ', 'kWh', 'Mcal', 'MJ', 'MWh', 'mWh', 'TWh', 'Wh'"
"expected one of 'cal', 'Gcal', 'GJ', 'GWh', 'J',"
" 'kcal', 'kJ', 'kWh', 'Mcal', 'MJ', 'MWh',"
" 'mWh', 'TWh', 'Wh'"
),
},
),
@@ -1504,8 +1530,14 @@ async def test_config_flow_preview_bad_state(
[
(
"binary_sensor",
"{{ states('binary_sensor.one') == 'on' or states('binary_sensor.two') == 'on' }}",
"{{ states('binary_sensor.one') == 'on' and states('binary_sensor.two') == 'on' }}",
(
"{{ states('binary_sensor.one') == 'on'"
" or states('binary_sensor.two') == 'on' }}"
),
(
"{{ states('binary_sensor.one') == 'on'"
" and states('binary_sensor.two') == 'on' }}"
),
{},
{},
{"one": "on", "two": "off"},
+17 -6
View File
@@ -524,22 +524,26 @@ async def test_position_out_of_bounds(hass: HomeAssistant) -> None:
(
ConfigurationStyle.MODERN,
{},
"Invalid config for 'template': must contain at least one of open_cover, set_cover_position.",
"Invalid config for 'template': must contain at least one"
" of open_cover, set_cover_position.",
),
(
ConfigurationStyle.MODERN,
OPEN_COVER,
"Invalid config for 'template': some but not all values in the same group of inclusion 'open_or_close'",
"Invalid config for 'template': some but not all values"
" in the same group of inclusion 'open_or_close'",
),
(
ConfigurationStyle.TRIGGER,
{},
"Invalid config for 'template': must contain at least one of open_cover, set_cover_position.",
"Invalid config for 'template': must contain at least one"
" of open_cover, set_cover_position.",
),
(
ConfigurationStyle.TRIGGER,
OPEN_COVER,
"Invalid config for 'template': some but not all values in the same group of inclusion 'open_or_close'",
"Invalid config for 'template': some but not all values"
" in the same group of inclusion 'open_or_close'",
),
],
)
@@ -740,7 +744,10 @@ async def test_set_position_optimistic(
ConfigurationStyle.TRIGGER,
{
**SET_COVER_POSITION,
"picture": "{{ 'foo.png' if is_state('sensor.test_state', 'open') else 'bar.png' }}",
"picture": (
"{{ 'foo.png' if is_state('sensor.test_state',"
" 'open') else 'bar.png' }}"
),
},
),
],
@@ -1013,7 +1020,11 @@ async def test_state_gets_lowercased(hass: HomeAssistant) -> None:
(
1,
"{{ states.sensor.test_state.state }}",
"mdi:window-shutter{{ '-open' if is_state('cover.test_template_cover', 'open') else '' }}",
(
"mdi:window-shutter{{ '-open'"
" if is_state('cover.test_template_cover', 'open')"
" else '' }}"
),
)
],
)
+2 -2
View File
@@ -286,7 +286,7 @@ async def test_yaml_device_actions(
entity_registry: er.EntityRegistry,
calls: list,
) -> None:
"""Test device actions in platforms that support both trigger and modern configurations."""
"""Test device actions in platforms supporting trigger and modern configs."""
await _setup_and_test_yaml_device_action(
hass,
style,
@@ -542,7 +542,7 @@ async def test_config_entry_device_actions(
async def test_platform_not_ready(
hass: HomeAssistant,
) -> None:
"""Test async_setup_template_platform raises PlatformNotReady when trigger object is None."""
"""Test async_setup_template_platform raises PlatformNotReady."""
with pytest.raises(PlatformNotReady):
await async_setup_template_platform(
hass,
+1 -1
View File
@@ -168,7 +168,7 @@ async def test_reloadable_stops_on_invalid_config(hass: HomeAssistant) -> None:
)
@pytest.mark.usefixtures("start_ha")
async def test_reloadable_handles_partial_valid_config(hass: HomeAssistant) -> None:
"""Test we can still setup valid sensors when configuration.yaml has a broken entry."""
"""Test we can still setup valid sensors when config has a broken entry."""
hass.states.async_set("sensor.test_sensor", "mytest")
await hass.async_block_till_done()
assert hass.states.get("sensor.state").state == "mytest"
+9 -3
View File
@@ -266,7 +266,9 @@ def _verify(
[
(
{
CONF_ICON: "{% if states.number.test_state.state == '1' %}mdi:check{% endif %}",
CONF_ICON: (
"{% if states.number.test_state.state == '1' %}mdi:check{% endif %}"
),
**TEST_REQUIRED,
},
ATTR_ICON,
@@ -274,7 +276,9 @@ def _verify(
),
(
{
CONF_PICTURE: "{% if states.number.test_state.state == '1' %}check.jpg{% endif %}",
CONF_PICTURE: (
"{% if states.number.test_state.state == '1' %}check.jpg{% endif %}"
),
**TEST_REQUIRED,
},
ATTR_ENTITY_PICTURE,
@@ -425,7 +429,9 @@ async def test_not_optimistic(hass: HomeAssistant) -> None:
{
"set_value": [],
"state": "{{ states('number.test_state') }}",
"availability": "{{ is_state('binary_sensor.test_availability', 'on') }}",
"availability": (
"{{ is_state('binary_sensor.test_availability', 'on') }}"
),
},
)
],
+11 -3
View File
@@ -239,7 +239,10 @@ def _verify(
(
{
**TEST_OPTIONS,
CONF_ICON: "{% if states.sensor.test_state.state == 'yes' %}mdi:check{% endif %}",
CONF_ICON: (
"{% if states.sensor.test_state.state == 'yes' %}"
"mdi:check{% endif %}"
),
},
ATTR_ICON,
"mdi:check",
@@ -247,7 +250,10 @@ def _verify(
(
{
**TEST_OPTIONS,
CONF_PICTURE: "{% if states.sensor.test_state.state == 'yes' %}check.jpg{% endif %}",
CONF_PICTURE: (
"{% if states.sensor.test_state.state == 'yes' %}"
"check.jpg{% endif %}"
),
},
ATTR_ENTITY_PICTURE,
"check.jpg",
@@ -441,7 +447,9 @@ async def test_not_optimistic(hass: HomeAssistant) -> None:
"options": "{{ ['test', 'yes', 'no'] }}",
"select_option": [],
"state": "{{ states('sensor.test_state') }}",
"availability": "{{ is_state('binary_sensor.test_availability', 'on') }}",
"availability": (
"{{ is_state('binary_sensor.test_availability', 'on') }}"
),
},
)
],
+126 -37
View File
@@ -261,7 +261,10 @@ async def test_icon_template(
("attribute_template", "before_update", "after_update"),
[
(
"{{ '/local/sensor.png' if is_state('sensor.test_state', 'Works') else '' }}",
(
"{{ '/local/sensor.png'"
" if is_state('sensor.test_state', 'Works') else '' }}"
),
"",
"/local/sensor.png",
),
@@ -305,7 +308,10 @@ async def test_entity_picture_template(
("attribute_template", "after_update"),
[
(
"{{ 'It Works.' if is_state('sensor.test_state', 'Works') else 'test_template_sensor' }}",
(
"{{ 'It Works.' if is_state('sensor.test_state',"
" 'Works') else 'test_template_sensor' }}"
),
"It Works.",
),
(
@@ -688,10 +694,31 @@ async def test_this_variable(hass: HomeAssistant, before: str, after: str) -> No
{
"template": {
"sensor": {
"state": "{{ this.attributes.get('test', 'no-test!') }}: {{ this.entity_id }}",
"icon": "mdi:{% if this.entity_id in states and 'friendly_name' in this.attributes %} {{this.attributes['friendly_name']}} {% else %}{{this.entity_id}}:{{this.entity_id in states}}{% endif %}",
"name": "{% if this.entity_id in states and 'friendly_name' in this.attributes %} {{this.attributes['friendly_name']}} {% else %}{{this.entity_id}}:{{this.entity_id in states}}{% endif %}",
"picture": "{% if this.entity_id in states and 'entity_picture' in this.attributes %} {{this.attributes['entity_picture']}} {% else %}{{this.entity_id}}:{{this.entity_id in states}}{% endif %}",
"state": (
"{{ this.attributes.get('test', 'no-test!') }}"
": {{ this.entity_id }}"
),
"icon": (
"mdi:{% if this.entity_id in states and"
" 'friendly_name' in this.attributes %}"
" {{this.attributes['friendly_name']}} "
"{% else %}{{this.entity_id}}:"
"{{this.entity_id in states}}{% endif %}"
),
"name": (
"{% if this.entity_id in states and"
" 'friendly_name' in this.attributes %}"
" {{this.attributes['friendly_name']}} "
"{% else %}{{this.entity_id}}:"
"{{this.entity_id in states}}{% endif %}"
),
"picture": (
"{% if this.entity_id in states and"
" 'entity_picture' in this.attributes %}"
" {{this.attributes['entity_picture']}} "
"{% else %}{{this.entity_id}}:"
"{{this.entity_id in states}}{% endif %}"
),
"attributes": {"test": "{{ this.entity_id }}"},
},
},
@@ -753,10 +780,31 @@ async def test_this_variable_early_hass_not_running(
{
"template": {
"sensor": {
"state": "{{ this.attributes.get('test', 'no-test!') }}: {{ this.entity_id }}",
"icon": "mdi:{% if this.entity_id in states and 'friendly_name' in this.attributes %} {{this.attributes['friendly_name']}} {% else %}{{this.entity_id}}:{{this.entity_id in states}}{% endif %}",
"name": "{% if this.entity_id in states and 'friendly_name' in this.attributes %} {{this.attributes['friendly_name']}} {% else %}{{this.entity_id}}:{{this.entity_id in states}}{% endif %}",
"picture": "{% if this.entity_id in states and 'entity_picture' in this.attributes %} {{this.attributes['entity_picture']}} {% else %}{{this.entity_id}}:{{this.entity_id in states}}{% endif %}",
"state": (
"{{ this.attributes.get('test', 'no-test!') }}"
": {{ this.entity_id }}"
),
"icon": (
"mdi:{% if this.entity_id in states and"
" 'friendly_name' in this.attributes %}"
" {{this.attributes['friendly_name']}} "
"{% else %}{{this.entity_id}}:"
"{{this.entity_id in states}}{% endif %}"
),
"name": (
"{% if this.entity_id in states and"
" 'friendly_name' in this.attributes %}"
" {{this.attributes['friendly_name']}} "
"{% else %}{{this.entity_id}}:"
"{{this.entity_id in states}}{% endif %}"
),
"picture": (
"{% if this.entity_id in states and"
" 'entity_picture' in this.attributes %}"
" {{this.attributes['entity_picture']}} "
"{% else %}{{this.entity_id}}:"
"{{this.entity_id in states}}{% endif %}"
),
"attributes": {"test": "{{ this.entity_id }}"},
},
},
@@ -828,17 +876,33 @@ async def test_self_referencing_sensor_loop(
[
(
{
"state": "{{ ((states.sensor.test_template_sensor.state or 0) | int) + 1 }}",
"icon": "{% if ((states.sensor.test_template_sensor.state or 0) | int) >= 1 %}mdi:greater{% else %}mdi:less{% endif %}",
"state": (
"{{ ((states.sensor.test_template_sensor.state or 0) | int) + 1 }}"
),
"icon": (
"{% if ((states.sensor.test_template_sensor"
".state or 0) | int) >= 1 %}mdi:greater"
"{% else %}mdi:less{% endif %}"
),
},
((ATTR_ICON, "mdi:greater"),),
3,
),
(
{
"state": "{{ ((states.sensor.test_template_sensor.state or 0) | int) + 1 }}",
"icon": "{% if ((states.sensor.test_template_sensor.state or 0) | int) > 3 %}mdi:greater{% else %}mdi:less{% endif %}",
"picture": "{% if ((states.sensor.test_template_sensor.state or 0) | int) >= 1 %}bigpic{% else %}smallpic{% endif %}",
"state": (
"{{ ((states.sensor.test_template_sensor.state or 0) | int) + 1 }}"
),
"icon": (
"{% if ((states.sensor.test_template_sensor"
".state or 0) | int) > 3 %}mdi:greater"
"{% else %}mdi:less{% endif %}"
),
"picture": (
"{% if ((states.sensor.test_template_sensor"
".state or 0) | int) >= 1 %}bigpic"
"{% else %}smallpic{% endif %}"
),
},
(
(ATTR_ICON, "mdi:less"),
@@ -850,8 +914,16 @@ async def test_self_referencing_sensor_loop(
{
"default_entity_id": TEST_SENSOR.entity_id,
"state": "{{ 1 }}",
"picture": "{{ ((states.sensor.test_template_sensor.attributes['entity_picture'] or 0) | int) + 1 }}",
"name": "{{ ((states.sensor.test_template_sensor.attributes['friendly_name'] or 0) | int) + 1 }}",
"picture": (
"{{ ((states.sensor.test_template_sensor"
".attributes['entity_picture'] or 0)"
" | int) + 1 }}"
),
"name": (
"{{ ((states.sensor.test_template_sensor"
".attributes['friendly_name'] or 0)"
" | int) + 1 }}"
),
},
(
(ATTR_ENTITY_PICTURE, "3"),
@@ -893,19 +965,27 @@ async def test_self_referencing_icon_with_no_loop(
hass.states.async_set("sensor.heartworm_avg_64", 10)
hass.states.async_set("sensor.heartworm_avg_57", 10)
value_template_str = """{% if (states.sensor.heartworm_high_80.state|int >= 10) and (states.sensor.heartworm_low_57.state|int >= 10) %}
extreme
{% elif (states.sensor.heartworm_avg_64.state|int >= 30) %}
high
{% elif (states.sensor.heartworm_avg_64.state|int >= 14) %}
moderate
{% elif (states.sensor.heartworm_avg_64.state|int >= 5) %}
slight
{% elif (states.sensor.heartworm_avg_57.state|int >= 5) %}
marginal
{% elif (states.sensor.heartworm_avg_57.state|int < 5) %}
none
{% endif %}"""
value_template_str = (
"{% if (states.sensor.heartworm_high_80.state|int >= 10)"
" and (states.sensor.heartworm_low_57.state|int >= 10) %}\n"
" extreme\n"
" {% elif (states.sensor.heartworm_avg_64.state"
"|int >= 30) %}\n"
" high\n"
" {% elif (states.sensor.heartworm_avg_64.state"
"|int >= 14) %}\n"
" moderate\n"
" {% elif (states.sensor.heartworm_avg_64.state"
"|int >= 5) %}\n"
" slight\n"
" {% elif (states.sensor.heartworm_avg_57.state"
"|int >= 5) %}\n"
" marginal\n"
" {% elif (states.sensor.heartworm_avg_57.state"
"|int < 5) %}\n"
" none\n"
" {% endif %}"
)
icon_template_str = """{% if is_state('sensor.heartworm_risk',"extreme") %}
mdi:hazard-lights
@@ -1051,7 +1131,9 @@ async def test_trigger_conditional_entity(hass: HomeAssistant) -> None:
"condition": [
{
"condition": "template",
"value_template": "{{ trigger.event.data.beer / 0 == 'narf' }}",
"value_template": (
"{{ trigger.event.data.beer / 0 == 'narf' }}"
),
}
],
"sensor": [
@@ -1204,7 +1286,9 @@ async def test_trigger_attribute_order(
"sensor": [
{
"name": "Test Sensor",
"availability": "{{ trigger and trigger.event.data.beer == 2 }}",
"availability": (
"{{ trigger and trigger.event.data.beer == 2 }}"
),
"state": "{{ trigger.event.data.beer }}",
"attributes": {
"beer": "{{ trigger.event.data.beer }}",
@@ -1235,13 +1319,16 @@ async def test_trigger_attribute_order(
assert state.attributes["beer"] == 2
assert "no_beer" not in state.attributes
assert (
"Error rendering attributes.no_beer template for sensor.test_sensor: UndefinedError: 'sad' is undefined"
in caplog.text
"Error rendering attributes.no_beer template for"
" sensor.test_sensor: UndefinedError: 'sad' is undefined" in caplog.text
)
assert state.attributes["more_beer"] == 3
assert (
"Error rendering attributes.all_the_beer template for sensor.test_sensor: ValueError: Template error: int got invalid input 'unknown' when rendering template '{{ this.state | int + more_beer }}' but no default was specified"
in caplog.text
"Error rendering attributes.all_the_beer template for"
" sensor.test_sensor: ValueError: Template error: int got"
" invalid input 'unknown' when rendering template"
" '{{ this.state | int + more_beer }}' but no default was"
" specified" in caplog.text
)
hass.bus.async_fire("test_event", {"beer": 2})
@@ -1256,7 +1343,9 @@ async def test_trigger_attribute_order(
assert (
caplog.text.count(
"Error rendering attributes.no_beer template for sensor.test_sensor: UndefinedError: 'sad' is undefined"
"Error rendering attributes.no_beer template for"
" sensor.test_sensor: UndefinedError:"
" 'sad' is undefined"
)
== 2
)
@@ -264,7 +264,7 @@ async def test_coordinator_shutdown_unloads_script_and_condition(
async def test_shutdown_stops_script_and_keeps_triggers_subscribed(
hass: HomeAssistant,
) -> None:
"""Test that HA shutdown stops coordinator scripts without unsubscribing triggers."""
"""Test HA shutdown stops coordinator scripts without unsubscribing."""
assert await async_setup_component(
hass,
"template",
+8 -2
View File
@@ -461,7 +461,10 @@ async def test_install_action(hass: HomeAssistant, calls: list[ServiceCall]) ->
),
(
"icon",
"{% if is_state('sensor.installed_update', 'on') %}mdi:something{% endif %}",
(
"{% if is_state('sensor.installed_update', 'on') %}"
"mdi:something{% endif %}"
),
ATTR_ICON,
"mdi:something",
),
@@ -701,7 +704,10 @@ async def test_update_percent_template(
TEST_INSTALLED_TEMPLATE,
TEST_LATEST_TEMPLATE,
"update_percentage",
"{% set e = 'sensor.test_update' %}{{ states(e) if e | has_value else None }}",
(
"{% set e = 'sensor.test_update' %}"
"{{ states(e) if e | has_value else None }}"
),
)
],
)
+24 -9
View File
@@ -1014,7 +1014,10 @@ async def test_not_optimistic(
"unique_id": TEST_VACUUM.entity_id,
"start": [],
**CLEAN_SEGMENTS_ACTION,
"segments": "{{ [{'id': '1', 'name': 'Livingroom'}, {'id': '2', 'name': 'Kitchen'}] }}",
"segments": (
"{{ [{'id': '1', 'name': 'Livingroom'},"
" {'id': '2', 'name': 'Kitchen'}] }}"
),
},
)
],
@@ -1130,39 +1133,47 @@ async def test_get_segments(
"unique_id": TEST_VACUUM.entity_id,
"segments": "{{ [ {'id': '1'} ] }}",
},
"expected dictionary with keys id, name and optional group and string values",
"expected dictionary with keys id, name and optional"
" group and string values",
),
(
{
"unique_id": TEST_VACUUM.entity_id,
"segments": "{{ [ {'name': 'kitchen'} ] }}",
},
"expected dictionary with keys id, name and optional group and string values",
"expected dictionary with keys id, name and optional"
" group and string values",
),
(
{
"unique_id": TEST_VACUUM.entity_id,
"segments": "{{ [ {} ] }}",
},
"expected dictionary with keys id, name and optional group and string values",
"expected dictionary with keys id, name and optional"
" group and string values",
),
(
{
"unique_id": TEST_VACUUM.entity_id,
"segments": "{{ [ {'id': '1', 'name': 'Kitchen', 'extra_key': 'value'} ] }}",
"segments": (
"{{ [ {'id': '1', 'name': 'Kitchen', 'extra_key': 'value'} ] }}"
),
},
"expected dictionary with keys id, name and optional group and string values",
"expected dictionary with keys id, name and optional"
" group and string values",
),
(
{"unique_id": TEST_VACUUM.entity_id, "segments": "{{ [[]] }}"},
"expected dictionary with keys id, name and optional group and string values",
"expected dictionary with keys id, name and optional"
" group and string values",
),
(
{
"unique_id": TEST_VACUUM.entity_id,
"segments": "{{ [ {'id': '1', 'name': 'Kitchen'}, [] ] }}",
},
"expected dictionary with keys id, name and optional group and string values",
"expected dictionary with keys id, name and optional"
" group and string values",
),
],
)
@@ -1197,7 +1208,11 @@ async def test_invalid_segments(
"unique_id": TEST_VACUUM.entity_id,
"start": [],
**CLEAN_SEGMENTS_ACTION,
"segments": "{{ [ {'id': '1', 'name': 'Kitchen'}, {'id': '2', 'name': states('sensor.test_attribute')}] }}",
"segments": (
"{{ [ {'id': '1', 'name': 'Kitchen'},"
" {'id': '2', 'name':"
" states('sensor.test_attribute')}] }}"
),
},
)
],
+65 -24
View File
@@ -74,11 +74,13 @@ def create_test_entity(hass: HomeAssistant, config: dict) -> TemplateEntity:
[
(
{"default_entity_id": "test.test"},
"Received invalid test state: {} for entity test.test, expected one of mmmm, beer, is, good",
"Received invalid test state: {} for entity"
" test.test, expected one of mmmm, beer, is, good",
),
(
{},
"Received invalid state: {} for entity Test, expected one of mmmm, beer, is, good",
"Received invalid state: {} for entity Test,"
" expected one of mmmm, beer, is, good",
),
],
)
@@ -152,11 +154,16 @@ async def test_none_on_unknown_and_unavailable(
[
(
{"default_entity_id": "test.test"},
"Received invalid test state: {} for entity test.test, expected one of mmmm, beer, is, good, 1, true, yes, on, enable, 0, false, no, off, disable",
"Received invalid test state: {} for entity"
" test.test, expected one of mmmm, beer, is, good,"
" 1, true, yes, on, enable, 0, false, no, off,"
" disable",
),
(
{},
"Received invalid state: {} for entity Test, expected one of mmmm, beer, is, good, 1, true, yes, on, enable, 0, false, no, off, disable",
"Received invalid state: {} for entity Test,"
" expected one of mmmm, beer, is, good, 1, true,"
" yes, on, enable, 0, false, no, off, disable",
),
],
)
@@ -210,11 +217,15 @@ async def test_enum_with_on_off(
[
(
{"default_entity_id": "test.test"},
"Received invalid test state: {} for entity test.test, expected one of mmmm, beer, is, good, 1, true, yes, on, enable",
"Received invalid test state: {} for entity"
" test.test, expected one of mmmm, beer, is, good,"
" 1, true, yes, on, enable",
),
(
{},
"Received invalid state: {} for entity Test, expected one of mmmm, beer, is, good, 1, true, yes, on, enable",
"Received invalid state: {} for entity Test,"
" expected one of mmmm, beer, is, good, 1, true,"
" yes, on, enable",
),
],
)
@@ -267,11 +278,15 @@ async def test_enum_with_on(
[
(
{"default_entity_id": "test.test"},
"Received invalid test state: {} for entity test.test, expected one of mmmm, beer, is, good, 0, false, no, off, disable",
"Received invalid test state: {} for entity"
" test.test, expected one of mmmm, beer, is, good,"
" 0, false, no, off, disable",
),
(
{},
"Received invalid state: {} for entity Test, expected one of mmmm, beer, is, good, 0, false, no, off, disable",
"Received invalid state: {} for entity Test,"
" expected one of mmmm, beer, is, good, 0, false,"
" no, off, disable",
),
],
)
@@ -324,11 +339,15 @@ async def test_enum_with_off(
[
(
{"default_entity_id": "test.test"},
"Received invalid test state: {} for entity test.test, expected one of 1, true, yes, on, enable, 0, false, no, off, disable",
"Received invalid test state: {} for entity"
" test.test, expected one of 1, true, yes, on,"
" enable, 0, false, no, off, disable",
),
(
{},
"Received invalid state: {} for entity Test, expected one of 1, true, yes, on, enable, 0, false, no, off, disable",
"Received invalid state: {} for entity Test,"
" expected one of 1, true, yes, on, enable, 0,"
" false, no, off, disable",
),
],
)
@@ -372,11 +391,15 @@ async def test_boolean(
[
(
{"default_entity_id": "test.test"},
"Received invalid test state: {} for entity test.test, expected one of 1, true, yes, on, enable, 0, false, no, off, disable",
"Received invalid test state: {} for entity"
" test.test, expected one of 1, true, yes, on,"
" enable, 0, false, no, off, disable",
),
(
{},
"Received invalid state: {} for entity Test, expected one of 1, true, yes, on, enable, 0, false, no, off, disable",
"Received invalid state: {} for entity Test,"
" expected one of 1, true, yes, on, enable, 0,"
" false, no, off, disable",
),
],
)
@@ -421,11 +444,16 @@ async def test_boolean_as_true(
[
(
{"default_entity_id": "test.test"},
"Received invalid test state: {} for entity test.test, expected one of 1, true, yes, on, enable, 0, false, no, off, disable, something_unique",
"Received invalid test state: {} for entity"
" test.test, expected one of 1, true, yes, on,"
" enable, 0, false, no, off, disable,"
" something_unique",
),
(
{},
"Received invalid state: {} for entity Test, expected one of 1, true, yes, on, enable, 0, false, no, off, disable, something_unique",
"Received invalid state: {} for entity Test,"
" expected one of 1, true, yes, on, enable, 0,"
" false, no, off, disable, something_unique",
),
],
)
@@ -584,11 +612,14 @@ async def test_number_as_int(
[
(
{"default_entity_id": "test.test"},
"Received invalid test state: {} for entity test.test, expected a number greater than or equal to 0.0",
"Received invalid test state: {} for entity"
" test.test, expected a number greater than or"
" equal to 0.0",
),
(
{},
"Received invalid state: {} for entity Test, expected a number greater than or equal to 0.0",
"Received invalid state: {} for entity Test,"
" expected a number greater than or equal to 0.0",
),
],
)
@@ -642,11 +673,14 @@ async def test_number_with_minimum(
[
(
{"default_entity_id": "test.test"},
"Received invalid test state: {} for entity test.test, expected a number less than or equal to 0.0",
"Received invalid test state: {} for entity"
" test.test, expected a number less than or equal"
" to 0.0",
),
(
{},
"Received invalid state: {} for entity Test, expected a number less than or equal to 0.0",
"Received invalid state: {} for entity Test,"
" expected a number less than or equal to 0.0",
),
],
)
@@ -696,11 +730,14 @@ async def test_number_with_maximum(
[
(
{"default_entity_id": "test.test"},
"Received invalid test state: {} for entity test.test, expected a number between 0.0 and 100.0",
"Received invalid test state: {} for entity"
" test.test, expected a number between 0.0 and"
" 100.0",
),
(
{},
"Received invalid state: {} for entity Test, expected a number between 0.0 and 100.0",
"Received invalid state: {} for entity Test,"
" expected a number between 0.0 and 100.0",
),
],
)
@@ -748,7 +785,8 @@ async def test_number_in_range(
[
(
{"default_entity_id": "test.test"},
"Received invalid test state: {} for entity test.test, expected a list of strings",
"Received invalid test state: {} for entity"
" test.test, expected a list of strings",
),
(
{},
@@ -807,7 +845,8 @@ async def test_list_of_strings_none_on_empty(
[
(
{"default_entity_id": "test.test"},
"Received invalid test state: {} for entity test.test, expected beer, is, GOOD",
"Received invalid test state: {} for entity"
" test.test, expected beer, is, GOOD",
),
(
{},
@@ -859,11 +898,13 @@ async def test_item_in_list(
[
(
{"default_entity_id": "test.test"},
"Received invalid test state: {} for entity test.test, expected one of beer, is, GOOD",
"Received invalid test state: {} for entity"
" test.test, expected one of beer, is, GOOD",
),
(
{},
"Received invalid state: {} for entity Test, expected one of beer, is, GOOD",
"Received invalid state: {} for entity Test,"
" expected one of beer, is, GOOD",
),
],
)
+110 -36
View File
@@ -147,7 +147,9 @@ async def test_template_state_exception(hass: HomeAssistant) -> None:
(
ConfigurationStyle.MODERN,
{
"apparent_temperature_template": "{{ states('sensor.apparent_temperature') }}",
"apparent_temperature_template": (
"{{ states('sensor.apparent_temperature') }}"
),
"attribution_template": "{{ states('sensor.attribution') }}",
"cloud_coverage_template": "{{ states('sensor.cloud_coverage') }}",
"condition_template": "{{ states('sensor.condition') }}",
@@ -167,7 +169,9 @@ async def test_template_state_exception(hass: HomeAssistant) -> None:
(
ConfigurationStyle.TRIGGER,
{
"apparent_temperature_template": "{{ states('sensor.apparent_temperature') }}",
"apparent_temperature_template": (
"{{ states('sensor.apparent_temperature') }}"
),
"attribution_template": "{{ states('sensor.attribution') }}",
"cloud_coverage_template": "{{ states('sensor.cloud_coverage') }}",
"condition_template": "{{ states('sensor.condition') }}",
@@ -264,15 +268,23 @@ async def test_template_state_text(hass: HomeAssistant) -> None:
"config",
[
{
"forecast_daily_template": "{{ state_attr('sensor.forecast', 'forecast') }}",
"forecast_hourly_template": "{{ state_attr('sensor.forecast', 'forecast') }}",
"forecast_twice_daily_template": "{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}",
"forecast_daily_template": (
"{{ state_attr('sensor.forecast', 'forecast') }}"
),
"forecast_hourly_template": (
"{{ state_attr('sensor.forecast', 'forecast') }}"
),
"forecast_twice_daily_template": (
"{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}"
),
**TEST_LEGACY_REQUIRED,
},
{
"forecast_daily": "{{ state_attr('sensor.forecast', 'forecast') }}",
"forecast_hourly": "{{ state_attr('sensor.forecast', 'forecast') }}",
"forecast_twice_daily": "{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}",
"forecast_twice_daily": (
"{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}"
),
**TEST_MODERN_REQUIRED,
},
],
@@ -365,36 +377,60 @@ async def test_forecasts(hass: HomeAssistant, snapshot: SnapshotAssertion) -> No
(
ConfigurationStyle.MODERN,
{
"forecast_daily_template": "{{ state_attr('sensor.forecast_daily', 'forecast') }}",
"forecast_hourly_template": "{{ state_attr('sensor.forecast_hourly', 'forecast') }}",
"forecast_twice_daily_template": "{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}",
"forecast_daily_template": (
"{{ state_attr('sensor.forecast_daily', 'forecast') }}"
),
"forecast_hourly_template": (
"{{ state_attr('sensor.forecast_hourly', 'forecast') }}"
),
"forecast_twice_daily_template": (
"{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}"
),
**TEST_LEGACY_REQUIRED,
},
),
(
ConfigurationStyle.TRIGGER,
{
"forecast_daily_template": "{{ state_attr('sensor.forecast_daily', 'forecast') }}",
"forecast_hourly_template": "{{ state_attr('sensor.forecast_hourly', 'forecast') }}",
"forecast_twice_daily_template": "{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}",
"forecast_daily_template": (
"{{ state_attr('sensor.forecast_daily', 'forecast') }}"
),
"forecast_hourly_template": (
"{{ state_attr('sensor.forecast_hourly', 'forecast') }}"
),
"forecast_twice_daily_template": (
"{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}"
),
**TEST_LEGACY_REQUIRED,
},
),
(
ConfigurationStyle.MODERN,
{
"forecast_daily": "{{ state_attr('sensor.forecast_daily', 'forecast') }}",
"forecast_hourly": "{{ state_attr('sensor.forecast_hourly', 'forecast') }}",
"forecast_twice_daily": "{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}",
"forecast_daily": (
"{{ state_attr('sensor.forecast_daily', 'forecast') }}"
),
"forecast_hourly": (
"{{ state_attr('sensor.forecast_hourly', 'forecast') }}"
),
"forecast_twice_daily": (
"{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}"
),
**TEST_MODERN_REQUIRED,
},
),
(
ConfigurationStyle.TRIGGER,
{
"forecast_daily": "{{ state_attr('sensor.forecast_daily', 'forecast') }}",
"forecast_hourly": "{{ state_attr('sensor.forecast_hourly', 'forecast') }}",
"forecast_twice_daily": "{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}",
"forecast_daily": (
"{{ state_attr('sensor.forecast_daily', 'forecast') }}"
),
"forecast_hourly": (
"{{ state_attr('sensor.forecast_hourly', 'forecast') }}"
),
"forecast_twice_daily": (
"{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}"
),
**TEST_MODERN_REQUIRED,
},
),
@@ -507,36 +543,60 @@ async def test_forecasts_invalid(
(
ConfigurationStyle.MODERN,
{
"forecast_daily_template": "{{ state_attr('sensor.forecast_daily', 'forecast') }}",
"forecast_hourly_template": "{{ state_attr('sensor.forecast_hourly', 'forecast') }}",
"forecast_twice_daily_template": "{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}",
"forecast_daily_template": (
"{{ state_attr('sensor.forecast_daily', 'forecast') }}"
),
"forecast_hourly_template": (
"{{ state_attr('sensor.forecast_hourly', 'forecast') }}"
),
"forecast_twice_daily_template": (
"{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}"
),
**TEST_LEGACY_REQUIRED,
},
),
(
ConfigurationStyle.TRIGGER,
{
"forecast_daily_template": "{{ state_attr('sensor.forecast_daily', 'forecast') }}",
"forecast_hourly_template": "{{ state_attr('sensor.forecast_hourly', 'forecast') }}",
"forecast_twice_daily_template": "{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}",
"forecast_daily_template": (
"{{ state_attr('sensor.forecast_daily', 'forecast') }}"
),
"forecast_hourly_template": (
"{{ state_attr('sensor.forecast_hourly', 'forecast') }}"
),
"forecast_twice_daily_template": (
"{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}"
),
**TEST_LEGACY_REQUIRED,
},
),
(
ConfigurationStyle.MODERN,
{
"forecast_daily": "{{ state_attr('sensor.forecast_daily', 'forecast') }}",
"forecast_hourly": "{{ state_attr('sensor.forecast_hourly', 'forecast') }}",
"forecast_twice_daily": "{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}",
"forecast_daily": (
"{{ state_attr('sensor.forecast_daily', 'forecast') }}"
),
"forecast_hourly": (
"{{ state_attr('sensor.forecast_hourly', 'forecast') }}"
),
"forecast_twice_daily": (
"{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}"
),
**TEST_MODERN_REQUIRED,
},
),
(
ConfigurationStyle.TRIGGER,
{
"forecast_daily": "{{ state_attr('sensor.forecast_daily', 'forecast') }}",
"forecast_hourly": "{{ state_attr('sensor.forecast_hourly', 'forecast') }}",
"forecast_twice_daily": "{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}",
"forecast_daily": (
"{{ state_attr('sensor.forecast_daily', 'forecast') }}"
),
"forecast_hourly": (
"{{ state_attr('sensor.forecast_hourly', 'forecast') }}"
),
"forecast_twice_daily": (
"{{ state_attr('sensor.forecast_twice_daily', 'forecast') }}"
),
**TEST_MODERN_REQUIRED,
},
),
@@ -635,7 +695,9 @@ SAVED_EXTRA_DATA_WITH_FUTURE_KEY = {
"weather": {
"name": "test",
"condition_template": "{{ trigger.event.data.condition }}",
"temperature_template": "{{ trigger.event.data.temperature | float }}",
"temperature_template": (
"{{ trigger.event.data.temperature | float }}"
),
"temperature_unit": "°C",
"humidity_template": "{{ trigger.event.data.humidity | float }}",
},
@@ -712,7 +774,9 @@ async def test_trigger_entity_restore_state(
"action": [
{
"variables": {
"my_variable": "{{ trigger.event.data.temperature + 1 }}"
"my_variable": (
"{{ trigger.event.data.temperature + 1 }}"
)
},
},
],
@@ -760,7 +824,9 @@ async def test_restore_weather_save_state(
"weather": {
"name": "test",
"condition_template": "{{ trigger.event.data.condition }}",
"temperature_template": "{{ trigger.event.data.temperature | float }}",
"temperature_template": (
"{{ trigger.event.data.temperature | float }}"
),
"temperature_unit": "°C",
"humidity_template": "{{ trigger.event.data.humidity | float }}",
},
@@ -853,7 +919,9 @@ async def test_trigger_entity_restore_state_fail(
"weather": {
"name": "test",
"condition_template": "{{ trigger.event.data.condition }}",
"temperature_template": "{{ trigger.event.data.temperature | float }}",
"temperature_template": (
"{{ trigger.event.data.temperature | float }}"
),
"temperature_unit": "°C",
"humidity_template": "{{ trigger.event.data.humidity | float }}",
},
@@ -879,7 +947,10 @@ async def test_trigger_entity_restore_state_fail(
[
(
{
CONF_ICON: "{% if states.weather.test_state.state == 'sunny' %}mdi:check{% endif %}",
CONF_ICON: (
"{% if states.weather.test_state.state =="
" 'sunny' %}mdi:check{% endif %}"
),
**TEST_LEGACY_REQUIRED,
},
ATTR_ICON,
@@ -887,7 +958,10 @@ async def test_trigger_entity_restore_state_fail(
),
(
{
CONF_PICTURE: "{% if states.weather.test_state.state == 'sunny' %}check.jpg{% endif %}",
CONF_PICTURE: (
"{% if states.weather.test_state.state =="
" 'sunny' %}check.jpg{% endif %}"
),
**TEST_LEGACY_REQUIRED,
},
ATTR_ENTITY_PICTURE,
+5 -1
View File
@@ -446,7 +446,11 @@ async def test_climate_notemp(
with pytest.raises(
ServiceValidationError,
match="Set temperature action was used with the 'Lower/Upper target temperature' parameter but the entity does not support it",
match=(
"Set temperature action was used with the"
" 'Lower/Upper target temperature' parameter but the"
" entity does not support it"
),
):
await hass.services.async_call(
CLIMATE_DOMAIN,
@@ -80,9 +80,14 @@ def mock_private_key():
public_key = Mock()
private_key.public_key.return_value = public_key
public_key.public_bytes.side_effect = [
b"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\n-----END PUBLIC KEY-----",
b"-----BEGIN PUBLIC KEY-----\n"
b"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\n"
b"-----END PUBLIC KEY-----",
bytes.fromhex(
"0404112233445566778899aabbccddeeff112233445566778899aabbccddeeff112233445566778899aabbccddeeff112233445566778899aabbccddeeff1122"
"0404112233445566778899aabbccddeeff"
"112233445566778899aabbccddeeff"
"112233445566778899aabbccddeeff"
"112233445566778899aabbccddeeff1122"
),
]
return private_key
@@ -171,7 +176,12 @@ async def test_partner_login_partial_failure(
},
)
public_key = "0404112233445566778899aabbccddeeff112233445566778899aabbccddeeff112233445566778899aabbccddeeff112233445566778899aabbccddeeff1122"
public_key = (
"0404112233445566778899aabbccddeeff"
"112233445566778899aabbccddeeff"
"112233445566778899aabbccddeeff"
"112233445566778899aabbccddeeff1122"
)
mock_api_na = AsyncMock()
mock_api_na.private_key = mock_private_key
@@ -265,10 +275,20 @@ async def test_full_flow_with_domain_registration(
mock_api.private_key = mock_private_key
mock_api.get_private_key = AsyncMock()
mock_api.partner_login = AsyncMock()
mock_api.public_uncompressed_point = "0404112233445566778899aabbccddeeff112233445566778899aabbccddeeff112233445566778899aabbccddeeff112233445566778899aabbccddeeff1122"
mock_api.public_uncompressed_point = (
"0404112233445566778899aabbccddeeff"
"112233445566778899aabbccddeeff"
"112233445566778899aabbccddeeff"
"112233445566778899aabbccddeeff1122"
)
mock_api.partner.register.return_value = {
"response": {
"public_key": "0404112233445566778899aabbccddeeff112233445566778899aabbccddeeff112233445566778899aabbccddeeff112233445566778899aabbccddeeff1122"
"public_key": (
"0404112233445566778899aabbccddeeff"
"112233445566778899aabbccddeeff"
"112233445566778899aabbccddeeff"
"112233445566778899aabbccddeeff1122"
)
}
}
mock_api_class.return_value = mock_api
@@ -278,7 +298,8 @@ async def test_full_flow_with_domain_registration(
assert result["type"] is FlowResultType.FORM
assert result["step_id"] == "domain_input"
# Enter domain - this should automatically register and go to registration_complete
# Enter domain - this should automatically register and go to
# registration_complete
result = await hass.config_entries.flow.async_configure(
result["flow_id"], {CONF_DOMAIN: "example.com"}
)
@@ -351,11 +372,22 @@ async def test_domain_input_invalid_domain(
assert result["step_id"] == "domain_input"
assert result["errors"] == {CONF_DOMAIN: "invalid_domain"}
# Enter valid domain - this should automatically register and go to registration_complete
mock_api.public_uncompressed_point = "0404112233445566778899aabbccddeeff112233445566778899aabbccddeeff112233445566778899aabbccddeeff112233445566778899aabbccddeeff1122"
# Enter valid domain - this should automatically register
# and go to registration_complete
mock_api.public_uncompressed_point = (
"0404112233445566778899aabbccddeeff"
"112233445566778899aabbccddeeff"
"112233445566778899aabbccddeeff"
"112233445566778899aabbccddeeff1122"
)
mock_api.partner.register.return_value = {
"response": {
"public_key": "0404112233445566778899aabbccddeeff112233445566778899aabbccddeeff112233445566778899aabbccddeeff112233445566778899aabbccddeeff1122"
"public_key": (
"0404112233445566778899aabbccddeeff"
"112233445566778899aabbccddeeff"
"112233445566778899aabbccddeeff"
"112233445566778899aabbccddeeff1122"
)
}
}
result = await hass.config_entries.flow.async_configure(
@@ -483,7 +515,8 @@ async def test_domain_registration_precondition_failed(
# Complete OAuth
result = await hass.config_entries.flow.async_configure(result["flow_id"])
# Enter domain - this should go to domain_registration and then fail back to domain_input
# Enter domain - this should go to domain_registration
# and then fail back to domain_input
result = await hass.config_entries.flow.async_configure(
result["flow_id"], {CONF_DOMAIN: "example.com"}
)
@@ -646,7 +679,12 @@ async def test_domain_registration_partial_failure(
},
)
public_key = "0404112233445566778899aabbccddeeff112233445566778899aabbccddeeff112233445566778899aabbccddeeff112233445566778899aabbccddeeff1122"
public_key = (
"0404112233445566778899aabbccddeeff"
"112233445566778899aabbccddeeff"
"112233445566778899aabbccddeeff"
"112233445566778899aabbccddeeff1122"
)
# Create two separate mocks for NA and EU
mock_api_na = AsyncMock()
@@ -115,7 +115,7 @@ def get_lifetime_mock() -> Lifetime:
@dataclass
class EntityAndExpectedValues:
"""Class for keeping entity id along with expected value for first and second data updates."""
"""Class for keeping entity id along with expected update values."""
entity_id: str
first_value: Any
@@ -142,7 +142,8 @@ async def _test_sensors(
state = hass.states.get(entity.entity_id)
assert state, f"Unable to get state of {entity.entity_id}"
assert state.state == entity.first_value, (
f"First update: {entity.entity_id} is expected to have state {entity.first_value} but has {state.state}"
f"First update: {entity.entity_id} is expected to have"
f" state {entity.first_value} but has {state.state}"
)
# Simulate second data update
@@ -165,5 +166,6 @@ async def _test_sensors(
for entity in entities_and_expected_values:
state = hass.states.get(entity.entity_id)
assert state.state == entity.second_value, (
f"Second update: {entity.entity_id} is expected to have state {entity.second_value} but has {state.state}"
f"Second update: {entity.entity_id} is expected to have"
f" state {entity.second_value} but has {state.state}"
)
+1 -1
View File
@@ -344,7 +344,7 @@ async def test_calendar_midnight_crossing_local_start(
freezer: FrozenDateTimeFactory,
mock_legacy: AsyncMock,
) -> None:
"""Test async_get_events includes overnight period when query starts at local midnight."""
"""Test async_get_events includes overnight period at local midnight."""
tz = dt_util.get_default_time_zone()
freezer.move_to(datetime(2024, 1, 1, 10, 0, 0, tzinfo=tz))
+3 -1
View File
@@ -326,7 +326,9 @@ async def test_select_streaming(
Signal.RIGHT_HAND_DRIVE: True,
Signal.HVAC_LEFT_TEMPERATURE_REQUEST: 22,
Signal.HVAC_RIGHT_TEMPERATURE_REQUEST: 21,
Signal.CABIN_OVERHEAT_PROTECTION_MODE: "CabinOverheatProtectionModeStateOn",
Signal.CABIN_OVERHEAT_PROTECTION_MODE: (
"CabinOverheatProtectionModeStateOn"
),
Signal.CABIN_OVERHEAT_PROTECTION_TEMPERATURE_LIMIT: 35,
},
"createdAt": "2024-10-04T10:45:17.537Z",
+2 -2
View File
@@ -781,7 +781,7 @@ async def test_vehicle_polling_version_update(
mock_legacy: AsyncMock,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test vehicle sw_version is updated when polling coordinator receives new version."""
"""Test vehicle sw_version updates when polling coordinator refreshes."""
entry = await setup_platform(hass)
assert entry.state is ConfigEntryState.LOADED
@@ -812,7 +812,7 @@ async def test_energy_site_version_update(
mock_site_info: AsyncMock,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test energy site sw_version is updated when info coordinator receives new version."""
"""Test energy site sw_version updates when info coordinator refreshes."""
entry = await setup_platform(hass)
assert entry.state is ConfigEntryState.LOADED
+2 -1
View File
@@ -239,7 +239,8 @@ async def test_export_rule_restore(
},
EnergyExportMode.NEVER.value,
),
# Path 3: In VPP, Export enabled but state shows disabled (current_option is NEVER)
# Path 3: In VPP, Export enabled but state shows disabled
# (current_option is NEVER)
(
{
"customer_preferred_export_rule": "never",
+4 -2
View File
@@ -389,7 +389,8 @@ async def test_service_validation_errors(
)
assert exc_info.value.translation_key == "set_scheduled_charging_time"
# Test set_scheduled_departure validation error (preconditioning_enabled=True but no departure_time)
# Test set_scheduled_departure validation error
# (preconditioning_enabled=True but no departure_time)
with pytest.raises(ServiceValidationError) as exc_info:
await hass.services.async_call(
DOMAIN,
@@ -402,7 +403,8 @@ async def test_service_validation_errors(
)
assert exc_info.value.translation_key == "set_scheduled_departure_preconditioning"
# Test set_scheduled_departure validation error (off_peak_charging_enabled=True but no end_off_peak_time)
# Test set_scheduled_departure validation error
# (off_peak_charging_enabled=True but no end_off_peak_time)
with pytest.raises(ServiceValidationError) as exc_info:
await hass.services.async_call(
DOMAIN,
+1 -1
View File
@@ -215,7 +215,7 @@ async def test_coordinator_energy_history_invalid_data(
async def test_coordinator_energy_history_cold_start_invalid_data(
hass: HomeAssistant, mock_energy_history, freezer: FrozenDateTimeFactory
) -> None:
"""Tests cold-start fallback when the very first energy history fetch has invalid data."""
"""Tests cold-start fallback when first energy history fetch has invalid data."""
mock_energy_history.side_effect = lambda *a, **kw: {"response": {}}
entry = await setup_platform(hass, [Platform.SENSOR])
+1 -1
View File
@@ -219,7 +219,7 @@ async def test_input_text_state_trigger(
trigger: str,
states: list[BasicTriggerStateDescription],
) -> None:
"""Test that the `text.changed` trigger fires when any input_text entity's state changes."""
"""Test text.changed trigger fires on any input_text state change."""
calls: list[str] = []
other_entity_ids = set(target_input_texts["included_entities"]) - {entity_id}
+2 -1
View File
@@ -59,7 +59,8 @@ def create_tibber_device(
charging_status: Charging status (for binary sensors).
device_status: Device on/off status (for binary sensors).
is_online: Device online status (for binary sensors).
sensor_values: Dictionary mapping sensor IDs to their values for additional sensors.
sensor_values: Dictionary mapping sensor IDs to their values
for additional sensors.
"""
capabilities = []
+1 -1
View File
@@ -170,7 +170,7 @@ async def test_new_data_api_sensors_with_disabled_by_default(
setup_credentials: None,
entity_registry: er.EntityRegistry,
) -> None:
"""Test that sensors with entity_registry_enabled_default=False are disabled by default."""
"""Test that sensors with entity_registry_enabled_default=False are disabled."""
sensor_values = {
"cellular.rssi": -75.0,
"energyFlow.hour.battery.source.grid": 500.0,
+2 -2
View File
@@ -941,7 +941,7 @@ async def test_state_changed_when_timer_restarted(hass: HomeAssistant) -> None:
async def test_last_transition_after_restarted_timer_expires(
hass: HomeAssistant, freezer: FrozenDateTimeFactory
) -> None:
"""Test that last_transition changes from restarted to finished when timer expires."""
"""Test last_transition changes from restarted to finished on expiry."""
hass.set_state(CoreState.starting)
await async_setup_component(hass, DOMAIN, {DOMAIN: {"test1": {CONF_DURATION: 10}}})
@@ -1366,7 +1366,7 @@ async def test_restore_active_resume(
async def test_restore_active_finished_outside_grace(
hass: HomeAssistant, last_transition: str | None
) -> None:
"""Test entity restore logic: timer is active, ended while Home Assistant was stopped."""
"""Test entity restore: timer active, ended while HA was stopped."""
events = async_capture_events(hass, EVENT_TIMER_FINISHED)
assert not events
utc_now = utcnow()
+7 -7
View File
@@ -144,7 +144,7 @@ async def test_timer_trigger_behavior_any(
trigger_options: dict[str, Any],
states: list[TriggerStateDescription],
) -> None:
"""Test that the timer trigger fires when any timer's last_transition changes to a specific value."""
"""Test timer trigger fires on any timer last_transition change."""
await assert_trigger_behavior_any(
hass,
target_entities=target_timers,
@@ -202,7 +202,7 @@ async def test_timer_trigger_behavior_first(
trigger_options: dict[str, Any],
states: list[TriggerStateDescription],
) -> None:
"""Test that the timer trigger fires when the first timer's last_transition changes to a specific value."""
"""Test timer trigger fires on first timer last_transition change."""
await assert_trigger_behavior_first(
hass,
target_entities=target_timers,
@@ -260,7 +260,7 @@ async def test_timer_trigger_behavior_last(
trigger_options: dict[str, Any],
states: list[TriggerStateDescription],
) -> None:
"""Test that the timer trigger fires when the last timer's last_transition changes to a specific value."""
"""Test timer trigger fires on last timer last_transition change."""
await assert_trigger_behavior_last(
hass,
target_entities=target_timers,
@@ -388,7 +388,7 @@ async def test_time_remaining_trigger_paused_before_threshold(
hass: HomeAssistant,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test time_remaining trigger does not fire when timer is paused before threshold."""
"""Test time_remaining trigger does not fire when timer is paused."""
now = dt_util.utcnow()
calls: list[dict[str, Any]] = []
@@ -427,7 +427,7 @@ async def test_time_remaining_trigger_cancelled_before_threshold(
hass: HomeAssistant,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test time_remaining trigger does not fire when timer is cancelled before threshold."""
"""Test time_remaining trigger does not fire when timer is cancelled."""
now = dt_util.utcnow()
calls: list[dict[str, Any]] = []
@@ -516,7 +516,7 @@ async def test_time_remaining_trigger_short_timer(
hass: HomeAssistant,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test time_remaining trigger does not fire when timer duration is shorter than remaining threshold."""
"""Test time_remaining trigger skips when duration < threshold."""
now = dt_util.utcnow()
calls: list[dict[str, Any]] = []
@@ -585,7 +585,7 @@ async def test_time_remaining_trigger_already_active_past_threshold_at_attach(
hass: HomeAssistant,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test trigger does not schedule for timers already past the fire point at attach."""
"""Test trigger ignores timers already past the fire point at attach."""
now = dt_util.utcnow()
calls: list[dict[str, Any]] = []
+9 -5
View File
@@ -150,7 +150,7 @@ async def test_midnight_turnover_before_midnight_outside_period(
@pytest.mark.freeze_time("2019-01-10 10:00:00-08:00")
async def test_after_happens_tomorrow(hass: HomeAssistant) -> None:
"""Test when both before and after are in the future, and after is later than before."""
"""Test when before and after are in the future, after is later than before."""
config = {
"binary_sensor": [
{"platform": "tod", "name": "Night", "after": "23:00", "before": "12:00"}
@@ -760,7 +760,8 @@ async def test_dst5(
]
}
# Test DST #5:
# Test the case where the end time does not exist (roll out to the next available time)
# Test case where end time does not exist
# (roll out to the next available time)
# First test before the sensor is turned on
entity_id = "binary_sensor.day"
freezer.move_to(test_time1)
@@ -774,7 +775,8 @@ async def test_dst5(
assert state.attributes["next_update"] == "2019-03-31T01:50:00+01:00"
assert state.state == STATE_OFF
# Seconds, test state when sensor is ON but end time has rolled out to next available time.
# Second, test state when sensor is ON but end time has rolled
# out to next available time.
freezer.move_to(test_time2)
async_fire_time_changed(hass, dt_util.utcnow())
await hass.async_block_till_done()
@@ -801,7 +803,8 @@ async def test_dst6(
]
}
# Test DST #6:
# Test the case where the end time does not exist (roll out to the next available time)
# Test case where end time does not exist
# (roll out to the next available time)
# First test before the sensor is turned on
entity_id = "binary_sensor.day"
freezer.move_to(test_time1)
@@ -815,7 +818,8 @@ async def test_dst6(
assert state.attributes["next_update"] == "2019-03-31T03:00:00+02:00"
assert state.state == STATE_OFF
# Seconds, test state when sensor is ON but end time has rolled out to next available time.
# Second, test state when sensor is ON but end time has rolled
# out to next available time.
freezer.move_to(test_time2)
async_fire_time_changed(hass, dt_util.utcnow())
await hass.async_block_till_done()
+1 -1
View File
@@ -180,7 +180,7 @@ def parametrize_incomplete_condition_states_any(
def parametrize_incomplete_condition_states_all(
condition: str,
) -> list[tuple[str, dict[str, Any], list[ConditionStateDescription]]]:
"""Parametrize above/below threshold test cases for incomplete conditions with 'all' behavior."""
"""Parametrize above/below threshold cases for incomplete 'all' conditions."""
return [
*parametrize_condition_states_all(
condition=condition,
+1 -1
View File
@@ -522,7 +522,7 @@ async def test_entity_rejoining_label_does_not_fire_trigger(
entity_registry: er.EntityRegistry,
label_registry: lr.LabelRegistry,
) -> None:
"""Test removing and re-adding an entity to a target does not fire stale triggers."""
"""Test removing and re-adding entity to target does not fire stale triggers."""
label_both = label_registry.async_get_label_by_name("label_both_lists")
assert label_both is not None
label_both_id = label_both.label_id
+7 -3
View File
@@ -60,7 +60,11 @@ async def set_time_zone(hass: HomeAssistant):
def get_events_url(entity: str, start: str, end: str) -> str:
"""Create a url to get events during the specified time range."""
return f"/api/calendars/{entity}?start={urllib.parse.quote(start)}&end={urllib.parse.quote(end)}"
return (
f"/api/calendars/{entity}"
f"?start={urllib.parse.quote(start)}"
f"&end={urllib.parse.quote(end)}"
)
def get_events_response(start: dict[str, str], end: dict[str, str]) -> dict[str, Any]:
@@ -138,7 +142,7 @@ async def test_update_entity_for_custom_project_no_due_date_on(
hass: HomeAssistant,
api: AsyncMock,
) -> None:
"""Test that a task without an explicit due date is considered to be in an on state."""
"""Test that a task without an explicit due date is in an on state."""
await async_update_entity(hass, "calendar.name")
state = hass.states.get("calendar.name")
assert state.state == "on"
@@ -166,7 +170,7 @@ async def test_update_entity_for_calendar_with_due_date_in_the_future(
api: AsyncMock,
due: Due,
) -> None:
"""Test that a task with a due date in the future has on state and correct end_time."""
"""Test that a task with a future due date has on state and correct end_time."""
await async_update_entity(hass, "calendar.name")
state = hass.states.get("calendar.name")
assert state.state == "on"
+1 -1
View File
@@ -20,7 +20,7 @@ from tests.components.bluetooth import inject_bluetooth_service_info
def patch_async_ble_device_from_address(
return_value: BluetoothServiceInfoBleak | None = None,
):
"""Patch async_ble_device_from_address to return a mocked BluetoothServiceInfoBleak."""
"""Patch async_ble_device_from_address to return a mock."""
return patch(
"homeassistant.components.bluetooth.async_ble_device_from_address",
return_value=return_value,
+3 -2
View File
@@ -30,7 +30,8 @@ def toloclient_fixture() -> Mock:
def coordinator_toloclient() -> Mock:
"""Patch ToloClient in async_setup_entry.
Throw exception to abort entry setup and prevent socket IO. Only testing config flow.
Throw exception to abort entry setup and prevent socket IO.
Only testing config flow.
"""
with patch(
"homeassistant.components.tolo.coordinator.ToloClient", side_effect=Exception
@@ -191,7 +192,7 @@ async def test_reconfigure_duplicate_ip(
coordinator_toloclient: Mock,
config_entry: MockConfigEntry,
) -> None:
"""Test a reconfigure flow where the user is trying to have to entries with the same IP."""
"""Test a reconfigure flow where the user tries to duplicate an IP."""
config_entry2 = MockConfigEntry(
domain=DOMAIN, data={CONF_HOST: "127.0.0.6"}, unique_id="second_entry"
)
@@ -24,7 +24,7 @@ CONFIG_DATA = {
async def test_config_flow_success(
hass: HomeAssistant, mock_setup_entry: AsyncMock, mock_touchlinesl_client: AsyncMock
) -> None:
"""Test the happy path where the provided username/password result in a new entry."""
"""Test the happy path where username/password result in a new entry."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
@@ -58,7 +58,7 @@ async def test_config_flow_failure_api_exceptions(
mock_setup_entry: AsyncMock,
mock_touchlinesl_client: AsyncMock,
) -> None:
"""Test for invalid credentials or API connection errors, and that the form can recover."""
"""Test for invalid credentials or API errors, and form recovery."""
mock_touchlinesl_client.user_id.side_effect = exception
result = await hass.config_entries.flow.async_init(
+8 -3
View File
@@ -104,14 +104,18 @@ async def snapshot_platform(
unique_device_classes = []
for entity_entry in entity_entries:
if entity_entry.translation_key:
key = f"component.{DOMAIN}.entity.{entity_entry.domain}.{entity_entry.translation_key}.name"
key = (
f"component.{DOMAIN}.entity.{entity_entry.domain}"
f".{entity_entry.translation_key}.name"
)
single_device_class_translation = False
if key not in translations: # No name translation
if entity_entry.original_device_class not in unique_device_classes:
single_device_class_translation = True
unique_device_classes.append(entity_entry.original_device_class)
assert (key in translations) or single_device_class_translation, (
f"No translation or non unique device_class for entity {entity_entry.unique_id}, expected {key}"
f"No translation or non unique device_class for"
f" entity {entity_entry.unique_id}, expected {key}"
)
assert entity_entry == snapshot(name=f"{entity_entry.entity_id}-entry"), (
f"entity entry snapshot failed for {entity_entry.entity_id}"
@@ -266,7 +270,8 @@ def _mocked_feature(
) -> Feature:
"""Get a mocked feature.
If kwargs are provided they will override the attributes for any features defined in fixtures.json
If kwargs are provided they will override the attributes for any
features defined in fixtures.json
"""
feature = MagicMock(spec=Feature, name=f"Mocked {id} feature")
feature.id = id
+1 -1
View File
@@ -1258,7 +1258,7 @@ async def test_manual_port_override_invalid(
async def test_discovered_by_discovery_and_dhcp(hass: HomeAssistant) -> None:
"""Test we get the form with discovery and abort for dhcp source when we get both."""
"""Test we get the form with discovery and abort for dhcp source."""
with _patch_discovery(), _patch_single_discovery(), _patch_connect():
result = await hass.config_entries.flow.async_init(
+6 -6
View File
@@ -192,8 +192,8 @@ async def test_config_entry_wrong_mac_Address(
assert already_migrated_config_entry.state is ConfigEntryState.SETUP_RETRY
assert (
"Unexpected device found at 127.0.0.1; expected aa:bb:cc:dd:ee:f0, found aa:bb:cc:dd:ee:ff"
in caplog.text
"Unexpected device found at 127.0.0.1; expected"
" aa:bb:cc:dd:ee:f0, found aa:bb:cc:dd:ee:ff" in caplog.text
)
@@ -273,8 +273,8 @@ async def test_config_entry_conn_params_invalid(
assert mock_config_entry.state is ConfigEntryState.LOADED
assert (
f"Invalid connection parameters dict for {IP_ADDRESS}: {entry_data.get(CONF_CONNECTION_PARAMETERS)}"
in caplog.text
f"Invalid connection parameters dict for {IP_ADDRESS}:"
f" {entry_data.get(CONF_CONNECTION_PARAMETERS)}" in caplog.text
)
@@ -519,8 +519,8 @@ async def test_unlink_devices(
update_msg_fragment = "identifiers for device dummy (hs300):"
update_msg = f"{expected_message} {update_msg_fragment}" if expected_message else ""
# Expected identifiers should include all other domains or all the newer non-mac device ids
# or just the parent mac device id
# Expected identifiers should include all other domains or all
# the newer non-mac device ids or just the parent mac device id
expected_identifiers = [
(domain, device_id)
for domain, device_id in test_identifiers
@@ -68,7 +68,7 @@ async def test_disconnected_device_sensor_not_registered(
mock_omada_site_client: MagicMock,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test that if the gateway is not connected to the controller, gateway entities are not created."""
"""Test gateway entities are not created when gateway is not connected."""
await _set_test_device_status(
hass,
@@ -140,7 +140,7 @@ async def test_service_reconnect_failed_raises_homeassistanterror(
mock_omada_client: MagicMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test reconnect client service raises the right kind of exception on service failure."""
"""Test reconnect client service raises correct exception on failure."""
mock_config_entry.add_to_hass(hass)
+2 -2
View File
@@ -106,8 +106,8 @@ async def test_trackable_without_details(
await init_integration(hass, mock_config_entry)
assert (
"Tracker xyz098 has no details and will be skipped. This happens for shared trackers"
in caplog.text
"Tracker xyz098 has no details and will be skipped."
" This happens for shared trackers" in caplog.text
)
assert mock_config_entry.state is ConfigEntryState.LOADED
+13 -8
View File
@@ -148,7 +148,8 @@ async def test_migrate_config_entry_and_identifiers(
name="Gateway",
)
# Create bulb 1 on gateway 1 in Device Registry - this has the old identifiers format
# Create bulb 1 on gateway 1 in Device Registry
# this has the old identifiers format
gateway1_bulb1 = device_registry.async_get_or_create(
config_entry_id=config_entry1.entry_id,
identifiers={(tradfri.DOMAIN, 65537)},
@@ -156,13 +157,14 @@ async def test_migrate_config_entry_and_identifiers(
)
# Update bulb 1 device to have both config entry IDs
# This is to simulate existing data scenario with older version of tradfri component
# This simulates existing data scenario with older tradfri version
device_registry.async_update_device(
gateway1_bulb1.id,
add_config_entry_id=config_entry2.entry_id,
)
# Create bulb 2 on gateway 1 in Device Registry - this has the new identifiers format
# Create bulb 2 on gateway 1 in Device Registry
# this has the new identifiers format
gateway1_bulb2 = device_registry.async_get_or_create(
config_entry_id=config_entry1.entry_id,
identifiers={(tradfri.DOMAIN, f"{GATEWAY_ID1}-65538")},
@@ -212,8 +214,9 @@ async def test_migrate_config_entry_and_identifiers(
assert device_entries[0].identifiers == gateway1_device.identifiers
assert device_entries[0].config_entries == gateway1_device.config_entries
# Validate that gateway 1 bulb 2 now only exists associated to config entry 3.
# The device will have had its identifiers updated to the new format (for the tradfri
# Validate that gateway 1 bulb 2 now only exists associated to
# config entry 3. The device will have had its identifiers
# updated to the new format (for the tradfri
# domain) per migrate_config_entry_and_identifiers().
# The device will have then been removed from config entry 1 (gateway1)
# due to it not matching a device in the command store.
@@ -230,9 +233,11 @@ async def test_migrate_config_entry_and_identifiers(
("test_domain", "config_entry_3-device2"),
}
# Validate that gateway 2 bulb 1 has been added to device registry and with correct unique identifiers
# (This bulb device exists on gateway 2 because the command_store created above will be executed
# for each gateway being set up.)
# Validate that gateway 2 bulb 1 has been added to device
# registry and with correct unique identifiers
# (This bulb device exists on gateway 2 because the
# command_store created above will be executed for each
# gateway being set up.)
device_entries = dr.async_entries_for_config_entry(
device_registry, config_entry2.entry_id
)
@@ -12,9 +12,19 @@ from homeassistant.data_entry_flow import FlowResultType
from tests.common import MockConfigEntry
invalid_token_with_length_100_or_more = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjEyMzQ1Njc4OTBxd2VydHl1aW9wYXNkZiIsImlhdCI6MTcxOTg4MTU4M30.E4T2S4RQfuI2ww74sUkkT-wyTGrV5_VDkgUdae5yo4E"
invalid_token_with_length_100_or_more = (
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
".eyJpZCI6IjEyMzQ1Njc4OTBxd2VydHl1aW9wYXNkZiIs"
"ImlhdCI6MTcxOTg4MTU4M30"
".E4T2S4RQfuI2ww74sUkkT-wyTGrV5_VDkgUdae5yo4E"
)
invalid_token_id = "1234567890qwertyuiopasdf"
invalid_token_with_length_100_or_more_and_no_id = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJub2lkIjoiMTIzNDU2Nzg5MHF3ZXJ0eXVpb3Bhc2RmIiwiaWF0IjoxNzE5ODgxNTgzfQ.MaJLNWPGCE51Zibhbq-Yz7h3GkUxLurR2eoM2frnO6Y"
invalid_token_with_length_100_or_more_and_no_id = (
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
".eyJub2lkIjoiMTIzNDU2Nzg5MHF3ZXJ0eXVpb3Bhc2Rm"
"IiwiaWF0IjoxNzE5ODgxNTgzfQ"
".MaJLNWPGCE51Zibhbq-Yz7h3GkUxLurR2eoM2frnO6Y"
)
async def test_full_flow(
+1 -1
View File
@@ -58,7 +58,7 @@ async def test_dynamic_new_device(
mock_config_entry: MockConfigEntry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test that new entities are added when a new device appears in coordinator data."""
"""Test new entities are added when a new device appears in data."""
await setup_integration(hass, mock_config_entry)
# Initially the existing device's battery sensor has a state
+1 -1
View File
@@ -113,7 +113,7 @@ async def test_dynamic_new_device(
mock_config_entry: MockConfigEntry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test that new entities are added when a new device appears in coordinator data."""
"""Test new entities are added when a new device appears in data."""
await setup_integration(hass, mock_config_entry)
assert hass.states.get("switch.test_trmnl_sleep_mode") is not None
+1 -1
View File
@@ -126,7 +126,7 @@ async def test_dynamic_new_device(
mock_config_entry: MockConfigEntry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test that new entities are added when a new device appears in coordinator data."""
"""Test new entities are added when a new device appears in data."""
await setup_integration(hass, mock_config_entry)
assert hass.states.get("time.test_trmnl_sleep_start_time") is not None
+13 -5
View File
@@ -59,7 +59,7 @@ async def test_restore_state(
async def test_tts_entity_subclass_properties(
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
) -> None:
"""Test for errors when subclasses of the TextToSpeechEntity are missing required properties."""
"""Test errors when TextToSpeechEntity subclasses miss required properties."""
class TestClass1(tts.TextToSpeechEntity):
_attr_default_language = DEFAULT_LANG
@@ -88,7 +88,9 @@ async def test_tts_entity_subclass_properties(
await mock_config_entry_setup(hass, TestClass3())
assert (
"TTS entities must either set the '_attr_supported_languages' attribute or override the 'supported_languages' property"
"TTS entities must either set the"
" '_attr_supported_languages' attribute or override"
" the 'supported_languages' property"
in [
str(record.exc_info[1])
for record in caplog.records
@@ -103,7 +105,9 @@ async def test_tts_entity_subclass_properties(
await mock_config_entry_setup(hass, TestClass4())
assert (
"TTS entities must either set the '_attr_default_language' attribute or override the 'default_language' property"
"TTS entities must either set the"
" '_attr_default_language' attribute or override"
" the 'default_language' property"
in [
str(record.exc_info[1])
for record in caplog.records
@@ -120,7 +124,9 @@ async def test_tts_entity_subclass_properties(
await mock_config_entry_setup(hass, TestClass5())
assert (
"TTS entities must either set the '_attr_supported_languages' attribute or override the 'supported_languages' property"
"TTS entities must either set the"
" '_attr_supported_languages' attribute or override"
" the 'supported_languages' property"
in [
str(record.exc_info[1])
for record in caplog.records
@@ -137,7 +143,9 @@ async def test_tts_entity_subclass_properties(
await mock_config_entry_setup(hass, TestClass6())
assert (
"TTS entities must either set the '_attr_default_language' attribute or override the 'default_language' property"
"TTS entities must either set the"
" '_attr_default_language' attribute or override"
" the 'default_language' property"
in [
str(record.exc_info[1])
for record in caplog.records
+13 -4
View File
@@ -175,7 +175,10 @@ async def test_service(
await hass.async_block_till_done(wait_background_tasks=True)
assert (
mock_tts_cache_dir
/ f"42f18378fd4393d18c8dd11d03fa9563c1e54491_en-us_-_{expected_url_suffix}.mp3"
/ (
"42f18378fd4393d18c8dd11d03fa9563c1e54491"
f"_en-us_-_{expected_url_suffix}.mp3"
)
).is_file()
@@ -301,7 +304,10 @@ async def test_service_default_special_language(
await hass.async_block_till_done(wait_background_tasks=True)
assert (
mock_tts_cache_dir
/ f"42f18378fd4393d18c8dd11d03fa9563c1e54491_en-us_-_{expected_url_suffix}.mp3"
/ (
"42f18378fd4393d18c8dd11d03fa9563c1e54491"
f"_en-us_-_{expected_url_suffix}.mp3"
)
).is_file()
@@ -361,7 +367,10 @@ async def test_service_language(
await hass.async_block_till_done(wait_background_tasks=True)
assert (
mock_tts_cache_dir
/ f"42f18378fd4393d18c8dd11d03fa9563c1e54491_de-de_-_{expected_url_suffix}.mp3"
/ (
"42f18378fd4393d18c8dd11d03fa9563c1e54491"
f"_de-de_-_{expected_url_suffix}.mp3"
)
).is_file()
@@ -2082,7 +2091,7 @@ async def test_async_internal_get_tts_audio_called(
mock_tts_entity: MockTTSEntity,
hass_client: ClientSessionGenerator,
) -> None:
"""Test that non-streaming entity has its async_internal_get_tts_audio method called."""
"""Test non-streaming entity calls async_internal_get_tts_audio."""
await mock_config_entry_setup(hass, mock_tts_entity)
+1 -1
View File
@@ -43,7 +43,7 @@ class TuyaNotificationHelper:
updated_status_properties: list[str] | None,
dp_timestamps: dict[str, int] | None,
) -> None:
"""Trigger dispatcher_send for device update and wait for entity tasks to complete."""
"""Trigger dispatcher_send for device update and wait for tasks."""
for listener in self.manager.device_listeners:
listener.update_device(device, updated_status_properties, dp_timestamps)
await self.hass.async_block_till_done()
@@ -128,7 +128,10 @@ async def test_service(
"master_mode": "home",
"master_state": "alarm",
# "Sensor Low Battery Test Sensor" in UTF-16BE
"alarm_msg": "AFMAZQBuAHMAbwByACAATABvAHcAIABCAGEAdAB0AGUAcgB5ACAAVABlAHMAdAAgAFMAZQBuAHMAbwBy",
"alarm_msg": (
"AFMAZQBuAHMAbwByACAATABvAHcAIABCAGEAdAB0"
"AGUAcgB5ACAAVABlAHMAdAAgAFMAZQBuAHMAbwBy"
),
},
AlarmControlPanelState.ARMED_HOME,
),
+1 -1
View File
@@ -117,7 +117,7 @@ async def test_device_registry(
entity_registry: er.EntityRegistry,
snapshot: SnapshotAssertion,
) -> None:
"""Validate device registry snapshots for all devices, including unsupported ones."""
"""Validate device registry snapshots for all devices."""
await initialize_entry(hass, mock_manager, mock_config_entry, mock_devices)
+3 -1
View File
@@ -154,7 +154,9 @@ async def test_set_feeder_meal_plan_unsupported_device(
mock_device.product_id = "unsupported_product"
with pytest.raises(
ServiceValidationError,
match=f"Feeder with ID {mock_device.id} does not support meal plan functionality",
match=(
f"Feeder with ID {mock_device.id} does not support meal plan functionality"
),
):
await hass.services.async_call(
DOMAIN,
+1 -1
View File
@@ -212,7 +212,7 @@ async def test_turn_on_with_missing_effect(
mock_twinkly_client: AsyncMock,
data: dict[str, Any],
) -> None:
"""Test support of the light.turn_on service with rgbw color and missing effect support."""
"""Test light.turn_on with rgbw color and missing effect support."""
mock_twinkly_client.is_on.return_value = False
mock_twinkly_client.get_firmware_version.return_value["version"] = "2.7.0"
+1 -1
View File
@@ -537,7 +537,7 @@ async def test_flow_integration_discovery_aborts_on_direct_connect_host(
async def test_flow_integration_discovery_updates_existing_entry_on_rediscovery(
hass: HomeAssistant,
) -> None:
"""Test that an existing entry's host is refreshed when rediscovered with the same MAC."""
"""Test existing entry's host is refreshed when rediscovered with same MAC."""
old_entry = MockConfigEntry(
domain=DOMAIN,
unique_id=format_mac(INTEGRATION_DISCOVERY_INFO["hw_addr"]),
@@ -448,7 +448,8 @@ async def test_wireless_client_go_wired_issue(
) -> None:
"""Test the solution to catch wireless device go wired UniFi issue.
UniFi Network has a known issue that when a wireless device goes away it sometimes gets marked as wired.
UniFi Network has a known issue that when a wireless device goes away
it sometimes gets marked as wired.
"""
client_payload.append(
WIRELESS_CLIENT_1 | {"last_seen": dt_util.as_timestamp(dt_util.utcnow())}
@@ -585,7 +586,7 @@ async def test_restoring_client(
client_payload: list[dict[str, Any]],
clients_all_payload: list[dict[str, Any]],
) -> None:
"""Verify clients are restored from clients_all if they ever was registered to entity registry."""
"""Verify clients are restored from clients_all if registered to entity registry."""
entity_registry.async_get_or_create(
TRACKER_DOMAIN,
DOMAIN,
+1 -1
View File
@@ -408,7 +408,7 @@ async def test_light_onoff_mode_turn_on_off(
async def test_light_rgb_vs_onoff_modes(
hass: HomeAssistant,
) -> None:
"""Test that RGB and ONOFF modes are correctly assigned based on device capabilities."""
"""Test RGB and ONOFF modes are assigned based on device capabilities."""
assert len(hass.states.async_entity_ids(LIGHT_DOMAIN)) == 2
# Device with LED ring support should have RGB mode
+1 -1
View File
@@ -1906,7 +1906,7 @@ async def test_device_with_no_matching_temperatures(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
) -> None:
"""Verify that device temperature sensors is not created if there is no matching data."""
"""Verify device temperature sensors are not created without matching data."""
assert len(hass.states.async_all()) == 6
assert len(hass.states.async_entity_ids(SENSOR_DOMAIN)) == 2
+4 -2
View File
@@ -1271,7 +1271,8 @@ async def test_traffic_routes(
{"entity_id": "switch.unifi_network_test_traffic_route"},
blocking=True,
)
# Updating the value for traffic routes will make another call to retrieve the values
# Updating the value for traffic routes will make another call
# to retrieve the values
assert aioclient_mock.call_count == call_count + 2
expected_disable_call = deepcopy(traffic_route)
expected_disable_call["enabled"] = False
@@ -1327,7 +1328,8 @@ async def test_firewall_policies(
{"entity_id": "switch.unifi_network_allow_internal_to_iot"},
blocking=True,
)
# Updating the value for firewall policies will make another call to retrieve the values
# Updating the value for firewall policies will make another call
# to retrieve the values
assert aioclient_mock.call_count == call_count + 2
expected_disable_call = deepcopy(firewall_policy)
expected_disable_call["enabled"] = False
@@ -157,7 +157,7 @@ async def test_v2_device_update_empty_location_id_ignored(
init_integration: MockConfigEntry,
mock_client: MagicMock,
) -> None:
"""Test access.data.v2.device.update with empty location_id does not update state."""
"""Test device.update with empty location_id does not update state."""
handlers = _get_ws_handlers(mock_client)
update_msg = V2DeviceUpdate(
@@ -362,7 +362,7 @@ async def test_user_flow_ssl_context(
verify_ssl: bool,
expected_ssl_context_type: type,
) -> None:
"""Test that a pre-warmed no-verify SSL context is passed when verify_ssl is False."""
"""Test no-verify SSL context is passed when verify_ssl is False."""
result = await hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_USER}
)
@@ -803,7 +803,7 @@ async def test_discovery_ignored_entry(
async def test_discovery_fallback_name_from_mac(
hass: HomeAssistant, mock_client: MagicMock
) -> None:
"""Test discovery confirm uses MAC-based name when hostname and platform are absent."""
"""Test discovery uses MAC-based name when hostname and platform are absent."""
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_INTEGRATION_DISCOVERY},
+6 -6
View File
@@ -817,7 +817,7 @@ async def test_remote_view_doorbell_ring_by_door_name_fallback(
init_integration: MockConfigEntry,
mock_client: MagicMock,
) -> None:
"""Test access.remote_view falls back to door_name lookup when device_id is unmapped."""
"""Test remote_view falls back to door_name when device_id is unmapped."""
handlers = _get_ws_handlers(mock_client)
remote_view_msg = RemoteView(
@@ -838,7 +838,7 @@ async def test_remote_view_unknown_device_and_door_ignored(
init_integration: MockConfigEntry,
mock_client: MagicMock,
) -> None:
"""Test access.remote_view is ignored when both device_id and door_name are unknown."""
"""Test remote_view is ignored when device_id and door_name are unknown."""
handlers = _get_ws_handlers(mock_client)
remote_view_msg = RemoteView(
@@ -859,7 +859,7 @@ async def test_remote_view_device_mapping_via_device_update(
init_integration: MockConfigEntry,
mock_client: MagicMock,
) -> None:
"""Test access.remote_view resolves device_id populated by access.data.device.update."""
"""Test remote_view resolves device_id populated by data.device.update."""
handlers = _get_ws_handlers(mock_client)
device_update_msg = DeviceUpdate(
@@ -891,7 +891,7 @@ async def test_remote_view_device_mapping_via_v2_device_update(
init_integration: MockConfigEntry,
mock_client: MagicMock,
) -> None:
"""Test access.remote_view resolves device_id populated by access.data.v2.device.update."""
"""Test remote_view resolves device_id from data.v2.device.update."""
handlers = _get_ws_handlers(mock_client)
v2_device_update_msg = V2DeviceUpdate(
@@ -1164,7 +1164,7 @@ async def test_logs_add_no_device_and_no_enriched_door_id_ignored(
init_integration: MockConfigEntry,
mock_client: MagicMock,
) -> None:
"""Test logs.add event is ignored when neither device mapping nor door_id resolves."""
"""Test logs.add is ignored when neither device mapping nor door_id resolves."""
handlers = _get_ws_handlers(mock_client)
log_msg = LogAdd(
@@ -1228,7 +1228,7 @@ async def test_logs_add_direction(
init_integration: MockConfigEntry,
mock_client: MagicMock,
) -> None:
"""Test direction attribute is included in access event from logs.add when present."""
"""Test direction attribute is included in event from logs.add."""
handlers = _get_ws_handlers(mock_client)
await _populate_device_mapping(handlers)
+1 -1
View File
@@ -74,7 +74,7 @@ async def test_setup_entry_ssl_context(
verify_ssl: bool,
expected_ssl_context_type: type,
) -> None:
"""Test that a pre-warmed no-verify SSL context is passed when verify_ssl is False."""
"""Test no-verify SSL context is passed when verify_ssl is False."""
entry = MockConfigEntry(
domain=DOMAIN,
title="UniFi Access",
+1 -1
View File
@@ -138,7 +138,7 @@ async def test_sensor_created_after_websocket_update_when_initial_fetch_fails(
mock_config_entry: MockConfigEntry,
mock_client: MagicMock,
) -> None:
"""Test websocket updates refine placeholder sensors after a transient startup error."""
"""Test websocket updates refine placeholders after a transient startup error."""
mock_client.get_door_lock_rule = AsyncMock(
side_effect=ApiConnectionError("Connection failed")
)
+1 -1
View File
@@ -470,7 +470,7 @@ def mock_ufp_reauth_entry():
@pytest.fixture(name="ufp_reauth_entry_alt")
def mock_ufp_reauth_entry_alt():
"""Mock the unifiprotect config entry with alternate port/SSL for reauth/reconfigure tests."""
"""Mock the unifiprotect config entry with alt port/SSL for reauth tests."""
return MockConfigEntry(
domain=DOMAIN,
data={
@@ -727,10 +727,11 @@ async def test_aiport_no_binary_sensor_entities(
ufp: MockUFPFixture,
aiport: AiPort,
) -> None:
"""Test that AI Port devices do not create camera-specific binary sensor entities."""
"""Test AI Port devices do not create camera-specific binary sensors."""
await init_entry(hass, ufp, [aiport])
# AI Port should not create any camera-specific binary sensors (motion, smart detection, etc.)
# AI Port should not create any camera-specific binary sensors
# (motion, smart detection, etc.)
# NVR HDD sensors will still be created, but no AI Port-specific entities
entity_registry = er.async_get(hass)
entities = er.async_entries_for_config_entry(entity_registry, ufp.entry.entry_id)
+4 -1
View File
@@ -166,7 +166,10 @@ def validate_rtsp_camera_entity(
entity_name = f"{camera_obj.name} {channel.name} Resolution Channel (Insecure)"
unique_id = f"{camera_obj.mac}_{channel.id}_insecure"
entity_id = f"camera.{entity_name.replace(' ', '_').replace('(', '').replace(')', '').lower()}"
entity_id = (
"camera."
f"{entity_name.replace(' ', '_').replace('(', '').replace(')', '').lower()}"
)
entity_registry = er.async_get(hass)
entity = entity_registry.async_get(entity_id)
@@ -676,10 +676,10 @@ async def test_discovered_by_unifi_discovery_direct_connect_updated(
assert mock_config.data[CONF_HOST] == DIRECT_CONNECT_DOMAIN
async def test_discovered_by_unifi_discovery_direct_connect_updated_but_not_using_direct_connect(
async def test_discovered_by_unifi_discovery_dc_updated_but_not_using_dc(
hass: HomeAssistant,
) -> None:
"""Test a discovery from unifi-discovery updates the host but not direct connect if its not in use."""
"""Test discovery updates the host but not direct connect if not in use."""
mock_config = MockConfigEntry(
domain=DOMAIN,
data={
@@ -713,10 +713,10 @@ async def test_discovered_by_unifi_discovery_direct_connect_updated_but_not_usin
assert mock_config.data[CONF_HOST] == "127.0.0.1"
async def test_discovered_by_unifi_discovery_does_not_update_ip_when_console_is_still_online(
async def test_discovered_by_unifi_discovery_no_update_ip_when_console_online(
hass: HomeAssistant,
) -> None:
"""Test a discovery from unifi-discovery does not update the ip unless the console at the old ip is offline."""
"""Test discovery does not update IP unless old console is offline."""
mock_config = MockConfigEntry(
domain=DOMAIN,
data={
@@ -948,10 +948,10 @@ async def test_discovered_by_unifi_discovery_direct_connect_on_different_interfa
assert result["reason"] == "already_configured"
async def test_discovered_by_unifi_discovery_direct_connect_on_different_interface_ip_matches(
async def test_discovered_by_unifi_discovery_dc_different_interface_ip_matches(
hass: HomeAssistant,
) -> None:
"""Test a discovery from unifi-discovery from an alternate interface when the ip matches."""
"""Test discovery from alternate interface when the IP matches."""
mock_config = MockConfigEntry(
domain=DOMAIN,
data={
@@ -978,10 +978,10 @@ async def test_discovered_by_unifi_discovery_direct_connect_on_different_interfa
assert result["reason"] == "already_configured"
async def test_discovered_by_unifi_discovery_direct_connect_on_different_interface_resolver(
async def test_discovered_by_unifi_discovery_dc_different_interface_resolver(
hass: HomeAssistant,
) -> None:
"""Test a discovery from unifi-discovery from an alternate interface when direct connect domain resolves to host ip."""
"""Test discovery from alternate interface when direct connect resolves."""
mock_config = MockConfigEntry(
domain=DOMAIN,
data={
@@ -1019,10 +1019,10 @@ async def test_discovered_by_unifi_discovery_direct_connect_on_different_interfa
assert result["reason"] == "already_configured"
async def test_discovered_by_unifi_discovery_direct_connect_on_different_interface_resolver_fails(
async def test_discovered_by_unifi_discovery_dc_different_interface_resolver_fails(
hass: HomeAssistant, bootstrap: Bootstrap, nvr: NVR
) -> None:
"""Test we can still configure if the resolver fails."""
"""Test we can still configure when the resolver fails."""
mock_config = MockConfigEntry(
domain=DOMAIN,
data={
@@ -1110,10 +1110,10 @@ async def test_discovered_by_unifi_discovery_direct_connect_on_different_interfa
assert len(mock_setup.mock_calls) == 1
async def test_discovered_by_unifi_discovery_direct_connect_on_different_interface_resolver_no_result(
async def test_discovered_by_unifi_discovery_dc_different_interface_resolver_no_result(
hass: HomeAssistant,
) -> None:
"""Test a discovery from unifi-discovery from an alternate interface when direct connect domain resolve has no result."""
"""Test discovery from alternate interface when resolve has no result."""
mock_config = MockConfigEntry(
domain=DOMAIN,
data={
+4 -2
View File
@@ -964,7 +964,8 @@ async def test_vehicle_detection_multiple_thumbnails(
unsub = async_track_state_change_event(hass, entity_id, _capture_event)
# Create event with multiple vehicle thumbnails - best should be highest confidence LPR
# Create event with multiple vehicle thumbnails
# best should be highest confidence LPR
event = Event(
model=ModelType.EVENT,
id="test_multi_thumbnail_id",
@@ -1605,5 +1606,6 @@ async def test_aiport_no_event_entities(
"""Test that AI Port devices do not create camera-specific event entities."""
await init_entry(hass, ufp, [aiport])
# AI Port should not create any camera-specific event entities (doorbell, motion, etc.)
# AI Port should not create any camera-specific event entities
# (doorbell, motion, etc.)
assert_entity_counts(hass, Platform.EVENT, 0, 0)
+4 -3
View File
@@ -308,7 +308,7 @@ async def test_setup_failed_error(hass: HomeAssistant, ufp: MockUFPFixture) -> N
async def test_setup_failed_auth(hass: HomeAssistant, ufp: MockUFPFixture) -> None:
"""Test setup of unifiprotect entry with unauthorized error after multiple retries."""
"""Test setup of unifiprotect entry with unauthorized error after retries."""
ufp.api.update = AsyncMock(side_effect=NotAuthorized)
@@ -437,7 +437,7 @@ async def test_async_ufp_instance_for_config_entry_ids(
mock_entries: list[MockConfigEntry],
expected_result: str | None,
) -> None:
"""Test async_ufp_instance_for_config_entry_ids with various entry configurations."""
"""Test async_ufp_instance_for_config_entry_ids with various configs."""
for index, entry in enumerate(mock_entries):
entry.add_to_hass(hass)
@@ -523,7 +523,8 @@ async def test_setup_handles_api_key_creation_bad_request(
hass: HomeAssistant, ufp: MockUFPFixture, mock_user_can_write_nvr: Mock
) -> None:
"""Test handling of API key creation BadRequest error."""
# Setup: API key is not set, user has write permissions, but creation fails with BadRequest
# Setup: API key is not set, user has write permissions,
# but creation fails with BadRequest
ufp.api.is_api_key_set.return_value = False
ufp.api.create_api_key = AsyncMock(
side_effect=BadRequest("Invalid API key creation request")
@@ -655,8 +655,8 @@ async def test_browse_media_recent_truncated(
browse = await source.async_browse_media(media_item)
assert (
browse.title
== f"UnifiProtect > {doorbell.name} > Motion Events > Last 24 Hours (1 TRUNCATED)"
browse.title == f"UnifiProtect > {doorbell.name} > Motion Events"
" > Last 24 Hours (1 TRUNCATED)"
)
assert browse.identifier == base_id
assert len(browse.children) == 1
@@ -898,7 +898,10 @@ async def test_browse_media_browse_day(
event._api = ufp.api
ufp.api.get_events_raw = AsyncMock(return_value=[event.unifi_dict()])
base_id = f"test_id:browse:{doorbell.id}:motion:range:{fixed_now.year}:{fixed_now.month}:1"
base_id = (
f"test_id:browse:{doorbell.id}:motion:range"
f":{fixed_now.year}:{fixed_now.month}:1"
)
source = await async_get_media_source(hass)
media_item = MediaSourceItem(hass, DOMAIN, base_id, None)
@@ -906,8 +909,8 @@ async def test_browse_media_browse_day(
start = fixed_now.replace(day=1)
assert (
browse.title
== f"UnifiProtect > {doorbell.name} > Motion Events > {fixed_now.strftime('%B %Y')} > {start.strftime('%x')} (1)"
browse.title == f"UnifiProtect > {doorbell.name} > Motion Events"
f" > {fixed_now.strftime('%B %Y')} > {start.strftime('%x')} (1)"
)
assert browse.identifier == base_id
assert len(browse.children) == 1
@@ -949,8 +952,8 @@ async def test_browse_media_browse_whole_month(
browse = await source.async_browse_media(media_item)
assert (
browse.title
== f"UnifiProtect > {doorbell.name} > All Events > {fixed_now.strftime('%B %Y')} > Whole Month (1)"
browse.title == f"UnifiProtect > {doorbell.name} > All Events"
f" > {fixed_now.strftime('%B %Y')} > Whole Month (1)"
)
assert browse.identifier == base_id
assert len(browse.children) == 1
@@ -1036,8 +1039,8 @@ async def test_browse_media_browse_whole_month_december(
browse = await source.async_browse_media(media_item)
assert (
browse.title
== f"UnifiProtect > {doorbell.name} > All Events > {fixed_now.strftime('%B %Y')} > Whole Month (1)"
browse.title == f"UnifiProtect > {doorbell.name} > All Events"
f" > {fixed_now.strftime('%B %Y')} > Whole Month (1)"
)
assert browse.identifier == base_id
assert len(browse.children) == 1
+1 -1
View File
@@ -447,7 +447,7 @@ async def test_relay_switch_command_when_output_gone(
hass: HomeAssistant,
ufp_with_relay: tuple[MockUFPFixture, Mock],
) -> None:
"""Command raises HomeAssistantError when the relay output channel is no longer present."""
"""Command raises HomeAssistantError when relay output channel is gone."""
ufp, relay = ufp_with_relay
await init_entry(hass, ufp, [])
@@ -525,7 +525,7 @@ async def test_ptz_goto_home_preset_client_error(
ufp: MockUFPFixture,
ptz_camera: Camera,
) -> None:
"""Test ptz_goto_preset service with home preset when ptz_goto_preset_public raises ClientError."""
"""Test ptz_goto_preset with home preset when it raises ClientError."""
ptz_camera.get_ptz_patrols.return_value = []
await init_entry(hass, ufp, [ptz_camera])
+2 -2
View File
@@ -179,7 +179,7 @@ async def test_siren_turn_on_with_duration(
seconds: int,
expected: SirenDuration,
) -> None:
"""Passing a valid duration to turn_on calls play with the matching SirenDuration."""
"""Valid duration to turn_on calls play with matching SirenDuration."""
await init_entry(hass, ufp_with_siren, [])
await hass.services.async_call(
@@ -603,7 +603,7 @@ async def test_siren_auto_off_timer_scheduled_at_startup(
ufp_with_siren: MockUFPFixture,
siren: Mock,
) -> None:
"""Auto-off timer is scheduled during async_added_to_hass for an already-active siren.
"""Auto-off timer is scheduled for an already-active siren.
If a timed run is already in progress when HA starts, the entity must
schedule its own auto-off callback immediately (not wait for a WS update)
+1 -1
View File
@@ -126,7 +126,7 @@ async def ids_from_device_description(
device: ProtectAdoptableDeviceModel,
description: EntityDescription,
) -> tuple[str, str]:
"""Return expected unique_id and entity_id using real Home Assistant translation logic."""
"""Return expected unique_id and entity_id using HA translation logic."""
entity_name = normalize_name(device.display_name)
+2 -1
View File
@@ -58,7 +58,8 @@ async def test_login_error(
ANY,
exc=UpCloudAPIError(
error_code="AUTHENTICATION_FAILED",
error_message="Authentication failed using the given username and password.",
error_message="Authentication failed using the given"
" username and password.",
),
)
result = await hass.config_entries.flow.async_init(
+2 -1
View File
@@ -323,7 +323,8 @@ async def test_entity_with_auto_update(
# Should not be able to clear a skipped the update
with pytest.raises(
HomeAssistantError,
match="Clearing skipped update is not supported for update.update_with_auto_update",
match="Clearing skipped update is not supported"
" for update.update_with_auto_update",
):
await hass.services.async_call(
DOMAIN,
+3 -3
View File
@@ -89,7 +89,7 @@ async def test_update_state_trigger_behavior_any(
trigger_options: dict[str, Any],
states: list[TriggerStateDescription],
) -> None:
"""Test that the update state trigger fires when any update state changes to a specific state."""
"""Test update state trigger fires when any update changes to a specific state."""
await assert_trigger_behavior_any(
hass,
target_entities=target_updates,
@@ -127,7 +127,7 @@ async def test_update_state_trigger_behavior_first(
trigger_options: dict[str, Any],
states: list[TriggerStateDescription],
) -> None:
"""Test that the update state trigger fires when the first update changes to a specific state."""
"""Test update state trigger fires when first update changes to a specific state."""
await assert_trigger_behavior_first(
hass,
target_entities=target_updates,
@@ -165,7 +165,7 @@ async def test_update_state_trigger_behavior_last(
trigger_options: dict[str, Any],
states: list[TriggerStateDescription],
) -> None:
"""Test that the update state trigger fires when the last update changes to a specific state."""
"""Test update state trigger fires when last update changes to a specific state."""
await assert_trigger_behavior_last(
hass,
target_entities=target_updates,
+7 -7
View File
@@ -141,7 +141,7 @@ async def test_flow_ssdp_non_igd_device(hass: HomeAssistant) -> None:
ssdp_location=TEST_LOCATION,
ssdp_all_locations=[TEST_LOCATION],
upnp={
ATTR_UPNP_DEVICE_TYPE: "urn:schemas-upnp-org:device:WFADevice:1", # Non-IGD
ATTR_UPNP_DEVICE_TYPE: "urn:schemas-upnp-org:device:WFADevice:1",
},
),
)
@@ -184,7 +184,7 @@ async def test_flow_ssdp_no_mac_address(hass: HomeAssistant) -> None:
@pytest.mark.usefixtures("mock_mac_address_from_host")
async def test_flow_ssdp_discovery_changed_udn_match_mac(hass: HomeAssistant) -> None:
"""Test config flow: discovery through ssdp, same device, but new UDN, matched on mac address."""
"""Test config flow: ssdp discovery, same device, new UDN, matched on MAC."""
entry = MockConfigEntry(
domain=DOMAIN,
unique_id=TEST_USN,
@@ -216,7 +216,7 @@ async def test_flow_ssdp_discovery_changed_udn_match_mac(hass: HomeAssistant) ->
@pytest.mark.usefixtures("mock_mac_address_from_host")
async def test_flow_ssdp_discovery_changed_udn_match_host(hass: HomeAssistant) -> None:
"""Test config flow: discovery through ssdp, same device, but new UDN, matched on mac address."""
"""Test config flow: ssdp discovery, same device, new UDN, matched on host."""
entry = MockConfigEntry(
domain=DOMAIN,
unique_id=TEST_USN,
@@ -253,7 +253,7 @@ async def test_flow_ssdp_discovery_changed_udn_match_host(hass: HomeAssistant) -
async def test_flow_ssdp_discovery_changed_udn_but_st_differs(
hass: HomeAssistant,
) -> None:
"""Test config flow: discovery through ssdp, same device, but new UDN, and different ST, so not matched --> new discovery."""
"""Test config flow: ssdp discovery, same device, new UDN, different ST."""
entry = MockConfigEntry(
domain=DOMAIN,
unique_id=TEST_USN,
@@ -342,7 +342,7 @@ async def test_flow_ssdp_discovery_changed_location(hass: HomeAssistant) -> None
@pytest.mark.usefixtures("mock_mac_address_from_host")
async def test_flow_ssdp_discovery_ignored_entry(hass: HomeAssistant) -> None:
"""Test config flow: discovery through ssdp, same device, but new UDN, matched on mac address."""
"""Test config flow: ssdp, same device, new UDN, matched on MAC."""
entry = MockConfigEntry(
domain=DOMAIN,
unique_id=TEST_USN,
@@ -370,7 +370,7 @@ async def test_flow_ssdp_discovery_ignored_entry(hass: HomeAssistant) -> None:
async def test_flow_ssdp_discovery_changed_udn_ignored_entry(
hass: HomeAssistant,
) -> None:
"""Test config flow: discovery through ssdp, same device, but new UDN, matched on mac address, entry ignored."""
"""Test config flow: ssdp, same device, new UDN, matched on MAC, ignored."""
entry = MockConfigEntry(
domain=DOMAIN,
unique_id=TEST_USN,
@@ -450,7 +450,7 @@ async def test_flow_user_no_discovery(hass: HomeAssistant) -> None:
"mock_mac_address_from_host",
)
async def test_flow_ssdp_with_mismatched_udn(hass: HomeAssistant) -> None:
"""Test config flow: discovered + configured through ssdp, where the UDN differs in the SSDP-discovery vs device description."""
"""Test config flow: UDN differs in SSDP-discovery vs device description."""
# Discovered via step ssdp.
test_discovery = copy.deepcopy(TEST_DISCOVERY)
test_discovery.upnp[ATTR_UPNP_UDN] = "uuid:another_udn"
+3 -2
View File
@@ -122,7 +122,7 @@ async def test_async_setup_entry_multi_location(
async def test_async_setup_udn_mismatch(
hass: HomeAssistant, mock_async_create_device: AsyncMock
) -> None:
"""Test async_setup_entry for a device which reports a different UDN from SSDP-discovery and device description."""
"""Test async_setup_entry for a device with different UDN from SSDP."""
test_discovery = copy.deepcopy(TEST_DISCOVERY)
test_discovery.upnp[ATTR_UPNP_UDN] = "uuid:another_udn"
@@ -236,7 +236,8 @@ async def test_async_setup_entry_force_poll_subscribe_error(
mock_igd_device.async_subscribe_services.side_effect = UpnpCommunicationError
mock_igd_device.async_unsubscribe_services.side_effect = UpnpCommunicationError
# Load config_entry, should still be able to load, falling back to polling/the old functionality.
# Load config_entry, should still be able to load,
# falling back to polling/the old functionality.
entry.add_to_hass(hass)
assert await hass.config_entries.async_setup(entry.entry_id) is True
@@ -462,7 +462,7 @@ async def test_hassio_addon_discovery_ignored(
async def test_hassio_addon_discovery_update_info(
hass: HomeAssistant,
) -> None:
"""Test we abort discovery flow if already configured and we update from discovery info."""
"""Test we abort discovery flow if already configured and update info."""
entry = MockConfigEntry(
domain=DOMAIN,
+5 -5
View File
@@ -55,8 +55,8 @@ async def test_reauthentication_trigger_in_setup(
assert flow["context"]["entry_id"] == mock_config_entry.entry_id
assert (
"Config entry 'test@test.test' for uptimerobot integration could not authenticate"
in caplog.text
"Config entry 'test@test.test' for uptimerobot integration"
" could not authenticate" in caplog.text
)
@@ -88,8 +88,8 @@ async def test_reauthentication_trigger_key_read_only(
assert flow["context"]["entry_id"] == mock_config_entry.entry_id
assert (
"Config entry 'test@test.test' for uptimerobot integration could not authenticate"
in caplog.text
"Config entry 'test@test.test' for uptimerobot integration"
" could not authenticate" in caplog.text
)
@@ -195,7 +195,7 @@ async def test_device_management(
device_registry: dr.DeviceRegistry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test that we are adding and removing devices for monitors returned from the API."""
"""Test adding and removing devices for monitors returned from the API."""
mock_entry = await setup_uptimerobot_integration(hass)
devices = dr.async_entries_for_config_entry(device_registry, mock_entry.entry_id)
+9 -9
View File
@@ -253,7 +253,7 @@ async def test_discovered_by_websocket_scan(
async def test_discovered_by_websocket_scan_limited_by_description_matcher(
hass: HomeAssistant, hass_ws_client: WebSocketGenerator
) -> None:
"""Test a device is discovered from websocket scan is limited by the description matcher."""
"""Test websocket scan discovery is limited by the description matcher."""
new_usb = [
{"domain": "test1", "vid": "3039", "pid": "3039", "description": "*2652*"}
]
@@ -380,7 +380,7 @@ async def test_most_targeted_matcher_wins(
async def test_discovered_by_websocket_scan_rejected_by_description_matcher(
hass: HomeAssistant, hass_ws_client: WebSocketGenerator
) -> None:
"""Test a device is discovered from websocket scan rejected by the description matcher."""
"""Test websocket scan discovery rejected by the description matcher."""
new_usb = [
{"domain": "test1", "vid": "3039", "pid": "3039", "description": "*not_it*"}
]
@@ -418,7 +418,7 @@ async def test_discovered_by_websocket_scan_rejected_by_description_matcher(
async def test_discovered_by_websocket_scan_limited_by_serial_number_matcher(
hass: HomeAssistant, hass_ws_client: WebSocketGenerator
) -> None:
"""Test a device is discovered from websocket scan is limited by the serial_number matcher."""
"""Test websocket scan discovery is limited by the serial_number matcher."""
new_usb = [
{
"domain": "test1",
@@ -462,7 +462,7 @@ async def test_discovered_by_websocket_scan_limited_by_serial_number_matcher(
async def test_discovered_by_websocket_scan_rejected_by_serial_number_matcher(
hass: HomeAssistant, hass_ws_client: WebSocketGenerator
) -> None:
"""Test a device is discovered from websocket scan is rejected by the serial_number matcher."""
"""Test websocket scan discovery is rejected by the serial_number matcher."""
new_usb = [
{"domain": "test1", "vid": "3039", "pid": "3039", "serial_number": "123*"}
]
@@ -500,7 +500,7 @@ async def test_discovered_by_websocket_scan_rejected_by_serial_number_matcher(
async def test_discovered_by_websocket_scan_limited_by_manufacturer_matcher(
hass: HomeAssistant, hass_ws_client: WebSocketGenerator
) -> None:
"""Test a device is discovered from websocket scan is limited by the manufacturer matcher."""
"""Test websocket scan discovery is limited by the manufacturer matcher."""
new_usb = [
{
"domain": "test1",
@@ -544,7 +544,7 @@ async def test_discovered_by_websocket_scan_limited_by_manufacturer_matcher(
async def test_discovered_by_websocket_scan_rejected_by_manufacturer_matcher(
hass: HomeAssistant, hass_ws_client: WebSocketGenerator
) -> None:
"""Test a device is discovered from websocket scan is rejected by the manufacturer matcher."""
"""Test websocket scan discovery is rejected by the manufacturer matcher."""
new_usb = [
{
"domain": "test1",
@@ -587,7 +587,7 @@ async def test_discovered_by_websocket_scan_rejected_by_manufacturer_matcher(
async def test_discovered_by_websocket_rejected_with_empty_serial_number_only(
hass: HomeAssistant, hass_ws_client: WebSocketGenerator
) -> None:
"""Test a device is discovered from websocket is rejected with empty serial number."""
"""Test websocket discovery is rejected with empty serial number."""
new_usb = [
{"domain": "test1", "vid": "3039", "pid": "3039", "serial_number": "123*"}
]
@@ -662,7 +662,7 @@ async def test_discovered_by_websocket_scan_match_vid_only(
async def test_discovered_by_websocket_scan_match_vid_wrong_pid(
hass: HomeAssistant, hass_ws_client: WebSocketGenerator
) -> None:
"""Test a device is discovered from websocket scan only matching vid but wrong pid."""
"""Test websocket scan discovery matching vid but wrong pid."""
new_usb = [{"domain": "test1", "vid": "3039", "pid": "9999"}]
mock_ports = [
@@ -769,7 +769,7 @@ async def test_non_matching_discovered_by_scanner_after_started(
async def test_aiousbwatcher_on_wsl_fallback_without_throwing_exception(
hass: HomeAssistant, hass_ws_client: WebSocketGenerator
) -> None:
"""Test that aiousbwatcher on WSL failure results in fallback to scanning without raising an exception."""
"""Test aiousbwatcher WSL failure falls back to scanning without exception."""
new_usb = [{"domain": "test1", "vid": "3039"}]
mock_ports = [
@@ -328,7 +328,7 @@ async def test_change_device_source(
device_registry: dr.DeviceRegistry,
entity_registry: er.EntityRegistry,
) -> None:
"""Test remove the device registry configuration entry when the source entity changes."""
"""Test remove device registry config entry when source entity changes."""
# Configure source entity 1 (with a linked device)
source_config_entry_1 = MockConfigEntry()
source_config_entry_1.add_to_hass(hass)
@@ -403,7 +403,8 @@ async def test_change_device_source(
assert await hass.config_entries.async_setup(utility_meter_config_entry.entry_id)
await hass.async_block_till_done()
# Confirm that the configuration entry has not been added to the source entity 1 (current) device registry
# Confirm that the configuration entry has not been added
# to the source entity 1 (current) device registry
current_device = device_registry.async_get(
device_id=current_entity_source.device_id
)
@@ -417,7 +418,8 @@ async def test_change_device_source(
):
assert utility_meter_entity.device_id == source_entity_1.device_id
# Change configuration options to use source entity 2 (with a linked device) and reload the integration
# Change configuration options to use source entity 2
# (with a linked device) and reload the integration
previous_entity_source = source_entity_1
current_entity_source = source_entity_2
@@ -435,13 +437,15 @@ async def test_change_device_source(
assert result["type"] is FlowResultType.CREATE_ENTRY
await hass.async_block_till_done()
# Confirm that the configuration entry is not in the source entity 1 (previous) device registry
# Confirm that the configuration entry is not in the
# source entity 1 (previous) device registry
previous_device = device_registry.async_get(
device_id=previous_entity_source.device_id
)
assert utility_meter_config_entry.entry_id not in previous_device.config_entries
# Confirm that the configuration entry is not in to the source entity 2 (current) device registry
# Confirm that the configuration entry is not in
# the source entity 2 (current) device registry
current_device = device_registry.async_get(
device_id=current_entity_source.device_id
)
@@ -455,7 +459,8 @@ async def test_change_device_source(
):
assert utility_meter_entity.device_id == source_entity_2.device_id
# Change configuration options to use source entity 3 (without a device) and reload the integration
# Change configuration options to use source entity 3
# (without a device) and reload the integration
previous_entity_source = source_entity_2
current_entity_source = source_entity_3
@@ -473,7 +478,8 @@ async def test_change_device_source(
assert result["type"] is FlowResultType.CREATE_ENTRY
await hass.async_block_till_done()
# Confirm that the configuration entry has is not in the source entity 2 (previous) device registry
# Confirm that the configuration entry is not in the
# source entity 2 (previous) device registry
previous_device = device_registry.async_get(
device_id=previous_entity_source.device_id
)
@@ -495,7 +501,8 @@ async def test_change_device_source(
== []
)
# Change configuration options to use source entity 2 (with a linked device) and reload the integration
# Change configuration options to use source entity 2
# (with a linked device) and reload the integration
previous_entity_source = source_entity_3
current_entity_source = source_entity_2
@@ -513,7 +520,8 @@ async def test_change_device_source(
assert result["type"] is FlowResultType.CREATE_ENTRY
await hass.async_block_till_done()
# Confirm that the configuration entry is not in the source entity 2 (current) device registry
# Confirm that the configuration entry is not in the
# source entity 2 (current) device registry
current_device = device_registry.async_get(
device_id=current_entity_source.device_id
)

Some files were not shown because too many files have changed in this diff Show More