mirror of
https://github.com/home-assistant/core.git
synced 2026-09-25 17:04:04 -04:00
Deprecate modbus get_hub in favour of async_get_unit (#179933)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com> Co-authored-by: Martin Hjelmare <marhje52@gmail.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
co-authored by
Paulus Schoutsen
Martin Hjelmare
Copilot Autofix powered by AI
parent
d0ebb31684
commit
f04652b324
@@ -5,6 +5,7 @@ import logging
|
||||
from homeassistant.const import SERVICE_RELOAD
|
||||
from homeassistant.core import Event, HomeAssistant, ServiceCall
|
||||
from homeassistant.helpers.entity_platform import async_get_platforms
|
||||
from homeassistant.helpers.frame import ReportBehavior, report_usage
|
||||
from homeassistant.helpers.reload import async_integration_yaml_config
|
||||
from homeassistant.helpers.service import async_register_admin_service
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
@@ -26,7 +27,25 @@ _LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_hub(hass: HomeAssistant, name: str) -> ModbusHub:
|
||||
"""Return modbus hub with name."""
|
||||
"""Return modbus hub with name.
|
||||
|
||||
Deprecated. Use `async_get_unit` instead, which builds a connection from
|
||||
credentials the integration holds rather than attaching to a hub the user
|
||||
configured in YAML under a name the integration has to be told.
|
||||
"""
|
||||
report_usage(
|
||||
"calls `modbus.get_hub`, which is deprecated in favour of "
|
||||
"`modbus.async_get_unit`. Collect the connection details in your own "
|
||||
"config flow and ask for a unit on them",
|
||||
breaks_in_ha_version="2027.10",
|
||||
core_behavior=ReportBehavior.IGNORE,
|
||||
core_integration_behavior=ReportBehavior.IGNORE,
|
||||
custom_integration_behavior=ReportBehavior.LOG,
|
||||
# get_hub is defined here, so its own frame is the first one the stack
|
||||
# walk meets. Without this it reports modbus every time, and the core
|
||||
# behavior above then silences the caller it was meant to name.
|
||||
exclude_integrations={DOMAIN},
|
||||
)
|
||||
return hass.data[DATA_MODBUS_HUBS][name]
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
"""Test the deprecation of get_hub."""
|
||||
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
import sys
|
||||
from types import ModuleType
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.modbus import get_hub
|
||||
from homeassistant.components.modbus.modbus import DATA_MODBUS_HUBS
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
|
||||
def _caller_in(root: Path, path: str) -> ModuleType:
|
||||
"""Load a module that calls get_hub, from a file at *path*.
|
||||
|
||||
The report names an integration by walking the stack for a file under
|
||||
`custom_components/` or `homeassistant/components/`, so a test of who gets
|
||||
named has to call from a file that actually sits there.
|
||||
"""
|
||||
source = root / path / "caller.py"
|
||||
source.parent.mkdir(parents=True, exist_ok=True)
|
||||
source.write_text(
|
||||
"from homeassistant.components.modbus import get_hub\n"
|
||||
"\n"
|
||||
"def call(hass):\n"
|
||||
' return get_hub(hass, "hub")\n'
|
||||
)
|
||||
|
||||
spec = importlib.util.spec_from_file_location(
|
||||
f"caller_{source.parent.name}", source
|
||||
)
|
||||
assert spec and spec.loader
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
sys.modules[spec.name] = module
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
@pytest.fixture(name="hub")
|
||||
def hub_fixture(hass: HomeAssistant) -> object:
|
||||
"""Put one hub in place for get_hub to return."""
|
||||
hub = object()
|
||||
hass.data[DATA_MODBUS_HUBS] = {"hub": hub}
|
||||
return hub
|
||||
|
||||
|
||||
async def test_a_custom_integration_is_warned(
|
||||
hass: HomeAssistant,
|
||||
hub: object,
|
||||
tmp_path: Path,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""A custom integration has its own config flow to collect details in.
|
||||
|
||||
Called through the real stack, so this also covers the report reaching
|
||||
past modbus's own frame to the caller that asked.
|
||||
"""
|
||||
caller = _caller_in(tmp_path, "custom_components/my_integration")
|
||||
|
||||
assert caller.call(hass) is hub
|
||||
|
||||
assert "deprecated" in caplog.text
|
||||
assert "async_get_unit" in caplog.text
|
||||
assert "my_integration" in caplog.text
|
||||
assert "2027.10" in caplog.text
|
||||
assert "modbus" not in caplog.text.split("my_integration")[0]
|
||||
|
||||
|
||||
async def test_a_core_integration_is_not_warned(
|
||||
hass: HomeAssistant,
|
||||
hub: object,
|
||||
tmp_path: Path,
|
||||
caplog: pytest.LogCaptureFixture,
|
||||
) -> None:
|
||||
"""Flexit is the one caller in core, and the user cannot act on it."""
|
||||
caller = _caller_in(tmp_path, "homeassistant/components/flexit")
|
||||
|
||||
assert caller.call(hass) is hub
|
||||
|
||||
assert "deprecated" not in caplog.text
|
||||
|
||||
|
||||
async def test_a_caller_outside_any_integration_is_not_warned(
|
||||
hass: HomeAssistant, hub: object, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""Nothing to name and nobody to tell, so it stays quiet."""
|
||||
assert get_hub(hass, "hub") is hub
|
||||
|
||||
assert "deprecated" not in caplog.text
|
||||
Reference in New Issue
Block a user