Catch all exceptions on import component/platform (#64930)

pull/64956/head
Paulus Schoutsen 2022-01-25 20:39:32 -08:00 committed by GitHub
parent a24f79434f
commit 24546dfdf9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 48 additions and 10 deletions

View File

@ -539,18 +539,44 @@ class Integration:
def get_component(self) -> ModuleType:
"""Return the component."""
cache = self.hass.data.setdefault(DATA_COMPONENTS, {})
if self.domain not in cache:
cache: dict[str, ModuleType] = self.hass.data.setdefault(DATA_COMPONENTS, {})
if self.domain in cache:
return cache[self.domain]
try:
cache[self.domain] = importlib.import_module(self.pkg_path)
return cache[self.domain] # type: ignore
except ImportError:
raise
except Exception as err:
_LOGGER.exception(
"Unexpected exception importing component %s", self.pkg_path
)
raise ImportError(f"Exception importing {self.pkg_path}") from err
return cache[self.domain]
def get_platform(self, platform_name: str) -> ModuleType:
"""Return a platform for an integration."""
cache = self.hass.data.setdefault(DATA_COMPONENTS, {})
cache: dict[str, ModuleType] = self.hass.data.setdefault(DATA_COMPONENTS, {})
full_name = f"{self.domain}.{platform_name}"
if full_name not in cache:
if full_name in cache:
return cache[full_name]
try:
cache[full_name] = self._import_platform(platform_name)
return cache[full_name] # type: ignore
except ImportError:
raise
except Exception as err:
_LOGGER.exception(
"Unexpected exception importing platform %s.%s",
self.pkg_path,
platform_name,
)
raise ImportError(
f"Exception importing {self.pkg_path}.{platform_name}"
) from err
return cache[full_name]
def _import_platform(self, platform_name: str) -> ModuleType:
"""Import the platform."""

View File

@ -181,9 +181,6 @@ async def _async_setup_component(
except ImportError as err:
log_error(f"Unable to import component: {err}", integration.documentation)
return False
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Setup failed for %s: unknown error", domain)
return False
processed_config = await conf_util.async_process_component_config(
hass, config, integration

View File

@ -157,6 +157,21 @@ async def test_get_integration(hass):
assert hue_light == integration.get_platform("light")
async def test_get_integration_exceptions(hass):
"""Test resolving integration."""
integration = await loader.async_get_integration(hass, "hue")
with pytest.raises(ImportError), patch(
"homeassistant.loader.importlib.import_module", side_effect=ValueError("Boom")
):
assert hue == integration.get_component()
with pytest.raises(ImportError), patch(
"homeassistant.loader.importlib.import_module", side_effect=ValueError("Boom")
):
assert hue_light == integration.get_platform("light")
async def test_get_integration_legacy(hass, enable_custom_integrations):
"""Test resolving integration."""
integration = await loader.async_get_integration(hass, "test_embedded")

View File

@ -577,7 +577,7 @@ async def test_async_when_setup_or_start_already_loaded(hass):
async def test_setup_import_blows_up(hass):
"""Test that we handle it correctly when importing integration blows up."""
with patch(
"homeassistant.loader.Integration.get_component", side_effect=ValueError
"homeassistant.loader.Integration.get_component", side_effect=ImportError
):
assert not await setup.async_setup_component(hass, "sun", {})