Catch all exceptions on import component/platform (#64930)
parent
a24f79434f
commit
24546dfdf9
|
@ -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."""
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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", {})
|
||||
|
||||
|
|
Loading…
Reference in New Issue