From 6ba9ccf05294451075e7147a225cf123c77ad34b Mon Sep 17 00:00:00 2001 From: Rohan Kapoor <rohan@rohankapoor.com> Date: Thu, 11 Apr 2019 01:26:36 -0700 Subject: [PATCH] Load requirements and dependencies from manifests. Fallback to current `REQUIREMENTS` and `DEPENDENCIES` (#22717) * Load dependencies from manifests. Fallback to current DEPENDENCIES * Fix typing * Ignore typing correctly * Split out dependency processing to a new method * Fix tests * Only pull from manifest if dependencies is non empty * Inline temporary function * Fix light tests [skip ci] * Fix tests/common * Fix some mqtt tests [skip ci] * Fix tests and component manifests which have only one platform * Fix rflink tests * Fix more tests and manifests * Readability over shorthand format * Fix demo/notify tests * Load dependencies from manifests. Fallback to current DEPENDENCIES * Load requirements from manifests. Fallback to current REQUIREMENTS * Fix typing * Ignore typing correctly * Split out dependency processing to a new method * Only pull from manifest if dependencies is non empty * Inline temporary function * Fix tests and component manifests which have only one platform * Fix rflink tests * Readability over shorthand format * Clean up requirements * Use integration to resolve deps/reqs * Lint * Lint * revert a change * Revert a test change * Fix types * Fix types * Add back cache for load component * Fix test_component_not_found * Move light.test and device_tracker.test into test package instead with manifest to fix tests * Fix broken device_tracker tests * Add docstrings to __init__ * Fix all of the light tests that I broke earlier * Embed the test.switch platform to fix other tests * Embed and fix the test.imagimage_processing platform * Fix tests for nx584 * Add dependencies from platform file's DEPENDENCIES * Try to setup component when entity_platform is setting up Fix tests in helpers folder * Rewrite test_setup * Simplify * Lint * Disable demo component if running in test Temp workaround to unblock CI tests * Skip demo tests * Fix config entry test * Fix repeat test * Clarify doc * One extra guard * Fix import * Lint * Workaround google tts --- homeassistant/components/arlo/manifest.json | 4 +- homeassistant/components/arwn/manifest.json | 4 +- .../components/asterisk_cdr/manifest.json | 4 +- .../components/automatic/manifest.json | 4 +- .../components/automation/manifest.json | 3 +- homeassistant/components/canary/manifest.json | 4 +- homeassistant/components/demo/__init__.py | 7 +- homeassistant/components/fitbit/manifest.json | 4 +- homeassistant/components/flexit/manifest.json | 4 +- homeassistant/components/flux/manifest.json | 4 +- .../generic_thermostat/manifest.json | 5 +- homeassistant/components/google/__init__.py | 3 + .../components/history_stats/manifest.json | 4 +- .../components/manual_mqtt/manifest.json | 4 +- homeassistant/components/mqtt/manifest.json | 4 +- .../components/mqtt_json/manifest.json | 4 +- .../components/mqtt_room/manifest.json | 4 +- .../components/mystrom/manifest.json | 4 +- .../components/netatmo_public/manifest.json | 4 +- homeassistant/components/netio/manifest.json | 4 +- homeassistant/components/onvif/manifest.json | 4 +- homeassistant/components/ring/manifest.json | 4 +- .../components/spotify/manifest.json | 4 +- .../components/telegram/manifest.json | 4 +- homeassistant/components/tof/manifest.json | 4 +- homeassistant/components/torque/manifest.json | 4 +- .../components/twilio_call/manifest.json | 4 +- .../components/twilio_sms/manifest.json | 4 +- homeassistant/components/xiaomi/manifest.json | 4 +- homeassistant/components/yi/manifest.json | 4 +- homeassistant/config_entries.py | 11 +- homeassistant/loader.py | 29 +++-- homeassistant/setup.py | 83 +++++++++----- requirements_test_all.txt | 10 ++ script/gen_requirements_all.py | 3 + tests/common.py | 23 +++- tests/components/demo/test_geo_location.py | 9 +- tests/components/demo/test_init.py | 3 + .../device_sun_light_trigger/test_init.py | 4 +- tests/components/device_tracker/test_init.py | 10 +- tests/components/flux/test_switch.py | 32 +++--- tests/components/frontend/test_init.py | 4 +- .../generic_thermostat/test_climate.py | 3 +- tests/components/light/test_init.py | 10 +- tests/components/nx584/test_binary_sensor.py | 2 +- tests/components/scene/test_init.py | 2 +- tests/components/switch/test_init.py | 6 +- tests/helpers/test_discovery.py | 10 +- tests/helpers/test_entity_component.py | 44 ++++---- tests/helpers/test_entity_platform.py | 21 ++-- tests/helpers/test_translation.py | 6 +- tests/test_config_entries.py | 33 ++++-- tests/test_loader.py | 28 ++--- tests/test_setup.py | 105 +++++++++--------- tests/testing_config/__init__.py | 1 + .../custom_components/__init__.py | 1 + .../{test_embedded.py => test_legacy.py} | 0 .../.translations/switch.de.json} | 0 .../.translations/switch.en.json} | 0 .../.translations/switch.es.json} | 0 .../custom_components/test/__init__.py | 1 + .../test.py => test/device_tracker.py} | 0 .../test.py => test/image_processing.py} | 0 .../{light/test.py => test/light.py} | 0 .../custom_components/test/manifest.json | 8 ++ .../{switch/test.py => test/switch.py} | 0 66 files changed, 391 insertions(+), 233 deletions(-) create mode 100644 tests/testing_config/__init__.py create mode 100644 tests/testing_config/custom_components/__init__.py rename tests/testing_config/custom_components/switch/{test_embedded.py => test_legacy.py} (100%) rename tests/testing_config/custom_components/{switch/.translations/test.de.json => test/.translations/switch.de.json} (100%) rename tests/testing_config/custom_components/{switch/.translations/test.en.json => test/.translations/switch.en.json} (100%) rename tests/testing_config/custom_components/{switch/.translations/test.es.json => test/.translations/switch.es.json} (100%) create mode 100644 tests/testing_config/custom_components/test/__init__.py rename tests/testing_config/custom_components/{device_tracker/test.py => test/device_tracker.py} (100%) rename tests/testing_config/custom_components/{image_processing/test.py => test/image_processing.py} (100%) rename tests/testing_config/custom_components/{light/test.py => test/light.py} (100%) create mode 100644 tests/testing_config/custom_components/test/manifest.json rename tests/testing_config/custom_components/{switch/test.py => test/switch.py} (100%) diff --git a/homeassistant/components/arlo/manifest.json b/homeassistant/components/arlo/manifest.json index a8b6befb70f..35803d0d4f6 100644 --- a/homeassistant/components/arlo/manifest.json +++ b/homeassistant/components/arlo/manifest.json @@ -5,6 +5,8 @@ "requirements": [ "pyarlo==0.2.3" ], - "dependencies": [], + "dependencies": [ + "ffmpeg" + ], "codeowners": [] } diff --git a/homeassistant/components/arwn/manifest.json b/homeassistant/components/arwn/manifest.json index 15ef7fa48ba..1c861aa67e2 100644 --- a/homeassistant/components/arwn/manifest.json +++ b/homeassistant/components/arwn/manifest.json @@ -3,6 +3,8 @@ "name": "Arwn", "documentation": "https://www.home-assistant.io/components/arwn", "requirements": [], - "dependencies": [], + "dependencies": [ + "mqtt" + ], "codeowners": [] } diff --git a/homeassistant/components/asterisk_cdr/manifest.json b/homeassistant/components/asterisk_cdr/manifest.json index 2c8713ac191..db1308b0483 100644 --- a/homeassistant/components/asterisk_cdr/manifest.json +++ b/homeassistant/components/asterisk_cdr/manifest.json @@ -3,6 +3,8 @@ "name": "Asterisk cdr", "documentation": "https://www.home-assistant.io/components/asterisk_cdr", "requirements": [], - "dependencies": [], + "dependencies": [ + "asterisk_mbox" + ], "codeowners": [] } diff --git a/homeassistant/components/automatic/manifest.json b/homeassistant/components/automatic/manifest.json index db2f676813e..50bd02d2ac1 100644 --- a/homeassistant/components/automatic/manifest.json +++ b/homeassistant/components/automatic/manifest.json @@ -5,7 +5,9 @@ "requirements": [ "aioautomatic==0.6.5" ], - "dependencies": [], + "dependencies": [ + "http" + ], "codeowners": [ "@armills" ] diff --git a/homeassistant/components/automation/manifest.json b/homeassistant/components/automation/manifest.json index 93f1abe0f0d..ea63d4ff98a 100644 --- a/homeassistant/components/automation/manifest.json +++ b/homeassistant/components/automation/manifest.json @@ -4,7 +4,8 @@ "documentation": "https://www.home-assistant.io/components/automation", "requirements": [], "dependencies": [ - "group" + "group", + "webhook" ], "codeowners": [ "@home-assistant/core" diff --git a/homeassistant/components/canary/manifest.json b/homeassistant/components/canary/manifest.json index e7cc5fa7efc..346c1c99f6d 100644 --- a/homeassistant/components/canary/manifest.json +++ b/homeassistant/components/canary/manifest.json @@ -5,6 +5,8 @@ "requirements": [ "py-canary==0.5.0" ], - "dependencies": [], + "dependencies": [ + "ffmpeg" + ], "codeowners": [] } diff --git a/homeassistant/components/demo/__init__.py b/homeassistant/components/demo/__init__.py index 70c1341145d..354f0c0e375 100644 --- a/homeassistant/components/demo/__init__.py +++ b/homeassistant/components/demo/__init__.py @@ -1,6 +1,7 @@ """Set up the demo environment that mimics interaction with devices.""" import asyncio import time +import sys from homeassistant import bootstrap import homeassistant.core as ha @@ -31,7 +32,7 @@ COMPONENTS_WITH_DEMO_PLATFORM = [ ] -async def async_setup(hass, config): +async def _async_setup(hass, config): """Set up the demo environment.""" group = hass.components.group configurator = hass.components.configurator @@ -224,3 +225,7 @@ async def async_setup(hass, config): hass.async_add_job(setup_configurator) return True + + +if 'pytest' not in sys.modules: + async_setup = _async_setup # pylint: disable=invalid-name diff --git a/homeassistant/components/fitbit/manifest.json b/homeassistant/components/fitbit/manifest.json index d1335a1347d..5b02bca4b6f 100644 --- a/homeassistant/components/fitbit/manifest.json +++ b/homeassistant/components/fitbit/manifest.json @@ -5,7 +5,9 @@ "requirements": [ "fitbit==0.3.0" ], - "dependencies": [], + "dependencies": [ + "http" + ], "codeowners": [ "@robbiet480" ] diff --git a/homeassistant/components/flexit/manifest.json b/homeassistant/components/flexit/manifest.json index 1af86243f86..0ee0e81143c 100644 --- a/homeassistant/components/flexit/manifest.json +++ b/homeassistant/components/flexit/manifest.json @@ -5,6 +5,8 @@ "requirements": [ "pyflexit==0.3" ], - "dependencies": [], + "dependencies": [ + "modbus" + ], "codeowners": [] } diff --git a/homeassistant/components/flux/manifest.json b/homeassistant/components/flux/manifest.json index 8c07a70bca6..d4d67edbd35 100644 --- a/homeassistant/components/flux/manifest.json +++ b/homeassistant/components/flux/manifest.json @@ -3,6 +3,8 @@ "name": "Flux", "documentation": "https://www.home-assistant.io/components/flux", "requirements": [], - "dependencies": [], + "dependencies": [ + "light" + ], "codeowners": [] } diff --git a/homeassistant/components/generic_thermostat/manifest.json b/homeassistant/components/generic_thermostat/manifest.json index 67306b1e7cd..41fb04c8456 100644 --- a/homeassistant/components/generic_thermostat/manifest.json +++ b/homeassistant/components/generic_thermostat/manifest.json @@ -3,6 +3,9 @@ "name": "Generic thermostat", "documentation": "https://www.home-assistant.io/components/generic_thermostat", "requirements": [], - "dependencies": [], + "dependencies": [ + "sensor", + "switch" + ], "codeowners": [] } diff --git a/homeassistant/components/google/__init__.py b/homeassistant/components/google/__init__.py index 37ee5efbd93..0216094de9b 100644 --- a/homeassistant/components/google/__init__.py +++ b/homeassistant/components/google/__init__.py @@ -153,6 +153,9 @@ def setup(hass, config): hass.data[DATA_INDEX] = {} conf = config.get(DOMAIN, {}) + if not conf: + # component is set up by tts platform + return True token_file = hass.config.path(TOKEN_FILE) if not os.path.isfile(token_file): diff --git a/homeassistant/components/history_stats/manifest.json b/homeassistant/components/history_stats/manifest.json index 8e0c1b24910..ea0abd87c28 100644 --- a/homeassistant/components/history_stats/manifest.json +++ b/homeassistant/components/history_stats/manifest.json @@ -3,6 +3,8 @@ "name": "History stats", "documentation": "https://www.home-assistant.io/components/history_stats", "requirements": [], - "dependencies": [], + "dependencies": [ + "history" + ], "codeowners": [] } diff --git a/homeassistant/components/manual_mqtt/manifest.json b/homeassistant/components/manual_mqtt/manifest.json index cc467ade5c1..81cd1338450 100644 --- a/homeassistant/components/manual_mqtt/manifest.json +++ b/homeassistant/components/manual_mqtt/manifest.json @@ -3,6 +3,8 @@ "name": "Manual mqtt", "documentation": "https://www.home-assistant.io/components/manual_mqtt", "requirements": [], - "dependencies": [], + "dependencies": [ + "mqtt" + ], "codeowners": [] } diff --git a/homeassistant/components/mqtt/manifest.json b/homeassistant/components/mqtt/manifest.json index deed878711a..dd4d0323a51 100644 --- a/homeassistant/components/mqtt/manifest.json +++ b/homeassistant/components/mqtt/manifest.json @@ -6,7 +6,9 @@ "hbmqtt==0.9.4", "paho-mqtt==1.4.0" ], - "dependencies": [], + "dependencies": [ + "http" + ], "codeowners": [ "@home-assistant/core" ] diff --git a/homeassistant/components/mqtt_json/manifest.json b/homeassistant/components/mqtt_json/manifest.json index 96a0a187e65..a1986b2bf2e 100644 --- a/homeassistant/components/mqtt_json/manifest.json +++ b/homeassistant/components/mqtt_json/manifest.json @@ -3,6 +3,8 @@ "name": "Mqtt json", "documentation": "https://www.home-assistant.io/components/mqtt_json", "requirements": [], - "dependencies": [], + "dependencies": [ + "mqtt" + ], "codeowners": [] } diff --git a/homeassistant/components/mqtt_room/manifest.json b/homeassistant/components/mqtt_room/manifest.json index e7b37aec50d..8fc90b0bcb1 100644 --- a/homeassistant/components/mqtt_room/manifest.json +++ b/homeassistant/components/mqtt_room/manifest.json @@ -3,6 +3,8 @@ "name": "Mqtt room", "documentation": "https://www.home-assistant.io/components/mqtt_room", "requirements": [], - "dependencies": [], + "dependencies": [ + "mqtt" + ], "codeowners": [] } diff --git a/homeassistant/components/mystrom/manifest.json b/homeassistant/components/mystrom/manifest.json index a3744baccb1..0e17f33f72e 100644 --- a/homeassistant/components/mystrom/manifest.json +++ b/homeassistant/components/mystrom/manifest.json @@ -5,7 +5,9 @@ "requirements": [ "python-mystrom==0.5.0" ], - "dependencies": [], + "dependencies": [ + "http" + ], "codeowners": [ "@fabaff" ] diff --git a/homeassistant/components/netatmo_public/manifest.json b/homeassistant/components/netatmo_public/manifest.json index 4327db3f298..1070f27b33c 100644 --- a/homeassistant/components/netatmo_public/manifest.json +++ b/homeassistant/components/netatmo_public/manifest.json @@ -3,6 +3,8 @@ "name": "Netatmo public", "documentation": "https://www.home-assistant.io/components/netatmo_public", "requirements": [], - "dependencies": [], + "dependencies": [ + "netatmo" + ], "codeowners": [] } diff --git a/homeassistant/components/netio/manifest.json b/homeassistant/components/netio/manifest.json index 75649c66abb..e3675db04d7 100644 --- a/homeassistant/components/netio/manifest.json +++ b/homeassistant/components/netio/manifest.json @@ -5,6 +5,8 @@ "requirements": [ "pynetio==0.1.9.1" ], - "dependencies": [], + "dependencies": [ + "http" + ], "codeowners": [] } diff --git a/homeassistant/components/onvif/manifest.json b/homeassistant/components/onvif/manifest.json index 6d5ad256f16..bade9f37022 100644 --- a/homeassistant/components/onvif/manifest.json +++ b/homeassistant/components/onvif/manifest.json @@ -7,6 +7,8 @@ "suds-passworddigest-homeassistant==0.1.2a0.dev0", "suds-py3==1.3.3.0" ], - "dependencies": [], + "dependencies": [ + "ffmpeg" + ], "codeowners": [] } diff --git a/homeassistant/components/ring/manifest.json b/homeassistant/components/ring/manifest.json index 4d1fc629035..9dbedad1ffc 100644 --- a/homeassistant/components/ring/manifest.json +++ b/homeassistant/components/ring/manifest.json @@ -5,6 +5,8 @@ "requirements": [ "ring_doorbell==0.2.3" ], - "dependencies": [], + "dependencies": [ + "ffmpeg" + ], "codeowners": [] } diff --git a/homeassistant/components/spotify/manifest.json b/homeassistant/components/spotify/manifest.json index 8c2c72e4d2a..a371f05629e 100644 --- a/homeassistant/components/spotify/manifest.json +++ b/homeassistant/components/spotify/manifest.json @@ -5,6 +5,8 @@ "requirements": [ "spotipy-homeassistant==2.4.4.dev1" ], - "dependencies": [], + "dependencies": [ + "http" + ], "codeowners": [] } diff --git a/homeassistant/components/telegram/manifest.json b/homeassistant/components/telegram/manifest.json index 6ace3cd5aa0..8a6dd7fb369 100644 --- a/homeassistant/components/telegram/manifest.json +++ b/homeassistant/components/telegram/manifest.json @@ -3,6 +3,8 @@ "name": "Telegram", "documentation": "https://www.home-assistant.io/components/telegram", "requirements": [], - "dependencies": [], + "dependencies": [ + "telegram_bot" + ], "codeowners": [] } diff --git a/homeassistant/components/tof/manifest.json b/homeassistant/components/tof/manifest.json index 4e1857379c0..5f64e661a9a 100644 --- a/homeassistant/components/tof/manifest.json +++ b/homeassistant/components/tof/manifest.json @@ -5,6 +5,8 @@ "requirements": [ "VL53L1X2==0.1.5" ], - "dependencies": [], + "dependencies": [ + "rpi_gpio" + ], "codeowners": [] } diff --git a/homeassistant/components/torque/manifest.json b/homeassistant/components/torque/manifest.json index 3e69cb62e68..9ce41b59861 100644 --- a/homeassistant/components/torque/manifest.json +++ b/homeassistant/components/torque/manifest.json @@ -3,6 +3,8 @@ "name": "Torque", "documentation": "https://www.home-assistant.io/components/torque", "requirements": [], - "dependencies": [], + "dependencies": [ + "http" + ], "codeowners": [] } diff --git a/homeassistant/components/twilio_call/manifest.json b/homeassistant/components/twilio_call/manifest.json index 85545084c7b..b235385396b 100644 --- a/homeassistant/components/twilio_call/manifest.json +++ b/homeassistant/components/twilio_call/manifest.json @@ -3,7 +3,9 @@ "name": "Twilio call", "documentation": "https://www.home-assistant.io/components/twilio_call", "requirements": [], - "dependencies": [], + "dependencies": [ + "twilio" + ], "codeowners": [ "@robbiet480" ] diff --git a/homeassistant/components/twilio_sms/manifest.json b/homeassistant/components/twilio_sms/manifest.json index 25cee38dbc8..2174dc275b5 100644 --- a/homeassistant/components/twilio_sms/manifest.json +++ b/homeassistant/components/twilio_sms/manifest.json @@ -3,7 +3,9 @@ "name": "Twilio sms", "documentation": "https://www.home-assistant.io/components/twilio_sms", "requirements": [], - "dependencies": [], + "dependencies": [ + "twilio" + ], "codeowners": [ "@robbiet480" ] diff --git a/homeassistant/components/xiaomi/manifest.json b/homeassistant/components/xiaomi/manifest.json index 158a2e9b2fc..d3587100501 100644 --- a/homeassistant/components/xiaomi/manifest.json +++ b/homeassistant/components/xiaomi/manifest.json @@ -3,6 +3,8 @@ "name": "Xiaomi", "documentation": "https://www.home-assistant.io/components/xiaomi", "requirements": [], - "dependencies": [], + "dependencies": [ + "ffmpeg" + ], "codeowners": [] } diff --git a/homeassistant/components/yi/manifest.json b/homeassistant/components/yi/manifest.json index 0a1a6aabc57..bb7fbf55cbc 100644 --- a/homeassistant/components/yi/manifest.json +++ b/homeassistant/components/yi/manifest.json @@ -5,7 +5,9 @@ "requirements": [ "aioftp==0.12.0" ], - "dependencies": [], + "dependencies": [ + "ffmpeg" + ], "codeowners": [ "@bachya" ] diff --git a/homeassistant/config_entries.py b/homeassistant/config_entries.py index 571cacbaf8f..917579d6cf1 100644 --- a/homeassistant/config_entries.py +++ b/homeassistant/config_entries.py @@ -126,7 +126,7 @@ import uuid from typing import Callable, Dict, List, Optional, Set # noqa pylint: disable=unused-import import weakref -from homeassistant import data_entry_flow +from homeassistant import data_entry_flow, loader from homeassistant.core import callback, HomeAssistant from homeassistant.exceptions import HomeAssistantError, ConfigEntryNotReady from homeassistant.setup import async_setup_component, async_process_deps_reqs @@ -688,7 +688,12 @@ class ConfigEntries: Handler key is the domain of the component that we want to set up. """ - component = getattr(self.hass.components, handler_key) + integration = await loader.async_get_integration( + self.hass, handler_key) + + if integration is None: + raise data_entry_flow.UnknownHandler + handler = HANDLERS.get(handler_key) if handler is None: @@ -698,7 +703,7 @@ class ConfigEntries: # Make sure requirements and dependencies of component are resolved await async_process_deps_reqs( - self.hass, self._hass_config, handler, component) + self.hass, self._hass_config, integration) # Create notification. if source in DISCOVERY_SOURCES: diff --git a/homeassistant/loader.py b/homeassistant/loader.py index 17f0130da4d..0b7495bcb69 100644 --- a/homeassistant/loader.py +++ b/homeassistant/loader.py @@ -52,11 +52,11 @@ LOOKUP_PATHS = [PACKAGE_CUSTOM_COMPONENTS, PACKAGE_BUILTIN] _UNDEF = object() -def manifest_from_legacy_module(module: Any) -> Dict: +def manifest_from_legacy_module(module: ModuleType) -> Dict: """Generate a manifest from a legacy module.""" return { - 'domain': module.DOMAIN, - 'name': module.DOMAIN, + 'domain': module.DOMAIN, # type: ignore + 'name': module.DOMAIN, # type: ignore 'documentation': None, 'requirements': getattr(module, 'REQUIREMENTS', []), 'dependencies': getattr(module, 'DEPENDENCIES', []), @@ -68,10 +68,10 @@ class Integration: """An integration in Home Assistant.""" @classmethod - def resolve_from_root(cls, hass: 'HomeAssistant', root_module: Any, + def resolve_from_root(cls, hass: 'HomeAssistant', root_module: ModuleType, domain: str) -> 'Optional[Integration]': """Resolve an integration from a root module.""" - for base in root_module.__path__: + for base in root_module.__path__: # type: ignore manifest_path = ( pathlib.Path(base) / domain / 'manifest.json' ) @@ -117,15 +117,22 @@ class Integration: self.dependencies = manifest['dependencies'] # type: List[str] self.requirements = manifest['requirements'] # type: List[str] - def get_component(self) -> Any: + def get_component(self) -> ModuleType: """Return the component.""" - return importlib.import_module(self.pkg_path) + cache = self.hass.data.setdefault(DATA_KEY, {}) + if self.domain not in cache: + cache[self.domain] = importlib.import_module(self.pkg_path) + return cache[self.domain] # type: ignore - def get_platform(self, platform_name: str) -> Any: + def get_platform(self, platform_name: str) -> ModuleType: """Return a platform for an integration.""" - return importlib.import_module( - "{}.{}".format(self.pkg_path, platform_name) - ) + cache = self.hass.data.setdefault(DATA_KEY, {}) + full_name = "{}.{}".format(self.domain, platform_name) + if full_name not in cache: + cache[full_name] = importlib.import_module( + "{}.{}".format(self.pkg_path, platform_name) + ) + return cache[full_name] # type: ignore async def async_get_integration(hass: 'HomeAssistant', domain: str)\ diff --git a/homeassistant/setup.py b/homeassistant/setup.py index 0e294200b5f..0160279a859 100644 --- a/homeassistant/setup.py +++ b/homeassistant/setup.py @@ -100,10 +100,16 @@ 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(hass, domain) + try: + integration = await loader.async_get_integration(hass, domain) + except loader.IntegrationNotFound: + log_error("Integration not found.", False) + return False - if not component: - log_error("Component not found.", False) + try: + component = integration.get_component() + except ImportError: + log_error("Unable to import component", False) return False # Validate all dependencies exist and there are no circular dependencies @@ -128,7 +134,7 @@ async def _async_setup_component(hass: core.HomeAssistant, return False try: - await async_process_deps_reqs(hass, config, domain, component) + await async_process_deps_reqs(hass, config, integration) except HomeAssistantError as err: log_error(str(err)) return False @@ -183,13 +189,14 @@ async def _async_setup_component(hass: core.HomeAssistant, hass.bus.async_fire( EVENT_COMPONENT_LOADED, - {ATTR_COMPONENT: component.DOMAIN} # type: ignore + {ATTR_COMPONENT: component.DOMAIN} # type: ignore ) return True -async def async_prepare_setup_platform(hass: core.HomeAssistant, config: Dict, +async def async_prepare_setup_platform(hass: core.HomeAssistant, + hass_config: Dict, domain: str, platform_name: str) \ -> Optional[ModuleType]: """Load a platform and makes sure dependencies are setup. @@ -202,13 +209,18 @@ async def async_prepare_setup_platform(hass: core.HomeAssistant, config: Dict, def log_error(msg: str) -> None: """Log helper.""" _LOGGER.error("Unable to prepare setup for platform %s: %s", - platform_path, msg) + platform_name, msg) async_notify_setup_error(hass, platform_path) - platform = loader.get_platform(hass, domain, platform_name) + try: + integration = await loader.async_get_integration(hass, platform_name) + except loader.IntegrationNotFound: + log_error("Integration not found") + return None - # Not found - if platform is None: + try: + platform = integration.get_platform(domain) + except ImportError: log_error("Platform not found.") return None @@ -216,9 +228,25 @@ async def async_prepare_setup_platform(hass: core.HomeAssistant, config: Dict, if platform_path in hass.config.components: return platform + # Platforms cannot exist on their own, they are part of their integration. + # If the integration is not set up yet, and can be set up, set it up. + if integration.domain not in hass.config.components: + try: + component = integration.get_component() + except ImportError: + log_error("Unable to import the component") + return None + + if (hasattr(component, 'setup') + or hasattr(component, 'async_setup')): + if not await async_setup_component( + hass, integration.domain, hass_config + ): + log_error("Unable to set up component.") + return None + try: - await async_process_deps_reqs( - hass, config, platform_path, platform) + await async_process_deps_reqs(hass, hass_config, integration) except HomeAssistantError as err: log_error(str(err)) return None @@ -227,8 +255,8 @@ async def async_prepare_setup_platform(hass: core.HomeAssistant, config: Dict, async def async_process_deps_reqs( - hass: core.HomeAssistant, config: Dict, name: str, - module: ModuleType) -> None: + hass: core.HomeAssistant, config: Dict, + integration: loader.Integration) -> None: """Process all dependencies and requirements for a module. Module is a Python module of either a component or platform. @@ -237,24 +265,23 @@ async def async_process_deps_reqs( if processed is None: processed = hass.data[DATA_DEPS_REQS] = set() - elif name in processed: + elif integration.domain in processed: return - if hasattr(module, 'DEPENDENCIES'): - dep_success = await _async_process_dependencies( - hass, config, name, module.DEPENDENCIES) # type: ignore - - if not dep_success: - raise HomeAssistantError("Could not set up all dependencies.") - - if not hass.config.skip_pip and hasattr(module, 'REQUIREMENTS'): - req_success = await requirements.async_process_requirements( - hass, name, module.REQUIREMENTS) # type: ignore + if integration.dependencies and not await _async_process_dependencies( + hass, + config, + integration.domain, + integration.dependencies + ): + raise HomeAssistantError("Could not set up all dependencies.") - if not req_success: - raise HomeAssistantError("Could not install all requirements.") + if (not hass.config.skip_pip and integration.requirements and + not await requirements.async_process_requirements( + hass, integration.domain, integration.requirements)): + raise HomeAssistantError("Could not install all requirements.") - processed.add(name) + processed.add(integration.domain) @core.callback diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 12c2f0e51ad..c69d4026227 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -111,6 +111,9 @@ geojson_client==0.3 # homeassistant.components.geo_rss_events georss_generic_client==0.2 +# homeassistant.components.google +google-api-python-client==1.6.4 + # homeassistant.components.ffmpeg ha-ffmpeg==2.0 @@ -138,6 +141,10 @@ homekit[IP]==0.13.0 # homeassistant.components.homematicip_cloud homematicip==0.10.6 +# homeassistant.components.google +# homeassistant.components.remember_the_milk +httplib2==0.10.3 + # homeassistant.components.influxdb influxdb==5.2.0 @@ -165,6 +172,9 @@ mficlient==0.3.0 # homeassistant.components.trend numpy==1.16.2 +# homeassistant.components.google +oauth2client==4.0.0 + # homeassistant.components.mqtt # homeassistant.components.shiftr paho-mqtt==1.4.0 diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py index 8f6172c2323..e1179c904ce 100755 --- a/script/gen_requirements_all.py +++ b/script/gen_requirements_all.py @@ -62,6 +62,7 @@ TEST_REQUIREMENTS = ( 'foobot_async', 'geojson_client', 'georss_generic_client', + 'google-api-python-client', 'gTTS-token', 'ha-ffmpeg', 'hangups', @@ -74,6 +75,7 @@ TEST_REQUIREMENTS = ( 'home-assistant-frontend', 'homekit[IP]', 'homematicip', + 'httplib2', 'influxdb', 'jsonpath', 'libpurecool', @@ -82,6 +84,7 @@ TEST_REQUIREMENTS = ( 'mbddns', 'mficlient', 'numpy', + 'oauth2client', 'paho-mqtt', 'pexpect', 'pilight', diff --git a/tests/common.py b/tests/common.py index 962e98b24e7..4aa13fc9be6 100644 --- a/tests/common.py +++ b/tests/common.py @@ -906,11 +906,26 @@ def mock_integration(hass, module): integration = loader.Integration( hass, 'homeassisant.components.{}'.format(module.DOMAIN), loader.manifest_from_legacy_module(module)) - integration.get_component = lambda: module - - # Backwards compat - loader.set_component(hass, module.DOMAIN, module) + _LOGGER.info("Adding mock integration: %s", module.DOMAIN) hass.data.setdefault( loader.DATA_INTEGRATIONS, {} )[module.DOMAIN] = integration + hass.data.setdefault(loader.DATA_KEY, {})[module.DOMAIN] = module + + +def mock_entity_platform(hass, platform_path, module): + """Mock a entity platform. + + platform_path is in form light.hue. Will create platform + hue.light. + """ + domain, platform_name = platform_path.split('.') + integration_cache = hass.data.setdefault(loader.DATA_KEY, {}) + module_cache = hass.data.setdefault(loader.DATA_KEY, {}) + + if platform_name not in integration_cache: + mock_integration(hass, MockModule(platform_name)) + + _LOGGER.info("Adding mock integration platform: %s", platform_path) + module_cache["{}.{}".format(platform_name, domain)] = module diff --git a/tests/components/demo/test_geo_location.py b/tests/components/demo/test_geo_location.py index c4d01b812f8..acfc97b00e6 100644 --- a/tests/components/demo/test_geo_location.py +++ b/tests/components/demo/test_geo_location.py @@ -40,14 +40,13 @@ class TestDemoPlatform(unittest.TestCase): assert setup_component(self.hass, geo_location.DOMAIN, CONFIG) self.hass.block_till_done() - # In this test, five geolocation entities have been + # In this test, one zone and geolocation entities have been # generated. all_states = self.hass.states.all() - print(all_states) - assert len(all_states) == NUMBER_OF_DEMO_DEVICES + assert len(all_states) == NUMBER_OF_DEMO_DEVICES + 1 # Check a single device's attributes. - state_first_entry = all_states[0] + state_first_entry = all_states[1] # 0 is zone assert abs( state_first_entry.attributes['latitude'] - self.hass.config.latitude @@ -64,5 +63,5 @@ class TestDemoPlatform(unittest.TestCase): # Get all states again, ensure that the number of states is still # the same, but the lists are different. all_states_updated = self.hass.states.all() - assert len(all_states_updated) == NUMBER_OF_DEMO_DEVICES + assert len(all_states_updated) == NUMBER_OF_DEMO_DEVICES + 1 assert all_states != all_states_updated diff --git a/tests/components/demo/test_init.py b/tests/components/demo/test_init.py index b0b2524180f..8ade4f4c278 100644 --- a/tests/components/demo/test_init.py +++ b/tests/components/demo/test_init.py @@ -38,6 +38,7 @@ def demo_cleanup(hass): pass +@pytest.mark.skip @asyncio.coroutine def test_if_demo_state_shows_by_default(hass, minimize_demo_platforms): """Test if demo state shows if we give no configuration.""" @@ -46,6 +47,7 @@ def test_if_demo_state_shows_by_default(hass, minimize_demo_platforms): assert hass.states.get('a.Demo_Mode') is not None +@pytest.mark.skip @asyncio.coroutine def test_hiding_demo_state(hass, minimize_demo_platforms): """Test if you can hide the demo card.""" @@ -55,6 +57,7 @@ def test_hiding_demo_state(hass, minimize_demo_platforms): assert hass.states.get('a.Demo_Mode') is None +@pytest.mark.skip @asyncio.coroutine def test_all_entities_can_be_loaded_over_json(hass): """Test if you can hide the demo card.""" diff --git a/tests/components/device_sun_light_trigger/test_init.py b/tests/components/device_sun_light_trigger/test_init.py index f1ef6aa5dd0..8c4417f5b29 100644 --- a/tests/components/device_sun_light_trigger/test_init.py +++ b/tests/components/device_sun_light_trigger/test_init.py @@ -19,12 +19,12 @@ from tests.components.light import common as common_light def scanner(hass): """Initialize components.""" scanner = loader.get_component( - hass, 'device_tracker.test').get_scanner(None, None) + hass, 'test.device_tracker').get_scanner(None, None) scanner.reset() scanner.come_home('DEV1') - loader.get_component(hass, 'light.test').init() + loader.get_component(hass, 'test.light').init() with patch( 'homeassistant.components.device_tracker.load_yaml_config_file', diff --git a/tests/components/device_tracker/test_init.py b/tests/components/device_tracker/test_init.py index 63f1c60327a..a7c5a1c3903 100644 --- a/tests/components/device_tracker/test_init.py +++ b/tests/components/device_tracker/test_init.py @@ -192,7 +192,7 @@ async def test_discover_platform(mock_demo_setup_scanner, mock_see, hass): async def test_update_stale(hass): """Test stalled update.""" - scanner = get_component(hass, 'device_tracker.test').SCANNER + scanner = get_component(hass, 'test.device_tracker').SCANNER scanner.reset() scanner.come_home('DEV1') @@ -256,7 +256,7 @@ async def test_device_hidden(hass, yaml_devices): hide_if_away=True) device_tracker.update_config(yaml_devices, dev_id, device) - scanner = get_component(hass, 'device_tracker.test').SCANNER + scanner = get_component(hass, 'test.device_tracker').SCANNER scanner.reset() with assert_setup_component(1, device_tracker.DOMAIN): @@ -275,7 +275,7 @@ async def test_group_all_devices(hass, yaml_devices): hide_if_away=True) device_tracker.update_config(yaml_devices, dev_id, device) - scanner = get_component(hass, 'device_tracker.test').SCANNER + scanner = get_component(hass, 'test.device_tracker').SCANNER scanner.reset() with assert_setup_component(1, device_tracker.DOMAIN): @@ -441,7 +441,7 @@ async def test_see_passive_zone_state(hass): 'zone': zone_info }) - scanner = get_component(hass, 'device_tracker.test').SCANNER + scanner = get_component(hass, 'test.device_tracker').SCANNER scanner.reset() scanner.come_home('dev1') @@ -557,7 +557,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(hass, 'device_tracker.test').SCANNER + scanner = get_component(hass, 'test.device_tracker').SCANNER scanner.reset() scanner.come_home('DEV1') diff --git a/tests/components/flux/test_switch.py b/tests/components/flux/test_switch.py index c43f1071e33..317e20f1457 100644 --- a/tests/components/flux/test_switch.py +++ b/tests/components/flux/test_switch.py @@ -74,7 +74,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(self.hass, 'light.test') + platform = loader.get_component(self.hass, 'test.light') platform.init() assert setup_component(self.hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: 'test'}}) @@ -114,7 +114,7 @@ class TestSwitchFlux(unittest.TestCase): def test_flux_before_sunrise(self): """Test the flux switch before sunrise.""" - platform = loader.get_component(self.hass, 'light.test') + platform = loader.get_component(self.hass, 'test.light') platform.init() assert setup_component(self.hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: 'test'}}) @@ -159,7 +159,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(self.hass, 'light.test') + platform = loader.get_component(self.hass, 'test.light') platform.init() assert setup_component(self.hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: 'test'}}) @@ -205,7 +205,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(self.hass, 'light.test') + platform = loader.get_component(self.hass, 'test.light') platform.init() assert setup_component(self.hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: 'test'}}) @@ -252,7 +252,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(self.hass, 'light.test') + platform = loader.get_component(self.hass, 'test.light') platform.init() assert setup_component(self.hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: 'test'}}) @@ -297,7 +297,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(self.hass, 'light.test') + platform = loader.get_component(self.hass, 'test.light') platform.init() assert setup_component(self.hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: 'test'}}) @@ -347,7 +347,7 @@ class TestSwitchFlux(unittest.TestCase): This test has the stop_time on the next day (after midnight). """ - platform = loader.get_component(self.hass, 'light.test') + platform = loader.get_component(self.hass, 'test.light') platform.init() assert setup_component(self.hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: 'test'}}) @@ -398,7 +398,7 @@ class TestSwitchFlux(unittest.TestCase): This test has the stop_time on the next day (after midnight). """ - platform = loader.get_component(self.hass, 'light.test') + platform = loader.get_component(self.hass, 'test.light') platform.init() assert setup_component(self.hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: 'test'}}) @@ -448,7 +448,7 @@ class TestSwitchFlux(unittest.TestCase): This test has the stop_time on the next day (after midnight). """ - platform = loader.get_component(self.hass, 'light.test') + platform = loader.get_component(self.hass, 'test.light') platform.init() assert setup_component(self.hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: 'test'}}) @@ -497,7 +497,7 @@ class TestSwitchFlux(unittest.TestCase): This test has the stop_time on the next day (after midnight). """ - platform = loader.get_component(self.hass, 'light.test') + platform = loader.get_component(self.hass, 'test.light') platform.init() assert setup_component(self.hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: 'test'}}) @@ -547,7 +547,7 @@ class TestSwitchFlux(unittest.TestCase): This test has the stop_time on the next day (after midnight). """ - platform = loader.get_component(self.hass, 'light.test') + platform = loader.get_component(self.hass, 'test.light') platform.init() assert setup_component(self.hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: 'test'}}) @@ -594,7 +594,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(self.hass, 'light.test') + platform = loader.get_component(self.hass, 'test.light') platform.init() assert setup_component(self.hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: 'test'}}) @@ -643,7 +643,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(self.hass, 'light.test') + platform = loader.get_component(self.hass, 'test.light') platform.init() assert setup_component(self.hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: 'test'}}) @@ -690,7 +690,7 @@ class TestSwitchFlux(unittest.TestCase): def test_flux_with_multiple_lights(self): """Test the flux switch with multiple light entities.""" - platform = loader.get_component(self.hass, 'light.test') + platform = loader.get_component(self.hass, 'test.light') platform.init() assert setup_component(self.hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: 'test'}}) @@ -758,7 +758,7 @@ class TestSwitchFlux(unittest.TestCase): def test_flux_with_mired(self): """Test the flux switch´s mode mired.""" - platform = loader.get_component(self.hass, 'light.test') + platform = loader.get_component(self.hass, 'test.light') platform.init() assert setup_component(self.hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: 'test'}}) @@ -802,7 +802,7 @@ class TestSwitchFlux(unittest.TestCase): def test_flux_with_rgb(self): """Test the flux switch´s mode rgb.""" - platform = loader.get_component(self.hass, 'light.test') + platform = loader.get_component(self.hass, 'test.light') platform.init() assert setup_component(self.hass, light.DOMAIN, {light.DOMAIN: {CONF_PLATFORM: 'test'}}) diff --git a/tests/components/frontend/test_init.py b/tests/components/frontend/test_init.py index e4ed2c15ecb..497dc25230e 100644 --- a/tests/components/frontend/test_init.py +++ b/tests/components/frontend/test_init.py @@ -78,9 +78,9 @@ def test_frontend_and_static(mock_http_client, mock_onboarded): # Test we can retrieve frontend.js frontendjs = re.search( - r'(?P<app>\/frontend_es5\/app-[A-Za-z0-9]{8}.js)', text) + r'(?P<app>\/frontend_es5\/app.[A-Za-z0-9]{8}.js)', text) - assert frontendjs is not None + assert frontendjs is not None, text resp = yield from mock_http_client.get(frontendjs.groups(0)[0]) assert resp.status == 200 assert 'public' in resp.headers.get('cache-control') diff --git a/tests/components/generic_thermostat/test_climate.py b/tests/components/generic_thermostat/test_climate.py index 49d49fdd3d4..2d9a5effc2c 100644 --- a/tests/components/generic_thermostat/test_climate.py +++ b/tests/components/generic_thermostat/test_climate.py @@ -98,7 +98,7 @@ async def test_heater_input_boolean(hass, setup_comp_1): async def test_heater_switch(hass, setup_comp_1): """Test heater switching test switch.""" - platform = loader.get_component(hass, 'switch.test') + platform = loader.get_component(hass, 'test.switch') platform.init() switch_1 = platform.DEVICES[1] assert await async_setup_component(hass, switch.DOMAIN, {'switch': { @@ -112,6 +112,7 @@ async def test_heater_switch(hass, setup_comp_1): 'target_sensor': ENT_SENSOR }}) + await hass.async_block_till_done() assert STATE_OFF == \ hass.states.get(heater_switch).state diff --git a/tests/components/light/test_init.py b/tests/components/light/test_init.py index 90f2651080c..c910c2a49a1 100644 --- a/tests/components/light/test_init.py +++ b/tests/components/light/test_init.py @@ -121,7 +121,7 @@ class TestLight(unittest.TestCase): def test_services(self): """Test the provided services.""" - platform = loader.get_component(self.hass, 'light.test') + platform = loader.get_component(self.hass, 'test.light') platform.init() assert setup_component(self.hass, light.DOMAIN, @@ -308,7 +308,7 @@ class TestLight(unittest.TestCase): def test_broken_light_profiles(self): """Test light profiles.""" - platform = loader.get_component(self.hass, 'light.test') + platform = loader.get_component(self.hass, 'test.light') platform.init() user_light_file = self.hass.config.path(light.LIGHT_PROFILES_FILE) @@ -323,7 +323,7 @@ class TestLight(unittest.TestCase): def test_light_profiles(self): """Test light profiles.""" - platform = loader.get_component(self.hass, 'light.test') + platform = loader.get_component(self.hass, 'test.light') platform.init() user_light_file = self.hass.config.path(light.LIGHT_PROFILES_FILE) @@ -362,7 +362,7 @@ class TestLight(unittest.TestCase): def test_default_profiles_group(self): """Test default turn-on light profile for all lights.""" - platform = loader.get_component(self.hass, 'light.test') + platform = loader.get_component(self.hass, 'test.light') platform.init() user_light_file = self.hass.config.path(light.LIGHT_PROFILES_FILE) @@ -400,7 +400,7 @@ class TestLight(unittest.TestCase): def test_default_profiles_light(self): """Test default turn-on light profile for a specific light.""" - platform = loader.get_component(self.hass, 'light.test') + platform = loader.get_component(self.hass, 'test.light') platform.init() user_light_file = self.hass.config.path(light.LIGHT_PROFILES_FILE) diff --git a/tests/components/nx584/test_binary_sensor.py b/tests/components/nx584/test_binary_sensor.py index 53516885f30..ae7b70e7fe6 100644 --- a/tests/components/nx584/test_binary_sensor.py +++ b/tests/components/nx584/test_binary_sensor.py @@ -85,7 +85,7 @@ class TestNX584SensorSetup(unittest.TestCase): def _test_assert_graceful_fail(self, config): """Test the failing.""" assert not setup_component( - self.hass, 'binary_sensor.nx584', config) + self.hass, 'nx584', config) def test_setup_bad_config(self): """Test the setup with bad configuration.""" diff --git a/tests/components/scene/test_init.py b/tests/components/scene/test_init.py index df96b19f351..804344ccb34 100644 --- a/tests/components/scene/test_init.py +++ b/tests/components/scene/test_init.py @@ -18,7 +18,7 @@ class TestScene(unittest.TestCase): def setUp(self): # pylint: disable=invalid-name """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() - test_light = loader.get_component(self.hass, 'light.test') + test_light = loader.get_component(self.hass, 'test.light') test_light.init() assert setup_component(self.hass, light.DOMAIN, { diff --git a/tests/components/switch/test_init.py b/tests/components/switch/test_init.py index d39c5a24ddc..c76278f9b22 100644 --- a/tests/components/switch/test_init.py +++ b/tests/components/switch/test_init.py @@ -18,7 +18,7 @@ class TestSwitch(unittest.TestCase): def setUp(self): """Set up things to be run when tests are started.""" self.hass = get_test_home_assistant() - platform = loader.get_component(self.hass, 'switch.test') + platform = loader.get_component(self.hass, 'test.switch') platform.init() # Switch 1 is ON, switch 2 is OFF self.switch_1, self.switch_2, self.switch_3 = \ @@ -77,7 +77,7 @@ 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(self.hass, 'switch.test') + test_platform = loader.get_component(self.hass, 'test.switch') test_platform.init(True) loader.set_component(self.hass, 'switch.test2', test_platform) @@ -99,6 +99,8 @@ async def test_switch_context(hass, hass_admin_user): } }) + await hass.async_block_till_done() + state = hass.states.get('switch.ac') assert state is not None diff --git a/tests/helpers/test_discovery.py b/tests/helpers/test_discovery.py index ffafd3ca146..8bd5e482da4 100644 --- a/tests/helpers/test_discovery.py +++ b/tests/helpers/test_discovery.py @@ -132,10 +132,14 @@ class TestHelpersDiscovery: self.hass, 'test_component', MockModule('test_component', setup=component_setup)) + # dependencies are only set in component level + # since we are using manifest to hold them loader.set_component( - self.hass, 'switch.test_circular', - MockPlatform(setup_platform, - dependencies=['test_component'])) + self.hass, 'test_circular', + MockModule('test_circular', dependencies=['test_component'])) + loader.set_component( + self.hass, 'test_circular.switch', + MockPlatform(setup_platform)) setup.setup_component(self.hass, 'test_component', { 'test_component': None, diff --git a/tests/helpers/test_entity_component.py b/tests/helpers/test_entity_component.py index 6da3293d597..790b7d638e4 100644 --- a/tests/helpers/test_entity_component.py +++ b/tests/helpers/test_entity_component.py @@ -21,7 +21,8 @@ import homeassistant.util.dt as dt_util from tests.common import ( get_test_home_assistant, MockPlatform, MockModule, mock_coro, - async_fire_time_changed, MockEntity, MockConfigEntry) + async_fire_time_changed, MockEntity, MockConfigEntry, + mock_entity_platform, mock_integration) _LOGGER = logging.getLogger(__name__) DOMAIN = "test_domain" @@ -74,11 +75,14 @@ class TestHelpersEntityComponent(unittest.TestCase): """Test the loading of the platforms.""" component_setup = Mock(return_value=True) platform_setup = Mock(return_value=None) - loader.set_component( - self.hass, 'test_component', - MockModule('test_component', setup=component_setup)) - loader.set_component(self.hass, 'test_domain.mod2', - MockPlatform(platform_setup, ['test_component'])) + + mock_integration(self.hass, + MockModule('test_component', setup=component_setup)) + # mock the dependencies + mock_integration(self.hass, + MockModule('mod2', dependencies=['test_component'])) + mock_entity_platform(self.hass, 'test_domain.mod2', + MockPlatform(platform_setup)) component = EntityComponent(_LOGGER, DOMAIN, self.hass) @@ -100,9 +104,9 @@ class TestHelpersEntityComponent(unittest.TestCase): platform1_setup = Mock(side_effect=Exception('Broken')) platform2_setup = Mock(return_value=None) - loader.set_component(self.hass, 'test_domain.mod1', + mock_entity_platform(self.hass, 'test_domain.mod1', MockPlatform(platform1_setup)) - loader.set_component(self.hass, 'test_domain.mod2', + mock_entity_platform(self.hass, 'test_domain.mod2', MockPlatform(platform2_setup)) component = EntityComponent(_LOGGER, DOMAIN, self.hass) @@ -147,7 +151,7 @@ class TestHelpersEntityComponent(unittest.TestCase): """Test the platform setup.""" add_entities([MockEntity(should_poll=True)]) - loader.set_component(self.hass, 'test_domain.platform', + mock_entity_platform(self.hass, 'test_domain.platform', MockPlatform(platform_setup)) component = EntityComponent(_LOGGER, DOMAIN, self.hass) @@ -174,7 +178,7 @@ class TestHelpersEntityComponent(unittest.TestCase): platform = MockPlatform(platform_setup) - loader.set_component(self.hass, 'test_domain.platform', platform) + mock_entity_platform(self.hass, 'test_domain.platform', platform) component = EntityComponent(_LOGGER, DOMAIN, self.hass) @@ -222,7 +226,9 @@ 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(hass, 'test_domain.mod1', + loader.set_component(hass, 'mod1', + MockModule('mod1')) + loader.set_component(hass, 'mod1.test_domain', MockPlatform(platform1_setup)) component = EntityComponent(_LOGGER, DOMAIN, hass) @@ -320,17 +326,15 @@ 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(hass, 'test_component', MockModule('test_component')) + loader.set_component(hass, 'test_component', + MockModule('test_component', + dependencies=['test_component2'])) loader.set_component(hass, 'test_component2', MockModule('test_component2')) - loader.set_component( - hass, 'test_component.test_domain', - MockPlatform(dependencies=['test_component', 'test_component2'])) + loader.set_component(hass, 'test_component.test_domain', MockPlatform()) component = EntityComponent(_LOGGER, DOMAIN, hass) - yield from async_setup_component(hass, 'test_component', {}) - yield from component.async_setup({ DOMAIN: { 'platform': 'test_component', @@ -345,7 +349,7 @@ def test_setup_dependencies_platform(hass): 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( + mock_entity_platform( hass, 'test_domain.entry_domain', MockPlatform(async_setup_entry=mock_setup_entry, scan_interval=timedelta(seconds=5))) @@ -374,7 +378,7 @@ async def test_setup_entry_platform_not_exist(hass): 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( + mock_entity_platform( hass, 'test_domain.entry_domain', MockPlatform(async_setup_entry=mock_setup_entry)) @@ -390,7 +394,7 @@ async def test_setup_entry_fails_duplicate(hass): 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( + mock_entity_platform( hass, 'test_domain.entry_domain', MockPlatform(async_setup_entry=mock_setup_entry)) diff --git a/tests/helpers/test_entity_platform.py b/tests/helpers/test_entity_platform.py index 6cf0bb0eeeb..0fed09b7cbc 100644 --- a/tests/helpers/test_entity_platform.py +++ b/tests/helpers/test_entity_platform.py @@ -8,7 +8,6 @@ from datetime import timedelta import pytest from homeassistant.exceptions import PlatformNotReady -import homeassistant.loader as loader from homeassistant.helpers.entity import generate_entity_id from homeassistant.helpers.entity_component import ( EntityComponent, DEFAULT_SCAN_INTERVAL) @@ -18,7 +17,7 @@ import homeassistant.util.dt as dt_util from tests.common import ( get_test_home_assistant, MockPlatform, fire_time_changed, mock_registry, - MockEntity, MockEntityPlatform, MockConfigEntry) + MockEntity, MockEntityPlatform, MockConfigEntry, mock_entity_platform) _LOGGER = logging.getLogger(__name__) DOMAIN = "test_domain" @@ -149,7 +148,7 @@ class TestHelpersEntityPlatform(unittest.TestCase): platform = MockPlatform(platform_setup) platform.SCAN_INTERVAL = timedelta(seconds=30) - loader.set_component(self.hass, 'test_domain.platform', platform) + mock_entity_platform(self.hass, 'test_domain.platform', platform) component = EntityComponent(_LOGGER, DOMAIN, self.hass) @@ -186,7 +185,7 @@ def test_platform_warn_slow_setup(hass): """Warn we log when platform setup takes a long time.""" platform = MockPlatform() - loader.set_component(hass, 'test_domain.platform', platform) + mock_entity_platform(hass, 'test_domain.platform', platform) component = EntityComponent(_LOGGER, DOMAIN, hass) @@ -199,7 +198,9 @@ def test_platform_warn_slow_setup(hass): }) assert mock_call.called - timeout, logger_method = mock_call.mock_calls[0][1][:2] + # mock_calls[0] is the warning message for component setup + # mock_calls[3] is the warning message for platform setup + timeout, logger_method = mock_call.mock_calls[3][1][:2] assert timeout == entity_platform.SLOW_SETUP_WARNING assert logger_method == _LOGGER.warning @@ -220,7 +221,7 @@ def test_platform_error_slow_setup(hass, caplog): platform = MockPlatform(async_setup_platform=setup_platform) component = EntityComponent(_LOGGER, DOMAIN, hass) - loader.set_component(hass, 'test_domain.test_platform', platform) + mock_entity_platform(hass, 'test_domain.test_platform', platform) yield from component.async_setup({ DOMAIN: { 'platform': 'test_platform', @@ -255,7 +256,7 @@ async def test_parallel_updates_async_platform(hass): """Test async platform does not have parallel_updates limit by default.""" platform = MockPlatform() - loader.set_component(hass, 'test_domain.platform', platform) + mock_entity_platform(hass, 'test_domain.platform', platform) component = EntityComponent(_LOGGER, DOMAIN, hass) component._platforms = {} @@ -285,7 +286,7 @@ async def test_parallel_updates_async_platform_with_constant(hass): platform = MockPlatform() platform.PARALLEL_UPDATES = 2 - loader.set_component(hass, 'test_domain.platform', platform) + mock_entity_platform(hass, 'test_domain.platform', platform) component = EntityComponent(_LOGGER, DOMAIN, hass) component._platforms = {} @@ -316,7 +317,7 @@ async def test_parallel_updates_sync_platform(hass): """Test sync platform parallel_updates default set to 1.""" platform = MockPlatform() - loader.set_component(hass, 'test_domain.platform', platform) + mock_entity_platform(hass, 'test_domain.platform', platform) component = EntityComponent(_LOGGER, DOMAIN, hass) component._platforms = {} @@ -347,7 +348,7 @@ async def test_parallel_updates_sync_platform_with_constant(hass): platform = MockPlatform() platform.PARALLEL_UPDATES = 2 - loader.set_component(hass, 'test_domain.platform', platform) + mock_entity_platform(hass, 'test_domain.platform', platform) component = EntityComponent(_LOGGER, DOMAIN, hass) component._platforms = {} diff --git a/tests/helpers/test_translation.py b/tests/helpers/test_translation.py index 9d62f204dcd..34d929b285a 100644 --- a/tests/helpers/test_translation.py +++ b/tests/helpers/test_translation.py @@ -54,7 +54,7 @@ async def test_component_translation_file(hass): assert path.normpath(translation.component_translation_file( hass, 'switch.test', 'en')) == path.normpath(hass.config.path( - 'custom_components', 'switch', '.translations', 'test.en.json')) + 'custom_components', 'test', '.translations', 'switch.en.json')) assert path.normpath(translation.component_translation_file( hass, 'switch.test_embedded', 'en')) == path.normpath(hass.config.path( @@ -74,9 +74,9 @@ def test_load_translations_files(hass): """Test the load translation files function.""" # Test one valid and one invalid file file1 = hass.config.path( - 'custom_components', 'switch', '.translations', 'test.en.json') + 'custom_components', 'test', '.translations', 'switch.en.json') file2 = hass.config.path( - 'custom_components', 'switch', '.translations', 'invalid.json') + 'custom_components', 'test', '.translations', 'invalid.json') assert translation.load_translations_files({ 'switch.test': file1, 'invalid': file2 diff --git a/tests/test_config_entries.py b/tests/test_config_entries.py index fc8541a096a..cd3f9fd1a89 100644 --- a/tests/test_config_entries.py +++ b/tests/test_config_entries.py @@ -13,15 +13,22 @@ from homeassistant.util import dt from tests.common import ( MockModule, mock_coro, MockConfigEntry, async_fire_time_changed, - MockPlatform, MockEntity) + MockPlatform, MockEntity, mock_integration, mock_entity_platform) -@config_entries.HANDLERS.register('test') -@config_entries.HANDLERS.register('comp') -class MockFlowHandler(config_entries.ConfigFlow): - """Define a mock flow handler.""" +@pytest.fixture(autouse=True) +def mock_handlers(): + """Mock config flows.""" + class MockFlowHandler(config_entries.ConfigFlow): + """Define a mock flow handler.""" - VERSION = 1 + VERSION = 1 + + with patch.dict(config_entries.HANDLERS, { + 'comp': MockFlowHandler, + 'test': MockFlowHandler, + }): + yield @pytest.fixture @@ -185,23 +192,27 @@ async def test_remove_entry(hass, manager): """Mock setting up platform.""" async_add_entities([entity]) - loader.set_component(hass, 'test', MockModule( + mock_integration(hass, MockModule( 'test', async_setup_entry=mock_setup_entry, async_unload_entry=mock_unload_entry, async_remove_entry=mock_remove_entry )) - loader.set_component( - hass, 'test.light', + mock_entity_platform( + hass, 'light.test', MockPlatform(async_setup_entry=mock_setup_entry_platform)) - MockConfigEntry(domain='test', entry_id='test1').add_to_manager(manager) + MockConfigEntry( + domain='test_other', entry_id='test1' + ).add_to_manager(manager) entry = MockConfigEntry( domain='test', entry_id='test2', ) entry.add_to_manager(manager) - MockConfigEntry(domain='test', entry_id='test3').add_to_manager(manager) + MockConfigEntry( + domain='test_other', entry_id='test3' + ).add_to_manager(manager) # Check all config entries exist assert [item.entry_id for item in manager.async_entries()] == \ diff --git a/tests/test_loader.py b/tests/test_loader.py index e3888412f0c..9598906a82b 100644 --- a/tests/test_loader.py +++ b/tests/test_loader.py @@ -1,6 +1,4 @@ """Test to verify that we can load components.""" -import asyncio - import pytest import homeassistant.loader as loader @@ -63,20 +61,18 @@ def test_component_loader_non_existing(hass): components.non_existing -@asyncio.coroutine -def test_component_wrapper(hass): +async def test_component_wrapper(hass): """Test component wrapper.""" calls = async_mock_service(hass, 'persistent_notification', 'create') components = loader.Components(hass) components.persistent_notification.async_create('message') - yield from hass.async_block_till_done() + await hass.async_block_till_done() assert len(calls) == 1 -@asyncio.coroutine -def test_helpers_wrapper(hass): +async def test_helpers_wrapper(hass): """Test helpers wrapper.""" helpers = loader.Helpers(hass) @@ -88,8 +84,8 @@ def test_helpers_wrapper(hass): helpers.discovery.async_listen('service_name', discovery_callback) - yield from helpers.discovery.async_discover('service_name', 'hello') - yield from hass.async_block_till_done() + await helpers.discovery.async_discover('service_name', 'hello') + await hass.async_block_till_done() assert result == ['hello'] @@ -104,9 +100,9 @@ async def test_custom_component_name(hass): assert comp.__name__ == 'custom_components.test_package' assert comp.__package__ == 'custom_components.test_package' - comp = loader.get_component(hass, 'light.test') - assert comp.__name__ == 'custom_components.light.test' - assert comp.__package__ == 'custom_components.light' + comp = loader.get_component(hass, 'test.light') + assert comp.__name__ == 'custom_components.test.light' + assert comp.__package__ == 'custom_components.test' # Test custom components is mounted from custom_components.test_package import TEST @@ -119,8 +115,8 @@ async def test_log_warning_custom_component(hass, caplog): assert \ 'You are using a custom component for test_standalone' in caplog.text - loader.get_component(hass, 'light.test') - assert 'You are using a custom component for light.test' in caplog.text + loader.get_component(hass, 'test.light') + assert 'You are using a custom component for test.light' in caplog.text async def test_get_platform(hass, caplog): @@ -132,8 +128,8 @@ async def test_get_platform(hass, caplog): caplog.clear() - legacy_platform = loader.get_platform(hass, 'switch', 'test') - assert legacy_platform.__name__ == 'custom_components.switch.test' + legacy_platform = loader.get_platform(hass, 'switch', 'test_legacy') + assert legacy_platform.__name__ == 'custom_components.switch.test_legacy' assert 'Integrations need to be in their own folder.' in caplog.text diff --git a/tests/test_setup.py b/tests/test_setup.py index 00518776b52..32c431d1d6a 100644 --- a/tests/test_setup.py +++ b/tests/test_setup.py @@ -20,7 +20,8 @@ from homeassistant.helpers import discovery from tests.common import \ get_test_home_assistant, MockModule, MockPlatform, \ - assert_setup_component, get_test_config_dir, mock_integration + assert_setup_component, get_test_config_dir, mock_integration, \ + mock_entity_platform ORIG_TIMEZONE = dt_util.DEFAULT_TIME_ZONE VERSION_PATH = os.path.join(get_test_config_dir(), config_util.VERSION_FILE) @@ -50,9 +51,9 @@ class TestSetup: 'hello': str } }, required=True) - loader.set_component( + mock_integration( self.hass, - 'comp_conf', MockModule('comp_conf', config_schema=config_schema)) + MockModule('comp_conf', config_schema=config_schema)) with assert_setup_component(0): assert not setup.setup_component(self.hass, 'comp_conf', {}) @@ -97,17 +98,15 @@ class TestSetup: }) platform_schema_base = PLATFORM_SCHEMA_BASE.extend({ }) - loader.set_component( + mock_integration( self.hass, - 'platform_conf', MockModule('platform_conf', - platform_schema_base=platform_schema_base)) - - loader.set_component( + platform_schema_base=platform_schema_base), + ) + mock_entity_platform( self.hass, 'platform_conf.whatever', - MockPlatform('whatever', - platform_schema=platform_schema)) + MockPlatform(platform_schema=platform_schema)) with assert_setup_component(1): assert setup.setup_component(self.hass, 'platform_conf', { @@ -195,14 +194,13 @@ class TestSetup: platform_schema_base = PLATFORM_SCHEMA_BASE.extend({ 'hello': 'world', }) - loader.set_component( + mock_integration( self.hass, - 'platform_conf', MockModule('platform_conf', platform_schema=platform_schema, platform_schema_base=platform_schema_base)) - loader.set_component( + mock_entity_platform( self.hass, 'platform_conf.whatever', MockPlatform('whatever', @@ -249,13 +247,12 @@ class TestSetup: 'cheers': str, 'hello': 'world', }) - loader.set_component( + mock_integration( self.hass, - 'platform_conf', MockModule('platform_conf', platform_schema=component_schema)) - loader.set_component( + mock_entity_platform( self.hass, 'platform_conf.whatever', MockPlatform('whatever', @@ -296,17 +293,15 @@ class TestSetup: """Test entity_namespace in PLATFORM_SCHEMA.""" component_schema = PLATFORM_SCHEMA_BASE platform_schema = PLATFORM_SCHEMA - loader.set_component( + mock_integration( self.hass, - 'platform_conf', MockModule('platform_conf', platform_schema_base=component_schema)) - loader.set_component( + mock_entity_platform( self.hass, 'platform_conf.whatever', - MockPlatform('whatever', - platform_schema=platform_schema)) + MockPlatform(platform_schema=platform_schema)) with assert_setup_component(1): assert setup.setup_component(self.hass, 'platform_conf', { @@ -322,14 +317,15 @@ class TestSetup: def test_component_not_found(self): """setup_component should not crash if component doesn't exist.""" - assert not setup.setup_component(self.hass, 'non_existing') + assert setup.setup_component(self.hass, 'non_existing') is False def test_component_not_double_initialized(self): """Test we do not set up a component twice.""" mock_setup = mock.MagicMock(return_value=True) - loader.set_component( - self.hass, 'comp', MockModule('comp', setup=mock_setup)) + mock_integration( + self.hass, + MockModule('comp', setup=mock_setup)) assert setup.setup_component(self.hass, 'comp') assert mock_setup.called @@ -344,9 +340,9 @@ class TestSetup: def test_component_not_installed_if_requirement_fails(self, mock_install): """Component setup should fail if requirement can't install.""" self.hass.config.skip_pip = False - loader.set_component( + mock_integration( self.hass, - 'comp', MockModule('comp', requirements=['package==0.0.1'])) + MockModule('comp', requirements=['package==0.0.1'])) assert not setup.setup_component(self.hass, 'comp') assert 'comp' not in self.hass.config.components @@ -360,9 +356,9 @@ class TestSetup: """Tracking Setup.""" result.append(1) - loader.set_component( + mock_integration( self.hass, - 'comp', MockModule('comp', async_setup=async_setup)) + MockModule('comp', async_setup=async_setup)) def setup_component(): """Set up the component.""" @@ -393,8 +389,8 @@ class TestSetup: def test_component_failing_setup(self): """Test component that fails setup.""" - loader.set_component( - self.hass, 'comp', + mock_integration( + self.hass, MockModule('comp', setup=lambda hass, config: False)) assert not setup.setup_component(self.hass, 'comp', {}) @@ -406,8 +402,8 @@ class TestSetup: """Raise exception.""" raise Exception('fail!') - loader.set_component( - self.hass, 'comp', MockModule('comp', setup=exception_setup)) + mock_integration(self.hass, + MockModule('comp', setup=exception_setup)) assert not setup.setup_component(self.hass, 'comp', {}) assert 'comp' not in self.hass.config.components @@ -420,12 +416,18 @@ class TestSetup: return True raise Exception('Config not passed in: {}'.format(config)) - loader.set_component( - self.hass, 'comp_a', - MockModule('comp_a', setup=config_check_setup)) + platform = MockPlatform() - loader.set_component( - self.hass, 'switch.platform_a', MockPlatform('comp_b', ['comp_a'])) + mock_integration(self.hass, + MockModule('comp_a', setup=config_check_setup)) + mock_integration( + self.hass, + MockModule('platform_a', + setup=config_check_setup, + dependencies=['comp_a']), + ) + + mock_entity_platform(self.hass, 'switch.platform_a', platform) setup.setup_component(self.hass, 'switch', { 'comp_a': { @@ -445,7 +447,7 @@ class TestSetup: mock_setup = mock.MagicMock(spec_set=True) - loader.set_component( + mock_entity_platform( self.hass, 'switch.platform_a', MockPlatform(platform_schema=platform_schema, @@ -476,7 +478,7 @@ class TestSetup: self.hass.data.pop(setup.DATA_SETUP) self.hass.config.components.remove('switch') - with assert_setup_component(1): + with assert_setup_component(1, 'switch'): assert setup.setup_component(self.hass, 'switch', { 'switch': { 'platform': 'platform_a', @@ -487,9 +489,8 @@ class TestSetup: def test_disable_component_if_invalid_return(self): """Test disabling component if invalid return.""" - loader.set_component( + mock_integration( self.hass, - 'disabled_component', MockModule('disabled_component', setup=lambda hass, config: None)) assert not setup.setup_component(self.hass, 'disabled_component') @@ -497,9 +498,8 @@ class TestSetup: assert 'disabled_component' not in self.hass.config.components self.hass.data.pop(setup.DATA_SETUP) - loader.set_component( + mock_integration( self.hass, - 'disabled_component', MockModule('disabled_component', setup=lambda hass, config: False)) assert not setup.setup_component(self.hass, 'disabled_component') @@ -508,9 +508,8 @@ class TestSetup: assert 'disabled_component' not in self.hass.config.components self.hass.data.pop(setup.DATA_SETUP) - loader.set_component( + mock_integration( self.hass, - 'disabled_component', MockModule('disabled_component', setup=lambda hass, config: True)) assert setup.setup_component(self.hass, 'disabled_component') @@ -535,19 +534,16 @@ class TestSetup: call_order.append(1) return True - loader.set_component( + mock_integration( self.hass, - 'test_component1', MockModule('test_component1', setup=component1_setup)) - loader.set_component( + mock_integration( self.hass, - 'test_component2', MockModule('test_component2', setup=component_track_setup)) - loader.set_component( + mock_integration( self.hass, - 'test_component3', MockModule('test_component3', setup=component_track_setup)) @callback @@ -575,8 +571,7 @@ 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( - hass, 'test_component1', MockModule('test_component1')) + mock_integration(hass, MockModule('test_component1')) with mock.patch.object(hass.loop, 'call_later', mock.MagicMock()) \ as mock_call: result = yield from setup.async_setup_component( @@ -596,8 +591,8 @@ def test_component_warn_slow_setup(hass): @asyncio.coroutine def test_platform_no_warn_slow(hass): """Do not warn for long entity setup time.""" - loader.set_component( - hass, 'test_component1', + mock_integration( + hass, 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/__init__.py b/tests/testing_config/__init__.py new file mode 100644 index 00000000000..98d2bc1bc8d --- /dev/null +++ b/tests/testing_config/__init__.py @@ -0,0 +1 @@ +"""Configuration that's used when running tests.""" diff --git a/tests/testing_config/custom_components/__init__.py b/tests/testing_config/custom_components/__init__.py new file mode 100644 index 00000000000..f84ba5808ae --- /dev/null +++ b/tests/testing_config/custom_components/__init__.py @@ -0,0 +1 @@ +"""A collection of custom integrations used when running tests.""" diff --git a/tests/testing_config/custom_components/switch/test_embedded.py b/tests/testing_config/custom_components/switch/test_legacy.py similarity index 100% rename from tests/testing_config/custom_components/switch/test_embedded.py rename to tests/testing_config/custom_components/switch/test_legacy.py diff --git a/tests/testing_config/custom_components/switch/.translations/test.de.json b/tests/testing_config/custom_components/test/.translations/switch.de.json similarity index 100% rename from tests/testing_config/custom_components/switch/.translations/test.de.json rename to tests/testing_config/custom_components/test/.translations/switch.de.json diff --git a/tests/testing_config/custom_components/switch/.translations/test.en.json b/tests/testing_config/custom_components/test/.translations/switch.en.json similarity index 100% rename from tests/testing_config/custom_components/switch/.translations/test.en.json rename to tests/testing_config/custom_components/test/.translations/switch.en.json diff --git a/tests/testing_config/custom_components/switch/.translations/test.es.json b/tests/testing_config/custom_components/test/.translations/switch.es.json similarity index 100% rename from tests/testing_config/custom_components/switch/.translations/test.es.json rename to tests/testing_config/custom_components/test/.translations/switch.es.json diff --git a/tests/testing_config/custom_components/test/__init__.py b/tests/testing_config/custom_components/test/__init__.py new file mode 100644 index 00000000000..206c97f847b --- /dev/null +++ b/tests/testing_config/custom_components/test/__init__.py @@ -0,0 +1 @@ +"""An integration with several platforms used with unit tests.""" diff --git a/tests/testing_config/custom_components/device_tracker/test.py b/tests/testing_config/custom_components/test/device_tracker.py similarity index 100% rename from tests/testing_config/custom_components/device_tracker/test.py rename to tests/testing_config/custom_components/test/device_tracker.py diff --git a/tests/testing_config/custom_components/image_processing/test.py b/tests/testing_config/custom_components/test/image_processing.py similarity index 100% rename from tests/testing_config/custom_components/image_processing/test.py rename to tests/testing_config/custom_components/test/image_processing.py diff --git a/tests/testing_config/custom_components/light/test.py b/tests/testing_config/custom_components/test/light.py similarity index 100% rename from tests/testing_config/custom_components/light/test.py rename to tests/testing_config/custom_components/test/light.py diff --git a/tests/testing_config/custom_components/test/manifest.json b/tests/testing_config/custom_components/test/manifest.json new file mode 100644 index 00000000000..70882fece05 --- /dev/null +++ b/tests/testing_config/custom_components/test/manifest.json @@ -0,0 +1,8 @@ +{ + "domain": "test", + "name": "Test Components", + "documentation": "http://example.com", + "requirements": [], + "dependencies": [], + "codeowners": [] +} diff --git a/tests/testing_config/custom_components/switch/test.py b/tests/testing_config/custom_components/test/switch.py similarity index 100% rename from tests/testing_config/custom_components/switch/test.py rename to tests/testing_config/custom_components/test/switch.py -- GitLab