1
0
mirror of https://github.com/home-assistant/core.git synced 2026-05-08 09:38:58 +01:00

Fix memory leak when importing a platform fails (#114602)

* Fix memory leak when importing a platform fails

re-raising ImportError would trigger a memory leak

* fixes, coverage

* Apply suggestions from code review
This commit is contained in:
J. Nick Koston
2024-04-01 15:36:48 -10:00
committed by GitHub
parent 0963f5e642
commit b12c69accb
2 changed files with 98 additions and 40 deletions
+83 -24
View File
@@ -274,7 +274,61 @@ async def test_get_integration_exceptions(hass: HomeAssistant) -> None:
async def test_get_platform_caches_failures_when_component_loaded(
hass: HomeAssistant,
) -> None:
"""Test get_platform cache failures only when the component is loaded."""
"""Test get_platform caches failures only when the component is loaded.
Only ModuleNotFoundError is cached, ImportError is not cached.
"""
integration = await loader.async_get_integration(hass, "hue")
with (
pytest.raises(ModuleNotFoundError),
patch(
"homeassistant.loader.importlib.import_module",
side_effect=ModuleNotFoundError("Boom"),
),
):
assert integration.get_component() == hue
with (
pytest.raises(ModuleNotFoundError),
patch(
"homeassistant.loader.importlib.import_module",
side_effect=ModuleNotFoundError("Boom"),
),
):
assert integration.get_platform("light") == hue_light
# Hue is not loaded so we should still hit the import_module path
with (
pytest.raises(ModuleNotFoundError),
patch(
"homeassistant.loader.importlib.import_module",
side_effect=ModuleNotFoundError("Boom"),
),
):
assert integration.get_platform("light") == hue_light
assert integration.get_component() == hue
# Hue is loaded so we should cache the import_module failure now
with (
pytest.raises(ModuleNotFoundError),
patch(
"homeassistant.loader.importlib.import_module",
side_effect=ModuleNotFoundError("Boom"),
),
):
assert integration.get_platform("light") == hue_light
# Hue is loaded and the last call should have cached the import_module failure
with pytest.raises(ModuleNotFoundError):
assert integration.get_platform("light") == hue_light
async def test_get_platform_only_cached_module_not_found_when_component_loaded(
hass: HomeAssistant,
) -> None:
"""Test get_platform cache only cache module not found when the component is loaded."""
integration = await loader.async_get_integration(hass, "hue")
with (
@@ -317,41 +371,43 @@ async def test_get_platform_caches_failures_when_component_loaded(
):
assert integration.get_platform("light") == hue_light
# Hue is loaded and the last call should have cached the import_module failure
with pytest.raises(ImportError):
assert integration.get_platform("light") == hue_light
# ImportError is not cached because we only cache ModuleNotFoundError
assert integration.get_platform("light") == hue_light
async def test_async_get_platform_caches_failures_when_component_loaded(
hass: HomeAssistant,
) -> None:
"""Test async_get_platform cache failures only when the component is loaded."""
"""Test async_get_platform caches failures only when the component is loaded.
Only ModuleNotFoundError is cached, ImportError is not cached.
"""
integration = await loader.async_get_integration(hass, "hue")
with (
pytest.raises(ImportError),
pytest.raises(ModuleNotFoundError),
patch(
"homeassistant.loader.importlib.import_module",
side_effect=ImportError("Boom"),
side_effect=ModuleNotFoundError("Boom"),
),
):
assert integration.get_component() == hue
with (
pytest.raises(ImportError),
pytest.raises(ModuleNotFoundError),
patch(
"homeassistant.loader.importlib.import_module",
side_effect=ImportError("Boom"),
side_effect=ModuleNotFoundError("Boom"),
),
):
assert await integration.async_get_platform("light") == hue_light
# Hue is not loaded so we should still hit the import_module path
with (
pytest.raises(ImportError),
pytest.raises(ModuleNotFoundError),
patch(
"homeassistant.loader.importlib.import_module",
side_effect=ImportError("Boom"),
side_effect=ModuleNotFoundError("Boom"),
),
):
assert await integration.async_get_platform("light") == hue_light
@@ -360,16 +416,16 @@ async def test_async_get_platform_caches_failures_when_component_loaded(
# Hue is loaded so we should cache the import_module failure now
with (
pytest.raises(ImportError),
pytest.raises(ModuleNotFoundError),
patch(
"homeassistant.loader.importlib.import_module",
side_effect=ImportError("Boom"),
side_effect=ModuleNotFoundError("Boom"),
),
):
assert await integration.async_get_platform("light") == hue_light
# Hue is loaded and the last call should have cached the import_module failure
with pytest.raises(ImportError):
with pytest.raises(ModuleNotFoundError):
assert await integration.async_get_platform("light") == hue_light
# The cache should never be filled because the import error is remembered
@@ -379,33 +435,36 @@ async def test_async_get_platform_caches_failures_when_component_loaded(
async def test_async_get_platforms_caches_failures_when_component_loaded(
hass: HomeAssistant,
) -> None:
"""Test async_get_platforms cache failures only when the component is loaded."""
"""Test async_get_platforms cache failures only when the component is loaded.
Only ModuleNotFoundError is cached, ImportError is not cached.
"""
integration = await loader.async_get_integration(hass, "hue")
with (
pytest.raises(ImportError),
pytest.raises(ModuleNotFoundError),
patch(
"homeassistant.loader.importlib.import_module",
side_effect=ImportError("Boom"),
side_effect=ModuleNotFoundError("Boom"),
),
):
assert integration.get_component() == hue
with (
pytest.raises(ImportError),
pytest.raises(ModuleNotFoundError),
patch(
"homeassistant.loader.importlib.import_module",
side_effect=ImportError("Boom"),
side_effect=ModuleNotFoundError("Boom"),
),
):
assert await integration.async_get_platforms(["light"]) == {"light": hue_light}
# Hue is not loaded so we should still hit the import_module path
with (
pytest.raises(ImportError),
pytest.raises(ModuleNotFoundError),
patch(
"homeassistant.loader.importlib.import_module",
side_effect=ImportError("Boom"),
side_effect=ModuleNotFoundError("Boom"),
),
):
assert await integration.async_get_platforms(["light"]) == {"light": hue_light}
@@ -414,16 +473,16 @@ async def test_async_get_platforms_caches_failures_when_component_loaded(
# Hue is loaded so we should cache the import_module failure now
with (
pytest.raises(ImportError),
pytest.raises(ModuleNotFoundError),
patch(
"homeassistant.loader.importlib.import_module",
side_effect=ImportError("Boom"),
side_effect=ModuleNotFoundError("Boom"),
),
):
assert await integration.async_get_platforms(["light"]) == {"light": hue_light}
# Hue is loaded and the last call should have cached the import_module failure
with pytest.raises(ImportError):
with pytest.raises(ModuleNotFoundError):
assert await integration.async_get_platforms(["light"]) == {"light": hue_light}
# The cache should never be filled because the import error is remembered