Skip to content

Commit

Permalink
Include a traceback for non-strict event loop blocking detection (#11…
Browse files Browse the repository at this point in the history
  • Loading branch information
bdraco authored Jun 2, 2024
1 parent e976db8 commit 8f94205
Show file tree
Hide file tree
Showing 6 changed files with 30 additions and 14 deletions.
8 changes: 4 additions & 4 deletions homeassistant/helpers/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,17 @@ class IntegrationFrame:
integration: str
module: str | None
relative_filename: str
_frame: FrameType
frame: FrameType

@cached_property
def line_number(self) -> int:
"""Return the line number of the frame."""
return self._frame.f_lineno
return self.frame.f_lineno

@cached_property
def filename(self) -> str:
"""Return the filename of the frame."""
return self._frame.f_code.co_filename
return self.frame.f_code.co_filename

@cached_property
def line(self) -> str:
Expand Down Expand Up @@ -119,7 +119,7 @@ def get_integration_frame(exclude_integrations: set | None = None) -> Integratio
integration=integration,
module=found_module,
relative_filename=found_frame.f_code.co_filename[index:],
_frame=found_frame,
frame=found_frame,
)


Expand Down
13 changes: 8 additions & 5 deletions homeassistant/util/loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import linecache
import logging
import threading
import traceback
from typing import Any

from homeassistant.core import async_get_hass_or_none
Expand Down Expand Up @@ -54,12 +55,14 @@ def raise_for_blocking_call(
if not strict_core:
_LOGGER.warning(
"Detected blocking call to %s with args %s in %s, "
"line %s: %s inside the event loop",
"line %s: %s inside the event loop\n"
"Traceback (most recent call last):\n%s",
func.__name__,
mapped_args.get("args"),
offender_filename,
offender_lineno,
offender_line,
"".join(traceback.format_stack(f=offender_frame)),
)
return

Expand All @@ -79,10 +82,9 @@ def raise_for_blocking_call(
)

_LOGGER.warning(
(
"Detected blocking call to %s inside the event loop by %sintegration '%s' "
"at %s, line %s: %s (offender: %s, line %s: %s), please %s"
),
"Detected blocking call to %s inside the event loop by %sintegration '%s' "
"at %s, line %s: %s (offender: %s, line %s: %s), please %s\n"
"Traceback (most recent call last):\n%s",
func.__name__,
"custom " if integration_frame.custom_integration else "",
integration_frame.integration,
Expand All @@ -93,6 +95,7 @@ def raise_for_blocking_call(
offender_lineno,
offender_line,
report_issue,
"".join(traceback.format_stack(f=integration_frame.frame)),
)

if strict:
Expand Down
2 changes: 2 additions & 0 deletions tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -1689,8 +1689,10 @@ def help_test_all(module: ModuleType) -> None:
def extract_stack_to_frame(extract_stack: list[Mock]) -> FrameType:
"""Convert an extract stack to a frame list."""
stack = list(extract_stack)
_globals = globals()
for frame in stack:
frame.f_back = None
frame.f_globals = _globals
frame.f_code.co_filename = frame.filename
frame.f_lineno = int(frame.lineno)

Expand Down
6 changes: 3 additions & 3 deletions tests/helpers/test_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ async def test_extract_frame_integration(
integration_frame = frame.get_integration_frame()
assert integration_frame == frame.IntegrationFrame(
custom_integration=False,
_frame=mock_integration_frame,
frame=mock_integration_frame,
integration="hue",
module=None,
relative_filename="homeassistant/components/hue/light.py",
Expand All @@ -42,7 +42,7 @@ async def test_extract_frame_resolve_module(

assert integration_frame == frame.IntegrationFrame(
custom_integration=True,
_frame=ANY,
frame=ANY,
integration="test_integration_frame",
module="custom_components.test_integration_frame",
relative_filename="custom_components/test_integration_frame/__init__.py",
Expand Down Expand Up @@ -98,7 +98,7 @@ async def test_extract_frame_integration_with_excluded_integration(

assert integration_frame == frame.IntegrationFrame(
custom_integration=False,
_frame=correct_frame,
frame=correct_frame,
integration="mdns",
module=None,
relative_filename="homeassistant/components/mdns/light.py",
Expand Down
4 changes: 2 additions & 2 deletions tests/test_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -1271,7 +1271,7 @@ async def test_hass_components_use_reported(
)
integration_frame = frame.IntegrationFrame(
custom_integration=True,
_frame=mock_integration_frame,
frame=mock_integration_frame,
integration="test_integration_frame",
module="custom_components.test_integration_frame",
relative_filename="custom_components/test_integration_frame/__init__.py",
Expand Down Expand Up @@ -1969,7 +1969,7 @@ async def test_hass_helpers_use_reported(
"""Test that use of hass.components is reported."""
integration_frame = frame.IntegrationFrame(
custom_integration=True,
_frame=mock_integration_frame,
frame=mock_integration_frame,
integration="test_integration_frame",
module="custom_components.test_integration_frame",
relative_filename="custom_components/test_integration_frame/__init__.py",
Expand Down
11 changes: 11 additions & 0 deletions tests/util/test_loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ async def test_raise_for_blocking_call_async_non_strict_core(
"""Test non_strict_core raise_for_blocking_call detects from event loop without integration context."""
haloop.raise_for_blocking_call(banned_function, strict_core=False)
assert "Detected blocking call to banned_function" in caplog.text
assert "Traceback (most recent call last)" in caplog.text


async def test_raise_for_blocking_call_async_integration(
Expand Down Expand Up @@ -130,6 +131,11 @@ async def test_raise_for_blocking_call_async_integration_non_strict(
"please create a bug report at https://github.com/home-assistant/core/issues?"
"q=is%3Aopen+is%3Aissue+label%3A%22integration%3A+hue%22" in caplog.text
)
assert "Traceback (most recent call last)" in caplog.text
assert (
'File "/home/paulus/homeassistant/components/hue/light.py", line 23'
in caplog.text
)


async def test_raise_for_blocking_call_async_custom(
Expand Down Expand Up @@ -182,6 +188,11 @@ async def test_raise_for_blocking_call_async_custom(
"please create a bug report at https://github.com/home-assistant/core/issues?"
"q=is%3Aopen+is%3Aissue+label%3A%22integration%3A+hue%22"
) in caplog.text
assert "Traceback (most recent call last)" in caplog.text
assert (
'File "/home/paulus/config/custom_components/hue/light.py", line 23'
in caplog.text
)


async def test_raise_for_blocking_call_sync(
Expand Down

0 comments on commit 8f94205

Please sign in to comment.