Custom component loading cleanup (#14211)

* Clean up custom component loading

* Fix some tests

* Fix some stuff

* Make imports work again

* Fix tests

* Remove debug print

* Lint
This commit is contained in:
Paulus Schoutsen 2018-05-01 14:57:30 -04:00 committed by Pascal Vizeli
parent 5d96751168
commit 83d300fd11
50 changed files with 315 additions and 392 deletions

View File

@ -12,8 +12,7 @@ from typing import Any, Optional, Dict
import voluptuous as vol
from homeassistant import (
core, config as conf_util, config_entries, loader,
components as core_components)
core, config as conf_util, config_entries, components as core_components)
from homeassistant.components import persistent_notification
from homeassistant.const import EVENT_HOMEASSISTANT_CLOSE
from homeassistant.setup import async_setup_component
@ -103,15 +102,12 @@ async def async_from_config_dict(config: Dict[str, Any],
_LOGGER.warning("Skipping pip installation of required modules. "
"This may cause issues")
if not loader.PREPARED:
await hass.async_add_job(loader.prepare, hass)
# Make a copy because we are mutating it.
config = OrderedDict(config)
# Merge packages
conf_util.merge_packages_config(
config, core_config.get(conf_util.CONF_PACKAGES, {}))
hass, config, core_config.get(conf_util.CONF_PACKAGES, {}))
# Ensure we have no None values after merge
for key, value in config.items():

View File

@ -6,6 +6,7 @@ https://home-assistant.io/components/automation/
"""
import asyncio
from functools import partial
import importlib
import logging
import voluptuous as vol
@ -22,7 +23,6 @@ from homeassistant.helpers import extract_domain_configs, script, condition
from homeassistant.helpers.entity import ToggleEntity
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.restore_state import async_get_last_state
from homeassistant.loader import get_platform
from homeassistant.util.dt import utcnow
import homeassistant.helpers.config_validation as cv
@ -58,12 +58,14 @@ _LOGGER = logging.getLogger(__name__)
def _platform_validator(config):
"""Validate it is a valid platform."""
platform = get_platform(DOMAIN, config[CONF_PLATFORM])
try:
platform = importlib.import_module(
'homeassistant.components.automation.{}'.format(
config[CONF_PLATFORM]))
except ImportError:
raise vol.Invalid('Invalid platform specified') from None
if not hasattr(platform, 'TRIGGER_SCHEMA'):
return config
return getattr(platform, 'TRIGGER_SCHEMA')(config)
return platform.TRIGGER_SCHEMA(config)
_TRIGGER_SCHEMA = vol.All(
@ -71,7 +73,7 @@ _TRIGGER_SCHEMA = vol.All(
[
vol.All(
vol.Schema({
vol.Required(CONF_PLATFORM): cv.platform_validator(DOMAIN)
vol.Required(CONF_PLATFORM): str
}, extra=vol.ALLOW_EXTRA),
_platform_validator
),

View File

@ -11,7 +11,6 @@ import voluptuous as vol
from homeassistant.components.binary_sensor import (
BinarySensorDevice, PLATFORM_SCHEMA)
from homeassistant.const import CONF_MONITORED_CONDITIONS
from homeassistant.loader import get_component
import homeassistant.helpers.config_validation as cv
_LOGGER = logging.getLogger(__name__)
@ -31,7 +30,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the available BloomSky weather binary sensors."""
bloomsky = get_component('bloomsky')
bloomsky = hass.components.bloomsky
# Default needed in case of discovery
sensors = config.get(CONF_MONITORED_CONDITIONS, SENSOR_TYPES)

View File

@ -13,7 +13,6 @@ import voluptuous as vol
from homeassistant.components.binary_sensor import (
BinarySensorDevice, PLATFORM_SCHEMA)
from homeassistant.components.netatmo import CameraData
from homeassistant.loader import get_component
from homeassistant.const import CONF_TIMEOUT
from homeassistant.helpers import config_validation as cv
@ -61,7 +60,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the access to Netatmo binary sensor."""
netatmo = get_component('netatmo')
netatmo = hass.components.netatmo
home = config.get(CONF_HOME)
timeout = config.get(CONF_TIMEOUT)
if timeout is None:

View File

@ -7,7 +7,6 @@ https://home-assistant.io/components/binary_sensor.wemo/
import logging
from homeassistant.components.binary_sensor import BinarySensorDevice
from homeassistant.loader import get_component
DEPENDENCIES = ['wemo']
@ -25,18 +24,18 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None):
device = discovery.device_from_description(location, mac)
if device:
add_devices_callback([WemoBinarySensor(device)])
add_devices_callback([WemoBinarySensor(hass, device)])
class WemoBinarySensor(BinarySensorDevice):
"""Representation a WeMo binary sensor."""
def __init__(self, device):
def __init__(self, hass, device):
"""Initialize the WeMo sensor."""
self.wemo = device
self._state = None
wemo = get_component('wemo')
wemo = hass.components.wemo
wemo.SUBSCRIPTION_REGISTRY.register(self.wemo)
wemo.SUBSCRIPTION_REGISTRY.on(self.wemo, None, self._update_callback)

View File

@ -9,7 +9,6 @@ import logging
import requests
from homeassistant.components.camera import Camera
from homeassistant.loader import get_component
DEPENDENCIES = ['bloomsky']
@ -17,7 +16,7 @@ DEPENDENCIES = ['bloomsky']
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up access to BloomSky cameras."""
bloomsky = get_component('bloomsky')
bloomsky = hass.components.bloomsky
for device in bloomsky.BLOOMSKY.devices.values():
add_devices([BloomSkyCamera(bloomsky.BLOOMSKY, device)])

View File

@ -12,7 +12,6 @@ import voluptuous as vol
from homeassistant.const import CONF_VERIFY_SSL
from homeassistant.components.netatmo import CameraData
from homeassistant.components.camera import (Camera, PLATFORM_SCHEMA)
from homeassistant.loader import get_component
from homeassistant.helpers import config_validation as cv
DEPENDENCIES = ['netatmo']
@ -33,7 +32,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up access to Netatmo cameras."""
netatmo = get_component('netatmo')
netatmo = hass.components.netatmo
home = config.get(CONF_HOME)
verify_ssl = config.get(CONF_VERIFY_SSL, True)
import lnetatmo

View File

@ -13,7 +13,6 @@ from homeassistant.components.climate import (
STATE_HEAT, STATE_IDLE, ClimateDevice, PLATFORM_SCHEMA,
SUPPORT_TARGET_TEMPERATURE, SUPPORT_OPERATION_MODE, SUPPORT_AWAY_MODE)
from homeassistant.util import Throttle
from homeassistant.loader import get_component
import homeassistant.helpers.config_validation as cv
DEPENDENCIES = ['netatmo']
@ -42,7 +41,7 @@ SUPPORT_FLAGS = (SUPPORT_TARGET_TEMPERATURE | SUPPORT_OPERATION_MODE |
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the NetAtmo Thermostat."""
netatmo = get_component('netatmo')
netatmo = hass.components.netatmo
device = config.get(CONF_RELAY)
import lnetatmo

View File

@ -16,7 +16,6 @@ from homeassistant.const import STATE_HOME, STATE_NOT_HOME
from homeassistant.helpers.event import (
async_track_point_in_utc_time, async_track_state_change)
from homeassistant.helpers.sun import is_up, get_astral_event_next
from homeassistant.loader import get_component
import homeassistant.helpers.config_validation as cv
DOMAIN = 'device_sun_light_trigger'
@ -48,9 +47,9 @@ CONFIG_SCHEMA = vol.Schema({
def async_setup(hass, config):
"""Set up the triggers to control lights based on device presence."""
logger = logging.getLogger(__name__)
device_tracker = get_component('device_tracker')
group = get_component('group')
light = get_component('light')
device_tracker = hass.components.device_tracker
group = hass.components.group
light = hass.components.light
conf = config[DOMAIN]
disable_turn_off = conf.get(CONF_DISABLE_TURN_OFF)
light_group = conf.get(CONF_LIGHT_GROUP, light.ENTITY_ID_ALL_LIGHTS)
@ -58,14 +57,14 @@ def async_setup(hass, config):
device_group = conf.get(
CONF_DEVICE_GROUP, device_tracker.ENTITY_ID_ALL_DEVICES)
device_entity_ids = group.get_entity_ids(
hass, device_group, device_tracker.DOMAIN)
device_group, device_tracker.DOMAIN)
if not device_entity_ids:
logger.error("No devices found to track")
return False
# Get the light IDs from the specified group
light_ids = group.get_entity_ids(hass, light_group, light.DOMAIN)
light_ids = group.get_entity_ids(light_group, light.DOMAIN)
if not light_ids:
logger.error("No lights found to turn on")
@ -85,9 +84,9 @@ def async_setup(hass, config):
def async_turn_on_before_sunset(light_id):
"""Turn on lights."""
if not device_tracker.is_on(hass) or light.is_on(hass, light_id):
if not device_tracker.is_on() or light.is_on(light_id):
return
light.async_turn_on(hass, light_id,
light.async_turn_on(light_id,
transition=LIGHT_TRANSITION_TIME.seconds,
profile=light_profile)
@ -129,7 +128,7 @@ def async_setup(hass, config):
@callback
def check_light_on_dev_state_change(entity, old_state, new_state):
"""Handle tracked device state changes."""
lights_are_on = group.is_on(hass, light_group)
lights_are_on = group.is_on(light_group)
light_needed = not (lights_are_on or is_up(hass))
# These variables are needed for the elif check
@ -139,7 +138,7 @@ def async_setup(hass, config):
# Do we need lights?
if light_needed:
logger.info("Home coming event for %s. Turning lights on", entity)
light.async_turn_on(hass, light_ids, profile=light_profile)
light.async_turn_on(light_ids, profile=light_profile)
# Are we in the time span were we would turn on the lights
# if someone would be home?
@ -152,7 +151,7 @@ def async_setup(hass, config):
# when the fading in started and turn it on if so
for index, light_id in enumerate(light_ids):
if now > start_point + index * LIGHT_TRANSITION_TIME:
light.async_turn_on(hass, light_id)
light.async_turn_on(light_id)
else:
# If this light didn't happen to be turned on yet so
@ -169,12 +168,12 @@ def async_setup(hass, config):
@callback
def turn_off_lights_when_all_leave(entity, old_state, new_state):
"""Handle device group state change."""
if not group.is_on(hass, light_group):
if not group.is_on(light_group):
return
logger.info(
"Everyone has left but there are lights on. Turning them off")
light.async_turn_off(hass, light_ids)
light.async_turn_off(light_ids)
async_track_state_change(
hass, device_group, turn_off_lights_when_all_leave,

View File

@ -24,7 +24,6 @@ from homeassistant.helpers.event import async_track_time_interval
from homeassistant.helpers.restore_state import async_get_last_state
from homeassistant.helpers.typing import GPSType, ConfigType, HomeAssistantType
import homeassistant.helpers.config_validation as cv
from homeassistant.loader import get_component
import homeassistant.util as util
from homeassistant.util.async_ import run_coroutine_threadsafe
import homeassistant.util.dt as dt_util
@ -322,7 +321,7 @@ class DeviceTracker(object):
# During init, we ignore the group
if self.group and self.track_new:
self.group.async_set_group(
self.hass, util.slugify(GROUP_NAME_ALL_DEVICES), visible=False,
util.slugify(GROUP_NAME_ALL_DEVICES), visible=False,
name=GROUP_NAME_ALL_DEVICES, add=[device.entity_id])
self.hass.bus.async_fire(EVENT_NEW_DEVICE, {
@ -357,9 +356,9 @@ class DeviceTracker(object):
entity_ids = [dev.entity_id for dev in self.devices.values()
if dev.track]
self.group = get_component('group')
self.group = self.hass.components.group
self.group.async_set_group(
self.hass, util.slugify(GROUP_NAME_ALL_DEVICES), visible=False,
util.slugify(GROUP_NAME_ALL_DEVICES), visible=False,
name=GROUP_NAME_ALL_DEVICES, entity_ids=entity_ids)
@callback

View File

@ -17,7 +17,6 @@ from homeassistant.exceptions import HomeAssistantError
from homeassistant.loader import bind_hass
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.loader import get_component
_LOGGER = logging.getLogger(__name__)
@ -121,12 +120,12 @@ class ImageProcessingEntity(Entity):
This method is a coroutine.
"""
camera = get_component('camera')
camera = self.hass.components.camera
image = None
try:
image = yield from camera.async_get_image(
self.hass, self.camera_entity, timeout=self.timeout)
self.camera_entity, timeout=self.timeout)
except HomeAssistantError as err:
_LOGGER.error("Error on receive image from entity: %s", err)

View File

@ -12,7 +12,6 @@ import homeassistant.util as util
from homeassistant.components.light import (
Light, ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_HS_COLOR, ATTR_TRANSITION,
SUPPORT_BRIGHTNESS, SUPPORT_COLOR_TEMP, SUPPORT_COLOR, SUPPORT_TRANSITION)
from homeassistant.loader import get_component
import homeassistant.util.color as color_util
DEPENDENCIES = ['wemo']
@ -151,7 +150,7 @@ class WemoDimmer(Light):
@asyncio.coroutine
def async_added_to_hass(self):
"""Register update callback."""
wemo = get_component('wemo')
wemo = self.hass.components.wemo
# The register method uses a threading condition, so call via executor.
# and yield from to wait until the task is done.
yield from self.hass.async_add_job(

View File

@ -18,7 +18,6 @@ from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity
from homeassistant.loader import get_component
from homeassistant.util import slugify
_LOGGER = logging.getLogger(__name__)
@ -231,7 +230,7 @@ def async_setup(hass, config):
p_id = face.store[g_id].get(service.data[ATTR_PERSON])
camera_entity = service.data[ATTR_CAMERA_ENTITY]
camera = get_component('camera')
camera = hass.components.camera
try:
image = yield from camera.async_get_image(hass, camera_entity)

View File

@ -10,7 +10,6 @@ import json
import voluptuous as vol
from homeassistant.core import callback
import homeassistant.loader as loader
from homeassistant.components.mqtt import (
valid_publish_topic, valid_subscribe_topic)
from homeassistant.const import (
@ -42,7 +41,7 @@ CONFIG_SCHEMA = vol.Schema({
@asyncio.coroutine
def async_setup(hass, config):
"""Set up the MQTT eventstream component."""
mqtt = loader.get_component('mqtt')
mqtt = hass.components.mqtt
conf = config.get(DOMAIN, {})
pub_topic = conf.get(CONF_PUBLISH_TOPIC)
sub_topic = conf.get(CONF_SUBSCRIBE_TOPIC)
@ -82,7 +81,7 @@ def async_setup(hass, config):
event_info = {'event_type': event.event_type, 'event_data': event.data}
msg = json.dumps(event_info, cls=JSONEncoder)
mqtt.async_publish(hass, pub_topic, msg)
mqtt.async_publish(pub_topic, msg)
# Only listen for local events if you are going to publish them.
if pub_topic:
@ -115,7 +114,7 @@ def async_setup(hass, config):
# Only subscribe if you specified a topic.
if sub_topic:
yield from mqtt.async_subscribe(hass, sub_topic, _event_receiver)
yield from mqtt.async_subscribe(sub_topic, _event_receiver)
hass.states.async_set('{domain}.initialized'.format(domain=DOMAIN), True)
return True

View File

@ -24,7 +24,6 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.dispatcher import (
async_dispatcher_connect, dispatcher_send)
from homeassistant.helpers.entity import Entity
from homeassistant.loader import get_component
from homeassistant.setup import setup_component
REQUIREMENTS = ['pymysensors==0.11.1']
@ -294,16 +293,16 @@ def setup(hass, config):
if device == MQTT_COMPONENT:
if not setup_component(hass, MQTT_COMPONENT, config):
return
mqtt = get_component(MQTT_COMPONENT)
mqtt = hass.components.mqtt
retain = config[DOMAIN].get(CONF_RETAIN)
def pub_callback(topic, payload, qos, retain):
"""Call MQTT publish function."""
mqtt.publish(hass, topic, payload, qos, retain)
mqtt.publish(topic, payload, qos, retain)
def sub_callback(topic, sub_cb, qos):
"""Call MQTT subscribe function."""
mqtt.subscribe(hass, topic, sub_cb, qos)
mqtt.subscribe(topic, sub_cb, qos)
gateway = mysensors.MQTTGateway(
pub_callback, sub_callback,
event_callback=None, persistence=persistence,

View File

@ -5,6 +5,7 @@ For more details about this component, please refer to the documentation at
https://home-assistant.io/components/scene/
"""
import asyncio
import importlib
import logging
import voluptuous as vol
@ -16,7 +17,6 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.state import HASS_DOMAIN
from homeassistant.loader import get_platform
DOMAIN = 'scene'
STATE = 'scening'
@ -34,20 +34,24 @@ def _hass_domain_validator(config):
def _platform_validator(config):
"""Validate it is a valid platform."""
p_name = config[CONF_PLATFORM]
platform = get_platform(DOMAIN, p_name)
try:
platform = importlib.import_module(
'homeassistant.components.scene.{}'.format(
config[CONF_PLATFORM]))
except ImportError:
raise vol.Invalid('Invalid platform specified') from None
if not hasattr(platform, 'PLATFORM_SCHEMA'):
return config
return getattr(platform, 'PLATFORM_SCHEMA')(config)
return platform.PLATFORM_SCHEMA(config)
PLATFORM_SCHEMA = vol.Schema(
vol.All(
_hass_domain_validator,
vol.Schema({
vol.Required(CONF_PLATFORM): cv.platform_validator(DOMAIN)
vol.Required(CONF_PLATFORM): str
}, extra=vol.ALLOW_EXTRA),
_platform_validator
), extra=vol.ALLOW_EXTRA)

View File

@ -11,7 +11,6 @@ import voluptuous as vol
from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import (TEMP_FAHRENHEIT, CONF_MONITORED_CONDITIONS)
from homeassistant.helpers.entity import Entity
from homeassistant.loader import get_component
import homeassistant.helpers.config_validation as cv
_LOGGER = logging.getLogger(__name__)
@ -45,7 +44,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
# pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the available BloomSky weather sensors."""
bloomsky = get_component('bloomsky')
bloomsky = hass.components.bloomsky
# Default needed in case of discovery
sensors = config.get(CONF_MONITORED_CONDITIONS, SENSOR_TYPES)

View File

@ -13,7 +13,6 @@ from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import TEMP_CELSIUS, STATE_UNKNOWN
from homeassistant.helpers.entity import Entity
from homeassistant.util import Throttle
from homeassistant.loader import get_component
import homeassistant.helpers.config_validation as cv
_LOGGER = logging.getLogger(__name__)
@ -64,7 +63,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the available Netatmo weather sensors."""
netatmo = get_component('netatmo')
netatmo = hass.components.netatmo
data = NetAtmoData(netatmo.NETATMO_AUTH, config.get(CONF_STATION, None))
dev = []

View File

@ -788,7 +788,7 @@ class ZWaveDeviceEntityValues():
if polling_intensity:
self.primary.enable_poll(polling_intensity)
platform = get_platform(component, DOMAIN)
platform = get_platform(self._hass, component, DOMAIN)
device = platform.get_device(
node=self._node, values=self,
node_config=node_config, hass=self._hass)

View File

@ -548,7 +548,8 @@ def _identify_config_schema(module):
return '', schema
def merge_packages_config(config, packages, _log_pkg_error=_log_pkg_error):
def merge_packages_config(hass, config, packages,
_log_pkg_error=_log_pkg_error):
"""Merge packages into the top-level configuration. Mutate config."""
# pylint: disable=too-many-nested-blocks
PACKAGES_CONFIG_SCHEMA(packages)
@ -556,7 +557,7 @@ def merge_packages_config(config, packages, _log_pkg_error=_log_pkg_error):
for comp_name, comp_conf in pack_conf.items():
if comp_name == CONF_CORE:
continue
component = get_component(comp_name)
component = get_component(hass, comp_name)
if component is None:
_log_pkg_error(pack_name, comp_name, config, "does not exist")
@ -625,7 +626,7 @@ def async_process_component_config(hass, config, domain):
This method must be run in the event loop.
"""
component = get_component(domain)
component = get_component(hass, domain)
if hasattr(component, 'CONFIG_SCHEMA'):
try:
@ -651,7 +652,7 @@ def async_process_component_config(hass, config, domain):
platforms.append(p_validated)
continue
platform = get_platform(domain, p_name)
platform = get_platform(hass, domain, p_name)
if platform is None:
continue

View File

@ -12,7 +12,6 @@ from typing import Any, Union, TypeVar, Callable, Sequence, Dict
import voluptuous as vol
from homeassistant.loader import get_platform
from homeassistant.const import (
CONF_PLATFORM, CONF_SCAN_INTERVAL, TEMP_CELSIUS, TEMP_FAHRENHEIT,
CONF_ALIAS, CONF_ENTITY_ID, CONF_VALUE_TEMPLATE, WEEKDAYS,
@ -283,19 +282,6 @@ def match_all(value):
return value
def platform_validator(domain):
"""Validate if platform exists for given domain."""
def validator(value):
"""Test if platform exists."""
if value is None:
raise vol.Invalid('platform cannot be None')
if get_platform(domain, str(value)):
return value
raise vol.Invalid(
'platform {} does not exist for {}'.format(value, domain))
return validator
def positive_timedelta(value: timedelta) -> timedelta:
"""Validate timedelta is positive."""
if value < timedelta(0):

View File

@ -92,7 +92,7 @@ def extract_entity_ids(hass, service_call, expand_group=True):
if not (service_call.data and ATTR_ENTITY_ID in service_call.data):
return []
group = get_component('group')
group = hass.components.group
# Entity ID attr can be a list or a string
service_ent_id = service_call.data[ATTR_ENTITY_ID]
@ -100,10 +100,10 @@ def extract_entity_ids(hass, service_call, expand_group=True):
if expand_group:
if isinstance(service_ent_id, str):
return group.expand_entity_ids(hass, [service_ent_id])
return group.expand_entity_ids([service_ent_id])
return [ent_id for ent_id in
group.expand_entity_ids(hass, service_ent_id)]
group.expand_entity_ids(service_ent_id)]
else:
@ -128,7 +128,7 @@ async def async_get_all_descriptions(hass):
import homeassistant.components as components
component_path = path.dirname(components.__file__)
else:
component_path = path.dirname(get_component(domain).__file__)
component_path = path.dirname(get_component(hass, domain).__file__)
return path.join(component_path, 'services.yaml')
def load_services_files(yaml_files):

View File

@ -16,7 +16,7 @@ from homeassistant.const import (
from homeassistant.core import State, valid_entity_id
from homeassistant.exceptions import TemplateError
from homeassistant.helpers import location as loc_helper
from homeassistant.loader import bind_hass, get_component
from homeassistant.loader import bind_hass
from homeassistant.util import convert
from homeassistant.util import dt as dt_util
from homeassistant.util import location as loc_util
@ -349,10 +349,10 @@ class TemplateMethods(object):
else:
gr_entity_id = str(entities)
group = get_component('group')
group = self._hass.components.group
states = [self._hass.states.get(entity_id) for entity_id
in group.expand_entity_ids(self._hass, [gr_entity_id])]
in group.expand_entity_ids([gr_entity_id])]
return _wrap_state(loc_helper.closest(latitude, longitude, states))

View File

@ -30,14 +30,14 @@ def flatten(data):
return recursive_flatten('', data)
def component_translation_file(component, language):
def component_translation_file(hass, component, language):
"""Return the translation json file location for a component."""
if '.' in component:
name = component.split('.', 1)[1]
else:
name = component
module = get_component(component)
module = get_component(hass, component)
component_path = path.dirname(module.__file__)
# If loading translations for the package root, (__init__.py), the
@ -97,7 +97,7 @@ async def async_get_component_resources(hass, language):
missing_files = {}
for component in missing_components:
missing_files[component] = component_translation_file(
component, language)
hass, component, language)
# Load missing files
if missing_files:

View File

@ -6,15 +6,13 @@ documentation as possible to keep it understandable.
Components can be accessed via hass.components.switch from your code.
If you want to retrieve a platform that is part of a component, you should
call get_component('switch.your_platform'). In both cases the config directory
is checked to see if it contains a user provided version. If not available it
will check the built-in components and platforms.
call get_component(hass, 'switch.your_platform'). In both cases the config
directory is checked to see if it contains a user provided version. If not
available it will check the built-in components and platforms.
"""
import functools as ft
import importlib
import logging
import os
import pkgutil
import sys
from types import ModuleType
@ -42,135 +40,94 @@ _COMPONENT_CACHE = {} # type: Dict[str, ModuleType]
_LOGGER = logging.getLogger(__name__)
def prepare(hass: 'HomeAssistant'):
"""Prepare the loading of components.
This method needs to run in an executor.
"""
global PREPARED # pylint: disable=global-statement
# Load the built-in components
import homeassistant.components as components
AVAILABLE_COMPONENTS.clear()
AVAILABLE_COMPONENTS.extend(
item[1] for item in
pkgutil.iter_modules(components.__path__, 'homeassistant.components.'))
# Look for available custom components
custom_path = hass.config.path("custom_components")
if os.path.isdir(custom_path):
# Ensure we can load custom components using Pythons import
sys.path.insert(0, hass.config.config_dir)
# We cannot use the same approach as for built-in components because
# custom components might only contain a platform for a component.
# ie custom_components/switch/some_platform.py. Using pkgutil would
# not give us the switch component (and neither should it).
# Assumption: the custom_components dir only contains directories or
# python components. If this assumption is not true, HA won't break,
# just might output more errors.
for fil in os.listdir(custom_path):
if fil == '__pycache__':
continue
elif os.path.isdir(os.path.join(custom_path, fil)):
AVAILABLE_COMPONENTS.append('custom_components.{}'.format(fil))
else:
# For files we will strip out .py extension
AVAILABLE_COMPONENTS.append(
'custom_components.{}'.format(fil[0:-3]))
PREPARED = True
DATA_KEY = 'components'
PATH_CUSTOM_COMPONENTS = 'custom_components'
PACKAGE_COMPONENTS = 'homeassistant.components'
def set_component(comp_name: str, component: ModuleType) -> None:
def set_component(hass, comp_name: str, component: ModuleType) -> None:
"""Set a component in the cache.
Async friendly.
"""
_check_prepared()
_COMPONENT_CACHE[comp_name] = component
cache = hass.data.get(DATA_KEY)
if cache is None:
cache = hass.data[DATA_KEY] = {}
cache[comp_name] = component
def get_platform(domain: str, platform: str) -> Optional[ModuleType]:
def get_platform(hass, domain: str, platform: str) -> Optional[ModuleType]:
"""Try to load specified platform.
Async friendly.
"""
return get_component(PLATFORM_FORMAT.format(domain, platform))
return get_component(hass, PLATFORM_FORMAT.format(domain, platform))
def get_component(comp_name) -> Optional[ModuleType]:
"""Try to load specified component.
def get_component(hass, comp_or_platform):
"""Load a module from either custom component or built-in."""
try:
return hass.data[DATA_KEY][comp_or_platform]
except KeyError:
pass
Looks in config dir first, then built-in components.
Only returns it if also found to be valid.
Async friendly.
"""
if comp_name in _COMPONENT_CACHE:
return _COMPONENT_CACHE[comp_name]
_check_prepared()
# If we ie. try to load custom_components.switch.wemo but the parent
# custom_components.switch does not exist, importing it will trigger
# an exception because it will try to import the parent.
# Because of this behavior, we will approach loading sub components
# with caution: only load it if we can verify that the parent exists.
# We do not want to silent the ImportErrors as they provide valuable
# information to track down when debugging Home Assistant.
# First check custom, then built-in
potential_paths = ['custom_components.{}'.format(comp_name),
'homeassistant.components.{}'.format(comp_name)]
for path in potential_paths:
# Validate here that root component exists
# If path contains a '.' we are specifying a sub-component
# Using rsplit we get the parent component from sub-component
root_comp = path.rsplit(".", 1)[0] if '.' in comp_name else path
if root_comp not in AVAILABLE_COMPONENTS:
continue
# Try custom component
module = _load_module(hass.config.path(PATH_CUSTOM_COMPONENTS),
comp_or_platform)
if module is None:
try:
module = importlib.import_module(path)
module = importlib.import_module(
'{}.{}'.format(PACKAGE_COMPONENTS, comp_or_platform))
except ImportError:
module = None
# In Python 3 you can import files from directories that do not
# contain the file __init__.py. A directory is a valid module if
# it contains a file with the .py extension. In this case Python
# will succeed in importing the directory as a module and call it
# a namespace. We do not care about namespaces.
# This prevents that when only
# custom_components/switch/some_platform.py exists,
# the import custom_components.switch would succeed.
if module.__spec__.origin == 'namespace':
continue
cache = hass.data.get(DATA_KEY)
if cache is None:
cache = hass.data[DATA_KEY] = {}
cache[comp_or_platform] = module
_LOGGER.info("Loaded %s from %s", comp_name, path)
return module
_COMPONENT_CACHE[comp_name] = module
return module
except ImportError as err:
# This error happens if for example custom_components/switch
# exists and we try to load switch.demo.
if str(err) != "No module named '{}'".format(path):
_LOGGER.exception(
("Error loading %s. Make sure all "
"dependencies are installed"), path)
_LOGGER.error("Unable to find component %s", comp_name)
def _find_spec(path, name):
for finder in sys.meta_path:
try:
spec = finder.find_spec(name, path=path)
if spec is not None:
return spec
except AttributeError:
# Not all finders have the find_spec method
pass
return None
def _load_module(path, name):
"""Load a module based on a folder and a name."""
spec = _find_spec([path], name)
# Special handling if loading platforms and the folder is a namespace
# (namespace is a folder without __init__.py)
if spec is None and '.' in name:
parent_spec = _find_spec([path], name.split('.')[0])
if (parent_spec is None or
parent_spec.submodule_search_locations is None):
return None
spec = _find_spec(parent_spec.submodule_search_locations, name)
# Not found
if spec is None:
return None
# This is a namespace
if spec.loader is None:
return None
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
class Components:
"""Helper to load components."""
@ -180,7 +137,7 @@ class Components:
def __getattr__(self, comp_name):
"""Fetch a component."""
component = get_component(comp_name)
component = get_component(self._hass, comp_name)
if component is None:
raise ImportError('Unable to load {}'.format(comp_name))
wrapped = ModuleWrapper(self._hass, component)
@ -230,7 +187,7 @@ def bind_hass(func):
return func
def load_order_component(comp_name: str) -> OrderedSet:
def load_order_component(hass, comp_name: str) -> OrderedSet:
"""Return an OrderedSet of components in the correct order of loading.
Raises HomeAssistantError if a circular dependency is detected.
@ -238,16 +195,16 @@ def load_order_component(comp_name: str) -> OrderedSet:
Async friendly.
"""
return _load_order_component(comp_name, OrderedSet(), set())
return _load_order_component(hass, comp_name, OrderedSet(), set())
def _load_order_component(comp_name: str, load_order: OrderedSet,
def _load_order_component(hass, comp_name: str, load_order: OrderedSet,
loading: Set) -> OrderedSet:
"""Recursive function to get load order of components.
Async friendly.
"""
component = get_component(comp_name)
component = get_component(hass, comp_name)
# If None it does not exist, error already thrown by get_component.
if component is None:
@ -266,7 +223,8 @@ def _load_order_component(comp_name: str, load_order: OrderedSet,
comp_name, dependency)
return OrderedSet()
dep_load_order = _load_order_component(dependency, load_order, loading)
dep_load_order = _load_order_component(
hass, dependency, load_order, loading)
# length == 0 means error loading dependency or children
if not dep_load_order:
@ -280,14 +238,3 @@ def _load_order_component(comp_name: str, load_order: OrderedSet,
loading.remove(comp_name)
return load_order
def _check_prepared() -> None:
"""Issue a warning if loader.prepare() has never been called.
Async friendly.
"""
if not PREPARED:
_LOGGER.warning((
"You did not call loader.prepare() yet. "
"Certain functionality might not be working"))

View File

@ -16,8 +16,8 @@ from homeassistant import bootstrap, core, loader
from homeassistant.config import (
get_default_config_dir, CONF_CORE, CORE_CONFIG_SCHEMA,
CONF_PACKAGES, merge_packages_config, _format_config_error,
find_config_file, load_yaml_config_file, get_component,
extract_domain_configs, config_per_platform, get_platform)
find_config_file, load_yaml_config_file,
extract_domain_configs, config_per_platform)
import homeassistant.util.yaml as yaml
from homeassistant.exceptions import HomeAssistantError
@ -201,18 +201,10 @@ def check(config_dir, secrets=False):
yaml.yaml.SafeLoader.add_constructor('!secret', yaml._secret_yaml)
try:
class HassConfig():
"""Hass object with config."""
def __init__(self, conf_dir):
"""Init the config_dir."""
self.config = core.Config()
self.config.config_dir = conf_dir
loader.prepare(HassConfig(config_dir))
res['components'] = check_ha_config_file(config_dir)
hass = core.HomeAssistant()
hass.config.config_dir = config_dir
res['components'] = check_ha_config_file(hass)
res['secret_cache'] = OrderedDict(yaml.__SECRET_CACHE)
for err in res['components'].errors:
@ -222,6 +214,7 @@ def check(config_dir, secrets=False):
res['except'].setdefault(domain, []).append(err.config)
except Exception as err: # pylint: disable=broad-except
_LOGGER.exception("BURB")
print(color('red', 'Fatal error while loading config:'), str(err))
res['except'].setdefault(ERROR_STR, []).append(str(err))
finally:
@ -290,8 +283,9 @@ class HomeAssistantConfig(OrderedDict):
return self
def check_ha_config_file(config_dir):
def check_ha_config_file(hass):
"""Check if Home Assistant configuration file is valid."""
config_dir = hass.config.config_dir
result = HomeAssistantConfig()
def _pack_error(package, component, config, message):
@ -330,7 +324,7 @@ def check_ha_config_file(config_dir):
# Merge packages
merge_packages_config(
config, core_config.get(CONF_PACKAGES, {}), _pack_error)
hass, config, core_config.get(CONF_PACKAGES, {}), _pack_error)
del core_config[CONF_PACKAGES]
# Ensure we have no None values after merge
@ -343,7 +337,7 @@ def check_ha_config_file(config_dir):
# Process and validate config
for domain in components:
component = get_component(domain)
component = loader.get_component(hass, domain)
if not component:
result.add_error("Component not found: {}".format(domain))
continue
@ -375,7 +369,7 @@ def check_ha_config_file(config_dir):
platforms.append(p_validated)
continue
platform = get_platform(domain, p_name)
platform = loader.get_platform(hass, domain, p_name)
if platform is None:
result.add_error(

View File

@ -98,14 +98,14 @@ async def _async_setup_component(hass: core.HomeAssistant,
_LOGGER.error("Setup failed for %s: %s", domain, msg)
async_notify_setup_error(hass, domain, link)
component = loader.get_component(domain)
component = loader.get_component(hass, domain)
if not component:
log_error("Component not found.", False)
return False
# Validate no circular dependencies
components = loader.load_order_component(domain)
components = loader.load_order_component(hass, domain)
# OrderedSet is empty if component or dependencies could not be resolved
if not components:
@ -159,7 +159,7 @@ async def _async_setup_component(hass: core.HomeAssistant,
elif result is not True:
log_error("Component did not return boolean if setup was successful. "
"Disabling component.")
loader.set_component(domain, None)
loader.set_component(hass, domain, None)
return False
for entry in hass.config_entries.async_entries(domain):
@ -193,7 +193,7 @@ async def async_prepare_setup_platform(hass: core.HomeAssistant, config,
platform_path, msg)
async_notify_setup_error(hass, platform_path)
platform = loader.get_platform(domain, platform_name)
platform = loader.get_platform(hass, domain, platform_name)
# Not found
if platform is None:

View File

@ -10,8 +10,7 @@ import logging
import threading
from contextlib import contextmanager
from homeassistant import (
auth, core as ha, loader, data_entry_flow, config_entries)
from homeassistant import auth, core as ha, data_entry_flow, config_entries
from homeassistant.setup import setup_component, async_setup_component
from homeassistant.config import async_process_component_config
from homeassistant.helpers import (
@ -138,9 +137,6 @@ def async_test_home_assistant(loop):
hass.config.units = METRIC_SYSTEM
hass.config.skip_pip = True
if 'custom_components.test' not in loader.AVAILABLE_COMPONENTS:
yield from loop.run_in_executor(None, loader.prepare, hass)
hass.state = ha.CoreState.running
# Mock async_start

View File

@ -116,7 +116,7 @@ class TestGenericThermostatHeaterSwitching(unittest.TestCase):
def test_heater_switch(self):
"""Test heater switching test switch."""
platform = loader.get_component('switch.test')
platform = loader.get_component(self.hass, 'switch.test')
platform.init()
self.switch_1 = platform.DEVICES[1]
assert setup_component(self.hass, switch.DOMAIN, {'switch': {

View File

@ -17,10 +17,10 @@ from homeassistant.loader import set_component
from tests.common import MockConfigEntry, MockModule, mock_coro_func
@pytest.fixture(scope='session', autouse=True)
def mock_test_component():
@pytest.fixture(autouse=True)
def mock_test_component(hass):
"""Ensure a component called 'test' exists."""
set_component('test', MockModule('test'))
set_component(hass, 'test', MockModule('test'))
@pytest.fixture
@ -172,7 +172,8 @@ def test_abort(hass, client):
def test_create_account(hass, client):
"""Test a flow that creates an account."""
set_component(
'test', MockModule('test', async_setup_entry=mock_coro_func(True)))
hass, 'test',
MockModule('test', async_setup_entry=mock_coro_func(True)))
class TestFlow(FlowHandler):
VERSION = 1
@ -204,7 +205,8 @@ def test_create_account(hass, client):
def test_two_step_flow(hass, client):
"""Test we can finish a two step flow."""
set_component(
'test', MockModule('test', async_setup_entry=mock_coro_func(True)))
hass, 'test',
MockModule('test', async_setup_entry=mock_coro_func(True)))
class TestFlow(FlowHandler):
VERSION = 1

View File

@ -3,9 +3,9 @@ import os
from datetime import timedelta
import unittest
from unittest import mock
import socket
import voluptuous as vol
from future.backports import socket
from homeassistant.setup import setup_component
from homeassistant.components import device_tracker

View File

@ -189,7 +189,7 @@ class TestComponentsDeviceTracker(unittest.TestCase):
def test_update_stale(self):
"""Test stalled update."""
scanner = get_component('device_tracker.test').SCANNER
scanner = get_component(self.hass, 'device_tracker.test').SCANNER
scanner.reset()
scanner.come_home('DEV1')
@ -251,7 +251,7 @@ class TestComponentsDeviceTracker(unittest.TestCase):
hide_if_away=True)
device_tracker.update_config(self.yaml_devices, dev_id, device)
scanner = get_component('device_tracker.test').SCANNER
scanner = get_component(self.hass, 'device_tracker.test').SCANNER
scanner.reset()
with assert_setup_component(1, device_tracker.DOMAIN):
@ -270,7 +270,7 @@ class TestComponentsDeviceTracker(unittest.TestCase):
hide_if_away=True)
device_tracker.update_config(self.yaml_devices, dev_id, device)
scanner = get_component('device_tracker.test').SCANNER
scanner = get_component(self.hass, 'device_tracker.test').SCANNER
scanner.reset()
with assert_setup_component(1, device_tracker.DOMAIN):
@ -431,7 +431,7 @@ class TestComponentsDeviceTracker(unittest.TestCase):
'zone': zone_info
})
scanner = get_component('device_tracker.test').SCANNER
scanner = get_component(self.hass, 'device_tracker.test').SCANNER
scanner.reset()
scanner.come_home('dev1')
@ -547,7 +547,7 @@ def test_bad_platform(hass):
async def test_adding_unknown_device_to_config(mock_device_tracker_conf, hass):
"""Test the adding of unknown devices to configuration file."""
scanner = get_component('device_tracker.test').SCANNER
scanner = get_component(hass, 'device_tracker.test').SCANNER
scanner.reset()
scanner.come_home('DEV1')

View File

@ -118,7 +118,7 @@ class TestLight(unittest.TestCase):
def test_services(self):
"""Test the provided services."""
platform = loader.get_component('light.test')
platform = loader.get_component(self.hass, 'light.test')
platform.init()
self.assertTrue(
@ -267,7 +267,7 @@ class TestLight(unittest.TestCase):
def test_broken_light_profiles(self):
"""Test light profiles."""
platform = loader.get_component('light.test')
platform = loader.get_component(self.hass, 'light.test')
platform.init()
user_light_file = self.hass.config.path(light.LIGHT_PROFILES_FILE)
@ -282,7 +282,7 @@ class TestLight(unittest.TestCase):
def test_light_profiles(self):
"""Test light profiles."""
platform = loader.get_component('light.test')
platform = loader.get_component(self.hass, 'light.test')
platform.init()
user_light_file = self.hass.config.path(light.LIGHT_PROFILES_FILE)

View File

@ -16,7 +16,7 @@ class TestScene(unittest.TestCase):
def setUp(self): # pylint: disable=invalid-name
"""Setup things to be run when tests are started."""
self.hass = get_test_home_assistant()
test_light = loader.get_component('light.test')
test_light = loader.get_component(self.hass, 'light.test')
test_light.init()
self.assertTrue(setup_component(self.hass, light.DOMAIN, {

View File

@ -71,7 +71,7 @@ class TestSwitchFlux(unittest.TestCase):
def test_flux_when_switch_is_off(self):
"""Test the flux switch when it is off."""
platform = loader.get_component('light.test')
platform = loader.get_component(self.hass, 'light.test')
platform.init()
self.assertTrue(
setup_component(self.hass, light.DOMAIN,
@ -113,7 +113,7 @@ class TestSwitchFlux(unittest.TestCase):
def test_flux_before_sunrise(self):
"""Test the flux switch before sunrise."""
platform = loader.get_component('light.test')
platform = loader.get_component(self.hass, 'light.test')
platform.init()
self.assertTrue(
setup_component(self.hass, light.DOMAIN,
@ -160,7 +160,7 @@ class TestSwitchFlux(unittest.TestCase):
# pylint: disable=invalid-name
def test_flux_after_sunrise_before_sunset(self):
"""Test the flux switch after sunrise and before sunset."""
platform = loader.get_component('light.test')
platform = loader.get_component(self.hass, 'light.test')
platform.init()
self.assertTrue(
setup_component(self.hass, light.DOMAIN,
@ -207,7 +207,7 @@ class TestSwitchFlux(unittest.TestCase):
# pylint: disable=invalid-name
def test_flux_after_sunset_before_stop(self):
"""Test the flux switch after sunset and before stop."""
platform = loader.get_component('light.test')
platform = loader.get_component(self.hass, 'light.test')
platform.init()
self.assertTrue(
setup_component(self.hass, light.DOMAIN,
@ -255,7 +255,7 @@ class TestSwitchFlux(unittest.TestCase):
# pylint: disable=invalid-name
def test_flux_after_stop_before_sunrise(self):
"""Test the flux switch after stop and before sunrise."""
platform = loader.get_component('light.test')
platform = loader.get_component(self.hass, 'light.test')
platform.init()
self.assertTrue(
setup_component(self.hass, light.DOMAIN,
@ -302,7 +302,7 @@ class TestSwitchFlux(unittest.TestCase):
# pylint: disable=invalid-name
def test_flux_with_custom_start_stop_times(self):
"""Test the flux with custom start and stop times."""
platform = loader.get_component('light.test')
platform = loader.get_component(self.hass, 'light.test')
platform.init()
self.assertTrue(
setup_component(self.hass, light.DOMAIN,
@ -353,7 +353,7 @@ class TestSwitchFlux(unittest.TestCase):
This test has the stop_time on the next day (after midnight).
"""
platform = loader.get_component('light.test')
platform = loader.get_component(self.hass, 'light.test')
platform.init()
self.assertTrue(
setup_component(self.hass, light.DOMAIN,
@ -405,7 +405,7 @@ class TestSwitchFlux(unittest.TestCase):
This test has the stop_time on the next day (after midnight).
"""
platform = loader.get_component('light.test')
platform = loader.get_component(self.hass, 'light.test')
platform.init()
self.assertTrue(
setup_component(self.hass, light.DOMAIN,
@ -456,7 +456,7 @@ class TestSwitchFlux(unittest.TestCase):
This test has the stop_time on the next day (after midnight).
"""
platform = loader.get_component('light.test')
platform = loader.get_component(self.hass, 'light.test')
platform.init()
self.assertTrue(
setup_component(self.hass, light.DOMAIN,
@ -507,7 +507,7 @@ class TestSwitchFlux(unittest.TestCase):
This test has the stop_time on the next day (after midnight).
"""
platform = loader.get_component('light.test')
platform = loader.get_component(self.hass, 'light.test')
platform.init()
self.assertTrue(
setup_component(self.hass, light.DOMAIN,
@ -558,7 +558,7 @@ class TestSwitchFlux(unittest.TestCase):
This test has the stop_time on the next day (after midnight).
"""
platform = loader.get_component('light.test')
platform = loader.get_component(self.hass, 'light.test')
platform.init()
self.assertTrue(
setup_component(self.hass, light.DOMAIN,
@ -606,7 +606,7 @@ class TestSwitchFlux(unittest.TestCase):
# pylint: disable=invalid-name
def test_flux_with_custom_colortemps(self):
"""Test the flux with custom start and stop colortemps."""
platform = loader.get_component('light.test')
platform = loader.get_component(self.hass, 'light.test')
platform.init()
self.assertTrue(
setup_component(self.hass, light.DOMAIN,
@ -656,7 +656,7 @@ class TestSwitchFlux(unittest.TestCase):
# pylint: disable=invalid-name
def test_flux_with_custom_brightness(self):
"""Test the flux with custom start and stop colortemps."""
platform = loader.get_component('light.test')
platform = loader.get_component(self.hass, 'light.test')
platform.init()
self.assertTrue(
setup_component(self.hass, light.DOMAIN,
@ -704,7 +704,7 @@ class TestSwitchFlux(unittest.TestCase):
def test_flux_with_multiple_lights(self):
"""Test the flux switch with multiple light entities."""
platform = loader.get_component('light.test')
platform = loader.get_component(self.hass, 'light.test')
platform.init()
self.assertTrue(
setup_component(self.hass, light.DOMAIN,
@ -773,7 +773,7 @@ class TestSwitchFlux(unittest.TestCase):
def test_flux_with_mired(self):
"""Test the flux switch´s mode mired."""
platform = loader.get_component('light.test')
platform = loader.get_component(self.hass, 'light.test')
platform.init()
self.assertTrue(
setup_component(self.hass, light.DOMAIN,
@ -818,7 +818,7 @@ class TestSwitchFlux(unittest.TestCase):
def test_flux_with_rgb(self):
"""Test the flux switch´s mode rgb."""
platform = loader.get_component('light.test')
platform = loader.get_component(self.hass, 'light.test')
platform.init()
self.assertTrue(
setup_component(self.hass, light.DOMAIN,

View File

@ -17,7 +17,7 @@ class TestSwitch(unittest.TestCase):
def setUp(self):
"""Setup things to be run when tests are started."""
self.hass = get_test_home_assistant()
platform = loader.get_component('switch.test')
platform = loader.get_component(self.hass, 'switch.test')
platform.init()
# Switch 1 is ON, switch 2 is OFF
self.switch_1, self.switch_2, self.switch_3 = \
@ -79,10 +79,10 @@ class TestSwitch(unittest.TestCase):
def test_setup_two_platforms(self):
"""Test with bad configuration."""
# Test if switch component returns 0 switches
test_platform = loader.get_component('switch.test')
test_platform = loader.get_component(self.hass, 'switch.test')
test_platform.init(True)
loader.set_component('switch.test2', test_platform)
loader.set_component(self.hass, 'switch.test2', test_platform)
test_platform.init(False)
self.assertTrue(setup_component(

View File

@ -22,12 +22,12 @@ class TestDeviceSunLightTrigger(unittest.TestCase):
self.hass = get_test_home_assistant()
self.scanner = loader.get_component(
'device_tracker.test').get_scanner(None, None)
self.hass, 'device_tracker.test').get_scanner(None, None)
self.scanner.reset()
self.scanner.come_home('DEV1')
loader.get_component('light.test').init()
loader.get_component(self.hass, 'light.test').init()
with patch(
'homeassistant.components.device_tracker.load_yaml_config_file',

View File

@ -10,8 +10,6 @@ import voluptuous as vol
import homeassistant.helpers.config_validation as cv
from tests.common import get_test_home_assistant
def test_boolean():
"""Test boolean validation."""
@ -256,24 +254,6 @@ def test_event_schema():
cv.EVENT_SCHEMA(value)
def test_platform_validator():
"""Test platform validation."""
hass = None
try:
hass = get_test_home_assistant()
schema = vol.Schema(cv.platform_validator('light'))
with pytest.raises(vol.MultipleInvalid):
schema('platform_that_does_not_exist')
schema('hue')
finally:
if hass is not None:
hass.stop()
def test_icon():
"""Test icon validation."""
schema = vol.Schema(cv.icon)

View File

@ -129,11 +129,11 @@ class TestHelpersDiscovery:
platform_calls.append('disc' if discovery_info else 'component')
loader.set_component(
'test_component',
self.hass, 'test_component',
MockModule('test_component', setup=component_setup))
loader.set_component(
'switch.test_circular',
self.hass, 'switch.test_circular',
MockPlatform(setup_platform,
dependencies=['test_component']))
@ -177,11 +177,11 @@ class TestHelpersDiscovery:
return True
loader.set_component(
'test_component1',
self.hass, 'test_component1',
MockModule('test_component1', setup=component1_setup))
loader.set_component(
'test_component2',
self.hass, 'test_component2',
MockModule('test_component2', setup=component2_setup))
@callback

View File

@ -75,9 +75,9 @@ class TestHelpersEntityComponent(unittest.TestCase):
component_setup = Mock(return_value=True)
platform_setup = Mock(return_value=None)
loader.set_component(
'test_component',
self.hass, 'test_component',
MockModule('test_component', setup=component_setup))
loader.set_component('test_domain.mod2',
loader.set_component(self.hass, 'test_domain.mod2',
MockPlatform(platform_setup, ['test_component']))
component = EntityComponent(_LOGGER, DOMAIN, self.hass)
@ -100,8 +100,10 @@ class TestHelpersEntityComponent(unittest.TestCase):
platform1_setup = Mock(side_effect=Exception('Broken'))
platform2_setup = Mock(return_value=None)
loader.set_component('test_domain.mod1', MockPlatform(platform1_setup))
loader.set_component('test_domain.mod2', MockPlatform(platform2_setup))
loader.set_component(self.hass, 'test_domain.mod1',
MockPlatform(platform1_setup))
loader.set_component(self.hass, 'test_domain.mod2',
MockPlatform(platform2_setup))
component = EntityComponent(_LOGGER, DOMAIN, self.hass)
@ -145,7 +147,7 @@ class TestHelpersEntityComponent(unittest.TestCase):
"""Test the platform setup."""
add_devices([MockEntity(should_poll=True)])
loader.set_component('test_domain.platform',
loader.set_component(self.hass, 'test_domain.platform',
MockPlatform(platform_setup))
component = EntityComponent(_LOGGER, DOMAIN, self.hass)
@ -172,7 +174,7 @@ class TestHelpersEntityComponent(unittest.TestCase):
platform = MockPlatform(platform_setup)
loader.set_component('test_domain.platform', platform)
loader.set_component(self.hass, 'test_domain.platform', platform)
component = EntityComponent(_LOGGER, DOMAIN, self.hass)
@ -220,7 +222,8 @@ def test_platform_not_ready(hass):
"""Test that we retry when platform not ready."""
platform1_setup = Mock(side_effect=[PlatformNotReady, PlatformNotReady,
None])
loader.set_component('test_domain.mod1', MockPlatform(platform1_setup))
loader.set_component(hass, 'test_domain.mod1',
MockPlatform(platform1_setup))
component = EntityComponent(_LOGGER, DOMAIN, hass)
@ -316,10 +319,11 @@ def test_setup_dependencies_platform(hass):
We're explictely testing that we process dependencies even if a component
with the same name has already been loaded.
"""
loader.set_component('test_component', MockModule('test_component'))
loader.set_component('test_component2', MockModule('test_component2'))
loader.set_component(hass, 'test_component', MockModule('test_component'))
loader.set_component(hass, 'test_component2',
MockModule('test_component2'))
loader.set_component(
'test_domain.test_component',
hass, 'test_domain.test_component',
MockPlatform(dependencies=['test_component', 'test_component2']))
component = EntityComponent(_LOGGER, DOMAIN, hass)
@ -341,7 +345,7 @@ async def test_setup_entry(hass):
"""Test setup entry calls async_setup_entry on platform."""
mock_setup_entry = Mock(return_value=mock_coro(True))
loader.set_component(
'test_domain.entry_domain',
hass, 'test_domain.entry_domain',
MockPlatform(async_setup_entry=mock_setup_entry))
component = EntityComponent(_LOGGER, DOMAIN, hass)
@ -366,7 +370,7 @@ async def test_setup_entry_fails_duplicate(hass):
"""Test we don't allow setting up a config entry twice."""
mock_setup_entry = Mock(return_value=mock_coro(True))
loader.set_component(
'test_domain.entry_domain',
hass, 'test_domain.entry_domain',
MockPlatform(async_setup_entry=mock_setup_entry))
component = EntityComponent(_LOGGER, DOMAIN, hass)
@ -382,7 +386,7 @@ async def test_unload_entry_resets_platform(hass):
"""Test unloading an entry removes all entities."""
mock_setup_entry = Mock(return_value=mock_coro(True))
loader.set_component(
'test_domain.entry_domain',
hass, 'test_domain.entry_domain',
MockPlatform(async_setup_entry=mock_setup_entry))
component = EntityComponent(_LOGGER, DOMAIN, hass)

View File

@ -147,7 +147,7 @@ class TestHelpersEntityPlatform(unittest.TestCase):
platform = MockPlatform(platform_setup)
platform.SCAN_INTERVAL = timedelta(seconds=30)
loader.set_component('test_domain.platform', platform)
loader.set_component(self.hass, 'test_domain.platform', platform)
component = EntityComponent(_LOGGER, DOMAIN, self.hass)
@ -184,7 +184,7 @@ def test_platform_warn_slow_setup(hass):
"""Warn we log when platform setup takes a long time."""
platform = MockPlatform()
loader.set_component('test_domain.platform', platform)
loader.set_component(hass, 'test_domain.platform', platform)
component = EntityComponent(_LOGGER, DOMAIN, hass)
@ -218,7 +218,7 @@ def test_platform_error_slow_setup(hass, caplog):
platform = MockPlatform(async_setup_platform=setup_platform)
component = EntityComponent(_LOGGER, DOMAIN, hass)
loader.set_component('test_domain.test_platform', platform)
loader.set_component(hass, 'test_domain.test_platform', platform)
yield from component.async_setup({
DOMAIN: {
'platform': 'test_platform',
@ -260,7 +260,7 @@ def test_parallel_updates_async_platform(hass):
platform.async_setup_platform = mock_update
loader.set_component('test_domain.platform', platform)
loader.set_component(hass, 'test_domain.platform', platform)
component = EntityComponent(_LOGGER, DOMAIN, hass)
component._platforms = {}
@ -288,7 +288,7 @@ def test_parallel_updates_async_platform_with_constant(hass):
platform.async_setup_platform = mock_update
platform.PARALLEL_UPDATES = 1
loader.set_component('test_domain.platform', platform)
loader.set_component(hass, 'test_domain.platform', platform)
component = EntityComponent(_LOGGER, DOMAIN, hass)
component._platforms = {}
@ -309,7 +309,7 @@ def test_parallel_updates_sync_platform(hass):
"""Warn we log when platform setup takes a long time."""
platform = MockPlatform(setup_platform=lambda *args: None)
loader.set_component('test_domain.platform', platform)
loader.set_component(hass, 'test_domain.platform', platform)
component = EntityComponent(_LOGGER, DOMAIN, hass)
component._platforms = {}

View File

@ -138,7 +138,7 @@ class TestServiceHelpers(unittest.TestCase):
self.hass.states.set('light.Ceiling', STATE_OFF)
self.hass.states.set('light.Kitchen', STATE_OFF)
loader.get_component('group').Group.create_group(
loader.get_component(self.hass, 'group').Group.create_group(
self.hass, 'test', ['light.Ceiling', 'light.Kitchen'])
call = ha.ServiceCall('light', 'turn_on',
@ -160,7 +160,7 @@ class TestServiceHelpers(unittest.TestCase):
@asyncio.coroutine
def test_async_get_all_descriptions(hass):
"""Test async_get_all_descriptions."""
group = loader.get_component('group')
group = loader.get_component(hass, 'group')
group_config = {group.DOMAIN: {}}
yield from async_setup_component(hass, group.DOMAIN, group_config)
descriptions = yield from service.async_get_all_descriptions(hass)
@ -170,7 +170,7 @@ def test_async_get_all_descriptions(hass):
assert 'description' in descriptions['group']['reload']
assert 'fields' in descriptions['group']['reload']
logger = loader.get_component('logger')
logger = loader.get_component(hass, 'logger')
logger_config = {logger.DOMAIN: {}}
yield from async_setup_component(hass, logger.DOMAIN, logger_config)
descriptions = yield from service.async_get_all_descriptions(hass)

View File

@ -50,15 +50,15 @@ async def test_component_translation_file(hass):
})
assert path.normpath(translation.component_translation_file(
'switch.test', 'en')) == path.normpath(hass.config.path(
hass, 'switch.test', 'en')) == path.normpath(hass.config.path(
'custom_components', 'switch', '.translations', 'test.en.json'))
assert path.normpath(translation.component_translation_file(
'test_standalone', 'en')) == path.normpath(hass.config.path(
hass, 'test_standalone', 'en')) == path.normpath(hass.config.path(
'custom_components', '.translations', 'test_standalone.en.json'))
assert path.normpath(translation.component_translation_file(
'test_package', 'en')) == path.normpath(hass.config.path(
hass, 'test_package', 'en')) == path.normpath(hass.config.path(
'custom_components', 'test_package', '.translations', 'en.json'))

View File

@ -7,7 +7,6 @@ from unittest.mock import patch
import homeassistant.scripts.check_config as check_config
from homeassistant.config import YAML_CONFIG_FILE
from homeassistant.loader import set_component
from tests.common import patch_yaml_files, get_test_config_dir
_LOGGER = logging.getLogger(__name__)
@ -106,7 +105,6 @@ class TestCheckConfig(unittest.TestCase):
def test_component_platform_not_found(self, isfile_patch):
"""Test errors if component or platform not found."""
# Make sure they don't exist
set_component('beer', None)
files = {
YAML_CONFIG_FILE: BASE_CONFIG + 'beer:',
}
@ -119,7 +117,6 @@ class TestCheckConfig(unittest.TestCase):
assert res['secrets'] == {}
assert len(res['yaml_files']) == 1
set_component('light.beer', None)
files = {
YAML_CONFIG_FILE: BASE_CONFIG + 'light:\n platform: beer',
}

View File

@ -568,7 +568,7 @@ def merge_log_err(hass):
yield logerr
def test_merge(merge_log_err):
def test_merge(merge_log_err, hass):
"""Test if we can merge packages."""
packages = {
'pack_dict': {'input_boolean': {'ib1': None}},
@ -582,7 +582,7 @@ def test_merge(merge_log_err):
'input_boolean': {'ib2': None},
'light': {'platform': 'test'}
}
config_util.merge_packages_config(config, packages)
config_util.merge_packages_config(hass, config, packages)
assert merge_log_err.call_count == 0
assert len(config) == 5
@ -592,7 +592,7 @@ def test_merge(merge_log_err):
assert config['wake_on_lan'] is None
def test_merge_try_falsy(merge_log_err):
def test_merge_try_falsy(merge_log_err, hass):
"""Ensure we dont add falsy items like empty OrderedDict() to list."""
packages = {
'pack_falsy_to_lst': {'automation': OrderedDict()},
@ -603,7 +603,7 @@ def test_merge_try_falsy(merge_log_err):
'automation': {'do': 'something'},
'light': {'some': 'light'},
}
config_util.merge_packages_config(config, packages)
config_util.merge_packages_config(hass, config, packages)
assert merge_log_err.call_count == 0
assert len(config) == 3
@ -611,7 +611,7 @@ def test_merge_try_falsy(merge_log_err):
assert len(config['light']) == 1
def test_merge_new(merge_log_err):
def test_merge_new(merge_log_err, hass):
"""Test adding new components to outer scope."""
packages = {
'pack_1': {'light': [{'platform': 'one'}]},
@ -624,7 +624,7 @@ def test_merge_new(merge_log_err):
config = {
config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages},
}
config_util.merge_packages_config(config, packages)
config_util.merge_packages_config(hass, config, packages)
assert merge_log_err.call_count == 0
assert 'api' in config
@ -633,7 +633,7 @@ def test_merge_new(merge_log_err):
assert len(config['panel_custom']) == 1
def test_merge_type_mismatch(merge_log_err):
def test_merge_type_mismatch(merge_log_err, hass):
"""Test if we have a type mismatch for packages."""
packages = {
'pack_1': {'input_boolean': [{'ib1': None}]},
@ -646,7 +646,7 @@ def test_merge_type_mismatch(merge_log_err):
'input_select': [{'ib2': None}],
'light': [{'platform': 'two'}]
}
config_util.merge_packages_config(config, packages)
config_util.merge_packages_config(hass, config, packages)
assert merge_log_err.call_count == 2
assert len(config) == 4
@ -654,7 +654,7 @@ def test_merge_type_mismatch(merge_log_err):
assert len(config['light']) == 2
def test_merge_once_only(merge_log_err):
def test_merge_once_only(merge_log_err, hass):
"""Test if we have a merge for a comp that may occur only once."""
packages = {
'pack_2': {
@ -666,7 +666,7 @@ def test_merge_once_only(merge_log_err):
config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages},
'mqtt': {}, 'api': {}
}
config_util.merge_packages_config(config, packages)
config_util.merge_packages_config(hass, config, packages)
assert merge_log_err.call_count == 1
assert len(config) == 3
@ -682,13 +682,13 @@ def test_merge_id_schema(hass):
'qwikswitch': 'dict',
}
for name, expected_type in types.items():
module = config_util.get_component(name)
module = config_util.get_component(hass, name)
typ, _ = config_util._identify_config_schema(module)
assert typ == expected_type, "{} expected {}, got {}".format(
name, expected_type, typ)
def test_merge_duplicate_keys(merge_log_err):
def test_merge_duplicate_keys(merge_log_err, hass):
"""Test if keys in dicts are duplicates."""
packages = {
'pack_1': {'input_select': {'ib1': None}},
@ -697,7 +697,7 @@ def test_merge_duplicate_keys(merge_log_err):
config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages},
'input_select': {'ib1': None},
}
config_util.merge_packages_config(config, packages)
config_util.merge_packages_config(hass, config, packages)
assert merge_log_err.call_count == 1
assert len(config) == 2

View File

@ -27,7 +27,7 @@ def test_call_setup_entry(hass):
mock_setup_entry = MagicMock(return_value=mock_coro(True))
loader.set_component(
'comp',
hass, 'comp',
MockModule('comp', async_setup_entry=mock_setup_entry))
result = yield from async_setup_component(hass, 'comp', {})
@ -36,12 +36,12 @@ def test_call_setup_entry(hass):
@asyncio.coroutine
def test_remove_entry(manager):
def test_remove_entry(hass, manager):
"""Test that we can remove an entry."""
mock_unload_entry = MagicMock(return_value=mock_coro(True))
loader.set_component(
'test',
hass, 'test',
MockModule('comp', async_unload_entry=mock_unload_entry))
MockConfigEntry(domain='test', entry_id='test1').add_to_manager(manager)
@ -63,7 +63,7 @@ def test_remove_entry(manager):
@asyncio.coroutine
def test_remove_entry_raises(manager):
def test_remove_entry_raises(hass, manager):
"""Test if a component raises while removing entry."""
@asyncio.coroutine
def mock_unload_entry(hass, entry):
@ -71,7 +71,7 @@ def test_remove_entry_raises(manager):
raise Exception("BROKEN")
loader.set_component(
'test',
hass, 'test',
MockModule('comp', async_unload_entry=mock_unload_entry))
MockConfigEntry(domain='test', entry_id='test1').add_to_manager(manager)
@ -96,7 +96,7 @@ def test_add_entry_calls_setup_entry(hass, manager):
mock_setup_entry = MagicMock(return_value=mock_coro(True))
loader.set_component(
'comp',
hass, 'comp',
MockModule('comp', async_setup_entry=mock_setup_entry))
class TestFlow(data_entry_flow.FlowHandler):
@ -151,6 +151,8 @@ def test_domains_gets_uniques(manager):
@asyncio.coroutine
def test_saving_and_loading(hass):
"""Test that we're saving and loading correctly."""
loader.set_component(hass, 'test', MockModule('test'))
class TestFlow(data_entry_flow.FlowHandler):
VERSION = 5
@ -217,12 +219,12 @@ async def test_forward_entry_sets_up_component(hass):
mock_original_setup_entry = MagicMock(return_value=mock_coro(True))
loader.set_component(
'original',
hass, 'original',
MockModule('original', async_setup_entry=mock_original_setup_entry))
mock_forwarded_setup_entry = MagicMock(return_value=mock_coro(True))
loader.set_component(
'forwarded',
hass, 'forwarded',
MockModule('forwarded', async_setup_entry=mock_forwarded_setup_entry))
await hass.config_entries.async_forward_entry_setup(entry, 'forwarded')
@ -236,7 +238,7 @@ async def test_forward_entry_does_not_setup_entry_if_setup_fails(hass):
mock_setup = MagicMock(return_value=mock_coro(False))
mock_setup_entry = MagicMock()
loader.set_component('forwarded', MockModule(
hass, loader.set_component(hass, 'forwarded', MockModule(
'forwarded',
async_setup=mock_setup,
async_setup_entry=mock_setup_entry,
@ -249,6 +251,7 @@ async def test_forward_entry_does_not_setup_entry_if_setup_fails(hass):
async def test_discovery_notification(hass):
"""Test that we create/dismiss a notification when source is discovery."""
loader.set_component(hass, 'test', MockModule('test'))
await async_setup_component(hass, 'persistent_notification', {})
class TestFlow(data_entry_flow.FlowHandler):

View File

@ -27,37 +27,40 @@ class TestLoader(unittest.TestCase):
def test_set_component(self):
"""Test if set_component works."""
loader.set_component('switch.test_set', http)
comp = object()
loader.set_component(self.hass, 'switch.test_set', comp)
self.assertEqual(http, loader.get_component('switch.test_set'))
self.assertEqual(comp,
loader.get_component(self.hass, 'switch.test_set'))
def test_get_component(self):
"""Test if get_component works."""
self.assertEqual(http, loader.get_component('http'))
self.assertIsNotNone(loader.get_component('switch.test'))
self.assertEqual(http, loader.get_component(self.hass, 'http'))
self.assertIsNotNone(loader.get_component(self.hass, 'light.hue'))
def test_load_order_component(self):
"""Test if we can get the proper load order of components."""
loader.set_component('mod1', MockModule('mod1'))
loader.set_component('mod2', MockModule('mod2', ['mod1']))
loader.set_component('mod3', MockModule('mod3', ['mod2']))
loader.set_component(self.hass, 'mod1', MockModule('mod1'))
loader.set_component(self.hass, 'mod2', MockModule('mod2', ['mod1']))
loader.set_component(self.hass, 'mod3', MockModule('mod3', ['mod2']))
self.assertEqual(
['mod1', 'mod2', 'mod3'], loader.load_order_component('mod3'))
['mod1', 'mod2', 'mod3'],
loader.load_order_component(self.hass, 'mod3'))
# Create circular dependency
loader.set_component('mod1', MockModule('mod1', ['mod3']))
loader.set_component(self.hass, 'mod1', MockModule('mod1', ['mod3']))
self.assertEqual([], loader.load_order_component('mod3'))
self.assertEqual([], loader.load_order_component(self.hass, 'mod3'))
# Depend on non-existing component
loader.set_component('mod1', MockModule('mod1', ['nonexisting']))
loader.set_component(self.hass, 'mod1',
MockModule('mod1', ['nonexisting']))
self.assertEqual([], loader.load_order_component('mod1'))
self.assertEqual([], loader.load_order_component(self.hass, 'mod1'))
# Try to get load order for non-existing component
self.assertEqual([], loader.load_order_component('mod1'))
self.assertEqual([], loader.load_order_component(self.hass, 'mod1'))
def test_component_loader(hass):

View File

@ -35,7 +35,8 @@ class TestRequirements:
mock_dirname.return_value = 'ha_package_path'
self.hass.config.skip_pip = False
loader.set_component(
'comp', MockModule('comp', requirements=['package==0.0.1']))
self.hass, 'comp',
MockModule('comp', requirements=['package==0.0.1']))
assert setup.setup_component(self.hass, 'comp')
assert 'comp' in self.hass.config.components
assert mock_install.call_args == mock.call(
@ -53,7 +54,8 @@ class TestRequirements:
mock_dirname.return_value = 'ha_package_path'
self.hass.config.skip_pip = False
loader.set_component(
'comp', MockModule('comp', requirements=['package==0.0.1']))
self.hass, 'comp',
MockModule('comp', requirements=['package==0.0.1']))
assert setup.setup_component(self.hass, 'comp')
assert 'comp' in self.hass.config.components
assert mock_install.call_args == mock.call(

View File

@ -49,6 +49,7 @@ class TestSetup:
}
}, required=True)
loader.set_component(
self.hass,
'comp_conf', MockModule('comp_conf', config_schema=config_schema))
with assert_setup_component(0):
@ -93,10 +94,12 @@ class TestSetup:
'hello': str,
})
loader.set_component(
self.hass,
'platform_conf',
MockModule('platform_conf', platform_schema=platform_schema))
loader.set_component(
self.hass,
'platform_conf.whatever', MockPlatform('whatever'))
with assert_setup_component(0):
@ -179,7 +182,8 @@ class TestSetup:
"""Test we do not setup a component twice."""
mock_setup = mock.MagicMock(return_value=True)
loader.set_component('comp', MockModule('comp', setup=mock_setup))
loader.set_component(
self.hass, 'comp', MockModule('comp', setup=mock_setup))
assert setup.setup_component(self.hass, 'comp')
assert mock_setup.called
@ -195,6 +199,7 @@ class TestSetup:
"""Component setup should fail if requirement can't install."""
self.hass.config.skip_pip = False
loader.set_component(
self.hass,
'comp', MockModule('comp', requirements=['package==0.0.1']))
assert not setup.setup_component(self.hass, 'comp')
@ -210,6 +215,7 @@ class TestSetup:
result.append(1)
loader.set_component(
self.hass,
'comp', MockModule('comp', async_setup=async_setup))
def setup_component():
@ -227,20 +233,23 @@ class TestSetup:
def test_component_not_setup_missing_dependencies(self):
"""Test we do not setup a component if not all dependencies loaded."""
deps = ['non_existing']
loader.set_component('comp', MockModule('comp', dependencies=deps))
loader.set_component(
self.hass, 'comp', MockModule('comp', dependencies=deps))
assert not setup.setup_component(self.hass, 'comp', {})
assert 'comp' not in self.hass.config.components
self.hass.data.pop(setup.DATA_SETUP)
loader.set_component('non_existing', MockModule('non_existing'))
loader.set_component(
self.hass, 'non_existing', MockModule('non_existing'))
assert setup.setup_component(self.hass, 'comp', {})
def test_component_failing_setup(self):
"""Test component that fails setup."""
loader.set_component(
'comp', MockModule('comp', setup=lambda hass, config: False))
self.hass, 'comp',
MockModule('comp', setup=lambda hass, config: False))
assert not setup.setup_component(self.hass, 'comp', {})
assert 'comp' not in self.hass.config.components
@ -251,7 +260,8 @@ class TestSetup:
"""Setup that raises exception."""
raise Exception('fail!')
loader.set_component('comp', MockModule('comp', setup=exception_setup))
loader.set_component(
self.hass, 'comp', MockModule('comp', setup=exception_setup))
assert not setup.setup_component(self.hass, 'comp', {})
assert 'comp' not in self.hass.config.components
@ -264,11 +274,12 @@ class TestSetup:
return True
raise Exception('Config not passed in: {}'.format(config))
loader.set_component('comp_a',
MockModule('comp_a', setup=config_check_setup))
loader.set_component(
self.hass, 'comp_a',
MockModule('comp_a', setup=config_check_setup))
loader.set_component('switch.platform_a', MockPlatform('comp_b',
['comp_a']))
loader.set_component(
self.hass, 'switch.platform_a', MockPlatform('comp_b', ['comp_a']))
setup.setup_component(self.hass, 'switch', {
'comp_a': {
@ -289,6 +300,7 @@ class TestSetup:
mock_setup = mock.MagicMock(spec_set=True)
loader.set_component(
self.hass,
'switch.platform_a',
MockPlatform(platform_schema=platform_schema,
setup_platform=mock_setup))
@ -330,29 +342,34 @@ class TestSetup:
def test_disable_component_if_invalid_return(self):
"""Test disabling component if invalid return."""
loader.set_component(
self.hass,
'disabled_component',
MockModule('disabled_component', setup=lambda hass, config: None))
assert not setup.setup_component(self.hass, 'disabled_component')
assert loader.get_component('disabled_component') is None
assert loader.get_component(self.hass, 'disabled_component') is None
assert 'disabled_component' not in self.hass.config.components
self.hass.data.pop(setup.DATA_SETUP)
loader.set_component(
self.hass,
'disabled_component',
MockModule('disabled_component', setup=lambda hass, config: False))
assert not setup.setup_component(self.hass, 'disabled_component')
assert loader.get_component('disabled_component') is not None
assert loader.get_component(
self.hass, 'disabled_component') is not None
assert 'disabled_component' not in self.hass.config.components
self.hass.data.pop(setup.DATA_SETUP)
loader.set_component(
self.hass,
'disabled_component',
MockModule('disabled_component', setup=lambda hass, config: True))
assert setup.setup_component(self.hass, 'disabled_component')
assert loader.get_component('disabled_component') is not None
assert loader.get_component(
self.hass, 'disabled_component') is not None
assert 'disabled_component' in self.hass.config.components
def test_all_work_done_before_start(self):
@ -373,14 +390,17 @@ class TestSetup:
return True
loader.set_component(
self.hass,
'test_component1',
MockModule('test_component1', setup=component1_setup))
loader.set_component(
self.hass,
'test_component2',
MockModule('test_component2', setup=component_track_setup))
loader.set_component(
self.hass,
'test_component3',
MockModule('test_component3', setup=component_track_setup))
@ -409,7 +429,8 @@ def test_component_cannot_depend_config(hass):
@asyncio.coroutine
def test_component_warn_slow_setup(hass):
"""Warn we log when a component setup takes a long time."""
loader.set_component('test_component1', MockModule('test_component1'))
loader.set_component(
hass, 'test_component1', MockModule('test_component1'))
with mock.patch.object(hass.loop, 'call_later', mock.MagicMock()) \
as mock_call:
result = yield from setup.async_setup_component(
@ -430,7 +451,7 @@ def test_component_warn_slow_setup(hass):
def test_platform_no_warn_slow(hass):
"""Do not warn for long entity setup time."""
loader.set_component(
'test_component1',
hass, 'test_component1',
MockModule('test_component1', platform_schema=PLATFORM_SCHEMA))
with mock.patch.object(hass.loop, 'call_later', mock.MagicMock()) \
as mock_call:

View File

@ -2,6 +2,6 @@
DOMAIN = 'test_standalone'
def setup(hass, config):
async def async_setup(hass, config):
"""Mock a successful setup."""
return True