mirror of
https://github.com/home-assistant/core.git
synced 2025-12-24 12:59:34 +00:00
Further integration load cleanups (#23104)
* Further integration load cleanups * Fix tests * Unflake MQTT vacuum command test
This commit is contained in:
@@ -22,8 +22,6 @@ from typing import (
|
||||
Dict
|
||||
)
|
||||
|
||||
from homeassistant.const import PLATFORM_FORMAT
|
||||
|
||||
# Typing imports that create a circular dependency
|
||||
# pylint: disable=using-constant-test,unused-import
|
||||
if TYPE_CHECKING:
|
||||
@@ -38,7 +36,7 @@ DEPENDENCY_BLACKLIST = {'config'}
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
DATA_KEY = 'components'
|
||||
DATA_COMPONENTS = 'components'
|
||||
DATA_INTEGRATIONS = 'integrations'
|
||||
PACKAGE_CUSTOM_COMPONENTS = 'custom_components'
|
||||
PACKAGE_BUILTIN = 'homeassistant.components'
|
||||
@@ -117,14 +115,14 @@ class Integration:
|
||||
|
||||
def get_component(self) -> ModuleType:
|
||||
"""Return the component."""
|
||||
cache = self.hass.data.setdefault(DATA_KEY, {})
|
||||
cache = self.hass.data.setdefault(DATA_COMPONENTS, {})
|
||||
if self.domain not in cache:
|
||||
cache[self.domain] = importlib.import_module(self.pkg_path)
|
||||
return cache[self.domain] # type: ignore
|
||||
|
||||
def get_platform(self, platform_name: str) -> ModuleType:
|
||||
"""Return a platform for an integration."""
|
||||
cache = self.hass.data.setdefault(DATA_KEY, {})
|
||||
cache = self.hass.data.setdefault(DATA_COMPONENTS, {})
|
||||
full_name = "{}.{}".format(self.domain, platform_name)
|
||||
if full_name not in cache:
|
||||
cache[full_name] = importlib.import_module(
|
||||
@@ -212,68 +210,6 @@ class CircularDependency(LoaderError):
|
||||
self.to_domain = to_domain
|
||||
|
||||
|
||||
def set_component(hass, # type: HomeAssistant
|
||||
comp_name: str, component: Optional[ModuleType]) -> None:
|
||||
"""Set a component in the cache.
|
||||
|
||||
Async friendly.
|
||||
"""
|
||||
cache = hass.data.setdefault(DATA_KEY, {})
|
||||
cache[comp_name] = component
|
||||
|
||||
|
||||
def get_platform(hass, # type: HomeAssistant
|
||||
domain: str, platform_name: str) -> Optional[ModuleType]:
|
||||
"""Try to load specified platform.
|
||||
|
||||
Example invocation: get_platform(hass, 'light', 'hue')
|
||||
|
||||
Async friendly.
|
||||
"""
|
||||
# If the platform has a component, we will limit the platform loading path
|
||||
# to be the same source (custom/built-in).
|
||||
component = _load_file(hass, platform_name, LOOKUP_PATHS)
|
||||
|
||||
# Until we have moved all platforms under their component/own folder, it
|
||||
# can be that the component is None.
|
||||
if component is not None:
|
||||
base_paths = [component.__name__.rsplit('.', 1)[0]]
|
||||
else:
|
||||
base_paths = LOOKUP_PATHS
|
||||
|
||||
platform = _load_file(
|
||||
hass, PLATFORM_FORMAT.format(domain=domain, platform=platform_name),
|
||||
base_paths)
|
||||
|
||||
if platform is not None:
|
||||
return platform
|
||||
|
||||
# Legacy platform check for custom: custom_components/light/hue.py
|
||||
# Only check if the component was also in custom components.
|
||||
if component is None or base_paths[0] == PACKAGE_CUSTOM_COMPONENTS:
|
||||
platform = _load_file(
|
||||
hass,
|
||||
PLATFORM_FORMAT.format(domain=platform_name, platform=domain),
|
||||
[PACKAGE_CUSTOM_COMPONENTS]
|
||||
)
|
||||
|
||||
if platform is None:
|
||||
if component is None:
|
||||
extra = ""
|
||||
else:
|
||||
extra = " Search path was limited to path of component: {}".format(
|
||||
base_paths[0])
|
||||
_LOGGER.error("Unable to find platform %s.%s", platform_name, extra)
|
||||
return None
|
||||
|
||||
_LOGGER.error(
|
||||
"Integrations need to be in their own folder. Change %s/%s.py to "
|
||||
"%s/%s.py. This will stop working soon.",
|
||||
domain, platform_name, platform_name, domain)
|
||||
|
||||
return platform
|
||||
|
||||
|
||||
def get_component(hass, # type: HomeAssistant
|
||||
comp_or_platform: str) -> Optional[ModuleType]:
|
||||
"""Try to load specified component.
|
||||
@@ -298,15 +234,15 @@ def _load_file(hass, # type: HomeAssistant
|
||||
Async friendly.
|
||||
"""
|
||||
try:
|
||||
return hass.data[DATA_KEY][comp_or_platform] # type: ignore
|
||||
return hass.data[DATA_COMPONENTS][comp_or_platform] # type: ignore
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
cache = hass.data.get(DATA_KEY)
|
||||
cache = hass.data.get(DATA_COMPONENTS)
|
||||
if cache is None:
|
||||
if not _async_mount_config_dir(hass):
|
||||
return None
|
||||
cache = hass.data[DATA_KEY] = {}
|
||||
cache = hass.data[DATA_COMPONENTS] = {}
|
||||
|
||||
for path in ('{}.{}'.format(base, comp_or_platform)
|
||||
for base in base_paths):
|
||||
@@ -392,9 +328,18 @@ class Components:
|
||||
|
||||
def __getattr__(self, comp_name: str) -> ModuleWrapper:
|
||||
"""Fetch a component."""
|
||||
component = get_component(self._hass, comp_name)
|
||||
# Test integration cache
|
||||
integration = self._hass.data.get(DATA_INTEGRATIONS, {}).get(comp_name)
|
||||
|
||||
if integration:
|
||||
component = integration.get_component()
|
||||
else:
|
||||
# Fallback to importing old-school
|
||||
component = _load_file(self._hass, comp_name, LOOKUP_PATHS)
|
||||
|
||||
if component is None:
|
||||
raise ImportError('Unable to load {}'.format(comp_name))
|
||||
|
||||
wrapped = ModuleWrapper(self._hass, component)
|
||||
setattr(self, comp_name, wrapped)
|
||||
return wrapped
|
||||
|
||||
Reference in New Issue
Block a user