1
0
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:
Paulus Schoutsen
2019-04-14 19:07:05 -07:00
committed by GitHub
parent 930f75220c
commit d722f4d64a
14 changed files with 160 additions and 237 deletions

View File

@@ -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