From 4a37ff2ddacd85c5b60bb826da5f5f41fff1de0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20S=C3=B8rensen?= Date: Thu, 5 Aug 2021 12:13:47 +0200 Subject: [PATCH] Bump pyuptimerobot to 21.8.1 (#53995) * Bump pyuptimerobot to 21.08.0 * pylint * bump to 21.8.1 * Uppdate strings * Update homeassistant/components/uptimerobot/strings.json Co-authored-by: Martin Hjelmare Co-authored-by: Martin Hjelmare --- .../components/uptimerobot/__init__.py | 41 ++++++++----------- .../components/uptimerobot/binary_sensor.py | 2 +- .../components/uptimerobot/config_flow.py | 35 ++++++++-------- homeassistant/components/uptimerobot/const.py | 36 ---------------- .../components/uptimerobot/entity.py | 11 +++-- .../components/uptimerobot/manifest.json | 2 +- .../components/uptimerobot/strings.json | 4 +- .../uptimerobot/translations/en.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- .../uptimerobot/test_config_flow.py | 38 ++++++++++------- 11 files changed, 73 insertions(+), 102 deletions(-) diff --git a/homeassistant/components/uptimerobot/__init__.py b/homeassistant/components/uptimerobot/__init__.py index b4d606ca637..17bc8f9a629 100644 --- a/homeassistant/components/uptimerobot/__init__.py +++ b/homeassistant/components/uptimerobot/__init__.py @@ -1,44 +1,35 @@ """The Uptime Robot integration.""" from __future__ import annotations -import async_timeout -from pyuptimerobot import UptimeRobot +from pyuptimerobot import UptimeRobot, UptimeRobotException, UptimeRobotMonitor from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_API_KEY from homeassistant.core import HomeAssistant +from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed -from .const import ( - API_ATTR_MONITORS, - API_ATTR_OK, - API_ATTR_STAT, - CONNECTION_ERROR, - COORDINATOR_UPDATE_INTERVAL, - DOMAIN, - LOGGER, - PLATFORMS, - MonitorData, -) +from .const import API_ATTR_OK, COORDINATOR_UPDATE_INTERVAL, DOMAIN, LOGGER, PLATFORMS async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up Uptime Robot from a config entry.""" hass.data.setdefault(DOMAIN, {}) - uptime_robot_api = UptimeRobot() + uptime_robot_api = UptimeRobot( + entry.data[CONF_API_KEY], async_get_clientsession(hass) + ) - async def async_update_data() -> list[MonitorData]: + async def async_update_data() -> list[UptimeRobotMonitor]: """Fetch data from API UptimeRobot API.""" - async with async_timeout.timeout(10): - monitors = await hass.async_add_executor_job( - uptime_robot_api.getMonitors, entry.data[CONF_API_KEY] - ) - if not monitors or monitors.get(API_ATTR_STAT) != API_ATTR_OK: - raise UpdateFailed(CONNECTION_ERROR) - return [ - MonitorData.from_dict(monitor) - for monitor in monitors.get(API_ATTR_MONITORS, []) - ] + try: + response = await uptime_robot_api.async_get_monitors() + except UptimeRobotException as exception: + raise UpdateFailed(exception) from exception + else: + if response.status == API_ATTR_OK: + monitors: list[UptimeRobotMonitor] = response.data + return monitors + raise UpdateFailed(response.error.message) hass.data[DOMAIN][entry.entry_id] = coordinator = DataUpdateCoordinator( hass, diff --git a/homeassistant/components/uptimerobot/binary_sensor.py b/homeassistant/components/uptimerobot/binary_sensor.py index 69daeaea7c8..f99689f2507 100644 --- a/homeassistant/components/uptimerobot/binary_sensor.py +++ b/homeassistant/components/uptimerobot/binary_sensor.py @@ -50,7 +50,7 @@ async def async_setup_entry( coordinator, BinarySensorEntityDescription( key=str(monitor.id), - name=monitor.name, + name=monitor.friendly_name, device_class=DEVICE_CLASS_CONNECTIVITY, ), target=monitor.url, diff --git a/homeassistant/components/uptimerobot/config_flow.py b/homeassistant/components/uptimerobot/config_flow.py index ad0d382061a..6bdd8a6e39c 100644 --- a/homeassistant/components/uptimerobot/config_flow.py +++ b/homeassistant/components/uptimerobot/config_flow.py @@ -1,7 +1,7 @@ """Config flow for Uptime Robot integration.""" from __future__ import annotations -from pyuptimerobot import UptimeRobot +from pyuptimerobot import UptimeRobot, UptimeRobotAccount, UptimeRobotException import voluptuous as vol from homeassistant import config_entries @@ -9,24 +9,26 @@ from homeassistant.const import CONF_API_KEY from homeassistant.core import HomeAssistant from homeassistant.data_entry_flow import FlowResult from homeassistant.exceptions import HomeAssistantError +from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.typing import ConfigType -from .const import API_ATTR_OK, API_ATTR_STAT, DOMAIN, LOGGER +from .const import API_ATTR_OK, DOMAIN, LOGGER STEP_USER_DATA_SCHEMA = vol.Schema({vol.Required(CONF_API_KEY): str}) -async def validate_input(hass: HomeAssistant, data: ConfigType) -> None: +async def validate_input(hass: HomeAssistant, data: ConfigType) -> UptimeRobotAccount: """Validate the user input allows us to connect.""" + uptime_robot_api = UptimeRobot(data[CONF_API_KEY], async_get_clientsession(hass)) - uptime_robot_api = UptimeRobot() - - monitors = await hass.async_add_executor_job( - uptime_robot_api.getMonitors, data[CONF_API_KEY] - ) - - if not monitors or monitors.get(API_ATTR_STAT) != API_ATTR_OK: - raise CannotConnect("Error communicating with Uptime Robot API") + try: + response = await uptime_robot_api.async_get_account_details() + except UptimeRobotException as exception: + raise CannotConnect(exception) from exception + else: + if response.status == API_ATTR_OK: + return response.data + raise CannotConnect(response.error.message) class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): @@ -43,14 +45,14 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): ) try: - await validate_input(self.hass, user_input) + account = await validate_input(self.hass, user_input) except CannotConnect: errors["base"] = "cannot_connect" except Exception: # pylint: disable=broad-except LOGGER.exception("Unexpected exception") errors["base"] = "unknown" else: - return self.async_create_entry(title="", data=user_input) + return self.async_create_entry(title=account.email, data=user_input) return self.async_show_form( step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors @@ -65,9 +67,10 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): ) return self.async_abort(reason="already_configured") - return self.async_create_entry( - title="", data={CONF_API_KEY: import_config[CONF_API_KEY]} - ) + imported_config = {CONF_API_KEY: import_config[CONF_API_KEY]} + + account = await validate_input(self.hass, imported_config) + return self.async_create_entry(title=account.email, data=imported_config) class CannotConnect(HomeAssistantError): diff --git a/homeassistant/components/uptimerobot/const.py b/homeassistant/components/uptimerobot/const.py index f0bc0699290..ee9832a040a 100644 --- a/homeassistant/components/uptimerobot/const.py +++ b/homeassistant/components/uptimerobot/const.py @@ -1,9 +1,7 @@ """Constants for the Uptime Robot integration.""" from __future__ import annotations -from dataclasses import dataclass from datetime import timedelta -from enum import Enum from logging import Logger, getLogger from typing import Final @@ -14,42 +12,8 @@ COORDINATOR_UPDATE_INTERVAL: timedelta = timedelta(seconds=60) DOMAIN: Final = "uptimerobot" PLATFORMS: Final = ["binary_sensor"] -CONNECTION_ERROR: Final = "Error connecting to the Uptime Robot API" - ATTRIBUTION: Final = "Data provided by Uptime Robot" ATTR_TARGET: Final = "target" -API_ATTR_STAT: Final = "stat" API_ATTR_OK: Final = "ok" -API_ATTR_MONITORS: Final = "monitors" - - -class MonitorType(Enum): - """Monitors type.""" - - HTTP = 1 - keyword = 2 - ping = 3 - - -@dataclass -class MonitorData: - """Dataclass for monitors.""" - - id: int - status: int - url: str - name: str - type: MonitorType - - @staticmethod - def from_dict(monitor: dict) -> MonitorData: - """Create a new monitor from a dict.""" - return MonitorData( - id=monitor["id"], - status=monitor["status"], - url=monitor["url"], - name=monitor["friendly_name"], - type=MonitorType(monitor["type"]), - ) diff --git a/homeassistant/components/uptimerobot/entity.py b/homeassistant/components/uptimerobot/entity.py index ed9d6b2a2f9..4b4847dfc7c 100644 --- a/homeassistant/components/uptimerobot/entity.py +++ b/homeassistant/components/uptimerobot/entity.py @@ -1,6 +1,8 @@ """Base UptimeRobot entity.""" from __future__ import annotations +from pyuptimerobot import UptimeRobotMonitor + from homeassistant.const import ATTR_ATTRIBUTION from homeassistant.helpers.entity import DeviceInfo, EntityDescription from homeassistant.helpers.update_coordinator import ( @@ -8,7 +10,7 @@ from homeassistant.helpers.update_coordinator import ( DataUpdateCoordinator, ) -from .const import ATTR_TARGET, ATTRIBUTION, DOMAIN, MonitorData +from .const import ATTR_TARGET, ATTRIBUTION, DOMAIN class UptimeRobotEntity(CoordinatorEntity): @@ -48,12 +50,12 @@ class UptimeRobotEntity(CoordinatorEntity): return {} @property - def monitors(self) -> list[MonitorData]: + def monitors(self) -> list[UptimeRobotMonitor]: """Return all monitors.""" return self.coordinator.data or [] @property - def monitor(self) -> MonitorData | None: + def monitor(self) -> UptimeRobotMonitor | None: """Return the monitor for this entity.""" return next( ( @@ -67,7 +69,8 @@ class UptimeRobotEntity(CoordinatorEntity): @property def monitor_available(self) -> bool: """Returtn if the monitor is available.""" - return self.monitor.status == 2 if self.monitor else False + status: bool = self.monitor.status == 2 if self.monitor else False + return status @property def available(self) -> bool: diff --git a/homeassistant/components/uptimerobot/manifest.json b/homeassistant/components/uptimerobot/manifest.json index c0f880facb1..9c91b32bdfd 100644 --- a/homeassistant/components/uptimerobot/manifest.json +++ b/homeassistant/components/uptimerobot/manifest.json @@ -3,7 +3,7 @@ "name": "Uptime Robot", "documentation": "https://www.home-assistant.io/integrations/uptimerobot", "requirements": [ - "pyuptimerobot==0.0.5" + "pyuptimerobot==21.8.1" ], "codeowners": [ "@ludeeus" diff --git a/homeassistant/components/uptimerobot/strings.json b/homeassistant/components/uptimerobot/strings.json index 817d79e57cc..bae1e54c2b6 100644 --- a/homeassistant/components/uptimerobot/strings.json +++ b/homeassistant/components/uptimerobot/strings.json @@ -12,7 +12,7 @@ "unknown": "[%key:common::config_flow::error::unknown%]" }, "abort": { - "already_configured": "[%key:common::config_flow::abort::already_configured_device%]" + "already_configured": "[%key:common::config_flow::abort::already_configured_account%]" } } -} \ No newline at end of file +} diff --git a/homeassistant/components/uptimerobot/translations/en.json b/homeassistant/components/uptimerobot/translations/en.json index 72433ab86c3..7e35d8e9531 100644 --- a/homeassistant/components/uptimerobot/translations/en.json +++ b/homeassistant/components/uptimerobot/translations/en.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "already_configured": "Device is already configured" + "already_configured": "Account already configured" }, "error": { "cannot_connect": "Failed to connect", diff --git a/requirements_all.txt b/requirements_all.txt index f88d8f5e7ae..1bf4ed9b063 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1948,7 +1948,7 @@ pytradfri[async]==7.0.6 pytrafikverket==0.1.6.2 # homeassistant.components.uptimerobot -pyuptimerobot==0.0.5 +pyuptimerobot==21.8.1 # homeassistant.components.keyboard # pyuserinput==0.1.11 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index a05331a0231..7d72f300d4e 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1077,7 +1077,7 @@ pytraccar==0.9.0 pytradfri[async]==7.0.6 # homeassistant.components.uptimerobot -pyuptimerobot==0.0.5 +pyuptimerobot==21.8.1 # homeassistant.components.vera pyvera==0.3.13 diff --git a/tests/components/uptimerobot/test_config_flow.py b/tests/components/uptimerobot/test_config_flow.py index 2c918204838..0da20086cc4 100644 --- a/tests/components/uptimerobot/test_config_flow.py +++ b/tests/components/uptimerobot/test_config_flow.py @@ -1,13 +1,10 @@ """Test the Uptime Robot config flow.""" from unittest.mock import patch +from pyuptimerobot import UptimeRobotApiResponse + from homeassistant import config_entries, setup -from homeassistant.components.uptimerobot.const import ( - API_ATTR_MONITORS, - API_ATTR_OK, - API_ATTR_STAT, - DOMAIN, -) +from homeassistant.components.uptimerobot.const import DOMAIN from homeassistant.core import HomeAssistant from homeassistant.data_entry_flow import ( RESULT_TYPE_ABORT, @@ -26,8 +23,13 @@ async def test_form(hass: HomeAssistant) -> None: assert result["errors"] == {} with patch( - "pyuptimerobot.UptimeRobot.getMonitors", - return_value={API_ATTR_STAT: API_ATTR_OK, API_ATTR_MONITORS: []}, + "pyuptimerobot.UptimeRobot.async_get_account_details", + return_value=UptimeRobotApiResponse.from_dict( + { + "stat": "ok", + "account": {"email": "test@test.test"}, + } + ), ), patch( "homeassistant.components.uptimerobot.async_setup_entry", return_value=True, @@ -39,7 +41,7 @@ async def test_form(hass: HomeAssistant) -> None: await hass.async_block_till_done() assert result2["type"] == RESULT_TYPE_CREATE_ENTRY - assert result2["title"] == "" + assert result2["title"] == "test@test.test" assert result2["data"] == {"api_key": "1234"} assert len(mock_setup_entry.mock_calls) == 1 @@ -50,7 +52,10 @@ async def test_form_cannot_connect(hass: HomeAssistant) -> None: DOMAIN, context={"source": config_entries.SOURCE_USER} ) - with patch("pyuptimerobot.UptimeRobot.getMonitors", return_value=None): + with patch( + "pyuptimerobot.UptimeRobot.async_get_account_details", + return_value=UptimeRobotApiResponse.from_dict({"stat": "fail", "error": {}}), + ): result2 = await hass.config_entries.flow.async_configure( result["flow_id"], {"api_key": "1234"}, @@ -63,8 +68,13 @@ async def test_form_cannot_connect(hass: HomeAssistant) -> None: async def test_flow_import(hass): """Test an import flow.""" with patch( - "pyuptimerobot.UptimeRobot.getMonitors", - return_value={API_ATTR_STAT: API_ATTR_OK, API_ATTR_MONITORS: []}, + "pyuptimerobot.UptimeRobot.async_get_account_details", + return_value=UptimeRobotApiResponse.from_dict( + { + "stat": "ok", + "account": {"email": "test@test.test"}, + } + ), ), patch( "homeassistant.components.uptimerobot.async_setup_entry", return_value=True, @@ -81,8 +91,8 @@ async def test_flow_import(hass): assert result["data"] == {"api_key": "1234"} with patch( - "pyuptimerobot.UptimeRobot.getMonitors", - return_value={API_ATTR_STAT: API_ATTR_OK, API_ATTR_MONITORS: []}, + "pyuptimerobot.UptimeRobot.async_get_account_details", + return_value=UptimeRobotApiResponse.from_dict({"stat": "ok", "monitors": []}), ), patch( "homeassistant.components.uptimerobot.async_setup_entry", return_value=True,