From 655e2f92ba8f7cfab3dd13b8676d9fcafd82ba1e Mon Sep 17 00:00:00 2001 From: Rami Mosleh Date: Fri, 19 Aug 2022 11:39:14 +0300 Subject: [PATCH] Add strict typing to mikrotik (#76974) add strict typing to mikrotik --- .strict-typing | 1 + homeassistant/components/mikrotik/__init__.py | 7 +- homeassistant/components/mikrotik/const.py | 3 - homeassistant/components/mikrotik/device.py | 66 ++++++++++++++++++ .../components/mikrotik/device_tracker.py | 2 +- homeassistant/components/mikrotik/hub.py | 67 ++----------------- mypy.ini | 10 +++ 7 files changed, 88 insertions(+), 68 deletions(-) create mode 100644 homeassistant/components/mikrotik/device.py diff --git a/.strict-typing b/.strict-typing index f8a0579433b..a215c2187ab 100644 --- a/.strict-typing +++ b/.strict-typing @@ -170,6 +170,7 @@ homeassistant.components.mailbox.* homeassistant.components.media_player.* homeassistant.components.media_source.* homeassistant.components.metoffice.* +homeassistant.components.mikrotik.* homeassistant.components.mjpeg.* homeassistant.components.modbus.* homeassistant.components.modem_callerid.* diff --git a/homeassistant/components/mikrotik/__init__.py b/homeassistant/components/mikrotik/__init__.py index f72c79c1559..6a158c60fcf 100644 --- a/homeassistant/components/mikrotik/__init__.py +++ b/homeassistant/components/mikrotik/__init__.py @@ -1,15 +1,18 @@ """The Mikrotik component.""" from homeassistant.config_entries import ConfigEntry +from homeassistant.const import Platform from homeassistant.core import HomeAssistant from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import config_validation as cv, device_registry as dr -from .const import ATTR_MANUFACTURER, DOMAIN, PLATFORMS +from .const import ATTR_MANUFACTURER, DOMAIN from .errors import CannotConnect, LoginError from .hub import MikrotikDataUpdateCoordinator, get_api CONFIG_SCHEMA = cv.removed(DOMAIN, raise_if_present=False) +PLATFORMS = [Platform.DEVICE_TRACKER] + async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool: """Set up the Mikrotik component.""" @@ -26,7 +29,7 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b hass.data.setdefault(DOMAIN, {})[config_entry.entry_id] = coordinator - hass.config_entries.async_setup_platforms(config_entry, PLATFORMS) + await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS) device_registry = dr.async_get(hass) device_registry.async_get_or_create( diff --git a/homeassistant/components/mikrotik/const.py b/homeassistant/components/mikrotik/const.py index bbe129c4a00..911d348365e 100644 --- a/homeassistant/components/mikrotik/const.py +++ b/homeassistant/components/mikrotik/const.py @@ -1,8 +1,6 @@ """Constants used in the Mikrotik components.""" from typing import Final -from homeassistant.const import Platform - DOMAIN: Final = "mikrotik" DEFAULT_NAME: Final = "Mikrotik" DEFAULT_API_PORT: Final = 8728 @@ -40,7 +38,6 @@ MIKROTIK_SERVICES: Final = { IS_CAPSMAN: "/caps-man/interface/print", } -PLATFORMS: Final = [Platform.DEVICE_TRACKER] ATTR_DEVICE_TRACKER: Final = [ "comment", diff --git a/homeassistant/components/mikrotik/device.py b/homeassistant/components/mikrotik/device.py new file mode 100644 index 00000000000..f37ef6fee80 --- /dev/null +++ b/homeassistant/components/mikrotik/device.py @@ -0,0 +1,66 @@ +"""Network client device class.""" + +from __future__ import annotations + +from datetime import datetime +from typing import Any + +from homeassistant.util import slugify +import homeassistant.util.dt as dt_util + +from .const import ATTR_DEVICE_TRACKER + + +class Device: + """Represents a network device.""" + + def __init__(self, mac: str, params: dict[str, Any]) -> None: + """Initialize the network device.""" + self._mac = mac + self._params = params + self._last_seen: datetime | None = None + self._attrs: dict[str, Any] = {} + self._wireless_params: dict[str, Any] = {} + + @property + def name(self) -> str: + """Return device name.""" + return self._params.get("host-name", self.mac) + + @property + def ip_address(self) -> str | None: + """Return device primary ip address.""" + return self._params.get("address") + + @property + def mac(self) -> str: + """Return device mac.""" + return self._mac + + @property + def last_seen(self) -> datetime | None: + """Return device last seen.""" + return self._last_seen + + @property + def attrs(self) -> dict[str, Any]: + """Return device attributes.""" + attr_data = self._wireless_params | self._params + for attr in ATTR_DEVICE_TRACKER: + if attr in attr_data: + self._attrs[slugify(attr)] = attr_data[attr] + return self._attrs + + def update( + self, + wireless_params: dict[str, Any] | None = None, + params: dict[str, Any] | None = None, + active: bool = False, + ) -> None: + """Update Device params.""" + if wireless_params: + self._wireless_params = wireless_params + if params: + self._params = params + if active: + self._last_seen = dt_util.utcnow() diff --git a/homeassistant/components/mikrotik/device_tracker.py b/homeassistant/components/mikrotik/device_tracker.py index 856521f019d..f50c49d5ab6 100644 --- a/homeassistant/components/mikrotik/device_tracker.py +++ b/homeassistant/components/mikrotik/device_tracker.py @@ -63,7 +63,7 @@ def update_items( coordinator: MikrotikDataUpdateCoordinator, async_add_entities: AddEntitiesCallback, tracked: dict[str, MikrotikDataUpdateCoordinatorTracker], -): +) -> None: """Update tracked device state from the hub.""" new_tracked: list[MikrotikDataUpdateCoordinatorTracker] = [] for mac, device in coordinator.api.devices.items(): diff --git a/homeassistant/components/mikrotik/hub.py b/homeassistant/components/mikrotik/hub.py index 914911ee5cc..08320c603f9 100644 --- a/homeassistant/components/mikrotik/hub.py +++ b/homeassistant/components/mikrotik/hub.py @@ -1,7 +1,7 @@ """The Mikrotik router class.""" from __future__ import annotations -from datetime import datetime, timedelta +from datetime import timedelta import logging import socket import ssl @@ -14,12 +14,9 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME, CONF_VERIFY_SSL from homeassistant.core import HomeAssistant from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed -from homeassistant.util import slugify -import homeassistant.util.dt as dt_util from .const import ( ARP, - ATTR_DEVICE_TRACKER, ATTR_FIRMWARE, ATTR_MODEL, ATTR_SERIAL_NUMBER, @@ -38,66 +35,12 @@ from .const import ( NAME, WIRELESS, ) +from .device import Device from .errors import CannotConnect, LoginError _LOGGER = logging.getLogger(__name__) -class Device: - """Represents a network device.""" - - def __init__(self, mac: str, params: dict[str, Any]) -> None: - """Initialize the network device.""" - self._mac = mac - self._params = params - self._last_seen: datetime | None = None - self._attrs: dict[str, Any] = {} - self._wireless_params: dict[str, Any] = {} - - @property - def name(self) -> str: - """Return device name.""" - return self._params.get("host-name", self.mac) - - @property - def ip_address(self) -> str | None: - """Return device primary ip address.""" - return self._params.get("address") - - @property - def mac(self) -> str: - """Return device mac.""" - return self._mac - - @property - def last_seen(self) -> datetime | None: - """Return device last seen.""" - return self._last_seen - - @property - def attrs(self) -> dict[str, Any]: - """Return device attributes.""" - attr_data = self._wireless_params | self._params - for attr in ATTR_DEVICE_TRACKER: - if attr in attr_data: - self._attrs[slugify(attr)] = attr_data[attr] - return self._attrs - - def update( - self, - wireless_params: dict[str, Any] | None = None, - params: dict[str, Any] | None = None, - active: bool = False, - ) -> None: - """Update Device params.""" - if wireless_params: - self._wireless_params = wireless_params - if params: - self._params = params - if active: - self._last_seen = dt_util.utcnow() - - class MikrotikData: """Handle all communication with the Mikrotik API.""" @@ -248,8 +191,8 @@ class MikrotikData: self, cmd: str, params: dict[str, Any] | None = None ) -> list[dict[str, Any]]: """Retrieve data from Mikrotik API.""" + _LOGGER.debug("Running command %s", cmd) try: - _LOGGER.debug("Running command %s", cmd) if params: return list(self.api(cmd=cmd, **params)) return list(self.api(cmd=cmd)) @@ -273,7 +216,7 @@ class MikrotikData: return [] -class MikrotikDataUpdateCoordinator(DataUpdateCoordinator): +class MikrotikDataUpdateCoordinator(DataUpdateCoordinator[None]): """Mikrotik Hub Object.""" def __init__( @@ -293,7 +236,7 @@ class MikrotikDataUpdateCoordinator(DataUpdateCoordinator): @property def host(self) -> str: """Return the host of this hub.""" - return self.config_entry.data[CONF_HOST] + return str(self.config_entry.data[CONF_HOST]) @property def hostname(self) -> str: diff --git a/mypy.ini b/mypy.ini index 051c1065423..fd609d8099b 100644 --- a/mypy.ini +++ b/mypy.ini @@ -1459,6 +1459,16 @@ disallow_untyped_defs = true warn_return_any = true warn_unreachable = true +[mypy-homeassistant.components.mikrotik.*] +check_untyped_defs = true +disallow_incomplete_defs = true +disallow_subclassing_any = true +disallow_untyped_calls = true +disallow_untyped_decorators = true +disallow_untyped_defs = true +warn_return_any = true +warn_unreachable = true + [mypy-homeassistant.components.mjpeg.*] check_untyped_defs = true disallow_incomplete_defs = true