Improve lupusec code quality (#109727)

* renamed async_add_devices

* fixed typo

* patch class instead of __init__

* ensure non blocking get_alarm

* exception handling

* added test case for json decode error

* avoid blockign calls

---------

Co-authored-by: suaveolent <suaveolent@users.noreply.github.com>
pull/109771/head
suaveolent 2024-02-06 01:20:14 +01:00 committed by GitHub
parent 965f31a9e0
commit 668d036f71
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 32 additions and 25 deletions

View File

@ -1,4 +1,5 @@
"""Support for Lupusec Home Security system."""
from json import JSONDecodeError
import logging
import lupupy
@ -111,16 +112,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
lupusec_system = await hass.async_add_executor_job(
lupupy.Lupusec, username, password, host
)
except LupusecException:
_LOGGER.error("Failed to connect to Lupusec device at %s", host)
return False
except Exception as ex: # pylint: disable=broad-except
_LOGGER.error(
"Unknown error while trying to connect to Lupusec device at %s: %s",
host,
ex,
)
except JSONDecodeError:
_LOGGER.error("Failed to connect to Lupusec device at %s", host)
return False
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = lupusec_system

View File

@ -29,14 +29,14 @@ SCAN_INTERVAL = timedelta(seconds=2)
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_devices: AddEntitiesCallback,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up an alarm control panel for a Lupusec device."""
data = hass.data[DOMAIN][config_entry.entry_id]
alarm_devices = [LupusecAlarm(data, data.get_alarm(), config_entry.entry_id)]
alarm = await hass.async_add_executor_job(data.get_alarm)
async_add_devices(alarm_devices)
async_add_entities([LupusecAlarm(data, alarm, config_entry.entry_id)])
class LupusecAlarm(LupusecDevice, AlarmControlPanelEntity):

View File

@ -2,6 +2,7 @@
from __future__ import annotations
from datetime import timedelta
from functools import partial
import logging
import lupupy.constants as CONST
@ -25,7 +26,7 @@ _LOGGER = logging.getLogger(__name__)
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_devices: AddEntitiesCallback,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up a binary sensors for a Lupusec device."""
@ -34,10 +35,12 @@ async def async_setup_entry(
device_types = CONST.TYPE_OPENING + CONST.TYPE_SENSOR
sensors = []
for device in data.get_devices(generic_type=device_types):
partial_func = partial(data.get_devices, generic_type=device_types)
devices = await hass.async_add_executor_job(partial_func)
for device in devices:
sensors.append(LupusecBinarySensor(device, config_entry.entry_id))
async_add_devices(sensors)
async_add_entities(sensors)
class LupusecBinarySensor(LupusecBaseSensor, BinarySensorEntity):

View File

@ -1,5 +1,6 @@
""""Config flow for Lupusec integration."""
from json import JSONDecodeError
import logging
from typing import Any
@ -50,6 +51,8 @@ class LupusecConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
await test_host_connection(self.hass, host, username, password)
except CannotConnect:
errors["base"] = "cannot_connect"
except JSONDecodeError:
errors["base"] = "cannot_connect"
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unexpected exception")
errors["base"] = "unknown"
@ -80,6 +83,8 @@ class LupusecConfigFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
await test_host_connection(self.hass, host, username, password)
except CannotConnect:
return self.async_abort(reason="cannot_connect")
except JSONDecodeError:
return self.async_abort(reason="cannot_connect")
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unexpected exception")
return self.async_abort(reason="unknown")

View File

@ -21,7 +21,7 @@
"issues": {
"deprecated_yaml_import_issue_cannot_connect": {
"title": "The Lupus Electronics LUPUSEC YAML configuration import failed",
"description": "Configuring Lupus Electronics LUPUSEC using YAML is being removed but there was an connection error importing your YAML configuration.\n\nEnsure connection to Lupus Electronics LUPUSEC works and restart Home Assistant to try again or remove the Lupus Electronics LUPUSEC YAML configuration from your configuration.yaml file and continue to [set up the integration]({url}) manually."
"description": "Configuring Lupus Electronics LUPUSEC using YAML is being removed but there was a connection error importing your YAML configuration.\n\nEnsure connection to Lupus Electronics LUPUSEC works and restart Home Assistant to try again or remove the Lupus Electronics LUPUSEC YAML configuration from your configuration.yaml file and continue to [set up the integration]({url}) manually."
},
"deprecated_yaml_import_issue_unknown": {
"title": "The Lupus Electronics LUPUSEC YAML configuration import failed",

View File

@ -2,6 +2,7 @@
from __future__ import annotations
from datetime import timedelta
from functools import partial
from typing import Any
import lupupy.constants as CONST
@ -20,7 +21,7 @@ SCAN_INTERVAL = timedelta(seconds=2)
async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_devices: AddEntitiesCallback,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up Lupusec switch devices."""
@ -29,10 +30,12 @@ async def async_setup_entry(
device_types = CONST.TYPE_SWITCH
switches = []
for device in data.get_devices(generic_type=device_types):
partial_func = partial(data.get_devices, generic_type=device_types)
devices = await hass.async_add_executor_job(partial_func)
for device in devices:
switches.append(LupusecSwitch(device, config_entry.entry_id))
async_add_devices(switches)
async_add_entities(switches)
class LupusecSwitch(LupusecBaseSensor, SwitchEntity):

View File

@ -1,5 +1,6 @@
""""Unit tests for the Lupusec config flow."""
from json import JSONDecodeError
from unittest.mock import patch
from lupupy import LupusecException
@ -51,8 +52,7 @@ async def test_form_valid_input(hass: HomeAssistant) -> None:
"homeassistant.components.lupusec.async_setup_entry",
return_value=True,
) as mock_setup_entry, patch(
"homeassistant.components.lupusec.config_flow.lupupy.Lupusec.__init__",
return_value=None,
"homeassistant.components.lupusec.config_flow.lupupy.Lupusec",
) as mock_initialize_lupusec:
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
@ -71,6 +71,7 @@ async def test_form_valid_input(hass: HomeAssistant) -> None:
("raise_error", "text_error"),
[
(LupusecException("Test lupusec exception"), "cannot_connect"),
(JSONDecodeError("Test JSONDecodeError", "test", 1), "cannot_connect"),
(Exception("Test unknown exception"), "unknown"),
],
)
@ -85,7 +86,7 @@ async def test_flow_user_init_data_error_and_recover(
assert result["errors"] == {}
with patch(
"homeassistant.components.lupusec.config_flow.lupupy.Lupusec.__init__",
"homeassistant.components.lupusec.config_flow.lupupy.Lupusec",
side_effect=raise_error,
) as mock_initialize_lupusec:
result2 = await hass.config_entries.flow.async_configure(
@ -104,8 +105,7 @@ async def test_flow_user_init_data_error_and_recover(
"homeassistant.components.lupusec.async_setup_entry",
return_value=True,
) as mock_setup_entry, patch(
"homeassistant.components.lupusec.config_flow.lupupy.Lupusec.__init__",
return_value=None,
"homeassistant.components.lupusec.config_flow.lupupy.Lupusec",
) as mock_initialize_lupusec:
result3 = await hass.config_entries.flow.async_configure(
result["flow_id"],
@ -164,8 +164,7 @@ async def test_flow_source_import(
"homeassistant.components.lupusec.async_setup_entry",
return_value=True,
) as mock_setup_entry, patch(
"homeassistant.components.lupusec.config_flow.lupupy.Lupusec.__init__",
return_value=None,
"homeassistant.components.lupusec.config_flow.lupupy.Lupusec",
) as mock_initialize_lupusec:
result = await hass.config_entries.flow.async_init(
DOMAIN,
@ -186,6 +185,7 @@ async def test_flow_source_import(
("raise_error", "text_error"),
[
(LupusecException("Test lupusec exception"), "cannot_connect"),
(JSONDecodeError("Test JSONDecodeError", "test", 1), "cannot_connect"),
(Exception("Test unknown exception"), "unknown"),
],
)
@ -195,7 +195,7 @@ async def test_flow_source_import_error_and_recover(
"""Test exceptions and recovery."""
with patch(
"homeassistant.components.lupusec.config_flow.lupupy.Lupusec.__init__",
"homeassistant.components.lupusec.config_flow.lupupy.Lupusec",
side_effect=raise_error,
) as mock_initialize_lupusec:
result = await hass.config_entries.flow.async_init(