Load integrations with requirements in device_automation (#33714)

* Load integrations with requirements in device_automation

- Split cached loader behavior out of async_get_integration
- Use cached loader for both async_get_integration and
  async_get_integration_with_requirements
- Use async_get_integration_with_requirements for device_automation

resolves #33104

* Duplicate caching logic in requirements, remove loader mods

* Update homeassistant/requirements.py

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
This commit is contained in:
Jason Cheatham 2020-04-08 14:42:15 -04:00 committed by GitHub
parent 5ff50e8b4f
commit 3b246fb40a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 35 additions and 4 deletions

View File

@ -13,7 +13,8 @@ from homeassistant.const import CONF_DEVICE_ID, CONF_DOMAIN, CONF_PLATFORM
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.entity_registry import async_entries_for_device
from homeassistant.loader import IntegrationNotFound, async_get_integration
from homeassistant.loader import IntegrationNotFound
from homeassistant.requirements import async_get_integration_with_requirements
from .exceptions import DeviceNotFound, InvalidDeviceAutomationConfig
@ -80,7 +81,7 @@ async def async_get_device_automation_platform(
"""
platform_name = TYPES[automation_type][0]
try:
integration = await async_get_integration(hass, domain)
integration = await async_get_integration_with_requirements(hass, domain)
platform = integration.get_platform(platform_name)
except IntegrationNotFound:
raise InvalidDeviceAutomationConfig(f"Integration '{domain}' not found")

View File

@ -3,15 +3,21 @@ import asyncio
import logging
import os
from pathlib import Path
from typing import Any, Dict, Iterable, List, Optional, Set
from typing import Any, Dict, Iterable, List, Optional, Set, Union, cast
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.loader import Integration, async_get_integration
from homeassistant.loader import (
Integration,
IntegrationNotFound,
_async_mount_config_dir,
async_get_integration,
)
import homeassistant.util.package as pkg_util
DATA_PIP_LOCK = "pip_lock"
DATA_PKG_CACHE = "pkg_cache"
DATA_INTEGRATIONS_WITH_REQS = "integrations_with_reqs"
CONSTRAINT_FILE = "package_constraints.txt"
PROGRESS_FILE = ".pip_progress"
_LOGGER = logging.getLogger(__name__)
@ -19,6 +25,7 @@ DISCOVERY_INTEGRATIONS: Dict[str, Iterable[str]] = {
"ssdp": ("ssdp",),
"zeroconf": ("zeroconf", "homekit"),
}
_UNDEF = object()
class RequirementsNotFound(HomeAssistantError):
@ -50,6 +57,27 @@ async def async_get_integration_with_requirements(
if hass.config.skip_pip:
return integration
cache = hass.data.get(DATA_INTEGRATIONS_WITH_REQS)
if cache is None:
cache = hass.data[DATA_INTEGRATIONS_WITH_REQS] = {}
int_or_evt: Union[Integration, asyncio.Event, None] = cache.get(domain, _UNDEF)
if isinstance(int_or_evt, asyncio.Event):
await int_or_evt.wait()
int_or_evt = cache.get(domain, _UNDEF)
# When we have waited and it's _UNDEF, it doesn't exist
# We don't cache that it doesn't exist, or else people can't fix it
# and then restart, because their config will never be valid.
if int_or_evt is _UNDEF:
raise IntegrationNotFound(domain)
if int_or_evt is not _UNDEF:
return cast(Integration, int_or_evt)
event = cache[domain] = asyncio.Event()
if integration.requirements:
await async_process_requirements(
hass, integration.domain, integration.requirements
@ -77,6 +105,8 @@ async def async_get_integration_with_requirements(
]
)
cache[domain] = integration
event.set()
return integration