Minor improvement of frame helper (#101387)

* Minor improvement of frame helper

* Add new custom integration for testing

* Make IntegrationFrame kw_only
pull/101418/head
Erik Montnemery 2023-10-04 21:43:00 +02:00 committed by GitHub
parent c495d607d8
commit 7e39acda37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 64 additions and 10 deletions

View File

@ -6,6 +6,7 @@ from collections.abc import Callable
from dataclasses import dataclass
import functools
import logging
import sys
from traceback import FrameSummary, extract_stack
from typing import Any, TypeVar, cast
@ -19,14 +20,15 @@ _REPORTED_INTEGRATIONS: set[str] = set()
_CallableT = TypeVar("_CallableT", bound=Callable)
@dataclass
@dataclass(kw_only=True)
class IntegrationFrame:
"""Integration frame container."""
custom_integration: bool
filename: str
frame: FrameSummary
integration: str
module: str | None
relative_filename: str
def get_integration_frame(exclude_integrations: set | None = None) -> IntegrationFrame:
@ -55,11 +57,20 @@ def get_integration_frame(exclude_integrations: set | None = None) -> Integratio
if found_frame is None:
raise MissingIntegrationFrame
found_module: str | None = None
for module, module_obj in dict(sys.modules).items():
if not hasattr(module_obj, "__file__"):
continue
if module_obj.__file__ == found_frame.filename:
found_module = module
break
return IntegrationFrame(
path == "custom_components/",
found_frame.filename[index:],
found_frame,
integration,
custom_integration=path == "custom_components/",
frame=found_frame,
integration=integration,
module=found_module,
relative_filename=found_frame.filename[index:],
)
@ -121,7 +132,7 @@ def _report_integration(
what,
extra,
integration_frame.integration,
integration_frame.filename,
integration_frame.relative_filename,
found_frame.lineno,
(found_frame.line or "?").strip(),
)

View File

@ -1,10 +1,11 @@
"""Test the frame helper."""
from collections.abc import Generator
from unittest.mock import Mock, patch
from unittest.mock import ANY, Mock, patch
import pytest
from homeassistant.core import HomeAssistant
from homeassistant.helpers import frame
@ -41,7 +42,28 @@ async def test_extract_frame_integration(
"""Test extracting the current frame from integration context."""
integration_frame = frame.get_integration_frame()
assert integration_frame == frame.IntegrationFrame(
False, "homeassistant/components/hue/light.py", mock_integration_frame, "hue"
custom_integration=False,
frame=mock_integration_frame,
integration="hue",
module=None,
relative_filename="homeassistant/components/hue/light.py",
)
async def test_extract_frame_resolve_module(
hass: HomeAssistant, enable_custom_integrations
) -> None:
"""Test extracting the current frame from integration context."""
from custom_components.test_integration_frame import call_get_integration_frame
integration_frame = call_get_integration_frame()
assert integration_frame == frame.IntegrationFrame(
custom_integration=True,
frame=ANY,
integration="test_integration_frame",
module="custom_components.test_integration_frame",
relative_filename="custom_components/test_integration_frame/__init__.py",
)
@ -80,7 +102,11 @@ async def test_extract_frame_integration_with_excluded_integration(
)
assert integration_frame == frame.IntegrationFrame(
False, "homeassistant/components/mdns/light.py", correct_frame, "mdns"
custom_integration=False,
frame=correct_frame,
integration="mdns",
module=None,
relative_filename="homeassistant/components/mdns/light.py",
)

View File

@ -0,0 +1,8 @@
"""An integration which calls helpers.frame.get_integration_frame."""
from homeassistant.helpers import frame
def call_get_integration_frame() -> frame.IntegrationFrame:
"""Call get_integration_frame."""
return frame.get_integration_frame()

View File

@ -0,0 +1,9 @@
{
"domain": "test_integration_frame",
"name": "Test Integration Frame",
"documentation": "http://example.com",
"requirements": [],
"dependencies": [],
"codeowners": [],
"version": "1.2.3"
}