Complete typing on AdGuard Home integration (#47477)
parent
d944bbbc52
commit
b01a6367cc
|
@ -1,6 +1,8 @@
|
|||
"""Support for AdGuard Home."""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Any, Dict
|
||||
from typing import Any
|
||||
|
||||
from adguardhome import AdGuardHome, AdGuardHomeConnectionError, AdGuardHomeError
|
||||
import voluptuous as vol
|
||||
|
@ -117,7 +119,7 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool
|
|||
return True
|
||||
|
||||
|
||||
async def async_unload_entry(hass: HomeAssistantType, entry: ConfigType) -> bool:
|
||||
async def async_unload_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool:
|
||||
"""Unload AdGuard Home config entry."""
|
||||
hass.services.async_remove(DOMAIN, SERVICE_ADD_URL)
|
||||
hass.services.async_remove(DOMAIN, SERVICE_REMOVE_URL)
|
||||
|
@ -191,7 +193,7 @@ class AdGuardHomeDeviceEntity(AdGuardHomeEntity):
|
|||
"""Defines a AdGuard Home device entity."""
|
||||
|
||||
@property
|
||||
def device_info(self) -> Dict[str, Any]:
|
||||
def device_info(self) -> dict[str, Any]:
|
||||
"""Return device information about this AdGuard Home instance."""
|
||||
return {
|
||||
"identifiers": {
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
"""Config flow to configure the AdGuard Home integration."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from adguardhome import AdGuardHome, AdGuardHomeConnectionError
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components.adguard.const import DOMAIN
|
||||
from homeassistant.config_entries import ConfigFlow
|
||||
from homeassistant.const import (
|
||||
CONF_HOST,
|
||||
|
@ -15,9 +18,10 @@ from homeassistant.const import (
|
|||
)
|
||||
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
||||
|
||||
from .const import DOMAIN # pylint: disable=unused-import
|
||||
|
||||
@config_entries.HANDLERS.register(DOMAIN)
|
||||
class AdGuardHomeFlowHandler(ConfigFlow):
|
||||
|
||||
class AdGuardHomeFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||
"""Handle a AdGuard Home config flow."""
|
||||
|
||||
VERSION = 1
|
||||
|
@ -25,7 +29,9 @@ class AdGuardHomeFlowHandler(ConfigFlow):
|
|||
|
||||
_hassio_discovery = None
|
||||
|
||||
async def _show_setup_form(self, errors=None):
|
||||
async def _show_setup_form(
|
||||
self, errors: dict[str, str] | None = None
|
||||
) -> dict[str, Any]:
|
||||
"""Show the setup form to the user."""
|
||||
return self.async_show_form(
|
||||
step_id="user",
|
||||
|
@ -42,7 +48,9 @@ class AdGuardHomeFlowHandler(ConfigFlow):
|
|||
errors=errors or {},
|
||||
)
|
||||
|
||||
async def _show_hassio_form(self, errors=None):
|
||||
async def _show_hassio_form(
|
||||
self, errors: dict[str, str] | None = None
|
||||
) -> dict[str, Any]:
|
||||
"""Show the Hass.io confirmation form to the user."""
|
||||
return self.async_show_form(
|
||||
step_id="hassio_confirm",
|
||||
|
@ -51,7 +59,9 @@ class AdGuardHomeFlowHandler(ConfigFlow):
|
|||
errors=errors or {},
|
||||
)
|
||||
|
||||
async def async_step_user(self, user_input=None):
|
||||
async def async_step_user(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> dict[str, Any]:
|
||||
"""Handle a flow initiated by the user."""
|
||||
if self._async_current_entries():
|
||||
return self.async_abort(reason="single_instance_allowed")
|
||||
|
@ -91,7 +101,7 @@ class AdGuardHomeFlowHandler(ConfigFlow):
|
|||
},
|
||||
)
|
||||
|
||||
async def async_step_hassio(self, discovery_info):
|
||||
async def async_step_hassio(self, discovery_info: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Prepare configuration for a Hass.io AdGuard Home add-on.
|
||||
|
||||
This flow is triggered by the discovery component.
|
||||
|
@ -129,7 +139,9 @@ class AdGuardHomeFlowHandler(ConfigFlow):
|
|||
|
||||
return self.async_abort(reason="existing_instance_updated")
|
||||
|
||||
async def async_step_hassio_confirm(self, user_input=None):
|
||||
async def async_step_hassio_confirm(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> dict[str, Any]:
|
||||
"""Confirm Hass.io discovery."""
|
||||
if user_input is None:
|
||||
return await self._show_hassio_form()
|
||||
|
|
|
@ -1,25 +1,28 @@
|
|||
"""Support for AdGuard Home sensors."""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import timedelta
|
||||
from typing import Callable
|
||||
|
||||
from adguardhome import AdGuardHomeConnectionError
|
||||
from adguardhome import AdGuardHome, AdGuardHomeConnectionError
|
||||
|
||||
from homeassistant.components.adguard import AdGuardHomeDeviceEntity
|
||||
from homeassistant.components.adguard.const import (
|
||||
DATA_ADGUARD_CLIENT,
|
||||
DATA_ADGUARD_VERION,
|
||||
DOMAIN,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import PERCENTAGE, TIME_MILLISECONDS
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import PlatformNotReady
|
||||
from homeassistant.helpers.typing import HomeAssistantType
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
from . import AdGuardHomeDeviceEntity
|
||||
from .const import DATA_ADGUARD_CLIENT, DATA_ADGUARD_VERION, DOMAIN
|
||||
|
||||
SCAN_INTERVAL = timedelta(seconds=300)
|
||||
PARALLEL_UPDATES = 4
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistantType, entry: ConfigEntry, async_add_entities
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
async_add_entities: Callable[[list[Entity], bool], None],
|
||||
) -> None:
|
||||
"""Set up AdGuard Home sensor based on a config entry."""
|
||||
adguard = hass.data[DOMAIN][DATA_ADGUARD_CLIENT]
|
||||
|
@ -50,7 +53,7 @@ class AdGuardHomeSensor(AdGuardHomeDeviceEntity):
|
|||
|
||||
def __init__(
|
||||
self,
|
||||
adguard,
|
||||
adguard: AdGuardHome,
|
||||
name: str,
|
||||
icon: str,
|
||||
measurement: str,
|
||||
|
@ -78,12 +81,12 @@ class AdGuardHomeSensor(AdGuardHomeDeviceEntity):
|
|||
)
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
def state(self) -> str | None:
|
||||
"""Return the state of the sensor."""
|
||||
return self._state
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self) -> str:
|
||||
def unit_of_measurement(self) -> str | None:
|
||||
"""Return the unit this state is expressed in."""
|
||||
return self._unit_of_measurement
|
||||
|
||||
|
@ -91,7 +94,7 @@ class AdGuardHomeSensor(AdGuardHomeDeviceEntity):
|
|||
class AdGuardHomeDNSQueriesSensor(AdGuardHomeSensor):
|
||||
"""Defines a AdGuard Home DNS Queries sensor."""
|
||||
|
||||
def __init__(self, adguard):
|
||||
def __init__(self, adguard: AdGuardHome) -> None:
|
||||
"""Initialize AdGuard Home sensor."""
|
||||
super().__init__(
|
||||
adguard, "AdGuard DNS Queries", "mdi:magnify", "dns_queries", "queries"
|
||||
|
@ -105,7 +108,7 @@ class AdGuardHomeDNSQueriesSensor(AdGuardHomeSensor):
|
|||
class AdGuardHomeBlockedFilteringSensor(AdGuardHomeSensor):
|
||||
"""Defines a AdGuard Home blocked by filtering sensor."""
|
||||
|
||||
def __init__(self, adguard):
|
||||
def __init__(self, adguard: AdGuardHome) -> None:
|
||||
"""Initialize AdGuard Home sensor."""
|
||||
super().__init__(
|
||||
adguard,
|
||||
|
@ -124,7 +127,7 @@ class AdGuardHomeBlockedFilteringSensor(AdGuardHomeSensor):
|
|||
class AdGuardHomePercentageBlockedSensor(AdGuardHomeSensor):
|
||||
"""Defines a AdGuard Home blocked percentage sensor."""
|
||||
|
||||
def __init__(self, adguard):
|
||||
def __init__(self, adguard: AdGuardHome) -> None:
|
||||
"""Initialize AdGuard Home sensor."""
|
||||
super().__init__(
|
||||
adguard,
|
||||
|
@ -143,7 +146,7 @@ class AdGuardHomePercentageBlockedSensor(AdGuardHomeSensor):
|
|||
class AdGuardHomeReplacedParentalSensor(AdGuardHomeSensor):
|
||||
"""Defines a AdGuard Home replaced by parental control sensor."""
|
||||
|
||||
def __init__(self, adguard):
|
||||
def __init__(self, adguard: AdGuardHome) -> None:
|
||||
"""Initialize AdGuard Home sensor."""
|
||||
super().__init__(
|
||||
adguard,
|
||||
|
@ -161,7 +164,7 @@ class AdGuardHomeReplacedParentalSensor(AdGuardHomeSensor):
|
|||
class AdGuardHomeReplacedSafeBrowsingSensor(AdGuardHomeSensor):
|
||||
"""Defines a AdGuard Home replaced by safe browsing sensor."""
|
||||
|
||||
def __init__(self, adguard):
|
||||
def __init__(self, adguard: AdGuardHome) -> None:
|
||||
"""Initialize AdGuard Home sensor."""
|
||||
super().__init__(
|
||||
adguard,
|
||||
|
@ -179,7 +182,7 @@ class AdGuardHomeReplacedSafeBrowsingSensor(AdGuardHomeSensor):
|
|||
class AdGuardHomeReplacedSafeSearchSensor(AdGuardHomeSensor):
|
||||
"""Defines a AdGuard Home replaced by safe search sensor."""
|
||||
|
||||
def __init__(self, adguard):
|
||||
def __init__(self, adguard: AdGuardHome) -> None:
|
||||
"""Initialize AdGuard Home sensor."""
|
||||
super().__init__(
|
||||
adguard,
|
||||
|
@ -197,7 +200,7 @@ class AdGuardHomeReplacedSafeSearchSensor(AdGuardHomeSensor):
|
|||
class AdGuardHomeAverageProcessingTimeSensor(AdGuardHomeSensor):
|
||||
"""Defines a AdGuard Home average processing time sensor."""
|
||||
|
||||
def __init__(self, adguard):
|
||||
def __init__(self, adguard: AdGuardHome) -> None:
|
||||
"""Initialize AdGuard Home sensor."""
|
||||
super().__init__(
|
||||
adguard,
|
||||
|
@ -216,7 +219,7 @@ class AdGuardHomeAverageProcessingTimeSensor(AdGuardHomeSensor):
|
|||
class AdGuardHomeRulesCountSensor(AdGuardHomeSensor):
|
||||
"""Defines a AdGuard Home rules count sensor."""
|
||||
|
||||
def __init__(self, adguard):
|
||||
def __init__(self, adguard: AdGuardHome) -> None:
|
||||
"""Initialize AdGuard Home sensor."""
|
||||
super().__init__(
|
||||
adguard,
|
||||
|
|
|
@ -1,19 +1,20 @@
|
|||
"""Support for AdGuard Home switches."""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
from typing import Callable
|
||||
|
||||
from adguardhome import AdGuardHomeConnectionError, AdGuardHomeError
|
||||
from adguardhome import AdGuardHome, AdGuardHomeConnectionError, AdGuardHomeError
|
||||
|
||||
from homeassistant.components.adguard import AdGuardHomeDeviceEntity
|
||||
from homeassistant.components.adguard.const import (
|
||||
DATA_ADGUARD_CLIENT,
|
||||
DATA_ADGUARD_VERION,
|
||||
DOMAIN,
|
||||
)
|
||||
from homeassistant.components.switch import SwitchEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import PlatformNotReady
|
||||
from homeassistant.helpers.typing import HomeAssistantType
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
from . import AdGuardHomeDeviceEntity
|
||||
from .const import DATA_ADGUARD_CLIENT, DATA_ADGUARD_VERION, DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -22,7 +23,9 @@ PARALLEL_UPDATES = 1
|
|||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistantType, entry: ConfigEntry, async_add_entities
|
||||
hass: HomeAssistant,
|
||||
entry: ConfigEntry,
|
||||
async_add_entities: Callable[[list[Entity], bool], None],
|
||||
) -> None:
|
||||
"""Set up AdGuard Home switch based on a config entry."""
|
||||
adguard = hass.data[DOMAIN][DATA_ADGUARD_CLIENT]
|
||||
|
@ -49,8 +52,13 @@ class AdGuardHomeSwitch(AdGuardHomeDeviceEntity, SwitchEntity):
|
|||
"""Defines a AdGuard Home switch."""
|
||||
|
||||
def __init__(
|
||||
self, adguard, name: str, icon: str, key: str, enabled_default: bool = True
|
||||
):
|
||||
self,
|
||||
adguard: AdGuardHome,
|
||||
name: str,
|
||||
icon: str,
|
||||
key: str,
|
||||
enabled_default: bool = True,
|
||||
) -> None:
|
||||
"""Initialize AdGuard Home switch."""
|
||||
self._state = False
|
||||
self._key = key
|
||||
|
@ -96,7 +104,7 @@ class AdGuardHomeSwitch(AdGuardHomeDeviceEntity, SwitchEntity):
|
|||
class AdGuardHomeProtectionSwitch(AdGuardHomeSwitch):
|
||||
"""Defines a AdGuard Home protection switch."""
|
||||
|
||||
def __init__(self, adguard) -> None:
|
||||
def __init__(self, adguard: AdGuardHome) -> None:
|
||||
"""Initialize AdGuard Home switch."""
|
||||
super().__init__(
|
||||
adguard, "AdGuard Protection", "mdi:shield-check", "protection"
|
||||
|
@ -118,7 +126,7 @@ class AdGuardHomeProtectionSwitch(AdGuardHomeSwitch):
|
|||
class AdGuardHomeParentalSwitch(AdGuardHomeSwitch):
|
||||
"""Defines a AdGuard Home parental control switch."""
|
||||
|
||||
def __init__(self, adguard) -> None:
|
||||
def __init__(self, adguard: AdGuardHome) -> None:
|
||||
"""Initialize AdGuard Home switch."""
|
||||
super().__init__(
|
||||
adguard, "AdGuard Parental Control", "mdi:shield-check", "parental"
|
||||
|
@ -140,7 +148,7 @@ class AdGuardHomeParentalSwitch(AdGuardHomeSwitch):
|
|||
class AdGuardHomeSafeSearchSwitch(AdGuardHomeSwitch):
|
||||
"""Defines a AdGuard Home safe search switch."""
|
||||
|
||||
def __init__(self, adguard) -> None:
|
||||
def __init__(self, adguard: AdGuardHome) -> None:
|
||||
"""Initialize AdGuard Home switch."""
|
||||
super().__init__(
|
||||
adguard, "AdGuard Safe Search", "mdi:shield-check", "safesearch"
|
||||
|
@ -162,7 +170,7 @@ class AdGuardHomeSafeSearchSwitch(AdGuardHomeSwitch):
|
|||
class AdGuardHomeSafeBrowsingSwitch(AdGuardHomeSwitch):
|
||||
"""Defines a AdGuard Home safe search switch."""
|
||||
|
||||
def __init__(self, adguard) -> None:
|
||||
def __init__(self, adguard: AdGuardHome) -> None:
|
||||
"""Initialize AdGuard Home switch."""
|
||||
super().__init__(
|
||||
adguard, "AdGuard Safe Browsing", "mdi:shield-check", "safebrowsing"
|
||||
|
@ -184,7 +192,7 @@ class AdGuardHomeSafeBrowsingSwitch(AdGuardHomeSwitch):
|
|||
class AdGuardHomeFilteringSwitch(AdGuardHomeSwitch):
|
||||
"""Defines a AdGuard Home filtering switch."""
|
||||
|
||||
def __init__(self, adguard) -> None:
|
||||
def __init__(self, adguard: AdGuardHome) -> None:
|
||||
"""Initialize AdGuard Home switch."""
|
||||
super().__init__(adguard, "AdGuard Filtering", "mdi:shield-check", "filtering")
|
||||
|
||||
|
@ -204,7 +212,7 @@ class AdGuardHomeFilteringSwitch(AdGuardHomeSwitch):
|
|||
class AdGuardHomeQueryLogSwitch(AdGuardHomeSwitch):
|
||||
"""Defines a AdGuard Home query log switch."""
|
||||
|
||||
def __init__(self, adguard) -> None:
|
||||
def __init__(self, adguard: AdGuardHome) -> None:
|
||||
"""Initialize AdGuard Home switch."""
|
||||
super().__init__(
|
||||
adguard,
|
||||
|
|
|
@ -16,8 +16,10 @@ from homeassistant.const import (
|
|||
CONF_VERIFY_SSL,
|
||||
CONTENT_TYPE_JSON,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
from tests.test_util.aiohttp import AiohttpClientMocker
|
||||
|
||||
FIXTURE_USER_INPUT = {
|
||||
CONF_HOST: "127.0.0.1",
|
||||
|
@ -29,7 +31,7 @@ FIXTURE_USER_INPUT = {
|
|||
}
|
||||
|
||||
|
||||
async def test_show_authenticate_form(hass):
|
||||
async def test_show_authenticate_form(hass: HomeAssistant) -> None:
|
||||
"""Test that the setup form is served."""
|
||||
flow = config_flow.AdGuardHomeFlowHandler()
|
||||
flow.hass = hass
|
||||
|
@ -39,7 +41,9 @@ async def test_show_authenticate_form(hass):
|
|||
assert result["step_id"] == "user"
|
||||
|
||||
|
||||
async def test_connection_error(hass, aioclient_mock):
|
||||
async def test_connection_error(
|
||||
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
|
||||
) -> None:
|
||||
"""Test we show user form on AdGuard Home connection error."""
|
||||
aioclient_mock.get(
|
||||
f"{'https' if FIXTURE_USER_INPUT[CONF_SSL] else 'http'}"
|
||||
|
@ -57,7 +61,9 @@ async def test_connection_error(hass, aioclient_mock):
|
|||
assert result["errors"] == {"base": "cannot_connect"}
|
||||
|
||||
|
||||
async def test_full_flow_implementation(hass, aioclient_mock):
|
||||
async def test_full_flow_implementation(
|
||||
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
|
||||
) -> None:
|
||||
"""Test registering an integration and finishing flow works."""
|
||||
aioclient_mock.get(
|
||||
f"{'https' if FIXTURE_USER_INPUT[CONF_SSL] else 'http'}"
|
||||
|
@ -84,7 +90,7 @@ async def test_full_flow_implementation(hass, aioclient_mock):
|
|||
assert result["data"][CONF_VERIFY_SSL] == FIXTURE_USER_INPUT[CONF_VERIFY_SSL]
|
||||
|
||||
|
||||
async def test_integration_already_exists(hass):
|
||||
async def test_integration_already_exists(hass: HomeAssistant) -> None:
|
||||
"""Test we only allow a single config flow."""
|
||||
MockConfigEntry(domain=DOMAIN).add_to_hass(hass)
|
||||
|
||||
|
@ -95,7 +101,7 @@ async def test_integration_already_exists(hass):
|
|||
assert result["reason"] == "single_instance_allowed"
|
||||
|
||||
|
||||
async def test_hassio_single_instance(hass):
|
||||
async def test_hassio_single_instance(hass: HomeAssistant) -> None:
|
||||
"""Test we only allow a single config flow."""
|
||||
MockConfigEntry(
|
||||
domain="adguard", data={"host": "mock-adguard", "port": "3000"}
|
||||
|
@ -110,7 +116,7 @@ async def test_hassio_single_instance(hass):
|
|||
assert result["reason"] == "single_instance_allowed"
|
||||
|
||||
|
||||
async def test_hassio_update_instance_not_running(hass):
|
||||
async def test_hassio_update_instance_not_running(hass: HomeAssistant) -> None:
|
||||
"""Test we only allow a single config flow."""
|
||||
entry = MockConfigEntry(
|
||||
domain="adguard", data={"host": "mock-adguard", "port": "3000"}
|
||||
|
@ -131,7 +137,9 @@ async def test_hassio_update_instance_not_running(hass):
|
|||
assert result["reason"] == "existing_instance_updated"
|
||||
|
||||
|
||||
async def test_hassio_update_instance_running(hass, aioclient_mock):
|
||||
async def test_hassio_update_instance_running(
|
||||
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
|
||||
) -> None:
|
||||
"""Test we only allow a single config flow."""
|
||||
aioclient_mock.get(
|
||||
"http://mock-adguard-updated:3000/control/status",
|
||||
|
@ -192,7 +200,9 @@ async def test_hassio_update_instance_running(hass, aioclient_mock):
|
|||
assert entry.data["host"] == "mock-adguard-updated"
|
||||
|
||||
|
||||
async def test_hassio_confirm(hass, aioclient_mock):
|
||||
async def test_hassio_confirm(
|
||||
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
|
||||
) -> None:
|
||||
"""Test we can finish a config flow."""
|
||||
aioclient_mock.get(
|
||||
"http://mock-adguard:3000/control/status",
|
||||
|
@ -220,7 +230,9 @@ async def test_hassio_confirm(hass, aioclient_mock):
|
|||
assert result["data"][CONF_VERIFY_SSL]
|
||||
|
||||
|
||||
async def test_hassio_connection_error(hass, aioclient_mock):
|
||||
async def test_hassio_connection_error(
|
||||
hass: HomeAssistant, aioclient_mock: AiohttpClientMocker
|
||||
) -> None:
|
||||
"""Test we show Hass.io confirm form on AdGuard Home connection error."""
|
||||
aioclient_mock.get(
|
||||
"http://mock-adguard:3000/control/status", exc=aiohttp.ClientError
|
||||
|
|
Loading…
Reference in New Issue