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 import voluptuous as vol
from homeassistant import ( from homeassistant import (
core, config as conf_util, config_entries, loader, core, config as conf_util, config_entries, components as core_components)
components as core_components)
from homeassistant.components import persistent_notification from homeassistant.components import persistent_notification
from homeassistant.const import EVENT_HOMEASSISTANT_CLOSE from homeassistant.const import EVENT_HOMEASSISTANT_CLOSE
from homeassistant.setup import async_setup_component 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. " _LOGGER.warning("Skipping pip installation of required modules. "
"This may cause issues") "This may cause issues")
if not loader.PREPARED:
await hass.async_add_job(loader.prepare, hass)
# Make a copy because we are mutating it. # Make a copy because we are mutating it.
config = OrderedDict(config) config = OrderedDict(config)
# Merge packages # Merge packages
conf_util.merge_packages_config( 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 # Ensure we have no None values after merge
for key, value in config.items(): for key, value in config.items():

View File

@ -6,6 +6,7 @@ https://home-assistant.io/components/automation/
""" """
import asyncio import asyncio
from functools import partial from functools import partial
import importlib
import logging import logging
import voluptuous as vol 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 import ToggleEntity
from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.restore_state import async_get_last_state from homeassistant.helpers.restore_state import async_get_last_state
from homeassistant.loader import get_platform
from homeassistant.util.dt import utcnow from homeassistant.util.dt import utcnow
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
@ -58,12 +58,14 @@ _LOGGER = logging.getLogger(__name__)
def _platform_validator(config): def _platform_validator(config):
"""Validate it is a valid platform.""" """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 platform.TRIGGER_SCHEMA(config)
return config
return getattr(platform, 'TRIGGER_SCHEMA')(config)
_TRIGGER_SCHEMA = vol.All( _TRIGGER_SCHEMA = vol.All(
@ -71,7 +73,7 @@ _TRIGGER_SCHEMA = vol.All(
[ [
vol.All( vol.All(
vol.Schema({ vol.Schema({
vol.Required(CONF_PLATFORM): cv.platform_validator(DOMAIN) vol.Required(CONF_PLATFORM): str
}, extra=vol.ALLOW_EXTRA), }, extra=vol.ALLOW_EXTRA),
_platform_validator _platform_validator
), ),

View File

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

View File

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

View File

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

View File

@ -9,7 +9,6 @@ import logging
import requests import requests
from homeassistant.components.camera import Camera from homeassistant.components.camera import Camera
from homeassistant.loader import get_component
DEPENDENCIES = ['bloomsky'] DEPENDENCIES = ['bloomsky']
@ -17,7 +16,7 @@ DEPENDENCIES = ['bloomsky']
# pylint: disable=unused-argument # pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None): def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up access to BloomSky cameras.""" """Set up access to BloomSky cameras."""
bloomsky = get_component('bloomsky') bloomsky = hass.components.bloomsky
for device in bloomsky.BLOOMSKY.devices.values(): for device in bloomsky.BLOOMSKY.devices.values():
add_devices([BloomSkyCamera(bloomsky.BLOOMSKY, device)]) 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.const import CONF_VERIFY_SSL
from homeassistant.components.netatmo import CameraData from homeassistant.components.netatmo import CameraData
from homeassistant.components.camera import (Camera, PLATFORM_SCHEMA) from homeassistant.components.camera import (Camera, PLATFORM_SCHEMA)
from homeassistant.loader import get_component
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
DEPENDENCIES = ['netatmo'] DEPENDENCIES = ['netatmo']
@ -33,7 +32,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
# pylint: disable=unused-argument # pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None): def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up access to Netatmo cameras.""" """Set up access to Netatmo cameras."""
netatmo = get_component('netatmo') netatmo = hass.components.netatmo
home = config.get(CONF_HOME) home = config.get(CONF_HOME)
verify_ssl = config.get(CONF_VERIFY_SSL, True) verify_ssl = config.get(CONF_VERIFY_SSL, True)
import lnetatmo import lnetatmo

View File

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

View File

@ -16,7 +16,6 @@ from homeassistant.const import STATE_HOME, STATE_NOT_HOME
from homeassistant.helpers.event import ( from homeassistant.helpers.event import (
async_track_point_in_utc_time, async_track_state_change) async_track_point_in_utc_time, async_track_state_change)
from homeassistant.helpers.sun import is_up, get_astral_event_next from homeassistant.helpers.sun import is_up, get_astral_event_next
from homeassistant.loader import get_component
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
DOMAIN = 'device_sun_light_trigger' DOMAIN = 'device_sun_light_trigger'
@ -48,9 +47,9 @@ CONFIG_SCHEMA = vol.Schema({
def async_setup(hass, config): def async_setup(hass, config):
"""Set up the triggers to control lights based on device presence.""" """Set up the triggers to control lights based on device presence."""
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
device_tracker = get_component('device_tracker') device_tracker = hass.components.device_tracker
group = get_component('group') group = hass.components.group
light = get_component('light') light = hass.components.light
conf = config[DOMAIN] conf = config[DOMAIN]
disable_turn_off = conf.get(CONF_DISABLE_TURN_OFF) disable_turn_off = conf.get(CONF_DISABLE_TURN_OFF)
light_group = conf.get(CONF_LIGHT_GROUP, light.ENTITY_ID_ALL_LIGHTS) 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( device_group = conf.get(
CONF_DEVICE_GROUP, device_tracker.ENTITY_ID_ALL_DEVICES) CONF_DEVICE_GROUP, device_tracker.ENTITY_ID_ALL_DEVICES)
device_entity_ids = group.get_entity_ids( device_entity_ids = group.get_entity_ids(
hass, device_group, device_tracker.DOMAIN) device_group, device_tracker.DOMAIN)
if not device_entity_ids: if not device_entity_ids:
logger.error("No devices found to track") logger.error("No devices found to track")
return False return False
# Get the light IDs from the specified group # 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: if not light_ids:
logger.error("No lights found to turn on") 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): def async_turn_on_before_sunset(light_id):
"""Turn on lights.""" """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 return
light.async_turn_on(hass, light_id, light.async_turn_on(light_id,
transition=LIGHT_TRANSITION_TIME.seconds, transition=LIGHT_TRANSITION_TIME.seconds,
profile=light_profile) profile=light_profile)
@ -129,7 +128,7 @@ def async_setup(hass, config):
@callback @callback
def check_light_on_dev_state_change(entity, old_state, new_state): def check_light_on_dev_state_change(entity, old_state, new_state):
"""Handle tracked device state changes.""" """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)) light_needed = not (lights_are_on or is_up(hass))
# These variables are needed for the elif check # These variables are needed for the elif check
@ -139,7 +138,7 @@ def async_setup(hass, config):
# Do we need lights? # Do we need lights?
if light_needed: if light_needed:
logger.info("Home coming event for %s. Turning lights on", entity) 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 # Are we in the time span were we would turn on the lights
# if someone would be home? # 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 # when the fading in started and turn it on if so
for index, light_id in enumerate(light_ids): for index, light_id in enumerate(light_ids):
if now > start_point + index * LIGHT_TRANSITION_TIME: if now > start_point + index * LIGHT_TRANSITION_TIME:
light.async_turn_on(hass, light_id) light.async_turn_on(light_id)
else: else:
# If this light didn't happen to be turned on yet so # If this light didn't happen to be turned on yet so
@ -169,12 +168,12 @@ def async_setup(hass, config):
@callback @callback
def turn_off_lights_when_all_leave(entity, old_state, new_state): def turn_off_lights_when_all_leave(entity, old_state, new_state):
"""Handle device group state change.""" """Handle device group state change."""
if not group.is_on(hass, light_group): if not group.is_on(light_group):
return return
logger.info( logger.info(
"Everyone has left but there are lights on. Turning them off") "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( async_track_state_change(
hass, device_group, turn_off_lights_when_all_leave, 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.restore_state import async_get_last_state
from homeassistant.helpers.typing import GPSType, ConfigType, HomeAssistantType from homeassistant.helpers.typing import GPSType, ConfigType, HomeAssistantType
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.loader import get_component
import homeassistant.util as util import homeassistant.util as util
from homeassistant.util.async_ import run_coroutine_threadsafe from homeassistant.util.async_ import run_coroutine_threadsafe
import homeassistant.util.dt as dt_util import homeassistant.util.dt as dt_util
@ -322,7 +321,7 @@ class DeviceTracker(object):
# During init, we ignore the group # During init, we ignore the group
if self.group and self.track_new: if self.group and self.track_new:
self.group.async_set_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, add=[device.entity_id]) name=GROUP_NAME_ALL_DEVICES, add=[device.entity_id])
self.hass.bus.async_fire(EVENT_NEW_DEVICE, { 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() entity_ids = [dev.entity_id for dev in self.devices.values()
if dev.track] if dev.track]
self.group = get_component('group') self.group = self.hass.components.group
self.group.async_set_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) name=GROUP_NAME_ALL_DEVICES, entity_ids=entity_ids)
@callback @callback

View File

@ -17,7 +17,6 @@ from homeassistant.exceptions import HomeAssistantError
from homeassistant.loader import bind_hass from homeassistant.loader import bind_hass
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.loader import get_component
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -121,12 +120,12 @@ class ImageProcessingEntity(Entity):
This method is a coroutine. This method is a coroutine.
""" """
camera = get_component('camera') camera = self.hass.components.camera
image = None image = None
try: try:
image = yield from camera.async_get_image( 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: except HomeAssistantError as err:
_LOGGER.error("Error on receive image from entity: %s", 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 ( from homeassistant.components.light import (
Light, ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_HS_COLOR, ATTR_TRANSITION, Light, ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_HS_COLOR, ATTR_TRANSITION,
SUPPORT_BRIGHTNESS, SUPPORT_COLOR_TEMP, SUPPORT_COLOR, SUPPORT_TRANSITION) SUPPORT_BRIGHTNESS, SUPPORT_COLOR_TEMP, SUPPORT_COLOR, SUPPORT_TRANSITION)
from homeassistant.loader import get_component
import homeassistant.util.color as color_util import homeassistant.util.color as color_util
DEPENDENCIES = ['wemo'] DEPENDENCIES = ['wemo']
@ -151,7 +150,7 @@ class WemoDimmer(Light):
@asyncio.coroutine @asyncio.coroutine
def async_added_to_hass(self): def async_added_to_hass(self):
"""Register update callback.""" """Register update callback."""
wemo = get_component('wemo') wemo = self.hass.components.wemo
# The register method uses a threading condition, so call via executor. # The register method uses a threading condition, so call via executor.
# and yield from to wait until the task is done. # and yield from to wait until the task is done.
yield from self.hass.async_add_job( 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 from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.loader import get_component
from homeassistant.util import slugify from homeassistant.util import slugify
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -231,7 +230,7 @@ def async_setup(hass, config):
p_id = face.store[g_id].get(service.data[ATTR_PERSON]) p_id = face.store[g_id].get(service.data[ATTR_PERSON])
camera_entity = service.data[ATTR_CAMERA_ENTITY] camera_entity = service.data[ATTR_CAMERA_ENTITY]
camera = get_component('camera') camera = hass.components.camera
try: try:
image = yield from camera.async_get_image(hass, camera_entity) image = yield from camera.async_get_image(hass, camera_entity)

View File

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

View File

@ -24,7 +24,6 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.dispatcher import ( from homeassistant.helpers.dispatcher import (
async_dispatcher_connect, dispatcher_send) async_dispatcher_connect, dispatcher_send)
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.loader import get_component
from homeassistant.setup import setup_component from homeassistant.setup import setup_component
REQUIREMENTS = ['pymysensors==0.11.1'] REQUIREMENTS = ['pymysensors==0.11.1']
@ -294,16 +293,16 @@ def setup(hass, config):
if device == MQTT_COMPONENT: if device == MQTT_COMPONENT:
if not setup_component(hass, MQTT_COMPONENT, config): if not setup_component(hass, MQTT_COMPONENT, config):
return return
mqtt = get_component(MQTT_COMPONENT) mqtt = hass.components.mqtt
retain = config[DOMAIN].get(CONF_RETAIN) retain = config[DOMAIN].get(CONF_RETAIN)
def pub_callback(topic, payload, qos, retain): def pub_callback(topic, payload, qos, retain):
"""Call MQTT publish function.""" """Call MQTT publish function."""
mqtt.publish(hass, topic, payload, qos, retain) mqtt.publish(topic, payload, qos, retain)
def sub_callback(topic, sub_cb, qos): def sub_callback(topic, sub_cb, qos):
"""Call MQTT subscribe function.""" """Call MQTT subscribe function."""
mqtt.subscribe(hass, topic, sub_cb, qos) mqtt.subscribe(topic, sub_cb, qos)
gateway = mysensors.MQTTGateway( gateway = mysensors.MQTTGateway(
pub_callback, sub_callback, pub_callback, sub_callback,
event_callback=None, persistence=persistence, 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/ https://home-assistant.io/components/scene/
""" """
import asyncio import asyncio
import importlib
import logging import logging
import voluptuous as vol 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 import Entity
from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.state import HASS_DOMAIN from homeassistant.helpers.state import HASS_DOMAIN
from homeassistant.loader import get_platform
DOMAIN = 'scene' DOMAIN = 'scene'
STATE = 'scening' STATE = 'scening'
@ -34,20 +34,24 @@ def _hass_domain_validator(config):
def _platform_validator(config): def _platform_validator(config):
"""Validate it is a valid platform.""" """Validate it is a valid platform."""
p_name = config[CONF_PLATFORM] try:
platform = get_platform(DOMAIN, p_name) 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'): if not hasattr(platform, 'PLATFORM_SCHEMA'):
return config return config
return getattr(platform, 'PLATFORM_SCHEMA')(config) return platform.PLATFORM_SCHEMA(config)
PLATFORM_SCHEMA = vol.Schema( PLATFORM_SCHEMA = vol.Schema(
vol.All( vol.All(
_hass_domain_validator, _hass_domain_validator,
vol.Schema({ vol.Schema({
vol.Required(CONF_PLATFORM): cv.platform_validator(DOMAIN) vol.Required(CONF_PLATFORM): str
}, extra=vol.ALLOW_EXTRA), }, extra=vol.ALLOW_EXTRA),
_platform_validator _platform_validator
), extra=vol.ALLOW_EXTRA) ), extra=vol.ALLOW_EXTRA)

View File

@ -11,7 +11,6 @@ import voluptuous as vol
from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.components.sensor import PLATFORM_SCHEMA
from homeassistant.const import (TEMP_FAHRENHEIT, CONF_MONITORED_CONDITIONS) from homeassistant.const import (TEMP_FAHRENHEIT, CONF_MONITORED_CONDITIONS)
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.loader import get_component
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -45,7 +44,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
# pylint: disable=unused-argument # pylint: disable=unused-argument
def setup_platform(hass, config, add_devices, discovery_info=None): def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the available BloomSky weather sensors.""" """Set up the available BloomSky weather sensors."""
bloomsky = get_component('bloomsky') bloomsky = hass.components.bloomsky
# Default needed in case of discovery # Default needed in case of discovery
sensors = config.get(CONF_MONITORED_CONDITIONS, SENSOR_TYPES) 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.const import TEMP_CELSIUS, STATE_UNKNOWN
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.util import Throttle from homeassistant.util import Throttle
from homeassistant.loader import get_component
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -64,7 +63,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
def setup_platform(hass, config, add_devices, discovery_info=None): def setup_platform(hass, config, add_devices, discovery_info=None):
"""Set up the available Netatmo weather sensors.""" """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)) data = NetAtmoData(netatmo.NETATMO_AUTH, config.get(CONF_STATION, None))
dev = [] dev = []

View File

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

View File

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

View File

@ -12,7 +12,6 @@ from typing import Any, Union, TypeVar, Callable, Sequence, Dict
import voluptuous as vol import voluptuous as vol
from homeassistant.loader import get_platform
from homeassistant.const import ( from homeassistant.const import (
CONF_PLATFORM, CONF_SCAN_INTERVAL, TEMP_CELSIUS, TEMP_FAHRENHEIT, CONF_PLATFORM, CONF_SCAN_INTERVAL, TEMP_CELSIUS, TEMP_FAHRENHEIT,
CONF_ALIAS, CONF_ENTITY_ID, CONF_VALUE_TEMPLATE, WEEKDAYS, CONF_ALIAS, CONF_ENTITY_ID, CONF_VALUE_TEMPLATE, WEEKDAYS,
@ -283,19 +282,6 @@ def match_all(value):
return 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: def positive_timedelta(value: timedelta) -> timedelta:
"""Validate timedelta is positive.""" """Validate timedelta is positive."""
if value < timedelta(0): 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): if not (service_call.data and ATTR_ENTITY_ID in service_call.data):
return [] return []
group = get_component('group') group = hass.components.group
# Entity ID attr can be a list or a string # Entity ID attr can be a list or a string
service_ent_id = service_call.data[ATTR_ENTITY_ID] 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 expand_group:
if isinstance(service_ent_id, str): 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 return [ent_id for ent_id in
group.expand_entity_ids(hass, service_ent_id)] group.expand_entity_ids(service_ent_id)]
else: else:
@ -128,7 +128,7 @@ async def async_get_all_descriptions(hass):
import homeassistant.components as components import homeassistant.components as components
component_path = path.dirname(components.__file__) component_path = path.dirname(components.__file__)
else: 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') return path.join(component_path, 'services.yaml')
def load_services_files(yaml_files): 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.core import State, valid_entity_id
from homeassistant.exceptions import TemplateError from homeassistant.exceptions import TemplateError
from homeassistant.helpers import location as loc_helper 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 convert
from homeassistant.util import dt as dt_util from homeassistant.util import dt as dt_util
from homeassistant.util import location as loc_util from homeassistant.util import location as loc_util
@ -349,10 +349,10 @@ class TemplateMethods(object):
else: else:
gr_entity_id = str(entities) gr_entity_id = str(entities)
group = get_component('group') group = self._hass.components.group
states = [self._hass.states.get(entity_id) for entity_id 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)) return _wrap_state(loc_helper.closest(latitude, longitude, states))

View File

@ -30,14 +30,14 @@ def flatten(data):
return recursive_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.""" """Return the translation json file location for a component."""
if '.' in component: if '.' in component:
name = component.split('.', 1)[1] name = component.split('.', 1)[1]
else: else:
name = component name = component
module = get_component(component) module = get_component(hass, component)
component_path = path.dirname(module.__file__) component_path = path.dirname(module.__file__)
# If loading translations for the package root, (__init__.py), the # If loading translations for the package root, (__init__.py), the
@ -97,7 +97,7 @@ async def async_get_component_resources(hass, language):
missing_files = {} missing_files = {}
for component in missing_components: for component in missing_components:
missing_files[component] = component_translation_file( missing_files[component] = component_translation_file(
component, language) hass, component, language)
# Load missing files # Load missing files
if 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. 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 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 call get_component(hass, 'switch.your_platform'). In both cases the config
is checked to see if it contains a user provided version. If not available it directory is checked to see if it contains a user provided version. If not
will check the built-in components and platforms. available it will check the built-in components and platforms.
""" """
import functools as ft import functools as ft
import importlib import importlib
import logging import logging
import os
import pkgutil
import sys import sys
from types import ModuleType from types import ModuleType
@ -42,135 +40,94 @@ _COMPONENT_CACHE = {} # type: Dict[str, ModuleType]
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
def prepare(hass: 'HomeAssistant'): DATA_KEY = 'components'
"""Prepare the loading of components. PATH_CUSTOM_COMPONENTS = 'custom_components'
PACKAGE_COMPONENTS = 'homeassistant.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
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. """Set a component in the cache.
Async friendly. Async friendly.
""" """
_check_prepared() cache = hass.data.get(DATA_KEY)
if cache is None:
_COMPONENT_CACHE[comp_name] = component 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. """Try to load specified platform.
Async friendly. 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]: def get_component(hass, comp_or_platform):
"""Try to load specified component. """Load a module from either custom component or built-in."""
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: try:
module = importlib.import_module(path) return hass.data[DATA_KEY][comp_or_platform]
except KeyError:
pass
# In Python 3 you can import files from directories that do not # Try custom component
# contain the file __init__.py. A directory is a valid module if module = _load_module(hass.config.path(PATH_CUSTOM_COMPONENTS),
# it contains a file with the .py extension. In this case Python comp_or_platform)
# 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
_LOGGER.info("Loaded %s from %s", comp_name, path) if module is None:
try:
module = importlib.import_module(
'{}.{}'.format(PACKAGE_COMPONENTS, comp_or_platform))
except ImportError:
module = None
_COMPONENT_CACHE[comp_name] = module cache = hass.data.get(DATA_KEY)
if cache is None:
cache = hass.data[DATA_KEY] = {}
cache[comp_or_platform] = module
return 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 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: class Components:
"""Helper to load components.""" """Helper to load components."""
@ -180,7 +137,7 @@ class Components:
def __getattr__(self, comp_name): def __getattr__(self, comp_name):
"""Fetch a component.""" """Fetch a component."""
component = get_component(comp_name) component = get_component(self._hass, comp_name)
if component is None: if component is None:
raise ImportError('Unable to load {}'.format(comp_name)) raise ImportError('Unable to load {}'.format(comp_name))
wrapped = ModuleWrapper(self._hass, component) wrapped = ModuleWrapper(self._hass, component)
@ -230,7 +187,7 @@ def bind_hass(func):
return 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. """Return an OrderedSet of components in the correct order of loading.
Raises HomeAssistantError if a circular dependency is detected. Raises HomeAssistantError if a circular dependency is detected.
@ -238,16 +195,16 @@ def load_order_component(comp_name: str) -> OrderedSet:
Async friendly. 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: loading: Set) -> OrderedSet:
"""Recursive function to get load order of components. """Recursive function to get load order of components.
Async friendly. 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 None it does not exist, error already thrown by get_component.
if component is None: if component is None:
@ -266,7 +223,8 @@ def _load_order_component(comp_name: str, load_order: OrderedSet,
comp_name, dependency) comp_name, dependency)
return OrderedSet() 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 # length == 0 means error loading dependency or children
if not dep_load_order: if not dep_load_order:
@ -280,14 +238,3 @@ def _load_order_component(comp_name: str, load_order: OrderedSet,
loading.remove(comp_name) loading.remove(comp_name)
return load_order 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 ( from homeassistant.config import (
get_default_config_dir, CONF_CORE, CORE_CONFIG_SCHEMA, get_default_config_dir, CONF_CORE, CORE_CONFIG_SCHEMA,
CONF_PACKAGES, merge_packages_config, _format_config_error, CONF_PACKAGES, merge_packages_config, _format_config_error,
find_config_file, load_yaml_config_file, get_component, find_config_file, load_yaml_config_file,
extract_domain_configs, config_per_platform, get_platform) extract_domain_configs, config_per_platform)
import homeassistant.util.yaml as yaml import homeassistant.util.yaml as yaml
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
@ -201,18 +201,10 @@ def check(config_dir, secrets=False):
yaml.yaml.SafeLoader.add_constructor('!secret', yaml._secret_yaml) yaml.yaml.SafeLoader.add_constructor('!secret', yaml._secret_yaml)
try: try:
class HassConfig(): hass = core.HomeAssistant()
"""Hass object with config.""" hass.config.config_dir = config_dir
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)
res['components'] = check_ha_config_file(hass)
res['secret_cache'] = OrderedDict(yaml.__SECRET_CACHE) res['secret_cache'] = OrderedDict(yaml.__SECRET_CACHE)
for err in res['components'].errors: for err in res['components'].errors:
@ -222,6 +214,7 @@ def check(config_dir, secrets=False):
res['except'].setdefault(domain, []).append(err.config) res['except'].setdefault(domain, []).append(err.config)
except Exception as err: # pylint: disable=broad-except except Exception as err: # pylint: disable=broad-except
_LOGGER.exception("BURB")
print(color('red', 'Fatal error while loading config:'), str(err)) print(color('red', 'Fatal error while loading config:'), str(err))
res['except'].setdefault(ERROR_STR, []).append(str(err)) res['except'].setdefault(ERROR_STR, []).append(str(err))
finally: finally:
@ -290,8 +283,9 @@ class HomeAssistantConfig(OrderedDict):
return self return self
def check_ha_config_file(config_dir): def check_ha_config_file(hass):
"""Check if Home Assistant configuration file is valid.""" """Check if Home Assistant configuration file is valid."""
config_dir = hass.config.config_dir
result = HomeAssistantConfig() result = HomeAssistantConfig()
def _pack_error(package, component, config, message): def _pack_error(package, component, config, message):
@ -330,7 +324,7 @@ def check_ha_config_file(config_dir):
# Merge packages # Merge packages
merge_packages_config( 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] del core_config[CONF_PACKAGES]
# Ensure we have no None values after merge # Ensure we have no None values after merge
@ -343,7 +337,7 @@ def check_ha_config_file(config_dir):
# Process and validate config # Process and validate config
for domain in components: for domain in components:
component = get_component(domain) component = loader.get_component(hass, domain)
if not component: if not component:
result.add_error("Component not found: {}".format(domain)) result.add_error("Component not found: {}".format(domain))
continue continue
@ -375,7 +369,7 @@ def check_ha_config_file(config_dir):
platforms.append(p_validated) platforms.append(p_validated)
continue continue
platform = get_platform(domain, p_name) platform = loader.get_platform(hass, domain, p_name)
if platform is None: if platform is None:
result.add_error( 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) _LOGGER.error("Setup failed for %s: %s", domain, msg)
async_notify_setup_error(hass, domain, link) async_notify_setup_error(hass, domain, link)
component = loader.get_component(domain) component = loader.get_component(hass, domain)
if not component: if not component:
log_error("Component not found.", False) log_error("Component not found.", False)
return False return False
# Validate no circular dependencies # 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 # OrderedSet is empty if component or dependencies could not be resolved
if not components: if not components:
@ -159,7 +159,7 @@ async def _async_setup_component(hass: core.HomeAssistant,
elif result is not True: elif result is not True:
log_error("Component did not return boolean if setup was successful. " log_error("Component did not return boolean if setup was successful. "
"Disabling component.") "Disabling component.")
loader.set_component(domain, None) loader.set_component(hass, domain, None)
return False return False
for entry in hass.config_entries.async_entries(domain): 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) platform_path, msg)
async_notify_setup_error(hass, platform_path) async_notify_setup_error(hass, platform_path)
platform = loader.get_platform(domain, platform_name) platform = loader.get_platform(hass, domain, platform_name)
# Not found # Not found
if platform is None: if platform is None:

View File

@ -10,8 +10,7 @@ import logging
import threading import threading
from contextlib import contextmanager from contextlib import contextmanager
from homeassistant import ( from homeassistant import auth, core as ha, data_entry_flow, config_entries
auth, core as ha, loader, data_entry_flow, config_entries)
from homeassistant.setup import setup_component, async_setup_component from homeassistant.setup import setup_component, async_setup_component
from homeassistant.config import async_process_component_config from homeassistant.config import async_process_component_config
from homeassistant.helpers import ( from homeassistant.helpers import (
@ -138,9 +137,6 @@ def async_test_home_assistant(loop):
hass.config.units = METRIC_SYSTEM hass.config.units = METRIC_SYSTEM
hass.config.skip_pip = True 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 hass.state = ha.CoreState.running
# Mock async_start # Mock async_start

View File

@ -116,7 +116,7 @@ class TestGenericThermostatHeaterSwitching(unittest.TestCase):
def test_heater_switch(self): def test_heater_switch(self):
"""Test heater switching test switch.""" """Test heater switching test switch."""
platform = loader.get_component('switch.test') platform = loader.get_component(self.hass, 'switch.test')
platform.init() platform.init()
self.switch_1 = platform.DEVICES[1] self.switch_1 = platform.DEVICES[1]
assert setup_component(self.hass, switch.DOMAIN, {'switch': { 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 from tests.common import MockConfigEntry, MockModule, mock_coro_func
@pytest.fixture(scope='session', autouse=True) @pytest.fixture(autouse=True)
def mock_test_component(): def mock_test_component(hass):
"""Ensure a component called 'test' exists.""" """Ensure a component called 'test' exists."""
set_component('test', MockModule('test')) set_component(hass, 'test', MockModule('test'))
@pytest.fixture @pytest.fixture
@ -172,7 +172,8 @@ def test_abort(hass, client):
def test_create_account(hass, client): def test_create_account(hass, client):
"""Test a flow that creates an account.""" """Test a flow that creates an account."""
set_component( 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): class TestFlow(FlowHandler):
VERSION = 1 VERSION = 1
@ -204,7 +205,8 @@ def test_create_account(hass, client):
def test_two_step_flow(hass, client): def test_two_step_flow(hass, client):
"""Test we can finish a two step flow.""" """Test we can finish a two step flow."""
set_component( 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): class TestFlow(FlowHandler):
VERSION = 1 VERSION = 1

View File

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

View File

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

View File

@ -118,7 +118,7 @@ class TestLight(unittest.TestCase):
def test_services(self): def test_services(self):
"""Test the provided services.""" """Test the provided services."""
platform = loader.get_component('light.test') platform = loader.get_component(self.hass, 'light.test')
platform.init() platform.init()
self.assertTrue( self.assertTrue(
@ -267,7 +267,7 @@ class TestLight(unittest.TestCase):
def test_broken_light_profiles(self): def test_broken_light_profiles(self):
"""Test light profiles.""" """Test light profiles."""
platform = loader.get_component('light.test') platform = loader.get_component(self.hass, 'light.test')
platform.init() platform.init()
user_light_file = self.hass.config.path(light.LIGHT_PROFILES_FILE) user_light_file = self.hass.config.path(light.LIGHT_PROFILES_FILE)
@ -282,7 +282,7 @@ class TestLight(unittest.TestCase):
def test_light_profiles(self): def test_light_profiles(self):
"""Test light profiles.""" """Test light profiles."""
platform = loader.get_component('light.test') platform = loader.get_component(self.hass, 'light.test')
platform.init() platform.init()
user_light_file = self.hass.config.path(light.LIGHT_PROFILES_FILE) 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 def setUp(self): # pylint: disable=invalid-name
"""Setup things to be run when tests are started.""" """Setup things to be run when tests are started."""
self.hass = get_test_home_assistant() 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() test_light.init()
self.assertTrue(setup_component(self.hass, light.DOMAIN, { 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): def test_flux_when_switch_is_off(self):
"""Test the flux switch when it is off.""" """Test the flux switch when it is off."""
platform = loader.get_component('light.test') platform = loader.get_component(self.hass, 'light.test')
platform.init() platform.init()
self.assertTrue( self.assertTrue(
setup_component(self.hass, light.DOMAIN, setup_component(self.hass, light.DOMAIN,
@ -113,7 +113,7 @@ class TestSwitchFlux(unittest.TestCase):
def test_flux_before_sunrise(self): def test_flux_before_sunrise(self):
"""Test the flux switch before sunrise.""" """Test the flux switch before sunrise."""
platform = loader.get_component('light.test') platform = loader.get_component(self.hass, 'light.test')
platform.init() platform.init()
self.assertTrue( self.assertTrue(
setup_component(self.hass, light.DOMAIN, setup_component(self.hass, light.DOMAIN,
@ -160,7 +160,7 @@ class TestSwitchFlux(unittest.TestCase):
# pylint: disable=invalid-name # pylint: disable=invalid-name
def test_flux_after_sunrise_before_sunset(self): def test_flux_after_sunrise_before_sunset(self):
"""Test the flux switch after sunrise and before sunset.""" """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() platform.init()
self.assertTrue( self.assertTrue(
setup_component(self.hass, light.DOMAIN, setup_component(self.hass, light.DOMAIN,
@ -207,7 +207,7 @@ class TestSwitchFlux(unittest.TestCase):
# pylint: disable=invalid-name # pylint: disable=invalid-name
def test_flux_after_sunset_before_stop(self): def test_flux_after_sunset_before_stop(self):
"""Test the flux switch after sunset and before stop.""" """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() platform.init()
self.assertTrue( self.assertTrue(
setup_component(self.hass, light.DOMAIN, setup_component(self.hass, light.DOMAIN,
@ -255,7 +255,7 @@ class TestSwitchFlux(unittest.TestCase):
# pylint: disable=invalid-name # pylint: disable=invalid-name
def test_flux_after_stop_before_sunrise(self): def test_flux_after_stop_before_sunrise(self):
"""Test the flux switch after stop and before sunrise.""" """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() platform.init()
self.assertTrue( self.assertTrue(
setup_component(self.hass, light.DOMAIN, setup_component(self.hass, light.DOMAIN,
@ -302,7 +302,7 @@ class TestSwitchFlux(unittest.TestCase):
# pylint: disable=invalid-name # pylint: disable=invalid-name
def test_flux_with_custom_start_stop_times(self): def test_flux_with_custom_start_stop_times(self):
"""Test the flux with custom start and stop times.""" """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() platform.init()
self.assertTrue( self.assertTrue(
setup_component(self.hass, light.DOMAIN, 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). 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() platform.init()
self.assertTrue( self.assertTrue(
setup_component(self.hass, light.DOMAIN, 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). 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() platform.init()
self.assertTrue( self.assertTrue(
setup_component(self.hass, light.DOMAIN, 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). 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() platform.init()
self.assertTrue( self.assertTrue(
setup_component(self.hass, light.DOMAIN, 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). 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() platform.init()
self.assertTrue( self.assertTrue(
setup_component(self.hass, light.DOMAIN, 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). 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() platform.init()
self.assertTrue( self.assertTrue(
setup_component(self.hass, light.DOMAIN, setup_component(self.hass, light.DOMAIN,
@ -606,7 +606,7 @@ class TestSwitchFlux(unittest.TestCase):
# pylint: disable=invalid-name # pylint: disable=invalid-name
def test_flux_with_custom_colortemps(self): def test_flux_with_custom_colortemps(self):
"""Test the flux with custom start and stop colortemps.""" """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() platform.init()
self.assertTrue( self.assertTrue(
setup_component(self.hass, light.DOMAIN, setup_component(self.hass, light.DOMAIN,
@ -656,7 +656,7 @@ class TestSwitchFlux(unittest.TestCase):
# pylint: disable=invalid-name # pylint: disable=invalid-name
def test_flux_with_custom_brightness(self): def test_flux_with_custom_brightness(self):
"""Test the flux with custom start and stop colortemps.""" """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() platform.init()
self.assertTrue( self.assertTrue(
setup_component(self.hass, light.DOMAIN, setup_component(self.hass, light.DOMAIN,
@ -704,7 +704,7 @@ class TestSwitchFlux(unittest.TestCase):
def test_flux_with_multiple_lights(self): def test_flux_with_multiple_lights(self):
"""Test the flux switch with multiple light entities.""" """Test the flux switch with multiple light entities."""
platform = loader.get_component('light.test') platform = loader.get_component(self.hass, 'light.test')
platform.init() platform.init()
self.assertTrue( self.assertTrue(
setup_component(self.hass, light.DOMAIN, setup_component(self.hass, light.DOMAIN,
@ -773,7 +773,7 @@ class TestSwitchFlux(unittest.TestCase):
def test_flux_with_mired(self): def test_flux_with_mired(self):
"""Test the flux switch´s mode mired.""" """Test the flux switch´s mode mired."""
platform = loader.get_component('light.test') platform = loader.get_component(self.hass, 'light.test')
platform.init() platform.init()
self.assertTrue( self.assertTrue(
setup_component(self.hass, light.DOMAIN, setup_component(self.hass, light.DOMAIN,
@ -818,7 +818,7 @@ class TestSwitchFlux(unittest.TestCase):
def test_flux_with_rgb(self): def test_flux_with_rgb(self):
"""Test the flux switch´s mode rgb.""" """Test the flux switch´s mode rgb."""
platform = loader.get_component('light.test') platform = loader.get_component(self.hass, 'light.test')
platform.init() platform.init()
self.assertTrue( self.assertTrue(
setup_component(self.hass, light.DOMAIN, setup_component(self.hass, light.DOMAIN,

View File

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

View File

@ -22,12 +22,12 @@ class TestDeviceSunLightTrigger(unittest.TestCase):
self.hass = get_test_home_assistant() self.hass = get_test_home_assistant()
self.scanner = loader.get_component( 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.reset()
self.scanner.come_home('DEV1') self.scanner.come_home('DEV1')
loader.get_component('light.test').init() loader.get_component(self.hass, 'light.test').init()
with patch( with patch(
'homeassistant.components.device_tracker.load_yaml_config_file', '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 import homeassistant.helpers.config_validation as cv
from tests.common import get_test_home_assistant
def test_boolean(): def test_boolean():
"""Test boolean validation.""" """Test boolean validation."""
@ -256,24 +254,6 @@ def test_event_schema():
cv.EVENT_SCHEMA(value) 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(): def test_icon():
"""Test icon validation.""" """Test icon validation."""
schema = vol.Schema(cv.icon) schema = vol.Schema(cv.icon)

View File

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

View File

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

View File

@ -147,7 +147,7 @@ class TestHelpersEntityPlatform(unittest.TestCase):
platform = MockPlatform(platform_setup) platform = MockPlatform(platform_setup)
platform.SCAN_INTERVAL = timedelta(seconds=30) 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) 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.""" """Warn we log when platform setup takes a long time."""
platform = MockPlatform() platform = MockPlatform()
loader.set_component('test_domain.platform', platform) loader.set_component(hass, 'test_domain.platform', platform)
component = EntityComponent(_LOGGER, DOMAIN, hass) component = EntityComponent(_LOGGER, DOMAIN, hass)
@ -218,7 +218,7 @@ def test_platform_error_slow_setup(hass, caplog):
platform = MockPlatform(async_setup_platform=setup_platform) platform = MockPlatform(async_setup_platform=setup_platform)
component = EntityComponent(_LOGGER, DOMAIN, hass) 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({ yield from component.async_setup({
DOMAIN: { DOMAIN: {
'platform': 'test_platform', 'platform': 'test_platform',
@ -260,7 +260,7 @@ def test_parallel_updates_async_platform(hass):
platform.async_setup_platform = mock_update 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 = EntityComponent(_LOGGER, DOMAIN, hass)
component._platforms = {} component._platforms = {}
@ -288,7 +288,7 @@ def test_parallel_updates_async_platform_with_constant(hass):
platform.async_setup_platform = mock_update platform.async_setup_platform = mock_update
platform.PARALLEL_UPDATES = 1 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 = EntityComponent(_LOGGER, DOMAIN, hass)
component._platforms = {} component._platforms = {}
@ -309,7 +309,7 @@ def test_parallel_updates_sync_platform(hass):
"""Warn we log when platform setup takes a long time.""" """Warn we log when platform setup takes a long time."""
platform = MockPlatform(setup_platform=lambda *args: None) 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 = EntityComponent(_LOGGER, DOMAIN, hass)
component._platforms = {} 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.Ceiling', STATE_OFF)
self.hass.states.set('light.Kitchen', 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']) self.hass, 'test', ['light.Ceiling', 'light.Kitchen'])
call = ha.ServiceCall('light', 'turn_on', call = ha.ServiceCall('light', 'turn_on',
@ -160,7 +160,7 @@ class TestServiceHelpers(unittest.TestCase):
@asyncio.coroutine @asyncio.coroutine
def test_async_get_all_descriptions(hass): def test_async_get_all_descriptions(hass):
"""Test async_get_all_descriptions.""" """Test async_get_all_descriptions."""
group = loader.get_component('group') group = loader.get_component(hass, 'group')
group_config = {group.DOMAIN: {}} group_config = {group.DOMAIN: {}}
yield from async_setup_component(hass, group.DOMAIN, group_config) yield from async_setup_component(hass, group.DOMAIN, group_config)
descriptions = yield from service.async_get_all_descriptions(hass) 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 'description' in descriptions['group']['reload']
assert 'fields' 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: {}} logger_config = {logger.DOMAIN: {}}
yield from async_setup_component(hass, logger.DOMAIN, logger_config) yield from async_setup_component(hass, logger.DOMAIN, logger_config)
descriptions = yield from service.async_get_all_descriptions(hass) 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( 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')) 'custom_components', 'switch', '.translations', 'test.en.json'))
assert path.normpath(translation.component_translation_file( 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')) 'custom_components', '.translations', 'test_standalone.en.json'))
assert path.normpath(translation.component_translation_file( 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')) '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 import homeassistant.scripts.check_config as check_config
from homeassistant.config import YAML_CONFIG_FILE from homeassistant.config import YAML_CONFIG_FILE
from homeassistant.loader import set_component
from tests.common import patch_yaml_files, get_test_config_dir from tests.common import patch_yaml_files, get_test_config_dir
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -106,7 +105,6 @@ class TestCheckConfig(unittest.TestCase):
def test_component_platform_not_found(self, isfile_patch): def test_component_platform_not_found(self, isfile_patch):
"""Test errors if component or platform not found.""" """Test errors if component or platform not found."""
# Make sure they don't exist # Make sure they don't exist
set_component('beer', None)
files = { files = {
YAML_CONFIG_FILE: BASE_CONFIG + 'beer:', YAML_CONFIG_FILE: BASE_CONFIG + 'beer:',
} }
@ -119,7 +117,6 @@ class TestCheckConfig(unittest.TestCase):
assert res['secrets'] == {} assert res['secrets'] == {}
assert len(res['yaml_files']) == 1 assert len(res['yaml_files']) == 1
set_component('light.beer', None)
files = { files = {
YAML_CONFIG_FILE: BASE_CONFIG + 'light:\n platform: beer', YAML_CONFIG_FILE: BASE_CONFIG + 'light:\n platform: beer',
} }

View File

@ -568,7 +568,7 @@ def merge_log_err(hass):
yield logerr yield logerr
def test_merge(merge_log_err): def test_merge(merge_log_err, hass):
"""Test if we can merge packages.""" """Test if we can merge packages."""
packages = { packages = {
'pack_dict': {'input_boolean': {'ib1': None}}, 'pack_dict': {'input_boolean': {'ib1': None}},
@ -582,7 +582,7 @@ def test_merge(merge_log_err):
'input_boolean': {'ib2': None}, 'input_boolean': {'ib2': None},
'light': {'platform': 'test'} '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 merge_log_err.call_count == 0
assert len(config) == 5 assert len(config) == 5
@ -592,7 +592,7 @@ def test_merge(merge_log_err):
assert config['wake_on_lan'] is None 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.""" """Ensure we dont add falsy items like empty OrderedDict() to list."""
packages = { packages = {
'pack_falsy_to_lst': {'automation': OrderedDict()}, 'pack_falsy_to_lst': {'automation': OrderedDict()},
@ -603,7 +603,7 @@ def test_merge_try_falsy(merge_log_err):
'automation': {'do': 'something'}, 'automation': {'do': 'something'},
'light': {'some': 'light'}, '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 merge_log_err.call_count == 0
assert len(config) == 3 assert len(config) == 3
@ -611,7 +611,7 @@ def test_merge_try_falsy(merge_log_err):
assert len(config['light']) == 1 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.""" """Test adding new components to outer scope."""
packages = { packages = {
'pack_1': {'light': [{'platform': 'one'}]}, 'pack_1': {'light': [{'platform': 'one'}]},
@ -624,7 +624,7 @@ def test_merge_new(merge_log_err):
config = { config = {
config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages}, 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 merge_log_err.call_count == 0
assert 'api' in config assert 'api' in config
@ -633,7 +633,7 @@ def test_merge_new(merge_log_err):
assert len(config['panel_custom']) == 1 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.""" """Test if we have a type mismatch for packages."""
packages = { packages = {
'pack_1': {'input_boolean': [{'ib1': None}]}, 'pack_1': {'input_boolean': [{'ib1': None}]},
@ -646,7 +646,7 @@ def test_merge_type_mismatch(merge_log_err):
'input_select': [{'ib2': None}], 'input_select': [{'ib2': None}],
'light': [{'platform': 'two'}] '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 merge_log_err.call_count == 2
assert len(config) == 4 assert len(config) == 4
@ -654,7 +654,7 @@ def test_merge_type_mismatch(merge_log_err):
assert len(config['light']) == 2 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.""" """Test if we have a merge for a comp that may occur only once."""
packages = { packages = {
'pack_2': { 'pack_2': {
@ -666,7 +666,7 @@ def test_merge_once_only(merge_log_err):
config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages}, config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages},
'mqtt': {}, 'api': {} '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 merge_log_err.call_count == 1
assert len(config) == 3 assert len(config) == 3
@ -682,13 +682,13 @@ def test_merge_id_schema(hass):
'qwikswitch': 'dict', 'qwikswitch': 'dict',
} }
for name, expected_type in types.items(): 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) typ, _ = config_util._identify_config_schema(module)
assert typ == expected_type, "{} expected {}, got {}".format( assert typ == expected_type, "{} expected {}, got {}".format(
name, expected_type, typ) 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.""" """Test if keys in dicts are duplicates."""
packages = { packages = {
'pack_1': {'input_select': {'ib1': None}}, '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}, config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages},
'input_select': {'ib1': None}, '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 merge_log_err.call_count == 1
assert len(config) == 2 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)) mock_setup_entry = MagicMock(return_value=mock_coro(True))
loader.set_component( loader.set_component(
'comp', hass, 'comp',
MockModule('comp', async_setup_entry=mock_setup_entry)) MockModule('comp', async_setup_entry=mock_setup_entry))
result = yield from async_setup_component(hass, 'comp', {}) result = yield from async_setup_component(hass, 'comp', {})
@ -36,12 +36,12 @@ def test_call_setup_entry(hass):
@asyncio.coroutine @asyncio.coroutine
def test_remove_entry(manager): def test_remove_entry(hass, manager):
"""Test that we can remove an entry.""" """Test that we can remove an entry."""
mock_unload_entry = MagicMock(return_value=mock_coro(True)) mock_unload_entry = MagicMock(return_value=mock_coro(True))
loader.set_component( loader.set_component(
'test', hass, 'test',
MockModule('comp', async_unload_entry=mock_unload_entry)) MockModule('comp', async_unload_entry=mock_unload_entry))
MockConfigEntry(domain='test', entry_id='test1').add_to_manager(manager) MockConfigEntry(domain='test', entry_id='test1').add_to_manager(manager)
@ -63,7 +63,7 @@ def test_remove_entry(manager):
@asyncio.coroutine @asyncio.coroutine
def test_remove_entry_raises(manager): def test_remove_entry_raises(hass, manager):
"""Test if a component raises while removing entry.""" """Test if a component raises while removing entry."""
@asyncio.coroutine @asyncio.coroutine
def mock_unload_entry(hass, entry): def mock_unload_entry(hass, entry):
@ -71,7 +71,7 @@ def test_remove_entry_raises(manager):
raise Exception("BROKEN") raise Exception("BROKEN")
loader.set_component( loader.set_component(
'test', hass, 'test',
MockModule('comp', async_unload_entry=mock_unload_entry)) MockModule('comp', async_unload_entry=mock_unload_entry))
MockConfigEntry(domain='test', entry_id='test1').add_to_manager(manager) 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)) mock_setup_entry = MagicMock(return_value=mock_coro(True))
loader.set_component( loader.set_component(
'comp', hass, 'comp',
MockModule('comp', async_setup_entry=mock_setup_entry)) MockModule('comp', async_setup_entry=mock_setup_entry))
class TestFlow(data_entry_flow.FlowHandler): class TestFlow(data_entry_flow.FlowHandler):
@ -151,6 +151,8 @@ def test_domains_gets_uniques(manager):
@asyncio.coroutine @asyncio.coroutine
def test_saving_and_loading(hass): def test_saving_and_loading(hass):
"""Test that we're saving and loading correctly.""" """Test that we're saving and loading correctly."""
loader.set_component(hass, 'test', MockModule('test'))
class TestFlow(data_entry_flow.FlowHandler): class TestFlow(data_entry_flow.FlowHandler):
VERSION = 5 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)) mock_original_setup_entry = MagicMock(return_value=mock_coro(True))
loader.set_component( loader.set_component(
'original', hass, 'original',
MockModule('original', async_setup_entry=mock_original_setup_entry)) MockModule('original', async_setup_entry=mock_original_setup_entry))
mock_forwarded_setup_entry = MagicMock(return_value=mock_coro(True)) mock_forwarded_setup_entry = MagicMock(return_value=mock_coro(True))
loader.set_component( loader.set_component(
'forwarded', hass, 'forwarded',
MockModule('forwarded', async_setup_entry=mock_forwarded_setup_entry)) MockModule('forwarded', async_setup_entry=mock_forwarded_setup_entry))
await hass.config_entries.async_forward_entry_setup(entry, 'forwarded') 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 = MagicMock(return_value=mock_coro(False))
mock_setup_entry = MagicMock() mock_setup_entry = MagicMock()
loader.set_component('forwarded', MockModule( hass, loader.set_component(hass, 'forwarded', MockModule(
'forwarded', 'forwarded',
async_setup=mock_setup, async_setup=mock_setup,
async_setup_entry=mock_setup_entry, 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): async def test_discovery_notification(hass):
"""Test that we create/dismiss a notification when source is discovery.""" """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', {}) await async_setup_component(hass, 'persistent_notification', {})
class TestFlow(data_entry_flow.FlowHandler): class TestFlow(data_entry_flow.FlowHandler):

View File

@ -27,37 +27,40 @@ class TestLoader(unittest.TestCase):
def test_set_component(self): def test_set_component(self):
"""Test if set_component works.""" """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): def test_get_component(self):
"""Test if get_component works.""" """Test if get_component works."""
self.assertEqual(http, loader.get_component('http')) self.assertEqual(http, loader.get_component(self.hass, 'http'))
self.assertIsNotNone(loader.get_component(self.hass, 'light.hue'))
self.assertIsNotNone(loader.get_component('switch.test'))
def test_load_order_component(self): def test_load_order_component(self):
"""Test if we can get the proper load order of components.""" """Test if we can get the proper load order of components."""
loader.set_component('mod1', MockModule('mod1')) loader.set_component(self.hass, 'mod1', MockModule('mod1'))
loader.set_component('mod2', MockModule('mod2', ['mod1'])) loader.set_component(self.hass, 'mod2', MockModule('mod2', ['mod1']))
loader.set_component('mod3', MockModule('mod3', ['mod2'])) loader.set_component(self.hass, 'mod3', MockModule('mod3', ['mod2']))
self.assertEqual( self.assertEqual(
['mod1', 'mod2', 'mod3'], loader.load_order_component('mod3')) ['mod1', 'mod2', 'mod3'],
loader.load_order_component(self.hass, 'mod3'))
# Create circular dependency # 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 # 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 # 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): def test_component_loader(hass):

View File

@ -35,7 +35,8 @@ class TestRequirements:
mock_dirname.return_value = 'ha_package_path' mock_dirname.return_value = 'ha_package_path'
self.hass.config.skip_pip = False self.hass.config.skip_pip = False
loader.set_component( 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 setup.setup_component(self.hass, 'comp')
assert 'comp' in self.hass.config.components assert 'comp' in self.hass.config.components
assert mock_install.call_args == mock.call( assert mock_install.call_args == mock.call(
@ -53,7 +54,8 @@ class TestRequirements:
mock_dirname.return_value = 'ha_package_path' mock_dirname.return_value = 'ha_package_path'
self.hass.config.skip_pip = False self.hass.config.skip_pip = False
loader.set_component( 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 setup.setup_component(self.hass, 'comp')
assert 'comp' in self.hass.config.components assert 'comp' in self.hass.config.components
assert mock_install.call_args == mock.call( assert mock_install.call_args == mock.call(

View File

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

View File

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