mirror of
https://github.com/home-assistant/core.git
synced 2025-04-24 01:08:12 +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,
|
||||
error_if_core: bool = True,
|
||||
level: int = logging.WARNING,
|
||||
log_custom_component_only: bool = False,
|
||||
) -> None:
|
||||
"""Report incorrect usage.
|
||||
|
||||
@ -99,10 +100,12 @@ def report(
|
||||
msg = f"Detected code that {what}. Please report this issue."
|
||||
if error_if_core:
|
||||
raise RuntimeError(msg) from err
|
||||
_LOGGER.warning(msg, stack_info=True)
|
||||
if not log_custom_component_only:
|
||||
_LOGGER.warning(msg, stack_info=True)
|
||||
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(
|
||||
|
@ -1247,6 +1247,19 @@ class Components:
|
||||
if component is None:
|
||||
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)
|
||||
setattr(self, comp_name, wrapped)
|
||||
return wrapped
|
||||
|
@ -1579,6 +1579,33 @@ def mock_bleak_scanner_start() -> Generator[MagicMock, None, None]:
|
||||
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
|
||||
def mock_bluetooth(
|
||||
mock_bleak_scanner_start: MagicMock, mock_bluetooth_adapters: None
|
||||
|
@ -1,6 +1,5 @@
|
||||
"""Test the frame helper."""
|
||||
|
||||
from collections.abc import Generator
|
||||
from unittest.mock import ANY, Mock, patch
|
||||
|
||||
import pytest
|
||||
@ -9,33 +8,6 @@ from homeassistant.core import HomeAssistant
|
||||
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(
|
||||
caplog: pytest.LogCaptureFixture, mock_integration_frame: Mock
|
||||
) -> None:
|
||||
@ -174,3 +146,8 @@ async def test_report_missing_integration_frame(
|
||||
frame.report(what, error_if_core=False)
|
||||
assert what in caplog.text
|
||||
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."""
|
||||
import asyncio
|
||||
from unittest.mock import patch
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
@ -8,6 +8,7 @@ from homeassistant import loader
|
||||
from homeassistant.components import http, hue
|
||||
from homeassistant.components.hue import light as hue_light
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers import frame
|
||||
|
||||
from .common import MockModule, async_get_persistent_notifications, mock_integration
|
||||
|
||||
@ -287,6 +288,7 @@ async def test_get_integration_custom_component(
|
||||
) -> None:
|
||||
"""Test resolving integration."""
|
||||
integration = await loader.async_get_integration(hass, "test_package")
|
||||
|
||||
assert integration.get_component().DOMAIN == "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
|
||||
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