mirror of
https://github.com/home-assistant/core.git
synced 2025-04-25 09:47:52 +00:00
Improve error reporting when an integration tries to create a task in a thread (#115307)
This commit is contained in:
parent
6ed2190c29
commit
f527fd0947
@ -24,12 +24,20 @@ def create_eager_task(
|
||||
loop: AbstractEventLoop | None = None,
|
||||
) -> Task[_T]:
|
||||
"""Create a task from a coroutine and schedule it to run immediately."""
|
||||
return Task(
|
||||
coro,
|
||||
loop=loop or get_running_loop(),
|
||||
name=name,
|
||||
eager_start=True,
|
||||
)
|
||||
if not loop:
|
||||
try:
|
||||
loop = get_running_loop()
|
||||
except RuntimeError:
|
||||
# If there is no running loop, create_eager_task is being called from
|
||||
# the wrong thread.
|
||||
# Late import to avoid circular dependencies
|
||||
# pylint: disable-next=import-outside-toplevel
|
||||
from homeassistant.helpers import frame
|
||||
|
||||
frame.report("attempted to create an asyncio task from a thread")
|
||||
raise
|
||||
|
||||
return Task(coro, loop=loop, name=name, eager_start=True)
|
||||
|
||||
|
||||
def cancelling(task: Future[Any]) -> bool:
|
||||
|
@ -9,6 +9,8 @@ import pytest
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.util import async_ as hasync
|
||||
|
||||
from tests.common import extract_stack_to_frame
|
||||
|
||||
|
||||
@patch("concurrent.futures.Future")
|
||||
@patch("threading.get_ident")
|
||||
@ -123,3 +125,73 @@ async def test_create_eager_task_312(hass: HomeAssistant) -> None:
|
||||
assert events == ["eager", "normal"]
|
||||
await task1
|
||||
await task2
|
||||
|
||||
|
||||
async def test_create_eager_task_from_thread(hass: HomeAssistant) -> None:
|
||||
"""Test we report trying to create an eager task from a thread."""
|
||||
|
||||
def create_task():
|
||||
hasync.create_eager_task(asyncio.sleep(0))
|
||||
|
||||
with pytest.raises(
|
||||
RuntimeError,
|
||||
match=(
|
||||
"Detected code that attempted to create an asyncio task from a thread. Please report this issue."
|
||||
),
|
||||
):
|
||||
await hass.async_add_executor_job(create_task)
|
||||
|
||||
|
||||
async def test_create_eager_task_from_thread_in_integration(
|
||||
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
|
||||
) -> None:
|
||||
"""Test we report trying to create an eager task from a thread."""
|
||||
|
||||
def create_task():
|
||||
hasync.create_eager_task(asyncio.sleep(0))
|
||||
|
||||
frames = extract_stack_to_frame(
|
||||
[
|
||||
Mock(
|
||||
filename="/home/paulus/homeassistant/core.py",
|
||||
lineno="23",
|
||||
line="do_something()",
|
||||
),
|
||||
Mock(
|
||||
filename="/home/paulus/homeassistant/components/hue/light.py",
|
||||
lineno="23",
|
||||
line="self.light.is_on",
|
||||
),
|
||||
Mock(
|
||||
filename="/home/paulus/aiohue/lights.py",
|
||||
lineno="2",
|
||||
line="something()",
|
||||
),
|
||||
]
|
||||
)
|
||||
with (
|
||||
pytest.raises(RuntimeError, match="no running event loop"),
|
||||
patch(
|
||||
"homeassistant.helpers.frame.linecache.getline",
|
||||
return_value="self.light.is_on",
|
||||
),
|
||||
patch(
|
||||
"homeassistant.util.loop._get_line_from_cache",
|
||||
return_value="mock_line",
|
||||
),
|
||||
patch(
|
||||
"homeassistant.util.loop.get_current_frame",
|
||||
return_value=frames,
|
||||
),
|
||||
patch(
|
||||
"homeassistant.helpers.frame.get_current_frame",
|
||||
return_value=frames,
|
||||
),
|
||||
):
|
||||
await hass.async_add_executor_job(create_task)
|
||||
|
||||
assert (
|
||||
"Detected that integration 'hue' attempted to create an asyncio task "
|
||||
"from a thread at homeassistant/components/hue/light.py, line 23: "
|
||||
"self.light.is_on"
|
||||
) in caplog.text
|
||||
|
Loading…
x
Reference in New Issue
Block a user