mirror of
https://github.com/home-assistant/core.git
synced 2025-04-23 08:47:57 +00:00
Use dataclass for DhcpServiceInfo (#60136)
Co-authored-by: epenet <epenet@users.noreply.github.com>
This commit is contained in:
parent
e673d9dbd0
commit
560546f65e
@ -1,12 +1,13 @@
|
||||
"""The dhcp integration."""
|
||||
|
||||
from dataclasses import dataclass
|
||||
from datetime import timedelta
|
||||
import fnmatch
|
||||
from ipaddress import ip_address as make_ip_address
|
||||
import logging
|
||||
import os
|
||||
import threading
|
||||
from typing import Final, TypedDict
|
||||
from typing import Any, Final
|
||||
|
||||
from aiodiscover import DiscoverHosts
|
||||
from aiodiscover.discovery import (
|
||||
@ -32,12 +33,14 @@ from homeassistant.const import (
|
||||
STATE_HOME,
|
||||
)
|
||||
from homeassistant.core import Event, HomeAssistant, State, callback
|
||||
from homeassistant.data_entry_flow import BaseServiceInfo
|
||||
from homeassistant.helpers import discovery_flow
|
||||
from homeassistant.helpers.device_registry import format_mac
|
||||
from homeassistant.helpers.event import (
|
||||
async_track_state_added_domain,
|
||||
async_track_time_interval,
|
||||
)
|
||||
from homeassistant.helpers.frame import report
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
from homeassistant.loader import async_get_dhcp
|
||||
from homeassistant.util.async_ import run_callback_threadsafe
|
||||
@ -55,13 +58,33 @@ SCAN_INTERVAL = timedelta(minutes=60)
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DhcpServiceInfo(TypedDict):
|
||||
@dataclass
|
||||
class DhcpServiceInfo(BaseServiceInfo):
|
||||
"""Prepared info from dhcp entries."""
|
||||
|
||||
ip: str
|
||||
ip: str # pylint: disable=invalid-name
|
||||
hostname: str
|
||||
macaddress: str
|
||||
|
||||
# Used to prevent log flooding. To be removed in 2022.6
|
||||
_warning_logged: bool = False
|
||||
|
||||
def __getitem__(self, name: str) -> Any:
|
||||
"""
|
||||
Allow property access by name for compatibility reason.
|
||||
|
||||
Deprecated, and will be removed in version 2022.6.
|
||||
"""
|
||||
if not self._warning_logged:
|
||||
report(
|
||||
f"accessed discovery_info['{name}'] instead of discovery_info.{name}; this will fail in version 2022.6",
|
||||
exclude_integrations={"dhcp"},
|
||||
error_if_core=False,
|
||||
level=logging.DEBUG,
|
||||
)
|
||||
self._warning_logged = True
|
||||
return getattr(self, name)
|
||||
|
||||
|
||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
"""Set up the dhcp component."""
|
||||
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
||||
import abc
|
||||
import asyncio
|
||||
from collections.abc import Iterable, Mapping
|
||||
from dataclasses import dataclass
|
||||
from types import MappingProxyType
|
||||
from typing import Any, TypedDict
|
||||
import uuid
|
||||
@ -25,6 +26,11 @@ RESULT_TYPE_SHOW_PROGRESS_DONE = "progress_done"
|
||||
EVENT_DATA_ENTRY_FLOW_PROGRESSED = "data_entry_flow_progressed"
|
||||
|
||||
|
||||
@dataclass
|
||||
class BaseServiceInfo:
|
||||
"""Base class for discovery ServiceInfo."""
|
||||
|
||||
|
||||
class FlowError(HomeAssistantError):
|
||||
"""Error while configuring an account."""
|
||||
|
||||
@ -301,7 +307,7 @@ class FlowManager(abc.ABC):
|
||||
self,
|
||||
flow: Any,
|
||||
step_id: str,
|
||||
user_input: dict | None,
|
||||
user_input: dict | BaseServiceInfo | None,
|
||||
step_done: asyncio.Future | None = None,
|
||||
) -> FlowResult:
|
||||
"""Handle a step of a flow."""
|
||||
|
@ -51,7 +51,10 @@ class MissingIntegrationFrame(HomeAssistantError):
|
||||
|
||||
|
||||
def report(
|
||||
what: str, exclude_integrations: set | None = None, error_if_core: bool = True
|
||||
what: str,
|
||||
exclude_integrations: set | None = None,
|
||||
error_if_core: bool = True,
|
||||
level: int = logging.WARNING,
|
||||
) -> None:
|
||||
"""Report incorrect usage.
|
||||
|
||||
@ -68,11 +71,13 @@ def report(
|
||||
_LOGGER.warning(msg, stack_info=True)
|
||||
return
|
||||
|
||||
report_integration(what, integration_frame)
|
||||
report_integration(what, integration_frame, level)
|
||||
|
||||
|
||||
def report_integration(
|
||||
what: str, integration_frame: tuple[FrameSummary, str, str]
|
||||
what: str,
|
||||
integration_frame: tuple[FrameSummary, str, str],
|
||||
level: int = logging.WARNING,
|
||||
) -> None:
|
||||
"""Report incorrect usage in an integration.
|
||||
|
||||
@ -86,7 +91,8 @@ def report_integration(
|
||||
else:
|
||||
extra = ""
|
||||
|
||||
_LOGGER.warning(
|
||||
_LOGGER.log(
|
||||
level,
|
||||
"Detected integration that %s. "
|
||||
"Please report issue%s for %s using this method at %s, line %s: %s",
|
||||
what,
|
||||
|
@ -191,7 +191,9 @@ async def test_discovered_dhcp(
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_DHCP},
|
||||
data=dhcp.DhcpServiceInfo(ip="1.2.3.4", macaddress=MOCK_MAC_ADDR),
|
||||
data=dhcp.DhcpServiceInfo(
|
||||
ip="1.2.3.4", macaddress=MOCK_MAC_ADDR, hostname="mock_hostname"
|
||||
),
|
||||
)
|
||||
assert result["type"] == RESULT_TYPE_FORM
|
||||
assert result["errors"] == {}
|
||||
@ -246,7 +248,9 @@ async def test_discovered_by_homekit_and_dhcp(hass):
|
||||
result2 = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_DHCP},
|
||||
data=dhcp.DhcpServiceInfo(ip="1.2.3.4", macaddress=MOCK_MAC_ADDR),
|
||||
data=dhcp.DhcpServiceInfo(
|
||||
ip="1.2.3.4", macaddress=MOCK_MAC_ADDR, hostname="mock_hostname"
|
||||
),
|
||||
)
|
||||
assert result2["type"] == RESULT_TYPE_ABORT
|
||||
assert result2["reason"] == "already_in_progress"
|
||||
@ -254,7 +258,9 @@ async def test_discovered_by_homekit_and_dhcp(hass):
|
||||
result3 = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_DHCP},
|
||||
data=dhcp.DhcpServiceInfo(ip="1.2.3.4", macaddress="00:00:00:00:00:00"),
|
||||
data=dhcp.DhcpServiceInfo(
|
||||
ip="1.2.3.4", macaddress="00:00:00:00:00:00", hostname="mock_hostname"
|
||||
),
|
||||
)
|
||||
assert result3["type"] == RESULT_TYPE_ABORT
|
||||
assert result3["reason"] == "already_in_progress"
|
||||
|
@ -23,7 +23,9 @@ ZEROCONF_DISCOVERY_INFO = zeroconf.ZeroconfServiceInfo(
|
||||
)
|
||||
|
||||
DHCP_DISCOVERY_INFO = dhcp.DhcpServiceInfo(
|
||||
hostname="Hunter Douglas Powerview Hub", ip="1.2.3.4"
|
||||
hostname="Hunter Douglas Powerview Hub",
|
||||
ip="1.2.3.4",
|
||||
macaddress="AA:BB:CC:DD:EE:FF",
|
||||
)
|
||||
|
||||
DISCOVERY_DATA = [
|
||||
|
@ -84,7 +84,9 @@ MOCK_SSDP_DATA_WRONGMODEL = {
|
||||
ATTR_UPNP_MODEL_NAME: "HW-Qfake",
|
||||
ATTR_UPNP_UDN: "uuid:0d1cef00-00dc-1000-9c80-4844f7b172df",
|
||||
}
|
||||
MOCK_DHCP_DATA = dhcp.DhcpServiceInfo(ip="fake_host", macaddress="aa:bb:cc:dd:ee:ff")
|
||||
MOCK_DHCP_DATA = dhcp.DhcpServiceInfo(
|
||||
ip="fake_host", macaddress="aa:bb:cc:dd:ee:ff", hostname="fake_hostname"
|
||||
)
|
||||
EXISTING_IP = "192.168.40.221"
|
||||
MOCK_ZEROCONF_DATA = zeroconf.ZeroconfServiceInfo(
|
||||
host="fake_host",
|
||||
@ -1131,7 +1133,9 @@ async def test_update_legacy_missing_mac_from_dhcp(hass, remote: Mock):
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_DHCP},
|
||||
data=dhcp.DhcpServiceInfo(ip=EXISTING_IP, macaddress="aa:bb:cc:dd:ee:ff"),
|
||||
data=dhcp.DhcpServiceInfo(
|
||||
ip=EXISTING_IP, macaddress="aa:bb:cc:dd:ee:ff", hostname="fake_hostname"
|
||||
),
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert len(mock_setup.mock_calls) == 1
|
||||
@ -1165,7 +1169,9 @@ async def test_update_legacy_missing_mac_from_dhcp_no_unique_id(hass, remote: Mo
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_DHCP},
|
||||
data=dhcp.DhcpServiceInfo(ip=EXISTING_IP, macaddress="aa:bb:cc:dd:ee:ff"),
|
||||
data=dhcp.DhcpServiceInfo(
|
||||
ip=EXISTING_IP, macaddress="aa:bb:cc:dd:ee:ff", hostname="fake_hostname"
|
||||
),
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert len(mock_setup.mock_calls) == 1
|
||||
|
@ -141,6 +141,7 @@ async def test_dhcp(hass):
|
||||
data=dhcp.DhcpServiceInfo(
|
||||
hostname="Pentair: 01-01-01",
|
||||
ip="1.1.1.1",
|
||||
macaddress="AA:BB:CC:DD:EE:FF",
|
||||
),
|
||||
)
|
||||
|
||||
|
@ -321,7 +321,9 @@ async def test_discovered_by_discovery_and_dhcp(hass):
|
||||
result3 = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_DHCP},
|
||||
data=dhcp.DhcpServiceInfo(ip=IP_ADDRESS, macaddress="00:00:00:00:00:00"),
|
||||
data=dhcp.DhcpServiceInfo(
|
||||
ip=IP_ADDRESS, macaddress="00:00:00:00:00:00", hostname="mock_hostname"
|
||||
),
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert result3["type"] == RESULT_TYPE_ABORT
|
||||
@ -331,7 +333,9 @@ async def test_discovered_by_discovery_and_dhcp(hass):
|
||||
result3 = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_DHCP},
|
||||
data=dhcp.DhcpServiceInfo(ip="1.2.3.5", macaddress="00:00:00:00:00:01"),
|
||||
data=dhcp.DhcpServiceInfo(
|
||||
ip="1.2.3.5", macaddress="00:00:00:00:00:01", hostname="mock_hostname"
|
||||
),
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert result3["type"] == RESULT_TYPE_ABORT
|
||||
|
@ -176,7 +176,9 @@ async def test_dhcp(hass: HomeAssistant) -> None:
|
||||
"""Test that DHCP discovery works."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
data=dhcp.DhcpServiceInfo(macaddress="01:23:45:67:89:ab"),
|
||||
data=dhcp.DhcpServiceInfo(
|
||||
ip="1.2.3.4", macaddress="01:23:45:67:89:ab", hostname="mock_hostname"
|
||||
),
|
||||
context={"source": config_entries.SOURCE_DHCP},
|
||||
)
|
||||
|
||||
|
@ -471,7 +471,9 @@ async def test_discovered_by_homekit_and_dhcp(hass):
|
||||
result2 = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_DHCP},
|
||||
data=dhcp.DhcpServiceInfo(ip=IP_ADDRESS, macaddress="aa:bb:cc:dd:ee:ff"),
|
||||
data=dhcp.DhcpServiceInfo(
|
||||
ip=IP_ADDRESS, macaddress="aa:bb:cc:dd:ee:ff", hostname="mock_hostname"
|
||||
),
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert result2["type"] == RESULT_TYPE_ABORT
|
||||
@ -483,7 +485,9 @@ async def test_discovered_by_homekit_and_dhcp(hass):
|
||||
result3 = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_DHCP},
|
||||
data=dhcp.DhcpServiceInfo(ip=IP_ADDRESS, macaddress="00:00:00:00:00:00"),
|
||||
data=dhcp.DhcpServiceInfo(
|
||||
ip=IP_ADDRESS, macaddress="00:00:00:00:00:00", hostname="mock_hostname"
|
||||
),
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert result3["type"] == RESULT_TYPE_ABORT
|
||||
@ -497,7 +501,9 @@ async def test_discovered_by_homekit_and_dhcp(hass):
|
||||
result3 = await hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": config_entries.SOURCE_DHCP},
|
||||
data=dhcp.DhcpServiceInfo(ip="1.2.3.5", macaddress="00:00:00:00:00:01"),
|
||||
data=dhcp.DhcpServiceInfo(
|
||||
ip="1.2.3.5", macaddress="00:00:00:00:00:01", hostname="mock_hostname"
|
||||
),
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert result3["type"] == RESULT_TYPE_ABORT
|
||||
@ -509,7 +515,9 @@ async def test_discovered_by_homekit_and_dhcp(hass):
|
||||
[
|
||||
(
|
||||
config_entries.SOURCE_DHCP,
|
||||
dhcp.DhcpServiceInfo(ip=IP_ADDRESS, macaddress="aa:bb:cc:dd:ee:ff"),
|
||||
dhcp.DhcpServiceInfo(
|
||||
ip=IP_ADDRESS, macaddress="aa:bb:cc:dd:ee:ff", hostname="mock_hostname"
|
||||
),
|
||||
),
|
||||
(
|
||||
config_entries.SOURCE_HOMEKIT,
|
||||
@ -570,7 +578,9 @@ async def test_discovered_by_dhcp_or_homekit(hass, source, data):
|
||||
[
|
||||
(
|
||||
config_entries.SOURCE_DHCP,
|
||||
dhcp.DhcpServiceInfo(ip=IP_ADDRESS, macaddress="aa:bb:cc:dd:ee:ff"),
|
||||
dhcp.DhcpServiceInfo(
|
||||
ip=IP_ADDRESS, macaddress="aa:bb:cc:dd:ee:ff", hostname="mock_hostname"
|
||||
),
|
||||
),
|
||||
(
|
||||
config_entries.SOURCE_HOMEKIT,
|
||||
|
Loading…
x
Reference in New Issue
Block a user