From e83ee00af8961d26fe9a0834f1a9fd23b49d0bb4 Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Wed, 15 Jan 2025 15:10:25 +0100 Subject: [PATCH] Move UsbServiceInfo to service_info helpers (#135663) * Move UsbServiceInfo to service_info helpers * Adjust components --- homeassistant/components/usb/__init__.py | 37 ++++++++++++------- homeassistant/config_entries.py | 2 +- homeassistant/helpers/service_info/usb.py | 17 +++++++++ .../homeassistant_sky_connect/test_util.py | 2 +- tests/components/usb/test_init.py | 30 +++++++++++++++ tests/components/zha/test_radio_manager.py | 2 +- 6 files changed, 73 insertions(+), 17 deletions(-) create mode 100644 homeassistant/helpers/service_info/usb.py diff --git a/homeassistant/components/usb/__init__.py b/homeassistant/components/usb/__init__.py index 4517501bf43..c502c81dae6 100644 --- a/homeassistant/components/usb/__init__.py +++ b/homeassistant/components/usb/__init__.py @@ -5,6 +5,7 @@ from __future__ import annotations from collections.abc import Coroutine, Sequence import dataclasses import fnmatch +from functools import partial import logging import os import sys @@ -24,9 +25,15 @@ from homeassistant.core import ( HomeAssistant, callback as hass_callback, ) -from homeassistant.data_entry_flow import BaseServiceInfo from homeassistant.helpers import config_validation as cv, discovery_flow, system_info from homeassistant.helpers.debounce import Debouncer +from homeassistant.helpers.deprecation import ( + DeprecatedConstant, + all_with_deprecated_constants, + check_if_deprecated_constant, + dir_with_deprecated_constants, +) +from homeassistant.helpers.service_info.usb import UsbServiceInfo as _UsbServiceInfo from homeassistant.helpers.typing import ConfigType from homeassistant.loader import USBMatcher, async_get_usb @@ -45,7 +52,6 @@ __all__ = [ "async_is_plugged_in", "async_register_scan_request_callback", "USBCallbackMatcher", - "UsbServiceInfo", ] CONFIG_SCHEMA = cv.empty_config_schema(DOMAIN) @@ -104,16 +110,11 @@ def async_is_plugged_in(hass: HomeAssistant, matcher: USBCallbackMatcher) -> boo ) -@dataclasses.dataclass(slots=True) -class UsbServiceInfo(BaseServiceInfo): - """Prepared info from usb entries.""" - - device: str - vid: str - pid: str - serial_number: str | None - manufacturer: str | None - description: str | None +_DEPRECATED_UsbServiceInfo = DeprecatedConstant( + _UsbServiceInfo, + "homeassistant.helpers.service_info.usb.UsbServiceInfo", + "2026.2", +) @overload @@ -352,7 +353,7 @@ class USBDiscovery: if not matched: return - service_info: UsbServiceInfo | None = None + service_info: _UsbServiceInfo | None = None sorted_by_most_targeted = sorted(matched, key=lambda item: -len(item)) most_matched_fields = len(sorted_by_most_targeted[0]) @@ -364,7 +365,7 @@ class USBDiscovery: break if service_info is None: - service_info = UsbServiceInfo( + service_info = _UsbServiceInfo( device=await self.hass.async_add_executor_job( get_serial_by_id, device.device ), @@ -457,3 +458,11 @@ async def websocket_usb_scan( if not usb_discovery.observer_active: await usb_discovery.async_request_scan() connection.send_result(msg["id"]) + + +# These can be removed if no deprecated constant are in this module anymore +__getattr__ = partial(check_if_deprecated_constant, module_globals=globals()) +__dir__ = partial( + dir_with_deprecated_constants, module_globals_keys=[*globals().keys()] +) +__all__ = all_with_deprecated_constants(globals()) diff --git a/homeassistant/config_entries.py b/homeassistant/config_entries.py index a8d1eb10ee7..930b3242aad 100644 --- a/homeassistant/config_entries.py +++ b/homeassistant/config_entries.py @@ -87,11 +87,11 @@ from .util.enum import try_parse_enum if TYPE_CHECKING: from .components.bluetooth import BluetoothServiceInfoBleak - from .components.usb import UsbServiceInfo from .helpers.service_info.dhcp import DhcpServiceInfo from .helpers.service_info.hassio import HassioServiceInfo from .helpers.service_info.mqtt import MqttServiceInfo from .helpers.service_info.ssdp import SsdpServiceInfo + from .helpers.service_info.usb import UsbServiceInfo from .helpers.service_info.zeroconf import ZeroconfServiceInfo diff --git a/homeassistant/helpers/service_info/usb.py b/homeassistant/helpers/service_info/usb.py new file mode 100644 index 00000000000..c7d6f6ea143 --- /dev/null +++ b/homeassistant/helpers/service_info/usb.py @@ -0,0 +1,17 @@ +"""USB discovery data.""" + +from dataclasses import dataclass + +from homeassistant.data_entry_flow import BaseServiceInfo + + +@dataclass(slots=True) +class UsbServiceInfo(BaseServiceInfo): + """Prepared info from usb entries.""" + + device: str + vid: str + pid: str + serial_number: str | None + manufacturer: str | None + description: str | None diff --git a/tests/components/homeassistant_sky_connect/test_util.py b/tests/components/homeassistant_sky_connect/test_util.py index 1d1d70c1b4c..2801b3d00bb 100644 --- a/tests/components/homeassistant_sky_connect/test_util.py +++ b/tests/components/homeassistant_sky_connect/test_util.py @@ -8,7 +8,7 @@ from homeassistant.components.homeassistant_sky_connect.util import ( get_hardware_variant, get_usb_service_info, ) -from homeassistant.components.usb import UsbServiceInfo +from homeassistant.helpers.service_info.usb import UsbServiceInfo from tests.common import MockConfigEntry diff --git a/tests/components/usb/test_init.py b/tests/components/usb/test_init.py index bbd802afc95..2f6dc72b4f8 100644 --- a/tests/components/usb/test_init.py +++ b/tests/components/usb/test_init.py @@ -2,6 +2,7 @@ import os import sys +from typing import Any from unittest.mock import MagicMock, Mock, call, patch, sentinel import pytest @@ -9,10 +10,12 @@ import pytest from homeassistant.components import usb from homeassistant.const import EVENT_HOMEASSISTANT_STARTED, EVENT_HOMEASSISTANT_STOP from homeassistant.core import HomeAssistant +from homeassistant.helpers.service_info.usb import UsbServiceInfo from homeassistant.setup import async_setup_component from . import conbee_device, slae_sh_device +from tests.common import import_and_test_deprecated_constant from tests.typing import WebSocketGenerator @@ -1160,3 +1163,30 @@ async def test_cp2102n_ordering_on_macos( # We always use `cu.SLAB_USBtoUART` assert mock_config_flow.mock_calls[0][2]["data"].device == "/dev/cu.SLAB_USBtoUART2" + + +@pytest.mark.parametrize( + ("constant_name", "replacement_name", "replacement"), + [ + ( + "UsbServiceInfo", + "homeassistant.helpers.service_info.usb.UsbServiceInfo", + UsbServiceInfo, + ), + ], +) +def test_deprecated_constants( + caplog: pytest.LogCaptureFixture, + constant_name: str, + replacement_name: str, + replacement: Any, +) -> None: + """Test deprecated automation constants.""" + import_and_test_deprecated_constant( + caplog, + usb, + constant_name, + replacement_name, + replacement, + "2026.2", + ) diff --git a/tests/components/zha/test_radio_manager.py b/tests/components/zha/test_radio_manager.py index 0a51aaa6dba..59494dd0d09 100644 --- a/tests/components/zha/test_radio_manager.py +++ b/tests/components/zha/test_radio_manager.py @@ -11,12 +11,12 @@ import zigpy.config from zigpy.config import CONF_DEVICE_PATH import zigpy.types -from homeassistant.components.usb import UsbServiceInfo from homeassistant.components.zha import radio_manager from homeassistant.components.zha.const import DOMAIN from homeassistant.components.zha.radio_manager import ProbeResult, ZhaRadioManager from homeassistant.config_entries import ConfigEntryState from homeassistant.core import HomeAssistant +from homeassistant.helpers.service_info.usb import UsbServiceInfo from tests.common import MockConfigEntry