mirror of
https://github.com/home-assistant/core.git
synced 2025-07-17 10:17:09 +00:00
Deprecate hass.components
and log warning if used inside custom component (#111508)
* Deprecate @bind_hass and log error if used inside custom component * Log also when accessing `hass.components` * Log warning only when `hass.components` is used * Change version * Process code review
This commit is contained in:
parent
af4771a198
commit
bc6b4d01c8
@ -86,6 +86,7 @@ def report(
|
|||||||
exclude_integrations: set | None = None,
|
exclude_integrations: set | None = None,
|
||||||
error_if_core: bool = True,
|
error_if_core: bool = True,
|
||||||
level: int = logging.WARNING,
|
level: int = logging.WARNING,
|
||||||
|
log_custom_component_only: bool = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Report incorrect usage.
|
"""Report incorrect usage.
|
||||||
|
|
||||||
@ -99,10 +100,12 @@ def report(
|
|||||||
msg = f"Detected code that {what}. Please report this issue."
|
msg = f"Detected code that {what}. Please report this issue."
|
||||||
if error_if_core:
|
if error_if_core:
|
||||||
raise RuntimeError(msg) from err
|
raise RuntimeError(msg) from err
|
||||||
_LOGGER.warning(msg, stack_info=True)
|
if not log_custom_component_only:
|
||||||
|
_LOGGER.warning(msg, stack_info=True)
|
||||||
return
|
return
|
||||||
|
|
||||||
_report_integration(what, integration_frame, level)
|
if not log_custom_component_only or integration_frame.custom_integration:
|
||||||
|
_report_integration(what, integration_frame, level)
|
||||||
|
|
||||||
|
|
||||||
def _report_integration(
|
def _report_integration(
|
||||||
|
@ -1247,6 +1247,19 @@ class Components:
|
|||||||
if component is None:
|
if component is None:
|
||||||
raise ImportError(f"Unable to load {comp_name}")
|
raise ImportError(f"Unable to load {comp_name}")
|
||||||
|
|
||||||
|
# Local import to avoid circular dependencies
|
||||||
|
from .helpers.frame import report # pylint: disable=import-outside-toplevel
|
||||||
|
|
||||||
|
report(
|
||||||
|
(
|
||||||
|
f"accesses hass.components.{comp_name}."
|
||||||
|
" This is deprecated and will stop working in Home Assistant 2024.6, it"
|
||||||
|
f" should be updated to import functions used from {comp_name} directly"
|
||||||
|
),
|
||||||
|
error_if_core=False,
|
||||||
|
log_custom_component_only=True,
|
||||||
|
)
|
||||||
|
|
||||||
wrapped = ModuleWrapper(self._hass, component)
|
wrapped = ModuleWrapper(self._hass, component)
|
||||||
setattr(self, comp_name, wrapped)
|
setattr(self, comp_name, wrapped)
|
||||||
return wrapped
|
return wrapped
|
||||||
|
@ -1579,6 +1579,33 @@ def mock_bleak_scanner_start() -> Generator[MagicMock, None, None]:
|
|||||||
yield mock_bleak_scanner_start
|
yield mock_bleak_scanner_start
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mock_integration_frame() -> Generator[Mock, None, None]:
|
||||||
|
"""Mock as if we're calling code from inside an integration."""
|
||||||
|
correct_frame = Mock(
|
||||||
|
filename="/home/paulus/homeassistant/components/hue/light.py",
|
||||||
|
lineno="23",
|
||||||
|
line="self.light.is_on",
|
||||||
|
)
|
||||||
|
with patch(
|
||||||
|
"homeassistant.helpers.frame.extract_stack",
|
||||||
|
return_value=[
|
||||||
|
Mock(
|
||||||
|
filename="/home/paulus/homeassistant/core.py",
|
||||||
|
lineno="23",
|
||||||
|
line="do_something()",
|
||||||
|
),
|
||||||
|
correct_frame,
|
||||||
|
Mock(
|
||||||
|
filename="/home/paulus/aiohue/lights.py",
|
||||||
|
lineno="2",
|
||||||
|
line="something()",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
):
|
||||||
|
yield correct_frame
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def mock_bluetooth(
|
def mock_bluetooth(
|
||||||
mock_bleak_scanner_start: MagicMock, mock_bluetooth_adapters: None
|
mock_bleak_scanner_start: MagicMock, mock_bluetooth_adapters: None
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
"""Test the frame helper."""
|
"""Test the frame helper."""
|
||||||
|
|
||||||
from collections.abc import Generator
|
|
||||||
from unittest.mock import ANY, Mock, patch
|
from unittest.mock import ANY, Mock, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@ -9,33 +8,6 @@ from homeassistant.core import HomeAssistant
|
|||||||
from homeassistant.helpers import frame
|
from homeassistant.helpers import frame
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def mock_integration_frame() -> Generator[Mock, None, None]:
|
|
||||||
"""Mock as if we're calling code from inside an integration."""
|
|
||||||
correct_frame = Mock(
|
|
||||||
filename="/home/paulus/homeassistant/components/hue/light.py",
|
|
||||||
lineno="23",
|
|
||||||
line="self.light.is_on",
|
|
||||||
)
|
|
||||||
with patch(
|
|
||||||
"homeassistant.helpers.frame.extract_stack",
|
|
||||||
return_value=[
|
|
||||||
Mock(
|
|
||||||
filename="/home/paulus/homeassistant/core.py",
|
|
||||||
lineno="23",
|
|
||||||
line="do_something()",
|
|
||||||
),
|
|
||||||
correct_frame,
|
|
||||||
Mock(
|
|
||||||
filename="/home/paulus/aiohue/lights.py",
|
|
||||||
lineno="2",
|
|
||||||
line="something()",
|
|
||||||
),
|
|
||||||
],
|
|
||||||
):
|
|
||||||
yield correct_frame
|
|
||||||
|
|
||||||
|
|
||||||
async def test_extract_frame_integration(
|
async def test_extract_frame_integration(
|
||||||
caplog: pytest.LogCaptureFixture, mock_integration_frame: Mock
|
caplog: pytest.LogCaptureFixture, mock_integration_frame: Mock
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -174,3 +146,8 @@ async def test_report_missing_integration_frame(
|
|||||||
frame.report(what, error_if_core=False)
|
frame.report(what, error_if_core=False)
|
||||||
assert what in caplog.text
|
assert what in caplog.text
|
||||||
assert caplog.text.count(what) == 1
|
assert caplog.text.count(what) == 1
|
||||||
|
|
||||||
|
caplog.clear()
|
||||||
|
|
||||||
|
frame.report(what, error_if_core=False, log_custom_component_only=True)
|
||||||
|
assert caplog.text == ""
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"""Test to verify that we can load components."""
|
"""Test to verify that we can load components."""
|
||||||
import asyncio
|
import asyncio
|
||||||
from unittest.mock import patch
|
from unittest.mock import Mock, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@ -8,6 +8,7 @@ from homeassistant import loader
|
|||||||
from homeassistant.components import http, hue
|
from homeassistant.components import http, hue
|
||||||
from homeassistant.components.hue import light as hue_light
|
from homeassistant.components.hue import light as hue_light
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
|
from homeassistant.helpers import frame
|
||||||
|
|
||||||
from .common import MockModule, async_get_persistent_notifications, mock_integration
|
from .common import MockModule, async_get_persistent_notifications, mock_integration
|
||||||
|
|
||||||
@ -287,6 +288,7 @@ async def test_get_integration_custom_component(
|
|||||||
) -> None:
|
) -> None:
|
||||||
"""Test resolving integration."""
|
"""Test resolving integration."""
|
||||||
integration = await loader.async_get_integration(hass, "test_package")
|
integration = await loader.async_get_integration(hass, "test_package")
|
||||||
|
|
||||||
assert integration.get_component().DOMAIN == "test_package"
|
assert integration.get_component().DOMAIN == "test_package"
|
||||||
assert integration.name == "Test Package"
|
assert integration.name == "Test Package"
|
||||||
|
|
||||||
@ -1001,3 +1003,33 @@ async def test_config_folder_not_in_path(hass):
|
|||||||
|
|
||||||
# Verify that we are able to load the file with absolute path
|
# Verify that we are able to load the file with absolute path
|
||||||
import tests.testing_config.check_config_not_in_path # noqa: F401
|
import tests.testing_config.check_config_not_in_path # noqa: F401
|
||||||
|
|
||||||
|
|
||||||
|
async def test_hass_components_use_reported(
|
||||||
|
hass: HomeAssistant, caplog: pytest.LogCaptureFixture, mock_integration_frame: Mock
|
||||||
|
) -> None:
|
||||||
|
"""Test that use of hass.components is reported."""
|
||||||
|
mock_integration_frame.filename = (
|
||||||
|
"/home/paulus/homeassistant/custom_components/demo/light.py"
|
||||||
|
)
|
||||||
|
integration_frame = frame.IntegrationFrame(
|
||||||
|
custom_integration=True,
|
||||||
|
frame=mock_integration_frame,
|
||||||
|
integration="test_integration_frame",
|
||||||
|
module="custom_components.test_integration_frame",
|
||||||
|
relative_filename="custom_components/test_integration_frame/__init__.py",
|
||||||
|
)
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"homeassistant.helpers.frame.get_integration_frame",
|
||||||
|
return_value=integration_frame,
|
||||||
|
), patch(
|
||||||
|
"homeassistant.components.http.start_http_server_and_save_config",
|
||||||
|
return_value=None,
|
||||||
|
):
|
||||||
|
hass.components.http.start_http_server_and_save_config(hass, [], None)
|
||||||
|
|
||||||
|
assert (
|
||||||
|
"Detected that custom integration 'test_integration_frame'"
|
||||||
|
" accesses hass.components.http. This is deprecated"
|
||||||
|
) in caplog.text
|
||||||
|
Loading…
x
Reference in New Issue
Block a user