diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py index 0abe5a7811e..826cc563e82 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -12,8 +12,7 @@ from typing import Any, Optional, Dict import voluptuous as vol from homeassistant import ( - core, config as conf_util, config_entries, loader, - components as core_components) + core, config as conf_util, config_entries, components as core_components) from homeassistant.components import persistent_notification from homeassistant.const import EVENT_HOMEASSISTANT_CLOSE from homeassistant.setup import async_setup_component @@ -103,15 +102,12 @@ async def async_from_config_dict(config: Dict[str, Any], _LOGGER.warning("Skipping pip installation of required modules. " "This may cause issues") - if not loader.PREPARED: - await hass.async_add_job(loader.prepare, hass) - # Make a copy because we are mutating it. config = OrderedDict(config) # Merge packages conf_util.merge_packages_config( - config, core_config.get(conf_util.CONF_PACKAGES, {})) + hass, config, core_config.get(conf_util.CONF_PACKAGES, {})) # Ensure we have no None values after merge for key, value in config.items(): diff --git a/homeassistant/components/automation/__init__.py b/homeassistant/components/automation/__init__.py index 8c490754f40..2f510fd33d6 100644 --- a/homeassistant/components/automation/__init__.py +++ b/homeassistant/components/automation/__init__.py @@ -6,6 +6,7 @@ https://home-assistant.io/components/automation/ """ import asyncio from functools import partial +import importlib import logging import voluptuous as vol @@ -22,7 +23,6 @@ from homeassistant.helpers import extract_domain_configs, script, condition from homeassistant.helpers.entity import ToggleEntity from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.restore_state import async_get_last_state -from homeassistant.loader import get_platform from homeassistant.util.dt import utcnow import homeassistant.helpers.config_validation as cv @@ -58,12 +58,14 @@ _LOGGER = logging.getLogger(__name__) def _platform_validator(config): """Validate it is a valid platform.""" - platform = get_platform(DOMAIN, config[CONF_PLATFORM]) + try: + platform = importlib.import_module( + 'homeassistant.components.automation.{}'.format( + config[CONF_PLATFORM])) + except ImportError: + raise vol.Invalid('Invalid platform specified') from None - if not hasattr(platform, 'TRIGGER_SCHEMA'): - return config - - return getattr(platform, 'TRIGGER_SCHEMA')(config) + return platform.TRIGGER_SCHEMA(config) _TRIGGER_SCHEMA = vol.All( @@ -71,7 +73,7 @@ _TRIGGER_SCHEMA = vol.All( [ vol.All( vol.Schema({ - vol.Required(CONF_PLATFORM): cv.platform_validator(DOMAIN) + vol.Required(CONF_PLATFORM): str }, extra=vol.ALLOW_EXTRA), _platform_validator ), diff --git a/homeassistant/components/binary_sensor/bloomsky.py b/homeassistant/components/binary_sensor/bloomsky.py index 53f148fe97f..3080cc65532 100644 --- a/homeassistant/components/binary_sensor/bloomsky.py +++ b/homeassistant/components/binary_sensor/bloomsky.py @@ -11,7 +11,6 @@ import voluptuous as vol from homeassistant.components.binary_sensor import ( BinarySensorDevice, PLATFORM_SCHEMA) from homeassistant.const import CONF_MONITORED_CONDITIONS -from homeassistant.loader import get_component import homeassistant.helpers.config_validation as cv _LOGGER = logging.getLogger(__name__) @@ -31,7 +30,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the available BloomSky weather binary sensors.""" - bloomsky = get_component('bloomsky') + bloomsky = hass.components.bloomsky # Default needed in case of discovery sensors = config.get(CONF_MONITORED_CONDITIONS, SENSOR_TYPES) diff --git a/homeassistant/components/binary_sensor/netatmo.py b/homeassistant/components/binary_sensor/netatmo.py index 7997e4e60db..fd0e30ccebc 100644 --- a/homeassistant/components/binary_sensor/netatmo.py +++ b/homeassistant/components/binary_sensor/netatmo.py @@ -13,7 +13,6 @@ import voluptuous as vol from homeassistant.components.binary_sensor import ( BinarySensorDevice, PLATFORM_SCHEMA) from homeassistant.components.netatmo import CameraData -from homeassistant.loader import get_component from homeassistant.const import CONF_TIMEOUT from homeassistant.helpers import config_validation as cv @@ -61,7 +60,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ # pylint: disable=unused-argument def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the access to Netatmo binary sensor.""" - netatmo = get_component('netatmo') + netatmo = hass.components.netatmo home = config.get(CONF_HOME) timeout = config.get(CONF_TIMEOUT) if timeout is None: diff --git a/homeassistant/components/binary_sensor/wemo.py b/homeassistant/components/binary_sensor/wemo.py index cc1f602d871..30a7e291401 100644 --- a/homeassistant/components/binary_sensor/wemo.py +++ b/homeassistant/components/binary_sensor/wemo.py @@ -7,7 +7,6 @@ https://home-assistant.io/components/binary_sensor.wemo/ import logging from homeassistant.components.binary_sensor import BinarySensorDevice -from homeassistant.loader import get_component DEPENDENCIES = ['wemo'] @@ -25,18 +24,18 @@ def setup_platform(hass, config, add_devices_callback, discovery_info=None): device = discovery.device_from_description(location, mac) if device: - add_devices_callback([WemoBinarySensor(device)]) + add_devices_callback([WemoBinarySensor(hass, device)]) class WemoBinarySensor(BinarySensorDevice): """Representation a WeMo binary sensor.""" - def __init__(self, device): + def __init__(self, hass, device): """Initialize the WeMo sensor.""" self.wemo = device self._state = None - wemo = get_component('wemo') + wemo = hass.components.wemo wemo.SUBSCRIPTION_REGISTRY.register(self.wemo) wemo.SUBSCRIPTION_REGISTRY.on(self.wemo, None, self._update_callback) diff --git a/homeassistant/components/camera/bloomsky.py b/homeassistant/components/camera/bloomsky.py index c3b4775b593..ef70692215d 100644 --- a/homeassistant/components/camera/bloomsky.py +++ b/homeassistant/components/camera/bloomsky.py @@ -9,7 +9,6 @@ import logging import requests from homeassistant.components.camera import Camera -from homeassistant.loader import get_component DEPENDENCIES = ['bloomsky'] @@ -17,7 +16,7 @@ DEPENDENCIES = ['bloomsky'] # pylint: disable=unused-argument def setup_platform(hass, config, add_devices, discovery_info=None): """Set up access to BloomSky cameras.""" - bloomsky = get_component('bloomsky') + bloomsky = hass.components.bloomsky for device in bloomsky.BLOOMSKY.devices.values(): add_devices([BloomSkyCamera(bloomsky.BLOOMSKY, device)]) diff --git a/homeassistant/components/camera/netatmo.py b/homeassistant/components/camera/netatmo.py index 48f2710ce2e..bf2dfe39bd8 100644 --- a/homeassistant/components/camera/netatmo.py +++ b/homeassistant/components/camera/netatmo.py @@ -12,7 +12,6 @@ import voluptuous as vol from homeassistant.const import CONF_VERIFY_SSL from homeassistant.components.netatmo import CameraData from homeassistant.components.camera import (Camera, PLATFORM_SCHEMA) -from homeassistant.loader import get_component from homeassistant.helpers import config_validation as cv DEPENDENCIES = ['netatmo'] @@ -33,7 +32,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ # pylint: disable=unused-argument def setup_platform(hass, config, add_devices, discovery_info=None): """Set up access to Netatmo cameras.""" - netatmo = get_component('netatmo') + netatmo = hass.components.netatmo home = config.get(CONF_HOME) verify_ssl = config.get(CONF_VERIFY_SSL, True) import lnetatmo diff --git a/homeassistant/components/climate/netatmo.py b/homeassistant/components/climate/netatmo.py index 5d54b39e773..49452662fc4 100644 --- a/homeassistant/components/climate/netatmo.py +++ b/homeassistant/components/climate/netatmo.py @@ -13,7 +13,6 @@ from homeassistant.components.climate import ( STATE_HEAT, STATE_IDLE, ClimateDevice, PLATFORM_SCHEMA, SUPPORT_TARGET_TEMPERATURE, SUPPORT_OPERATION_MODE, SUPPORT_AWAY_MODE) from homeassistant.util import Throttle -from homeassistant.loader import get_component import homeassistant.helpers.config_validation as cv DEPENDENCIES = ['netatmo'] @@ -42,7 +41,7 @@ SUPPORT_FLAGS = (SUPPORT_TARGET_TEMPERATURE | SUPPORT_OPERATION_MODE | def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the NetAtmo Thermostat.""" - netatmo = get_component('netatmo') + netatmo = hass.components.netatmo device = config.get(CONF_RELAY) import lnetatmo diff --git a/homeassistant/components/device_sun_light_trigger.py b/homeassistant/components/device_sun_light_trigger.py index a1297c5c118..641ade7308b 100644 --- a/homeassistant/components/device_sun_light_trigger.py +++ b/homeassistant/components/device_sun_light_trigger.py @@ -16,7 +16,6 @@ from homeassistant.const import STATE_HOME, STATE_NOT_HOME from homeassistant.helpers.event import ( async_track_point_in_utc_time, async_track_state_change) from homeassistant.helpers.sun import is_up, get_astral_event_next -from homeassistant.loader import get_component import homeassistant.helpers.config_validation as cv DOMAIN = 'device_sun_light_trigger' @@ -48,9 +47,9 @@ CONFIG_SCHEMA = vol.Schema({ def async_setup(hass, config): """Set up the triggers to control lights based on device presence.""" logger = logging.getLogger(__name__) - device_tracker = get_component('device_tracker') - group = get_component('group') - light = get_component('light') + device_tracker = hass.components.device_tracker + group = hass.components.group + light = hass.components.light conf = config[DOMAIN] disable_turn_off = conf.get(CONF_DISABLE_TURN_OFF) light_group = conf.get(CONF_LIGHT_GROUP, light.ENTITY_ID_ALL_LIGHTS) @@ -58,14 +57,14 @@ def async_setup(hass, config): device_group = conf.get( CONF_DEVICE_GROUP, device_tracker.ENTITY_ID_ALL_DEVICES) device_entity_ids = group.get_entity_ids( - hass, device_group, device_tracker.DOMAIN) + device_group, device_tracker.DOMAIN) if not device_entity_ids: logger.error("No devices found to track") return False # Get the light IDs from the specified group - light_ids = group.get_entity_ids(hass, light_group, light.DOMAIN) + light_ids = group.get_entity_ids(light_group, light.DOMAIN) if not light_ids: logger.error("No lights found to turn on") @@ -85,9 +84,9 @@ def async_setup(hass, config): def async_turn_on_before_sunset(light_id): """Turn on lights.""" - if not device_tracker.is_on(hass) or light.is_on(hass, light_id): + if not device_tracker.is_on() or light.is_on(light_id): return - light.async_turn_on(hass, light_id, + light.async_turn_on(light_id, transition=LIGHT_TRANSITION_TIME.seconds, profile=light_profile) @@ -129,7 +128,7 @@ def async_setup(hass, config): @callback def check_light_on_dev_state_change(entity, old_state, new_state): """Handle tracked device state changes.""" - lights_are_on = group.is_on(hass, light_group) + lights_are_on = group.is_on(light_group) light_needed = not (lights_are_on or is_up(hass)) # These variables are needed for the elif check @@ -139,7 +138,7 @@ def async_setup(hass, config): # Do we need lights? if light_needed: logger.info("Home coming event for %s. Turning lights on", entity) - light.async_turn_on(hass, light_ids, profile=light_profile) + light.async_turn_on(light_ids, profile=light_profile) # Are we in the time span were we would turn on the lights # if someone would be home? @@ -152,7 +151,7 @@ def async_setup(hass, config): # when the fading in started and turn it on if so for index, light_id in enumerate(light_ids): if now > start_point + index * LIGHT_TRANSITION_TIME: - light.async_turn_on(hass, light_id) + light.async_turn_on(light_id) else: # If this light didn't happen to be turned on yet so @@ -169,12 +168,12 @@ def async_setup(hass, config): @callback def turn_off_lights_when_all_leave(entity, old_state, new_state): """Handle device group state change.""" - if not group.is_on(hass, light_group): + if not group.is_on(light_group): return logger.info( "Everyone has left but there are lights on. Turning them off") - light.async_turn_off(hass, light_ids) + light.async_turn_off(light_ids) async_track_state_change( hass, device_group, turn_off_lights_when_all_leave, diff --git a/homeassistant/components/device_tracker/__init__.py b/homeassistant/components/device_tracker/__init__.py index 2f068481953..e1dd52a28ea 100644 --- a/homeassistant/components/device_tracker/__init__.py +++ b/homeassistant/components/device_tracker/__init__.py @@ -24,7 +24,6 @@ from homeassistant.helpers.event import async_track_time_interval from homeassistant.helpers.restore_state import async_get_last_state from homeassistant.helpers.typing import GPSType, ConfigType, HomeAssistantType import homeassistant.helpers.config_validation as cv -from homeassistant.loader import get_component import homeassistant.util as util from homeassistant.util.async_ import run_coroutine_threadsafe import homeassistant.util.dt as dt_util @@ -322,7 +321,7 @@ class DeviceTracker(object): # During init, we ignore the group if self.group and self.track_new: self.group.async_set_group( - self.hass, util.slugify(GROUP_NAME_ALL_DEVICES), visible=False, + util.slugify(GROUP_NAME_ALL_DEVICES), visible=False, name=GROUP_NAME_ALL_DEVICES, add=[device.entity_id]) self.hass.bus.async_fire(EVENT_NEW_DEVICE, { @@ -357,9 +356,9 @@ class DeviceTracker(object): entity_ids = [dev.entity_id for dev in self.devices.values() if dev.track] - self.group = get_component('group') + self.group = self.hass.components.group self.group.async_set_group( - self.hass, util.slugify(GROUP_NAME_ALL_DEVICES), visible=False, + util.slugify(GROUP_NAME_ALL_DEVICES), visible=False, name=GROUP_NAME_ALL_DEVICES, entity_ids=entity_ids) @callback diff --git a/homeassistant/components/image_processing/__init__.py b/homeassistant/components/image_processing/__init__.py index 061fd5d7074..de195ce0165 100644 --- a/homeassistant/components/image_processing/__init__.py +++ b/homeassistant/components/image_processing/__init__.py @@ -17,7 +17,6 @@ from homeassistant.exceptions import HomeAssistantError from homeassistant.loader import bind_hass from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity_component import EntityComponent -from homeassistant.loader import get_component _LOGGER = logging.getLogger(__name__) @@ -121,12 +120,12 @@ class ImageProcessingEntity(Entity): This method is a coroutine. """ - camera = get_component('camera') + camera = self.hass.components.camera image = None try: image = yield from camera.async_get_image( - self.hass, self.camera_entity, timeout=self.timeout) + self.camera_entity, timeout=self.timeout) except HomeAssistantError as err: _LOGGER.error("Error on receive image from entity: %s", err) diff --git a/homeassistant/components/light/wemo.py b/homeassistant/components/light/wemo.py index d0575105235..fcf3d2f7a7d 100644 --- a/homeassistant/components/light/wemo.py +++ b/homeassistant/components/light/wemo.py @@ -12,7 +12,6 @@ import homeassistant.util as util from homeassistant.components.light import ( Light, ATTR_BRIGHTNESS, ATTR_COLOR_TEMP, ATTR_HS_COLOR, ATTR_TRANSITION, SUPPORT_BRIGHTNESS, SUPPORT_COLOR_TEMP, SUPPORT_COLOR, SUPPORT_TRANSITION) -from homeassistant.loader import get_component import homeassistant.util.color as color_util DEPENDENCIES = ['wemo'] @@ -151,7 +150,7 @@ class WemoDimmer(Light): @asyncio.coroutine def async_added_to_hass(self): """Register update callback.""" - wemo = get_component('wemo') + wemo = self.hass.components.wemo # The register method uses a threading condition, so call via executor. # and yield from to wait until the task is done. yield from self.hass.async_add_job( diff --git a/homeassistant/components/microsoft_face.py b/homeassistant/components/microsoft_face.py index 5a0bf2af1c4..e99d8d4a5f6 100644 --- a/homeassistant/components/microsoft_face.py +++ b/homeassistant/components/microsoft_face.py @@ -18,7 +18,6 @@ from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.aiohttp_client import async_get_clientsession import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity -from homeassistant.loader import get_component from homeassistant.util import slugify _LOGGER = logging.getLogger(__name__) @@ -231,7 +230,7 @@ def async_setup(hass, config): p_id = face.store[g_id].get(service.data[ATTR_PERSON]) camera_entity = service.data[ATTR_CAMERA_ENTITY] - camera = get_component('camera') + camera = hass.components.camera try: image = yield from camera.async_get_image(hass, camera_entity) diff --git a/homeassistant/components/mqtt_eventstream.py b/homeassistant/components/mqtt_eventstream.py index 6f6cb312f2b..aa670578172 100644 --- a/homeassistant/components/mqtt_eventstream.py +++ b/homeassistant/components/mqtt_eventstream.py @@ -10,7 +10,6 @@ import json import voluptuous as vol from homeassistant.core import callback -import homeassistant.loader as loader from homeassistant.components.mqtt import ( valid_publish_topic, valid_subscribe_topic) from homeassistant.const import ( @@ -42,7 +41,7 @@ CONFIG_SCHEMA = vol.Schema({ @asyncio.coroutine def async_setup(hass, config): """Set up the MQTT eventstream component.""" - mqtt = loader.get_component('mqtt') + mqtt = hass.components.mqtt conf = config.get(DOMAIN, {}) pub_topic = conf.get(CONF_PUBLISH_TOPIC) sub_topic = conf.get(CONF_SUBSCRIBE_TOPIC) @@ -82,7 +81,7 @@ def async_setup(hass, config): event_info = {'event_type': event.event_type, 'event_data': event.data} msg = json.dumps(event_info, cls=JSONEncoder) - mqtt.async_publish(hass, pub_topic, msg) + mqtt.async_publish(pub_topic, msg) # Only listen for local events if you are going to publish them. if pub_topic: @@ -115,7 +114,7 @@ def async_setup(hass, config): # Only subscribe if you specified a topic. if sub_topic: - yield from mqtt.async_subscribe(hass, sub_topic, _event_receiver) + yield from mqtt.async_subscribe(sub_topic, _event_receiver) hass.states.async_set('{domain}.initialized'.format(domain=DOMAIN), True) return True diff --git a/homeassistant/components/mysensors.py b/homeassistant/components/mysensors.py index 17c9129a31d..9b394457973 100644 --- a/homeassistant/components/mysensors.py +++ b/homeassistant/components/mysensors.py @@ -24,7 +24,6 @@ import homeassistant.helpers.config_validation as cv from homeassistant.helpers.dispatcher import ( async_dispatcher_connect, dispatcher_send) from homeassistant.helpers.entity import Entity -from homeassistant.loader import get_component from homeassistant.setup import setup_component REQUIREMENTS = ['pymysensors==0.11.1'] @@ -294,16 +293,16 @@ def setup(hass, config): if device == MQTT_COMPONENT: if not setup_component(hass, MQTT_COMPONENT, config): return - mqtt = get_component(MQTT_COMPONENT) + mqtt = hass.components.mqtt retain = config[DOMAIN].get(CONF_RETAIN) def pub_callback(topic, payload, qos, retain): """Call MQTT publish function.""" - mqtt.publish(hass, topic, payload, qos, retain) + mqtt.publish(topic, payload, qos, retain) def sub_callback(topic, sub_cb, qos): """Call MQTT subscribe function.""" - mqtt.subscribe(hass, topic, sub_cb, qos) + mqtt.subscribe(topic, sub_cb, qos) gateway = mysensors.MQTTGateway( pub_callback, sub_callback, event_callback=None, persistence=persistence, diff --git a/homeassistant/components/scene/__init__.py b/homeassistant/components/scene/__init__.py index 2394d538f2f..7b76836555c 100644 --- a/homeassistant/components/scene/__init__.py +++ b/homeassistant/components/scene/__init__.py @@ -5,6 +5,7 @@ For more details about this component, please refer to the documentation at https://home-assistant.io/components/scene/ """ import asyncio +import importlib import logging import voluptuous as vol @@ -16,7 +17,6 @@ import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.state import HASS_DOMAIN -from homeassistant.loader import get_platform DOMAIN = 'scene' STATE = 'scening' @@ -34,20 +34,24 @@ def _hass_domain_validator(config): def _platform_validator(config): """Validate it is a valid platform.""" - p_name = config[CONF_PLATFORM] - platform = get_platform(DOMAIN, p_name) + try: + platform = importlib.import_module( + 'homeassistant.components.scene.{}'.format( + config[CONF_PLATFORM])) + except ImportError: + raise vol.Invalid('Invalid platform specified') from None if not hasattr(platform, 'PLATFORM_SCHEMA'): return config - return getattr(platform, 'PLATFORM_SCHEMA')(config) + return platform.PLATFORM_SCHEMA(config) PLATFORM_SCHEMA = vol.Schema( vol.All( _hass_domain_validator, vol.Schema({ - vol.Required(CONF_PLATFORM): cv.platform_validator(DOMAIN) + vol.Required(CONF_PLATFORM): str }, extra=vol.ALLOW_EXTRA), _platform_validator ), extra=vol.ALLOW_EXTRA) diff --git a/homeassistant/components/sensor/bloomsky.py b/homeassistant/components/sensor/bloomsky.py index ce44abdb087..b460498c901 100644 --- a/homeassistant/components/sensor/bloomsky.py +++ b/homeassistant/components/sensor/bloomsky.py @@ -11,7 +11,6 @@ import voluptuous as vol from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.const import (TEMP_FAHRENHEIT, CONF_MONITORED_CONDITIONS) from homeassistant.helpers.entity import Entity -from homeassistant.loader import get_component import homeassistant.helpers.config_validation as cv _LOGGER = logging.getLogger(__name__) @@ -45,7 +44,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ # pylint: disable=unused-argument def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the available BloomSky weather sensors.""" - bloomsky = get_component('bloomsky') + bloomsky = hass.components.bloomsky # Default needed in case of discovery sensors = config.get(CONF_MONITORED_CONDITIONS, SENSOR_TYPES) diff --git a/homeassistant/components/sensor/netatmo.py b/homeassistant/components/sensor/netatmo.py index 4dddaf45aa4..4aeba082e55 100644 --- a/homeassistant/components/sensor/netatmo.py +++ b/homeassistant/components/sensor/netatmo.py @@ -13,7 +13,6 @@ from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.const import TEMP_CELSIUS, STATE_UNKNOWN from homeassistant.helpers.entity import Entity from homeassistant.util import Throttle -from homeassistant.loader import get_component import homeassistant.helpers.config_validation as cv _LOGGER = logging.getLogger(__name__) @@ -64,7 +63,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the available Netatmo weather sensors.""" - netatmo = get_component('netatmo') + netatmo = hass.components.netatmo data = NetAtmoData(netatmo.NETATMO_AUTH, config.get(CONF_STATION, None)) dev = [] diff --git a/homeassistant/components/zwave/__init__.py b/homeassistant/components/zwave/__init__.py index 02d2b574592..d56b4bc91b4 100644 --- a/homeassistant/components/zwave/__init__.py +++ b/homeassistant/components/zwave/__init__.py @@ -788,7 +788,7 @@ class ZWaveDeviceEntityValues(): if polling_intensity: self.primary.enable_poll(polling_intensity) - platform = get_platform(component, DOMAIN) + platform = get_platform(self._hass, component, DOMAIN) device = platform.get_device( node=self._node, values=self, node_config=node_config, hass=self._hass) diff --git a/homeassistant/config.py b/homeassistant/config.py index 2c440485e49..d69704a7032 100644 --- a/homeassistant/config.py +++ b/homeassistant/config.py @@ -548,7 +548,8 @@ def _identify_config_schema(module): return '', schema -def merge_packages_config(config, packages, _log_pkg_error=_log_pkg_error): +def merge_packages_config(hass, config, packages, + _log_pkg_error=_log_pkg_error): """Merge packages into the top-level configuration. Mutate config.""" # pylint: disable=too-many-nested-blocks PACKAGES_CONFIG_SCHEMA(packages) @@ -556,7 +557,7 @@ def merge_packages_config(config, packages, _log_pkg_error=_log_pkg_error): for comp_name, comp_conf in pack_conf.items(): if comp_name == CONF_CORE: continue - component = get_component(comp_name) + component = get_component(hass, comp_name) if component is None: _log_pkg_error(pack_name, comp_name, config, "does not exist") @@ -625,7 +626,7 @@ def async_process_component_config(hass, config, domain): This method must be run in the event loop. """ - component = get_component(domain) + component = get_component(hass, domain) if hasattr(component, 'CONFIG_SCHEMA'): try: @@ -651,7 +652,7 @@ def async_process_component_config(hass, config, domain): platforms.append(p_validated) continue - platform = get_platform(domain, p_name) + platform = get_platform(hass, domain, p_name) if platform is None: continue diff --git a/homeassistant/helpers/config_validation.py b/homeassistant/helpers/config_validation.py index 4b7c58f6e66..8177999cc94 100644 --- a/homeassistant/helpers/config_validation.py +++ b/homeassistant/helpers/config_validation.py @@ -12,7 +12,6 @@ from typing import Any, Union, TypeVar, Callable, Sequence, Dict import voluptuous as vol -from homeassistant.loader import get_platform from homeassistant.const import ( CONF_PLATFORM, CONF_SCAN_INTERVAL, TEMP_CELSIUS, TEMP_FAHRENHEIT, CONF_ALIAS, CONF_ENTITY_ID, CONF_VALUE_TEMPLATE, WEEKDAYS, @@ -283,19 +282,6 @@ def match_all(value): return value -def platform_validator(domain): - """Validate if platform exists for given domain.""" - def validator(value): - """Test if platform exists.""" - if value is None: - raise vol.Invalid('platform cannot be None') - if get_platform(domain, str(value)): - return value - raise vol.Invalid( - 'platform {} does not exist for {}'.format(value, domain)) - return validator - - def positive_timedelta(value: timedelta) -> timedelta: """Validate timedelta is positive.""" if value < timedelta(0): diff --git a/homeassistant/helpers/service.py b/homeassistant/helpers/service.py index 3595b258f12..9114a4db941 100644 --- a/homeassistant/helpers/service.py +++ b/homeassistant/helpers/service.py @@ -92,7 +92,7 @@ def extract_entity_ids(hass, service_call, expand_group=True): if not (service_call.data and ATTR_ENTITY_ID in service_call.data): return [] - group = get_component('group') + group = hass.components.group # Entity ID attr can be a list or a string service_ent_id = service_call.data[ATTR_ENTITY_ID] @@ -100,10 +100,10 @@ def extract_entity_ids(hass, service_call, expand_group=True): if expand_group: if isinstance(service_ent_id, str): - return group.expand_entity_ids(hass, [service_ent_id]) + return group.expand_entity_ids([service_ent_id]) return [ent_id for ent_id in - group.expand_entity_ids(hass, service_ent_id)] + group.expand_entity_ids(service_ent_id)] else: @@ -128,7 +128,7 @@ async def async_get_all_descriptions(hass): import homeassistant.components as components component_path = path.dirname(components.__file__) else: - component_path = path.dirname(get_component(domain).__file__) + component_path = path.dirname(get_component(hass, domain).__file__) return path.join(component_path, 'services.yaml') def load_services_files(yaml_files): diff --git a/homeassistant/helpers/template.py b/homeassistant/helpers/template.py index 3a24de6b39c..f523726c388 100644 --- a/homeassistant/helpers/template.py +++ b/homeassistant/helpers/template.py @@ -16,7 +16,7 @@ from homeassistant.const import ( from homeassistant.core import State, valid_entity_id from homeassistant.exceptions import TemplateError from homeassistant.helpers import location as loc_helper -from homeassistant.loader import bind_hass, get_component +from homeassistant.loader import bind_hass from homeassistant.util import convert from homeassistant.util import dt as dt_util from homeassistant.util import location as loc_util @@ -349,10 +349,10 @@ class TemplateMethods(object): else: gr_entity_id = str(entities) - group = get_component('group') + group = self._hass.components.group states = [self._hass.states.get(entity_id) for entity_id - in group.expand_entity_ids(self._hass, [gr_entity_id])] + in group.expand_entity_ids([gr_entity_id])] return _wrap_state(loc_helper.closest(latitude, longitude, states)) diff --git a/homeassistant/helpers/translation.py b/homeassistant/helpers/translation.py index 26cb34ede8c..f1335f73346 100644 --- a/homeassistant/helpers/translation.py +++ b/homeassistant/helpers/translation.py @@ -30,14 +30,14 @@ def flatten(data): return recursive_flatten('', data) -def component_translation_file(component, language): +def component_translation_file(hass, component, language): """Return the translation json file location for a component.""" if '.' in component: name = component.split('.', 1)[1] else: name = component - module = get_component(component) + module = get_component(hass, component) component_path = path.dirname(module.__file__) # If loading translations for the package root, (__init__.py), the @@ -97,7 +97,7 @@ async def async_get_component_resources(hass, language): missing_files = {} for component in missing_components: missing_files[component] = component_translation_file( - component, language) + hass, component, language) # Load missing files if missing_files: diff --git a/homeassistant/loader.py b/homeassistant/loader.py index a3ce2a13f56..322870952f2 100644 --- a/homeassistant/loader.py +++ b/homeassistant/loader.py @@ -6,15 +6,13 @@ documentation as possible to keep it understandable. Components can be accessed via hass.components.switch from your code. If you want to retrieve a platform that is part of a component, you should -call get_component('switch.your_platform'). In both cases the config directory -is checked to see if it contains a user provided version. If not available it -will check the built-in components and platforms. +call get_component(hass, 'switch.your_platform'). In both cases the config +directory is checked to see if it contains a user provided version. If not +available it will check the built-in components and platforms. """ import functools as ft import importlib import logging -import os -import pkgutil import sys from types import ModuleType @@ -42,135 +40,94 @@ _COMPONENT_CACHE = {} # type: Dict[str, ModuleType] _LOGGER = logging.getLogger(__name__) -def prepare(hass: 'HomeAssistant'): - """Prepare the loading of components. - - This method needs to run in an executor. - """ - global PREPARED # pylint: disable=global-statement - - # Load the built-in components - import homeassistant.components as components - - AVAILABLE_COMPONENTS.clear() - - AVAILABLE_COMPONENTS.extend( - item[1] for item in - pkgutil.iter_modules(components.__path__, 'homeassistant.components.')) - - # Look for available custom components - custom_path = hass.config.path("custom_components") - - if os.path.isdir(custom_path): - # Ensure we can load custom components using Pythons import - sys.path.insert(0, hass.config.config_dir) - - # We cannot use the same approach as for built-in components because - # custom components might only contain a platform for a component. - # ie custom_components/switch/some_platform.py. Using pkgutil would - # not give us the switch component (and neither should it). - - # Assumption: the custom_components dir only contains directories or - # python components. If this assumption is not true, HA won't break, - # just might output more errors. - for fil in os.listdir(custom_path): - if fil == '__pycache__': - continue - elif os.path.isdir(os.path.join(custom_path, fil)): - AVAILABLE_COMPONENTS.append('custom_components.{}'.format(fil)) - else: - # For files we will strip out .py extension - AVAILABLE_COMPONENTS.append( - 'custom_components.{}'.format(fil[0:-3])) - - PREPARED = True +DATA_KEY = 'components' +PATH_CUSTOM_COMPONENTS = 'custom_components' +PACKAGE_COMPONENTS = 'homeassistant.components' -def set_component(comp_name: str, component: ModuleType) -> None: +def set_component(hass, comp_name: str, component: ModuleType) -> None: """Set a component in the cache. Async friendly. """ - _check_prepared() - - _COMPONENT_CACHE[comp_name] = component + cache = hass.data.get(DATA_KEY) + if cache is None: + cache = hass.data[DATA_KEY] = {} + cache[comp_name] = component -def get_platform(domain: str, platform: str) -> Optional[ModuleType]: +def get_platform(hass, domain: str, platform: str) -> Optional[ModuleType]: """Try to load specified platform. Async friendly. """ - return get_component(PLATFORM_FORMAT.format(domain, platform)) + return get_component(hass, PLATFORM_FORMAT.format(domain, platform)) -def get_component(comp_name) -> Optional[ModuleType]: - """Try to load specified component. +def get_component(hass, comp_or_platform): + """Load a module from either custom component or built-in.""" + try: + return hass.data[DATA_KEY][comp_or_platform] + except KeyError: + pass - Looks in config dir first, then built-in components. - Only returns it if also found to be valid. - - Async friendly. - """ - if comp_name in _COMPONENT_CACHE: - return _COMPONENT_CACHE[comp_name] - - _check_prepared() - - # If we ie. try to load custom_components.switch.wemo but the parent - # custom_components.switch does not exist, importing it will trigger - # an exception because it will try to import the parent. - # Because of this behavior, we will approach loading sub components - # with caution: only load it if we can verify that the parent exists. - # We do not want to silent the ImportErrors as they provide valuable - # information to track down when debugging Home Assistant. - - # First check custom, then built-in - potential_paths = ['custom_components.{}'.format(comp_name), - 'homeassistant.components.{}'.format(comp_name)] - - for path in potential_paths: - # Validate here that root component exists - # If path contains a '.' we are specifying a sub-component - # Using rsplit we get the parent component from sub-component - root_comp = path.rsplit(".", 1)[0] if '.' in comp_name else path - - if root_comp not in AVAILABLE_COMPONENTS: - continue + # Try custom component + module = _load_module(hass.config.path(PATH_CUSTOM_COMPONENTS), + comp_or_platform) + if module is None: try: - module = importlib.import_module(path) + module = importlib.import_module( + '{}.{}'.format(PACKAGE_COMPONENTS, comp_or_platform)) + except ImportError: + module = None - # In Python 3 you can import files from directories that do not - # contain the file __init__.py. A directory is a valid module if - # it contains a file with the .py extension. In this case Python - # will succeed in importing the directory as a module and call it - # a namespace. We do not care about namespaces. - # This prevents that when only - # custom_components/switch/some_platform.py exists, - # the import custom_components.switch would succeed. - if module.__spec__.origin == 'namespace': - continue + cache = hass.data.get(DATA_KEY) + if cache is None: + cache = hass.data[DATA_KEY] = {} + cache[comp_or_platform] = module - _LOGGER.info("Loaded %s from %s", comp_name, path) + return module - _COMPONENT_CACHE[comp_name] = module - - return module - - except ImportError as err: - # This error happens if for example custom_components/switch - # exists and we try to load switch.demo. - if str(err) != "No module named '{}'".format(path): - _LOGGER.exception( - ("Error loading %s. Make sure all " - "dependencies are installed"), path) - - _LOGGER.error("Unable to find component %s", comp_name) +def _find_spec(path, name): + for finder in sys.meta_path: + try: + spec = finder.find_spec(name, path=path) + if spec is not None: + return spec + except AttributeError: + # Not all finders have the find_spec method + pass return None +def _load_module(path, name): + """Load a module based on a folder and a name.""" + spec = _find_spec([path], name) + + # Special handling if loading platforms and the folder is a namespace + # (namespace is a folder without __init__.py) + if spec is None and '.' in name: + parent_spec = _find_spec([path], name.split('.')[0]) + if (parent_spec is None or + parent_spec.submodule_search_locations is None): + return None + spec = _find_spec(parent_spec.submodule_search_locations, name) + + # Not found + if spec is None: + return None + + # This is a namespace + if spec.loader is None: + return None + + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module + + class Components: """Helper to load components.""" @@ -180,7 +137,7 @@ class Components: def __getattr__(self, comp_name): """Fetch a component.""" - component = get_component(comp_name) + component = get_component(self._hass, comp_name) if component is None: raise ImportError('Unable to load {}'.format(comp_name)) wrapped = ModuleWrapper(self._hass, component) @@ -230,7 +187,7 @@ def bind_hass(func): return func -def load_order_component(comp_name: str) -> OrderedSet: +def load_order_component(hass, comp_name: str) -> OrderedSet: """Return an OrderedSet of components in the correct order of loading. Raises HomeAssistantError if a circular dependency is detected. @@ -238,16 +195,16 @@ def load_order_component(comp_name: str) -> OrderedSet: Async friendly. """ - return _load_order_component(comp_name, OrderedSet(), set()) + return _load_order_component(hass, comp_name, OrderedSet(), set()) -def _load_order_component(comp_name: str, load_order: OrderedSet, +def _load_order_component(hass, comp_name: str, load_order: OrderedSet, loading: Set) -> OrderedSet: """Recursive function to get load order of components. Async friendly. """ - component = get_component(comp_name) + component = get_component(hass, comp_name) # If None it does not exist, error already thrown by get_component. if component is None: @@ -266,7 +223,8 @@ def _load_order_component(comp_name: str, load_order: OrderedSet, comp_name, dependency) return OrderedSet() - dep_load_order = _load_order_component(dependency, load_order, loading) + dep_load_order = _load_order_component( + hass, dependency, load_order, loading) # length == 0 means error loading dependency or children if not dep_load_order: @@ -280,14 +238,3 @@ def _load_order_component(comp_name: str, load_order: OrderedSet, loading.remove(comp_name) return load_order - - -def _check_prepared() -> None: - """Issue a warning if loader.prepare() has never been called. - - Async friendly. - """ - if not PREPARED: - _LOGGER.warning(( - "You did not call loader.prepare() yet. " - "Certain functionality might not be working")) diff --git a/homeassistant/scripts/check_config.py b/homeassistant/scripts/check_config.py index 4375d973a0b..3a1ffa82d47 100644 --- a/homeassistant/scripts/check_config.py +++ b/homeassistant/scripts/check_config.py @@ -16,8 +16,8 @@ from homeassistant import bootstrap, core, loader from homeassistant.config import ( get_default_config_dir, CONF_CORE, CORE_CONFIG_SCHEMA, CONF_PACKAGES, merge_packages_config, _format_config_error, - find_config_file, load_yaml_config_file, get_component, - extract_domain_configs, config_per_platform, get_platform) + find_config_file, load_yaml_config_file, + extract_domain_configs, config_per_platform) import homeassistant.util.yaml as yaml from homeassistant.exceptions import HomeAssistantError @@ -201,18 +201,10 @@ def check(config_dir, secrets=False): yaml.yaml.SafeLoader.add_constructor('!secret', yaml._secret_yaml) try: - class HassConfig(): - """Hass object with config.""" - - def __init__(self, conf_dir): - """Init the config_dir.""" - self.config = core.Config() - self.config.config_dir = conf_dir - - loader.prepare(HassConfig(config_dir)) - - res['components'] = check_ha_config_file(config_dir) + hass = core.HomeAssistant() + hass.config.config_dir = config_dir + res['components'] = check_ha_config_file(hass) res['secret_cache'] = OrderedDict(yaml.__SECRET_CACHE) for err in res['components'].errors: @@ -222,6 +214,7 @@ def check(config_dir, secrets=False): res['except'].setdefault(domain, []).append(err.config) except Exception as err: # pylint: disable=broad-except + _LOGGER.exception("BURB") print(color('red', 'Fatal error while loading config:'), str(err)) res['except'].setdefault(ERROR_STR, []).append(str(err)) finally: @@ -290,8 +283,9 @@ class HomeAssistantConfig(OrderedDict): return self -def check_ha_config_file(config_dir): +def check_ha_config_file(hass): """Check if Home Assistant configuration file is valid.""" + config_dir = hass.config.config_dir result = HomeAssistantConfig() def _pack_error(package, component, config, message): @@ -330,7 +324,7 @@ def check_ha_config_file(config_dir): # Merge packages merge_packages_config( - config, core_config.get(CONF_PACKAGES, {}), _pack_error) + hass, config, core_config.get(CONF_PACKAGES, {}), _pack_error) del core_config[CONF_PACKAGES] # Ensure we have no None values after merge @@ -343,7 +337,7 @@ def check_ha_config_file(config_dir): # Process and validate config for domain in components: - component = get_component(domain) + component = loader.get_component(hass, domain) if not component: result.add_error("Component not found: {}".format(domain)) continue @@ -375,7 +369,7 @@ def check_ha_config_file(config_dir): platforms.append(p_validated) continue - platform = get_platform(domain, p_name) + platform = loader.get_platform(hass, domain, p_name) if platform is None: result.add_error( diff --git a/homeassistant/setup.py b/homeassistant/setup.py index 169a160af65..f26aa9b61f1 100644 --- a/homeassistant/setup.py +++ b/homeassistant/setup.py @@ -98,14 +98,14 @@ async def _async_setup_component(hass: core.HomeAssistant, _LOGGER.error("Setup failed for %s: %s", domain, msg) async_notify_setup_error(hass, domain, link) - component = loader.get_component(domain) + component = loader.get_component(hass, domain) if not component: log_error("Component not found.", False) return False # Validate no circular dependencies - components = loader.load_order_component(domain) + components = loader.load_order_component(hass, domain) # OrderedSet is empty if component or dependencies could not be resolved if not components: @@ -159,7 +159,7 @@ async def _async_setup_component(hass: core.HomeAssistant, elif result is not True: log_error("Component did not return boolean if setup was successful. " "Disabling component.") - loader.set_component(domain, None) + loader.set_component(hass, domain, None) return False for entry in hass.config_entries.async_entries(domain): @@ -193,7 +193,7 @@ async def async_prepare_setup_platform(hass: core.HomeAssistant, config, platform_path, msg) async_notify_setup_error(hass, platform_path) - platform = loader.get_platform(domain, platform_name) + platform = loader.get_platform(hass, domain, platform_name) # Not found if platform is None: diff --git a/tests/common.py b/tests/common.py index b04abda7c28..f53d1c2be2b 100644 --- a/tests/common.py +++ b/tests/common.py @@ -10,8 +10,7 @@ import logging import threading from contextlib import contextmanager -from homeassistant import ( - auth, core as ha, loader, data_entry_flow, config_entries) +from homeassistant import auth, core as ha, data_entry_flow, config_entries from homeassistant.setup import setup_component, async_setup_component from homeassistant.config import async_process_component_config from homeassistant.helpers import ( @@ -138,9 +137,6 @@ def async_test_home_assistant(loop): hass.config.units = METRIC_SYSTEM hass.config.skip_pip = True - if 'custom_components.test' not in loader.AVAILABLE_COMPONENTS: - yield from loop.run_in_executor(None, loader.prepare, hass) - hass.state = ha.CoreState.running # Mock async_start diff --git a/tests/components/climate/test_generic_thermostat.py b/tests/components/climate/test_generic_thermostat.py index bd0b764c6fe..7bc0b0a18e7 100644 --- a/tests/components/climate/test_generic_thermostat.py +++ b/tests/components/climate/test_generic_thermostat.py @@ -116,7 +116,7 @@ class TestGenericThermostatHeaterSwitching(unittest.TestCase): def test_heater_switch(self): """Test heater switching test switch.""" - platform = loader.get_component('switch.test') + platform = loader.get_component(self.hass, 'switch.test') platform.init() self.switch_1 = platform.DEVICES[1] assert setup_component(self.hass, switch.DOMAIN, {'switch': { diff --git a/tests/components/config/test_config_entries.py b/tests/components/config/test_config_entries.py index f53be8818a3..84d15578e13 100644 --- a/tests/components/config/test_config_entries.py +++ b/tests/components/config/test_config_entries.py @@ -17,10 +17,10 @@ from homeassistant.loader import set_component from tests.common import MockConfigEntry, MockModule, mock_coro_func -@pytest.fixture(scope='session', autouse=True) -def mock_test_component(): +@pytest.fixture(autouse=True) +def mock_test_component(hass): """Ensure a component called 'test' exists.""" - set_component('test', MockModule('test')) + set_component(hass, 'test', MockModule('test')) @pytest.fixture @@ -172,7 +172,8 @@ def test_abort(hass, client): def test_create_account(hass, client): """Test a flow that creates an account.""" set_component( - 'test', MockModule('test', async_setup_entry=mock_coro_func(True))) + hass, 'test', + MockModule('test', async_setup_entry=mock_coro_func(True))) class TestFlow(FlowHandler): VERSION = 1 @@ -204,7 +205,8 @@ def test_create_account(hass, client): def test_two_step_flow(hass, client): """Test we can finish a two step flow.""" set_component( - 'test', MockModule('test', async_setup_entry=mock_coro_func(True))) + hass, 'test', + MockModule('test', async_setup_entry=mock_coro_func(True))) class TestFlow(FlowHandler): VERSION = 1 diff --git a/tests/components/device_tracker/test_asuswrt.py b/tests/components/device_tracker/test_asuswrt.py index d2ae8965668..0cbece6d1b0 100644 --- a/tests/components/device_tracker/test_asuswrt.py +++ b/tests/components/device_tracker/test_asuswrt.py @@ -3,9 +3,9 @@ import os from datetime import timedelta import unittest from unittest import mock +import socket import voluptuous as vol -from future.backports import socket from homeassistant.setup import setup_component from homeassistant.components import device_tracker diff --git a/tests/components/device_tracker/test_init.py b/tests/components/device_tracker/test_init.py index 912bd315ecd..0b17b4e0ac8 100644 --- a/tests/components/device_tracker/test_init.py +++ b/tests/components/device_tracker/test_init.py @@ -189,7 +189,7 @@ class TestComponentsDeviceTracker(unittest.TestCase): def test_update_stale(self): """Test stalled update.""" - scanner = get_component('device_tracker.test').SCANNER + scanner = get_component(self.hass, 'device_tracker.test').SCANNER scanner.reset() scanner.come_home('DEV1') @@ -251,7 +251,7 @@ class TestComponentsDeviceTracker(unittest.TestCase): hide_if_away=True) device_tracker.update_config(self.yaml_devices, dev_id, device) - scanner = get_component('device_tracker.test').SCANNER + scanner = get_component(self.hass, 'device_tracker.test').SCANNER scanner.reset() with assert_setup_component(1, device_tracker.DOMAIN): @@ -270,7 +270,7 @@ class TestComponentsDeviceTracker(unittest.TestCase): hide_if_away=True) device_tracker.update_config(self.yaml_devices, dev_id, device) - scanner = get_component('device_tracker.test').SCANNER + scanner = get_component(self.hass, 'device_tracker.test').SCANNER scanner.reset() with assert_setup_component(1, device_tracker.DOMAIN): @@ -431,7 +431,7 @@ class TestComponentsDeviceTracker(unittest.TestCase): 'zone': zone_info }) - scanner = get_component('device_tracker.test').SCANNER + scanner = get_component(self.hass, 'device_tracker.test').SCANNER scanner.reset() scanner.come_home('dev1') @@ -547,7 +547,7 @@ def test_bad_platform(hass): async def test_adding_unknown_device_to_config(mock_device_tracker_conf, hass): """Test the adding of unknown devices to configuration file.""" - scanner = get_component('device_tracker.test').SCANNER + scanner = get_component(hass, 'device_tracker.test').SCANNER scanner.reset() scanner.come_home('DEV1') diff --git a/tests/components/light/test_init.py b/tests/components/light/test_init.py index 4e8fad261bd..634e3774b8a 100644 --- a/tests/components/light/test_init.py +++ b/tests/components/light/test_init.py @@ -118,7 +118,7 @@ class TestLight(unittest.TestCase): def test_services(self): """Test the provided services.""" - platform = loader.get_component('light.test') + platform = loader.get_component(self.hass, 'light.test') platform.init() self.assertTrue( @@ -267,7 +267,7 @@ class TestLight(unittest.TestCase): def test_broken_light_profiles(self): """Test light profiles.""" - platform = loader.get_component('light.test') + platform = loader.get_component(self.hass, 'light.test') platform.init() user_light_file = self.hass.config.path(light.LIGHT_PROFILES_FILE) @@ -282,7 +282,7 @@ class TestLight(unittest.TestCase): def test_light_profiles(self): """Test light profiles.""" - platform = loader.get_component('light.test') + platform = loader.get_component(self.hass, 'light.test') platform.init() user_light_file = self.hass.config.path(light.LIGHT_PROFILES_FILE) diff --git a/tests/components/scene/test_init.py b/tests/components/scene/test_init.py index 25ea818c774..a832e249832 100644 --- a/tests/components/scene/test_init.py +++ b/tests/components/scene/test_init.py @@ -16,7 +16,7 @@ class TestScene(unittest.TestCase): def setUp(self): # pylint: disable=invalid-name """Setup things to be run when tests are started.""" self.hass = get_test_home_assistant() - test_light = loader.get_component('light.test') + test_light = loader.get_component(self.hass, 'light.test') test_light.init() self.assertTrue(setup_component(self.hass, light.DOMAIN, { diff --git a/tests/components/switch/test_flux.py b/tests/components/switch/test_flux.py index c42061db958..61e665f265c 100644 --- a/tests/components/switch/test_flux.py +++ b/tests/components/switch/test_flux.py @@ -71,7 +71,7 @@ class TestSwitchFlux(unittest.TestCase): def test_flux_when_switch_is_off(self): """Test the flux switch when it is off.""" - platform = loader.get_component('light.test') + platform = loader.get_component(self.hass, 'light.test') platform.init() self.assertTrue( setup_component(self.hass, light.DOMAIN, @@ -113,7 +113,7 @@ class TestSwitchFlux(unittest.TestCase): def test_flux_before_sunrise(self): """Test the flux switch before sunrise.""" - platform = loader.get_component('light.test') + platform = loader.get_component(self.hass, 'light.test') platform.init() self.assertTrue( setup_component(self.hass, light.DOMAIN, @@ -160,7 +160,7 @@ class TestSwitchFlux(unittest.TestCase): # pylint: disable=invalid-name def test_flux_after_sunrise_before_sunset(self): """Test the flux switch after sunrise and before sunset.""" - platform = loader.get_component('light.test') + platform = loader.get_component(self.hass, 'light.test') platform.init() self.assertTrue( setup_component(self.hass, light.DOMAIN, @@ -207,7 +207,7 @@ class TestSwitchFlux(unittest.TestCase): # pylint: disable=invalid-name def test_flux_after_sunset_before_stop(self): """Test the flux switch after sunset and before stop.""" - platform = loader.get_component('light.test') + platform = loader.get_component(self.hass, 'light.test') platform.init() self.assertTrue( setup_component(self.hass, light.DOMAIN, @@ -255,7 +255,7 @@ class TestSwitchFlux(unittest.TestCase): # pylint: disable=invalid-name def test_flux_after_stop_before_sunrise(self): """Test the flux switch after stop and before sunrise.""" - platform = loader.get_component('light.test') + platform = loader.get_component(self.hass, 'light.test') platform.init() self.assertTrue( setup_component(self.hass, light.DOMAIN, @@ -302,7 +302,7 @@ class TestSwitchFlux(unittest.TestCase): # pylint: disable=invalid-name def test_flux_with_custom_start_stop_times(self): """Test the flux with custom start and stop times.""" - platform = loader.get_component('light.test') + platform = loader.get_component(self.hass, 'light.test') platform.init() self.assertTrue( setup_component(self.hass, light.DOMAIN, @@ -353,7 +353,7 @@ class TestSwitchFlux(unittest.TestCase): This test has the stop_time on the next day (after midnight). """ - platform = loader.get_component('light.test') + platform = loader.get_component(self.hass, 'light.test') platform.init() self.assertTrue( setup_component(self.hass, light.DOMAIN, @@ -405,7 +405,7 @@ class TestSwitchFlux(unittest.TestCase): This test has the stop_time on the next day (after midnight). """ - platform = loader.get_component('light.test') + platform = loader.get_component(self.hass, 'light.test') platform.init() self.assertTrue( setup_component(self.hass, light.DOMAIN, @@ -456,7 +456,7 @@ class TestSwitchFlux(unittest.TestCase): This test has the stop_time on the next day (after midnight). """ - platform = loader.get_component('light.test') + platform = loader.get_component(self.hass, 'light.test') platform.init() self.assertTrue( setup_component(self.hass, light.DOMAIN, @@ -507,7 +507,7 @@ class TestSwitchFlux(unittest.TestCase): This test has the stop_time on the next day (after midnight). """ - platform = loader.get_component('light.test') + platform = loader.get_component(self.hass, 'light.test') platform.init() self.assertTrue( setup_component(self.hass, light.DOMAIN, @@ -558,7 +558,7 @@ class TestSwitchFlux(unittest.TestCase): This test has the stop_time on the next day (after midnight). """ - platform = loader.get_component('light.test') + platform = loader.get_component(self.hass, 'light.test') platform.init() self.assertTrue( setup_component(self.hass, light.DOMAIN, @@ -606,7 +606,7 @@ class TestSwitchFlux(unittest.TestCase): # pylint: disable=invalid-name def test_flux_with_custom_colortemps(self): """Test the flux with custom start and stop colortemps.""" - platform = loader.get_component('light.test') + platform = loader.get_component(self.hass, 'light.test') platform.init() self.assertTrue( setup_component(self.hass, light.DOMAIN, @@ -656,7 +656,7 @@ class TestSwitchFlux(unittest.TestCase): # pylint: disable=invalid-name def test_flux_with_custom_brightness(self): """Test the flux with custom start and stop colortemps.""" - platform = loader.get_component('light.test') + platform = loader.get_component(self.hass, 'light.test') platform.init() self.assertTrue( setup_component(self.hass, light.DOMAIN, @@ -704,7 +704,7 @@ class TestSwitchFlux(unittest.TestCase): def test_flux_with_multiple_lights(self): """Test the flux switch with multiple light entities.""" - platform = loader.get_component('light.test') + platform = loader.get_component(self.hass, 'light.test') platform.init() self.assertTrue( setup_component(self.hass, light.DOMAIN, @@ -773,7 +773,7 @@ class TestSwitchFlux(unittest.TestCase): def test_flux_with_mired(self): """Test the flux switch´s mode mired.""" - platform = loader.get_component('light.test') + platform = loader.get_component(self.hass, 'light.test') platform.init() self.assertTrue( setup_component(self.hass, light.DOMAIN, @@ -818,7 +818,7 @@ class TestSwitchFlux(unittest.TestCase): def test_flux_with_rgb(self): """Test the flux switch´s mode rgb.""" - platform = loader.get_component('light.test') + platform = loader.get_component(self.hass, 'light.test') platform.init() self.assertTrue( setup_component(self.hass, light.DOMAIN, diff --git a/tests/components/switch/test_init.py b/tests/components/switch/test_init.py index 090e3c74bf1..d679aa2c827 100644 --- a/tests/components/switch/test_init.py +++ b/tests/components/switch/test_init.py @@ -17,7 +17,7 @@ class TestSwitch(unittest.TestCase): def setUp(self): """Setup things to be run when tests are started.""" self.hass = get_test_home_assistant() - platform = loader.get_component('switch.test') + platform = loader.get_component(self.hass, 'switch.test') platform.init() # Switch 1 is ON, switch 2 is OFF self.switch_1, self.switch_2, self.switch_3 = \ @@ -79,10 +79,10 @@ class TestSwitch(unittest.TestCase): def test_setup_two_platforms(self): """Test with bad configuration.""" # Test if switch component returns 0 switches - test_platform = loader.get_component('switch.test') + test_platform = loader.get_component(self.hass, 'switch.test') test_platform.init(True) - loader.set_component('switch.test2', test_platform) + loader.set_component(self.hass, 'switch.test2', test_platform) test_platform.init(False) self.assertTrue(setup_component( diff --git a/tests/components/test_device_sun_light_trigger.py b/tests/components/test_device_sun_light_trigger.py index 3c73e85c4e5..a8b8a201217 100644 --- a/tests/components/test_device_sun_light_trigger.py +++ b/tests/components/test_device_sun_light_trigger.py @@ -22,12 +22,12 @@ class TestDeviceSunLightTrigger(unittest.TestCase): self.hass = get_test_home_assistant() self.scanner = loader.get_component( - 'device_tracker.test').get_scanner(None, None) + self.hass, 'device_tracker.test').get_scanner(None, None) self.scanner.reset() self.scanner.come_home('DEV1') - loader.get_component('light.test').init() + loader.get_component(self.hass, 'light.test').init() with patch( 'homeassistant.components.device_tracker.load_yaml_config_file', diff --git a/tests/helpers/test_config_validation.py b/tests/helpers/test_config_validation.py index 90be56bbc7c..aff0acf9e3a 100644 --- a/tests/helpers/test_config_validation.py +++ b/tests/helpers/test_config_validation.py @@ -10,8 +10,6 @@ import voluptuous as vol import homeassistant.helpers.config_validation as cv -from tests.common import get_test_home_assistant - def test_boolean(): """Test boolean validation.""" @@ -256,24 +254,6 @@ def test_event_schema(): cv.EVENT_SCHEMA(value) -def test_platform_validator(): - """Test platform validation.""" - hass = None - - try: - hass = get_test_home_assistant() - - schema = vol.Schema(cv.platform_validator('light')) - - with pytest.raises(vol.MultipleInvalid): - schema('platform_that_does_not_exist') - - schema('hue') - finally: - if hass is not None: - hass.stop() - - def test_icon(): """Test icon validation.""" schema = vol.Schema(cv.icon) diff --git a/tests/helpers/test_discovery.py b/tests/helpers/test_discovery.py index b345400ba17..c7b39954d85 100644 --- a/tests/helpers/test_discovery.py +++ b/tests/helpers/test_discovery.py @@ -129,11 +129,11 @@ class TestHelpersDiscovery: platform_calls.append('disc' if discovery_info else 'component') loader.set_component( - 'test_component', + self.hass, 'test_component', MockModule('test_component', setup=component_setup)) loader.set_component( - 'switch.test_circular', + self.hass, 'switch.test_circular', MockPlatform(setup_platform, dependencies=['test_component'])) @@ -177,11 +177,11 @@ class TestHelpersDiscovery: return True loader.set_component( - 'test_component1', + self.hass, 'test_component1', MockModule('test_component1', setup=component1_setup)) loader.set_component( - 'test_component2', + self.hass, 'test_component2', MockModule('test_component2', setup=component2_setup)) @callback diff --git a/tests/helpers/test_entity_component.py b/tests/helpers/test_entity_component.py index 0bc6a7601dc..504f31cc987 100644 --- a/tests/helpers/test_entity_component.py +++ b/tests/helpers/test_entity_component.py @@ -75,9 +75,9 @@ class TestHelpersEntityComponent(unittest.TestCase): component_setup = Mock(return_value=True) platform_setup = Mock(return_value=None) loader.set_component( - 'test_component', + self.hass, 'test_component', MockModule('test_component', setup=component_setup)) - loader.set_component('test_domain.mod2', + loader.set_component(self.hass, 'test_domain.mod2', MockPlatform(platform_setup, ['test_component'])) component = EntityComponent(_LOGGER, DOMAIN, self.hass) @@ -100,8 +100,10 @@ class TestHelpersEntityComponent(unittest.TestCase): platform1_setup = Mock(side_effect=Exception('Broken')) platform2_setup = Mock(return_value=None) - loader.set_component('test_domain.mod1', MockPlatform(platform1_setup)) - loader.set_component('test_domain.mod2', MockPlatform(platform2_setup)) + loader.set_component(self.hass, 'test_domain.mod1', + MockPlatform(platform1_setup)) + loader.set_component(self.hass, 'test_domain.mod2', + MockPlatform(platform2_setup)) component = EntityComponent(_LOGGER, DOMAIN, self.hass) @@ -145,7 +147,7 @@ class TestHelpersEntityComponent(unittest.TestCase): """Test the platform setup.""" add_devices([MockEntity(should_poll=True)]) - loader.set_component('test_domain.platform', + loader.set_component(self.hass, 'test_domain.platform', MockPlatform(platform_setup)) component = EntityComponent(_LOGGER, DOMAIN, self.hass) @@ -172,7 +174,7 @@ class TestHelpersEntityComponent(unittest.TestCase): platform = MockPlatform(platform_setup) - loader.set_component('test_domain.platform', platform) + loader.set_component(self.hass, 'test_domain.platform', platform) component = EntityComponent(_LOGGER, DOMAIN, self.hass) @@ -220,7 +222,8 @@ def test_platform_not_ready(hass): """Test that we retry when platform not ready.""" platform1_setup = Mock(side_effect=[PlatformNotReady, PlatformNotReady, None]) - loader.set_component('test_domain.mod1', MockPlatform(platform1_setup)) + loader.set_component(hass, 'test_domain.mod1', + MockPlatform(platform1_setup)) component = EntityComponent(_LOGGER, DOMAIN, hass) @@ -316,10 +319,11 @@ def test_setup_dependencies_platform(hass): We're explictely testing that we process dependencies even if a component with the same name has already been loaded. """ - loader.set_component('test_component', MockModule('test_component')) - loader.set_component('test_component2', MockModule('test_component2')) + loader.set_component(hass, 'test_component', MockModule('test_component')) + loader.set_component(hass, 'test_component2', + MockModule('test_component2')) loader.set_component( - 'test_domain.test_component', + hass, 'test_domain.test_component', MockPlatform(dependencies=['test_component', 'test_component2'])) component = EntityComponent(_LOGGER, DOMAIN, hass) @@ -341,7 +345,7 @@ async def test_setup_entry(hass): """Test setup entry calls async_setup_entry on platform.""" mock_setup_entry = Mock(return_value=mock_coro(True)) loader.set_component( - 'test_domain.entry_domain', + hass, 'test_domain.entry_domain', MockPlatform(async_setup_entry=mock_setup_entry)) component = EntityComponent(_LOGGER, DOMAIN, hass) @@ -366,7 +370,7 @@ async def test_setup_entry_fails_duplicate(hass): """Test we don't allow setting up a config entry twice.""" mock_setup_entry = Mock(return_value=mock_coro(True)) loader.set_component( - 'test_domain.entry_domain', + hass, 'test_domain.entry_domain', MockPlatform(async_setup_entry=mock_setup_entry)) component = EntityComponent(_LOGGER, DOMAIN, hass) @@ -382,7 +386,7 @@ async def test_unload_entry_resets_platform(hass): """Test unloading an entry removes all entities.""" mock_setup_entry = Mock(return_value=mock_coro(True)) loader.set_component( - 'test_domain.entry_domain', + hass, 'test_domain.entry_domain', MockPlatform(async_setup_entry=mock_setup_entry)) component = EntityComponent(_LOGGER, DOMAIN, hass) diff --git a/tests/helpers/test_entity_platform.py b/tests/helpers/test_entity_platform.py index 2018cb27541..4e09f9576f2 100644 --- a/tests/helpers/test_entity_platform.py +++ b/tests/helpers/test_entity_platform.py @@ -147,7 +147,7 @@ class TestHelpersEntityPlatform(unittest.TestCase): platform = MockPlatform(platform_setup) platform.SCAN_INTERVAL = timedelta(seconds=30) - loader.set_component('test_domain.platform', platform) + loader.set_component(self.hass, 'test_domain.platform', platform) component = EntityComponent(_LOGGER, DOMAIN, self.hass) @@ -184,7 +184,7 @@ def test_platform_warn_slow_setup(hass): """Warn we log when platform setup takes a long time.""" platform = MockPlatform() - loader.set_component('test_domain.platform', platform) + loader.set_component(hass, 'test_domain.platform', platform) component = EntityComponent(_LOGGER, DOMAIN, hass) @@ -218,7 +218,7 @@ def test_platform_error_slow_setup(hass, caplog): platform = MockPlatform(async_setup_platform=setup_platform) component = EntityComponent(_LOGGER, DOMAIN, hass) - loader.set_component('test_domain.test_platform', platform) + loader.set_component(hass, 'test_domain.test_platform', platform) yield from component.async_setup({ DOMAIN: { 'platform': 'test_platform', @@ -260,7 +260,7 @@ def test_parallel_updates_async_platform(hass): platform.async_setup_platform = mock_update - loader.set_component('test_domain.platform', platform) + loader.set_component(hass, 'test_domain.platform', platform) component = EntityComponent(_LOGGER, DOMAIN, hass) component._platforms = {} @@ -288,7 +288,7 @@ def test_parallel_updates_async_platform_with_constant(hass): platform.async_setup_platform = mock_update platform.PARALLEL_UPDATES = 1 - loader.set_component('test_domain.platform', platform) + loader.set_component(hass, 'test_domain.platform', platform) component = EntityComponent(_LOGGER, DOMAIN, hass) component._platforms = {} @@ -309,7 +309,7 @@ def test_parallel_updates_sync_platform(hass): """Warn we log when platform setup takes a long time.""" platform = MockPlatform(setup_platform=lambda *args: None) - loader.set_component('test_domain.platform', platform) + loader.set_component(hass, 'test_domain.platform', platform) component = EntityComponent(_LOGGER, DOMAIN, hass) component._platforms = {} diff --git a/tests/helpers/test_service.py b/tests/helpers/test_service.py index a987f5130f1..79054726c03 100644 --- a/tests/helpers/test_service.py +++ b/tests/helpers/test_service.py @@ -138,7 +138,7 @@ class TestServiceHelpers(unittest.TestCase): self.hass.states.set('light.Ceiling', STATE_OFF) self.hass.states.set('light.Kitchen', STATE_OFF) - loader.get_component('group').Group.create_group( + loader.get_component(self.hass, 'group').Group.create_group( self.hass, 'test', ['light.Ceiling', 'light.Kitchen']) call = ha.ServiceCall('light', 'turn_on', @@ -160,7 +160,7 @@ class TestServiceHelpers(unittest.TestCase): @asyncio.coroutine def test_async_get_all_descriptions(hass): """Test async_get_all_descriptions.""" - group = loader.get_component('group') + group = loader.get_component(hass, 'group') group_config = {group.DOMAIN: {}} yield from async_setup_component(hass, group.DOMAIN, group_config) descriptions = yield from service.async_get_all_descriptions(hass) @@ -170,7 +170,7 @@ def test_async_get_all_descriptions(hass): assert 'description' in descriptions['group']['reload'] assert 'fields' in descriptions['group']['reload'] - logger = loader.get_component('logger') + logger = loader.get_component(hass, 'logger') logger_config = {logger.DOMAIN: {}} yield from async_setup_component(hass, logger.DOMAIN, logger_config) descriptions = yield from service.async_get_all_descriptions(hass) diff --git a/tests/helpers/test_translation.py b/tests/helpers/test_translation.py index c72efca8c29..99c6f7dddf1 100644 --- a/tests/helpers/test_translation.py +++ b/tests/helpers/test_translation.py @@ -50,15 +50,15 @@ async def test_component_translation_file(hass): }) assert path.normpath(translation.component_translation_file( - 'switch.test', 'en')) == path.normpath(hass.config.path( + hass, 'switch.test', 'en')) == path.normpath(hass.config.path( 'custom_components', 'switch', '.translations', 'test.en.json')) assert path.normpath(translation.component_translation_file( - 'test_standalone', 'en')) == path.normpath(hass.config.path( + hass, 'test_standalone', 'en')) == path.normpath(hass.config.path( 'custom_components', '.translations', 'test_standalone.en.json')) assert path.normpath(translation.component_translation_file( - 'test_package', 'en')) == path.normpath(hass.config.path( + hass, 'test_package', 'en')) == path.normpath(hass.config.path( 'custom_components', 'test_package', '.translations', 'en.json')) diff --git a/tests/scripts/test_check_config.py b/tests/scripts/test_check_config.py index 28a3f2ebdc8..8dfc5db90e0 100644 --- a/tests/scripts/test_check_config.py +++ b/tests/scripts/test_check_config.py @@ -7,7 +7,6 @@ from unittest.mock import patch import homeassistant.scripts.check_config as check_config from homeassistant.config import YAML_CONFIG_FILE -from homeassistant.loader import set_component from tests.common import patch_yaml_files, get_test_config_dir _LOGGER = logging.getLogger(__name__) @@ -106,7 +105,6 @@ class TestCheckConfig(unittest.TestCase): def test_component_platform_not_found(self, isfile_patch): """Test errors if component or platform not found.""" # Make sure they don't exist - set_component('beer', None) files = { YAML_CONFIG_FILE: BASE_CONFIG + 'beer:', } @@ -119,7 +117,6 @@ class TestCheckConfig(unittest.TestCase): assert res['secrets'] == {} assert len(res['yaml_files']) == 1 - set_component('light.beer', None) files = { YAML_CONFIG_FILE: BASE_CONFIG + 'light:\n platform: beer', } diff --git a/tests/test_config.py b/tests/test_config.py index 652b931366a..4b1115c3814 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -568,7 +568,7 @@ def merge_log_err(hass): yield logerr -def test_merge(merge_log_err): +def test_merge(merge_log_err, hass): """Test if we can merge packages.""" packages = { 'pack_dict': {'input_boolean': {'ib1': None}}, @@ -582,7 +582,7 @@ def test_merge(merge_log_err): 'input_boolean': {'ib2': None}, 'light': {'platform': 'test'} } - config_util.merge_packages_config(config, packages) + config_util.merge_packages_config(hass, config, packages) assert merge_log_err.call_count == 0 assert len(config) == 5 @@ -592,7 +592,7 @@ def test_merge(merge_log_err): assert config['wake_on_lan'] is None -def test_merge_try_falsy(merge_log_err): +def test_merge_try_falsy(merge_log_err, hass): """Ensure we dont add falsy items like empty OrderedDict() to list.""" packages = { 'pack_falsy_to_lst': {'automation': OrderedDict()}, @@ -603,7 +603,7 @@ def test_merge_try_falsy(merge_log_err): 'automation': {'do': 'something'}, 'light': {'some': 'light'}, } - config_util.merge_packages_config(config, packages) + config_util.merge_packages_config(hass, config, packages) assert merge_log_err.call_count == 0 assert len(config) == 3 @@ -611,7 +611,7 @@ def test_merge_try_falsy(merge_log_err): assert len(config['light']) == 1 -def test_merge_new(merge_log_err): +def test_merge_new(merge_log_err, hass): """Test adding new components to outer scope.""" packages = { 'pack_1': {'light': [{'platform': 'one'}]}, @@ -624,7 +624,7 @@ def test_merge_new(merge_log_err): config = { config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages}, } - config_util.merge_packages_config(config, packages) + config_util.merge_packages_config(hass, config, packages) assert merge_log_err.call_count == 0 assert 'api' in config @@ -633,7 +633,7 @@ def test_merge_new(merge_log_err): assert len(config['panel_custom']) == 1 -def test_merge_type_mismatch(merge_log_err): +def test_merge_type_mismatch(merge_log_err, hass): """Test if we have a type mismatch for packages.""" packages = { 'pack_1': {'input_boolean': [{'ib1': None}]}, @@ -646,7 +646,7 @@ def test_merge_type_mismatch(merge_log_err): 'input_select': [{'ib2': None}], 'light': [{'platform': 'two'}] } - config_util.merge_packages_config(config, packages) + config_util.merge_packages_config(hass, config, packages) assert merge_log_err.call_count == 2 assert len(config) == 4 @@ -654,7 +654,7 @@ def test_merge_type_mismatch(merge_log_err): assert len(config['light']) == 2 -def test_merge_once_only(merge_log_err): +def test_merge_once_only(merge_log_err, hass): """Test if we have a merge for a comp that may occur only once.""" packages = { 'pack_2': { @@ -666,7 +666,7 @@ def test_merge_once_only(merge_log_err): config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages}, 'mqtt': {}, 'api': {} } - config_util.merge_packages_config(config, packages) + config_util.merge_packages_config(hass, config, packages) assert merge_log_err.call_count == 1 assert len(config) == 3 @@ -682,13 +682,13 @@ def test_merge_id_schema(hass): 'qwikswitch': 'dict', } for name, expected_type in types.items(): - module = config_util.get_component(name) + module = config_util.get_component(hass, name) typ, _ = config_util._identify_config_schema(module) assert typ == expected_type, "{} expected {}, got {}".format( name, expected_type, typ) -def test_merge_duplicate_keys(merge_log_err): +def test_merge_duplicate_keys(merge_log_err, hass): """Test if keys in dicts are duplicates.""" packages = { 'pack_1': {'input_select': {'ib1': None}}, @@ -697,7 +697,7 @@ def test_merge_duplicate_keys(merge_log_err): config_util.CONF_CORE: {config_util.CONF_PACKAGES: packages}, 'input_select': {'ib1': None}, } - config_util.merge_packages_config(config, packages) + config_util.merge_packages_config(hass, config, packages) assert merge_log_err.call_count == 1 assert len(config) == 2 diff --git a/tests/test_config_entries.py b/tests/test_config_entries.py index b46909d7732..1518706db55 100644 --- a/tests/test_config_entries.py +++ b/tests/test_config_entries.py @@ -27,7 +27,7 @@ def test_call_setup_entry(hass): mock_setup_entry = MagicMock(return_value=mock_coro(True)) loader.set_component( - 'comp', + hass, 'comp', MockModule('comp', async_setup_entry=mock_setup_entry)) result = yield from async_setup_component(hass, 'comp', {}) @@ -36,12 +36,12 @@ def test_call_setup_entry(hass): @asyncio.coroutine -def test_remove_entry(manager): +def test_remove_entry(hass, manager): """Test that we can remove an entry.""" mock_unload_entry = MagicMock(return_value=mock_coro(True)) loader.set_component( - 'test', + hass, 'test', MockModule('comp', async_unload_entry=mock_unload_entry)) MockConfigEntry(domain='test', entry_id='test1').add_to_manager(manager) @@ -63,7 +63,7 @@ def test_remove_entry(manager): @asyncio.coroutine -def test_remove_entry_raises(manager): +def test_remove_entry_raises(hass, manager): """Test if a component raises while removing entry.""" @asyncio.coroutine def mock_unload_entry(hass, entry): @@ -71,7 +71,7 @@ def test_remove_entry_raises(manager): raise Exception("BROKEN") loader.set_component( - 'test', + hass, 'test', MockModule('comp', async_unload_entry=mock_unload_entry)) MockConfigEntry(domain='test', entry_id='test1').add_to_manager(manager) @@ -96,7 +96,7 @@ def test_add_entry_calls_setup_entry(hass, manager): mock_setup_entry = MagicMock(return_value=mock_coro(True)) loader.set_component( - 'comp', + hass, 'comp', MockModule('comp', async_setup_entry=mock_setup_entry)) class TestFlow(data_entry_flow.FlowHandler): @@ -151,6 +151,8 @@ def test_domains_gets_uniques(manager): @asyncio.coroutine def test_saving_and_loading(hass): """Test that we're saving and loading correctly.""" + loader.set_component(hass, 'test', MockModule('test')) + class TestFlow(data_entry_flow.FlowHandler): VERSION = 5 @@ -217,12 +219,12 @@ async def test_forward_entry_sets_up_component(hass): mock_original_setup_entry = MagicMock(return_value=mock_coro(True)) loader.set_component( - 'original', + hass, 'original', MockModule('original', async_setup_entry=mock_original_setup_entry)) mock_forwarded_setup_entry = MagicMock(return_value=mock_coro(True)) loader.set_component( - 'forwarded', + hass, 'forwarded', MockModule('forwarded', async_setup_entry=mock_forwarded_setup_entry)) await hass.config_entries.async_forward_entry_setup(entry, 'forwarded') @@ -236,7 +238,7 @@ async def test_forward_entry_does_not_setup_entry_if_setup_fails(hass): mock_setup = MagicMock(return_value=mock_coro(False)) mock_setup_entry = MagicMock() - loader.set_component('forwarded', MockModule( + hass, loader.set_component(hass, 'forwarded', MockModule( 'forwarded', async_setup=mock_setup, async_setup_entry=mock_setup_entry, @@ -249,6 +251,7 @@ async def test_forward_entry_does_not_setup_entry_if_setup_fails(hass): async def test_discovery_notification(hass): """Test that we create/dismiss a notification when source is discovery.""" + loader.set_component(hass, 'test', MockModule('test')) await async_setup_component(hass, 'persistent_notification', {}) class TestFlow(data_entry_flow.FlowHandler): diff --git a/tests/test_loader.py b/tests/test_loader.py index 7fc33df57bb..646526e94ea 100644 --- a/tests/test_loader.py +++ b/tests/test_loader.py @@ -27,37 +27,40 @@ class TestLoader(unittest.TestCase): def test_set_component(self): """Test if set_component works.""" - loader.set_component('switch.test_set', http) + comp = object() + loader.set_component(self.hass, 'switch.test_set', comp) - self.assertEqual(http, loader.get_component('switch.test_set')) + self.assertEqual(comp, + loader.get_component(self.hass, 'switch.test_set')) def test_get_component(self): """Test if get_component works.""" - self.assertEqual(http, loader.get_component('http')) - - self.assertIsNotNone(loader.get_component('switch.test')) + self.assertEqual(http, loader.get_component(self.hass, 'http')) + self.assertIsNotNone(loader.get_component(self.hass, 'light.hue')) def test_load_order_component(self): """Test if we can get the proper load order of components.""" - loader.set_component('mod1', MockModule('mod1')) - loader.set_component('mod2', MockModule('mod2', ['mod1'])) - loader.set_component('mod3', MockModule('mod3', ['mod2'])) + loader.set_component(self.hass, 'mod1', MockModule('mod1')) + loader.set_component(self.hass, 'mod2', MockModule('mod2', ['mod1'])) + loader.set_component(self.hass, 'mod3', MockModule('mod3', ['mod2'])) self.assertEqual( - ['mod1', 'mod2', 'mod3'], loader.load_order_component('mod3')) + ['mod1', 'mod2', 'mod3'], + loader.load_order_component(self.hass, 'mod3')) # Create circular dependency - loader.set_component('mod1', MockModule('mod1', ['mod3'])) + loader.set_component(self.hass, 'mod1', MockModule('mod1', ['mod3'])) - self.assertEqual([], loader.load_order_component('mod3')) + self.assertEqual([], loader.load_order_component(self.hass, 'mod3')) # Depend on non-existing component - loader.set_component('mod1', MockModule('mod1', ['nonexisting'])) + loader.set_component(self.hass, 'mod1', + MockModule('mod1', ['nonexisting'])) - self.assertEqual([], loader.load_order_component('mod1')) + self.assertEqual([], loader.load_order_component(self.hass, 'mod1')) # Try to get load order for non-existing component - self.assertEqual([], loader.load_order_component('mod1')) + self.assertEqual([], loader.load_order_component(self.hass, 'mod1')) def test_component_loader(hass): diff --git a/tests/test_requirements.py b/tests/test_requirements.py index 5f09e0bd83e..8ae0f6c11de 100644 --- a/tests/test_requirements.py +++ b/tests/test_requirements.py @@ -35,7 +35,8 @@ class TestRequirements: mock_dirname.return_value = 'ha_package_path' self.hass.config.skip_pip = False loader.set_component( - 'comp', MockModule('comp', requirements=['package==0.0.1'])) + self.hass, 'comp', + MockModule('comp', requirements=['package==0.0.1'])) assert setup.setup_component(self.hass, 'comp') assert 'comp' in self.hass.config.components assert mock_install.call_args == mock.call( @@ -53,7 +54,8 @@ class TestRequirements: mock_dirname.return_value = 'ha_package_path' self.hass.config.skip_pip = False loader.set_component( - 'comp', MockModule('comp', requirements=['package==0.0.1'])) + self.hass, 'comp', + MockModule('comp', requirements=['package==0.0.1'])) assert setup.setup_component(self.hass, 'comp') assert 'comp' in self.hass.config.components assert mock_install.call_args == mock.call( diff --git a/tests/test_setup.py b/tests/test_setup.py index 6a94310793c..6f0c282e016 100644 --- a/tests/test_setup.py +++ b/tests/test_setup.py @@ -49,6 +49,7 @@ class TestSetup: } }, required=True) loader.set_component( + self.hass, 'comp_conf', MockModule('comp_conf', config_schema=config_schema)) with assert_setup_component(0): @@ -93,10 +94,12 @@ class TestSetup: 'hello': str, }) loader.set_component( + self.hass, 'platform_conf', MockModule('platform_conf', platform_schema=platform_schema)) loader.set_component( + self.hass, 'platform_conf.whatever', MockPlatform('whatever')) with assert_setup_component(0): @@ -179,7 +182,8 @@ class TestSetup: """Test we do not setup a component twice.""" mock_setup = mock.MagicMock(return_value=True) - loader.set_component('comp', MockModule('comp', setup=mock_setup)) + loader.set_component( + self.hass, 'comp', MockModule('comp', setup=mock_setup)) assert setup.setup_component(self.hass, 'comp') assert mock_setup.called @@ -195,6 +199,7 @@ class TestSetup: """Component setup should fail if requirement can't install.""" self.hass.config.skip_pip = False loader.set_component( + self.hass, 'comp', MockModule('comp', requirements=['package==0.0.1'])) assert not setup.setup_component(self.hass, 'comp') @@ -210,6 +215,7 @@ class TestSetup: result.append(1) loader.set_component( + self.hass, 'comp', MockModule('comp', async_setup=async_setup)) def setup_component(): @@ -227,20 +233,23 @@ class TestSetup: def test_component_not_setup_missing_dependencies(self): """Test we do not setup a component if not all dependencies loaded.""" deps = ['non_existing'] - loader.set_component('comp', MockModule('comp', dependencies=deps)) + loader.set_component( + self.hass, 'comp', MockModule('comp', dependencies=deps)) assert not setup.setup_component(self.hass, 'comp', {}) assert 'comp' not in self.hass.config.components self.hass.data.pop(setup.DATA_SETUP) - loader.set_component('non_existing', MockModule('non_existing')) + loader.set_component( + self.hass, 'non_existing', MockModule('non_existing')) assert setup.setup_component(self.hass, 'comp', {}) def test_component_failing_setup(self): """Test component that fails setup.""" loader.set_component( - 'comp', MockModule('comp', setup=lambda hass, config: False)) + self.hass, 'comp', + MockModule('comp', setup=lambda hass, config: False)) assert not setup.setup_component(self.hass, 'comp', {}) assert 'comp' not in self.hass.config.components @@ -251,7 +260,8 @@ class TestSetup: """Setup that raises exception.""" raise Exception('fail!') - loader.set_component('comp', MockModule('comp', setup=exception_setup)) + loader.set_component( + self.hass, 'comp', MockModule('comp', setup=exception_setup)) assert not setup.setup_component(self.hass, 'comp', {}) assert 'comp' not in self.hass.config.components @@ -264,11 +274,12 @@ class TestSetup: return True raise Exception('Config not passed in: {}'.format(config)) - loader.set_component('comp_a', - MockModule('comp_a', setup=config_check_setup)) + loader.set_component( + self.hass, 'comp_a', + MockModule('comp_a', setup=config_check_setup)) - loader.set_component('switch.platform_a', MockPlatform('comp_b', - ['comp_a'])) + loader.set_component( + self.hass, 'switch.platform_a', MockPlatform('comp_b', ['comp_a'])) setup.setup_component(self.hass, 'switch', { 'comp_a': { @@ -289,6 +300,7 @@ class TestSetup: mock_setup = mock.MagicMock(spec_set=True) loader.set_component( + self.hass, 'switch.platform_a', MockPlatform(platform_schema=platform_schema, setup_platform=mock_setup)) @@ -330,29 +342,34 @@ class TestSetup: def test_disable_component_if_invalid_return(self): """Test disabling component if invalid return.""" loader.set_component( + self.hass, 'disabled_component', MockModule('disabled_component', setup=lambda hass, config: None)) assert not setup.setup_component(self.hass, 'disabled_component') - assert loader.get_component('disabled_component') is None + assert loader.get_component(self.hass, 'disabled_component') is None assert 'disabled_component' not in self.hass.config.components self.hass.data.pop(setup.DATA_SETUP) loader.set_component( + self.hass, 'disabled_component', MockModule('disabled_component', setup=lambda hass, config: False)) assert not setup.setup_component(self.hass, 'disabled_component') - assert loader.get_component('disabled_component') is not None + assert loader.get_component( + self.hass, 'disabled_component') is not None assert 'disabled_component' not in self.hass.config.components self.hass.data.pop(setup.DATA_SETUP) loader.set_component( + self.hass, 'disabled_component', MockModule('disabled_component', setup=lambda hass, config: True)) assert setup.setup_component(self.hass, 'disabled_component') - assert loader.get_component('disabled_component') is not None + assert loader.get_component( + self.hass, 'disabled_component') is not None assert 'disabled_component' in self.hass.config.components def test_all_work_done_before_start(self): @@ -373,14 +390,17 @@ class TestSetup: return True loader.set_component( + self.hass, 'test_component1', MockModule('test_component1', setup=component1_setup)) loader.set_component( + self.hass, 'test_component2', MockModule('test_component2', setup=component_track_setup)) loader.set_component( + self.hass, 'test_component3', MockModule('test_component3', setup=component_track_setup)) @@ -409,7 +429,8 @@ def test_component_cannot_depend_config(hass): @asyncio.coroutine def test_component_warn_slow_setup(hass): """Warn we log when a component setup takes a long time.""" - loader.set_component('test_component1', MockModule('test_component1')) + loader.set_component( + hass, 'test_component1', MockModule('test_component1')) with mock.patch.object(hass.loop, 'call_later', mock.MagicMock()) \ as mock_call: result = yield from setup.async_setup_component( @@ -430,7 +451,7 @@ def test_component_warn_slow_setup(hass): def test_platform_no_warn_slow(hass): """Do not warn for long entity setup time.""" loader.set_component( - 'test_component1', + hass, 'test_component1', MockModule('test_component1', platform_schema=PLATFORM_SCHEMA)) with mock.patch.object(hass.loop, 'call_later', mock.MagicMock()) \ as mock_call: diff --git a/tests/testing_config/custom_components/test_standalone.py b/tests/testing_config/custom_components/test_standalone.py index f0d4ba7982b..de3a360a4da 100644 --- a/tests/testing_config/custom_components/test_standalone.py +++ b/tests/testing_config/custom_components/test_standalone.py @@ -2,6 +2,6 @@ DOMAIN = 'test_standalone' -def setup(hass, config): +async def async_setup(hass, config): """Mock a successful setup.""" return True