From a4bf42104489c2ee4558596ae19b106812dafbcb Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Sun, 29 Apr 2018 01:26:20 +0200 Subject: [PATCH] Convert more files to async/await syntax (#14142) * Move more files to async/await syntax * Attempt Work around pylint bug Using lazytox :P --- homeassistant/bootstrap.py | 68 +++++++++--------- homeassistant/components/api.py | 50 ++++++------- .../components/device_tracker/gpslogger.py | 9 ++- homeassistant/components/dialogflow.py | 16 ++--- homeassistant/components/fan/mqtt.py | 31 ++++---- .../components/google_assistant/__init__.py | 10 ++- .../components/google_assistant/auth.py | 4 +- .../components/google_assistant/http.py | 8 +-- homeassistant/components/group/__init__.py | 71 ++++++++----------- homeassistant/components/history.py | 14 ++-- homeassistant/components/history_graph.py | 6 +- homeassistant/components/input_boolean.py | 25 +++---- homeassistant/components/light/mqtt_json.py | 19 +++-- homeassistant/components/logbook.py | 12 ++-- homeassistant/components/logger.py | 7 +- homeassistant/components/map.py | 7 +- .../components/media_player/__init__.py | 46 +++++------- .../components/media_player/universal.py | 20 +++--- homeassistant/components/recorder/__init__.py | 8 +-- homeassistant/components/sensor/mqtt.py | 15 ++-- .../components/sensor/wunderground.py | 7 +- homeassistant/components/switch/mqtt.py | 18 ++--- homeassistant/components/timer/__init__.py | 40 +++++------ homeassistant/components/tts/google.py | 12 ++-- homeassistant/components/updater.py | 24 +++---- homeassistant/util/logging.py | 7 +- tests/test_bootstrap.py | 2 +- 27 files changed, 229 insertions(+), 327 deletions(-) diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py index e0962568a66..0abe5a7811e 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -67,16 +67,15 @@ def from_config_dict(config: Dict[str, Any], return hass -@asyncio.coroutine -def async_from_config_dict(config: Dict[str, Any], - hass: core.HomeAssistant, - config_dir: Optional[str] = None, - enable_log: bool = True, - verbose: bool = False, - skip_pip: bool = False, - log_rotate_days: Any = None, - log_file: Any = None, - log_no_color: bool = False) \ +async def async_from_config_dict(config: Dict[str, Any], + hass: core.HomeAssistant, + config_dir: Optional[str] = None, + enable_log: bool = True, + verbose: bool = False, + skip_pip: bool = False, + log_rotate_days: Any = None, + log_file: Any = None, + log_no_color: bool = False) \ -> Optional[core.HomeAssistant]: """Try to configure Home Assistant from a configuration dictionary. @@ -92,12 +91,12 @@ def async_from_config_dict(config: Dict[str, Any], core_config = config.get(core.DOMAIN, {}) try: - yield from conf_util.async_process_ha_core_config(hass, core_config) + await conf_util.async_process_ha_core_config(hass, core_config) except vol.Invalid as ex: conf_util.async_log_exception(ex, 'homeassistant', core_config, hass) return None - yield from hass.async_add_job(conf_util.process_ha_config_upgrade, hass) + await hass.async_add_job(conf_util.process_ha_config_upgrade, hass) hass.config.skip_pip = skip_pip if skip_pip: @@ -105,7 +104,7 @@ def async_from_config_dict(config: Dict[str, Any], "This may cause issues") if not loader.PREPARED: - yield from hass.async_add_job(loader.prepare, hass) + await hass.async_add_job(loader.prepare, hass) # Make a copy because we are mutating it. config = OrderedDict(config) @@ -120,7 +119,7 @@ def async_from_config_dict(config: Dict[str, Any], config[key] = {} hass.config_entries = config_entries.ConfigEntries(hass, config) - yield from hass.config_entries.async_load() + await hass.config_entries.async_load() # Filter out the repeating and common config section [homeassistant] components = set(key.split(' ')[0] for key in config.keys() @@ -129,13 +128,13 @@ def async_from_config_dict(config: Dict[str, Any], # setup components # pylint: disable=not-an-iterable - res = yield from core_components.async_setup(hass, config) + res = await core_components.async_setup(hass, config) if not res: _LOGGER.error("Home Assistant core failed to initialize. " "further initialization aborted") return hass - yield from persistent_notification.async_setup(hass, config) + await persistent_notification.async_setup(hass, config) _LOGGER.info("Home Assistant core initialized") @@ -145,7 +144,7 @@ def async_from_config_dict(config: Dict[str, Any], continue hass.async_add_job(async_setup_component(hass, component, config)) - yield from hass.async_block_till_done() + await hass.async_block_till_done() # stage 2 for component in components: @@ -153,7 +152,7 @@ def async_from_config_dict(config: Dict[str, Any], continue hass.async_add_job(async_setup_component(hass, component, config)) - yield from hass.async_block_till_done() + await hass.async_block_till_done() stop = time() _LOGGER.info("Home Assistant initialized in %.2fs", stop-start) @@ -187,14 +186,13 @@ def from_config_file(config_path: str, return hass -@asyncio.coroutine -def async_from_config_file(config_path: str, - hass: core.HomeAssistant, - verbose: bool = False, - skip_pip: bool = True, - log_rotate_days: Any = None, - log_file: Any = None, - log_no_color: bool = False): +async def async_from_config_file(config_path: str, + hass: core.HomeAssistant, + verbose: bool = False, + skip_pip: bool = True, + log_rotate_days: Any = None, + log_file: Any = None, + log_no_color: bool = False): """Read the configuration file and try to start all the functionality. Will add functionality to 'hass' parameter. @@ -203,13 +201,13 @@ def async_from_config_file(config_path: str, # Set config dir to directory holding config file config_dir = os.path.abspath(os.path.dirname(config_path)) hass.config.config_dir = config_dir - yield from async_mount_local_lib_path(config_dir, hass.loop) + await async_mount_local_lib_path(config_dir, hass.loop) async_enable_logging(hass, verbose, log_rotate_days, log_file, log_no_color) try: - config_dict = yield from hass.async_add_job( + config_dict = await hass.async_add_job( conf_util.load_yaml_config_file, config_path) except HomeAssistantError as err: _LOGGER.error("Error loading %s: %s", config_path, err) @@ -217,7 +215,7 @@ def async_from_config_file(config_path: str, finally: clear_secret_cache() - hass = yield from async_from_config_dict( + hass = await async_from_config_dict( config_dict, hass, enable_log=False, skip_pip=skip_pip) return hass @@ -294,11 +292,10 @@ def async_enable_logging(hass: core.HomeAssistant, async_handler = AsyncHandler(hass.loop, err_handler) - @asyncio.coroutine - def async_stop_async_handler(event): + async def async_stop_async_handler(event): """Cleanup async handler.""" logging.getLogger('').removeHandler(async_handler) - yield from async_handler.async_close(blocking=True) + await async_handler.async_close(blocking=True) hass.bus.async_listen_once( EVENT_HOMEASSISTANT_CLOSE, async_stop_async_handler) @@ -323,15 +320,14 @@ def mount_local_lib_path(config_dir: str) -> str: return deps_dir -@asyncio.coroutine -def async_mount_local_lib_path(config_dir: str, - loop: asyncio.AbstractEventLoop) -> str: +async def async_mount_local_lib_path(config_dir: str, + loop: asyncio.AbstractEventLoop) -> str: """Add local library to Python Path. This function is a coroutine. """ deps_dir = os.path.join(config_dir, 'deps') - lib_dir = yield from async_get_user_site(deps_dir, loop=loop) + lib_dir = await async_get_user_site(deps_dir, loop=loop) if lib_dir not in sys.path: sys.path.insert(0, lib_dir) return deps_dir diff --git a/homeassistant/components/api.py b/homeassistant/components/api.py index 6fdf0c027a4..83e05dae641 100644 --- a/homeassistant/components/api.py +++ b/homeassistant/components/api.py @@ -76,8 +76,7 @@ class APIEventStream(HomeAssistantView): url = URL_API_STREAM name = "api:stream" - @asyncio.coroutine - def get(self, request): + async def get(self, request): """Provide a streaming interface for the event bus.""" # pylint: disable=no-self-use hass = request.app['hass'] @@ -88,8 +87,7 @@ class APIEventStream(HomeAssistantView): if restrict: restrict = restrict.split(',') + [EVENT_HOMEASSISTANT_STOP] - @asyncio.coroutine - def forward_events(event): + async def forward_events(event): """Forward events to the open request.""" if event.event_type == EVENT_TIME_CHANGED: return @@ -104,11 +102,11 @@ class APIEventStream(HomeAssistantView): else: data = json.dumps(event, cls=rem.JSONEncoder) - yield from to_write.put(data) + await to_write.put(data) response = web.StreamResponse() response.content_type = 'text/event-stream' - yield from response.prepare(request) + await response.prepare(request) unsub_stream = hass.bus.async_listen(MATCH_ALL, forward_events) @@ -116,13 +114,13 @@ class APIEventStream(HomeAssistantView): _LOGGER.debug('STREAM %s ATTACHED', id(stop_obj)) # Fire off one message so browsers fire open event right away - yield from to_write.put(STREAM_PING_PAYLOAD) + await to_write.put(STREAM_PING_PAYLOAD) while True: try: with async_timeout.timeout(STREAM_PING_INTERVAL, loop=hass.loop): - payload = yield from to_write.get() + payload = await to_write.get() if payload is stop_obj: break @@ -130,9 +128,9 @@ class APIEventStream(HomeAssistantView): msg = "data: {}\n\n".format(payload) _LOGGER.debug('STREAM %s WRITING %s', id(stop_obj), msg.strip()) - yield from response.write(msg.encode("UTF-8")) + await response.write(msg.encode("UTF-8")) except asyncio.TimeoutError: - yield from to_write.put(STREAM_PING_PAYLOAD) + await to_write.put(STREAM_PING_PAYLOAD) except asyncio.CancelledError: _LOGGER.debug('STREAM %s ABORT', id(stop_obj)) @@ -200,12 +198,11 @@ class APIEntityStateView(HomeAssistantView): return self.json(state) return self.json_message('Entity not found', HTTP_NOT_FOUND) - @asyncio.coroutine - def post(self, request, entity_id): + async def post(self, request, entity_id): """Update state of entity.""" hass = request.app['hass'] try: - data = yield from request.json() + data = await request.json() except ValueError: return self.json_message('Invalid JSON specified', HTTP_BAD_REQUEST) @@ -257,10 +254,9 @@ class APIEventView(HomeAssistantView): url = '/api/events/{event_type}' name = "api:event" - @asyncio.coroutine - def post(self, request, event_type): + async def post(self, request, event_type): """Fire events.""" - body = yield from request.text() + body = await request.text() try: event_data = json.loads(body) if body else None except ValueError: @@ -292,10 +288,9 @@ class APIServicesView(HomeAssistantView): url = URL_API_SERVICES name = "api:services" - @asyncio.coroutine - def get(self, request): + async def get(self, request): """Get registered services.""" - services = yield from async_services_json(request.app['hass']) + services = await async_services_json(request.app['hass']) return self.json(services) @@ -305,14 +300,13 @@ class APIDomainServicesView(HomeAssistantView): url = "/api/services/{domain}/{service}" name = "api:domain-services" - @asyncio.coroutine - def post(self, request, domain, service): + async def post(self, request, domain, service): """Call a service. Returns a list of changed states. """ hass = request.app['hass'] - body = yield from request.text() + body = await request.text() try: data = json.loads(body) if body else None except ValueError: @@ -320,7 +314,7 @@ class APIDomainServicesView(HomeAssistantView): HTTP_BAD_REQUEST) with AsyncTrackStates(hass) as changed_states: - yield from hass.services.async_call(domain, service, data, True) + await hass.services.async_call(domain, service, data, True) return self.json(changed_states) @@ -343,11 +337,10 @@ class APITemplateView(HomeAssistantView): url = URL_API_TEMPLATE name = "api:template" - @asyncio.coroutine - def post(self, request): + async def post(self, request): """Render a template.""" try: - data = yield from request.json() + data = await request.json() tpl = template.Template(data['template'], request.app['hass']) return tpl.async_render(data.get('variables')) except (ValueError, TemplateError) as ex: @@ -366,10 +359,9 @@ class APIErrorLog(HomeAssistantView): return await self.file(request, request.app['hass'].data[DATA_LOGGING]) -@asyncio.coroutine -def async_services_json(hass): +async def async_services_json(hass): """Generate services data to JSONify.""" - descriptions = yield from async_get_all_descriptions(hass) + descriptions = await async_get_all_descriptions(hass) return [{"domain": key, "services": value} for key, value in descriptions.items()] diff --git a/homeassistant/components/device_tracker/gpslogger.py b/homeassistant/components/device_tracker/gpslogger.py index 1952e6d676d..68ea9ac88ae 100644 --- a/homeassistant/components/device_tracker/gpslogger.py +++ b/homeassistant/components/device_tracker/gpslogger.py @@ -4,7 +4,6 @@ Support for the GPSLogger platform. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/device_tracker.gpslogger/ """ -import asyncio import logging from hmac import compare_digest @@ -22,6 +21,7 @@ from homeassistant.components.http import ( from homeassistant.components.device_tracker import ( # NOQA DOMAIN, PLATFORM_SCHEMA ) +from homeassistant.helpers.typing import HomeAssistantType, ConfigType _LOGGER = logging.getLogger(__name__) @@ -32,8 +32,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -@asyncio.coroutine -def async_setup_scanner(hass, config, async_see, discovery_info=None): +async def async_setup_scanner(hass: HomeAssistantType, config: ConfigType, + async_see, discovery_info=None): """Set up an endpoint for the GPSLogger application.""" hass.http.register_view(GPSLoggerView(async_see, config)) @@ -54,8 +54,7 @@ class GPSLoggerView(HomeAssistantView): # password is set self.requires_auth = self._password is None - @asyncio.coroutine - def get(self, request: Request): + async def get(self, request: Request): """Handle for GPSLogger message received as GET.""" hass = request.app['hass'] data = request.query diff --git a/homeassistant/components/dialogflow.py b/homeassistant/components/dialogflow.py index 63205c5479c..7a0918aab25 100644 --- a/homeassistant/components/dialogflow.py +++ b/homeassistant/components/dialogflow.py @@ -4,7 +4,6 @@ Support for Dialogflow webhook. For more details about this component, please refer to the documentation at https://home-assistant.io/components/dialogflow/ """ -import asyncio import logging import voluptuous as vol @@ -37,8 +36,7 @@ class DialogFlowError(HomeAssistantError): """Raised when a DialogFlow error happens.""" -@asyncio.coroutine -def async_setup(hass, config): +async def async_setup(hass, config): """Set up Dialogflow component.""" hass.http.register_view(DialogflowIntentsView) @@ -51,16 +49,15 @@ class DialogflowIntentsView(HomeAssistantView): url = INTENTS_API_ENDPOINT name = 'api:dialogflow' - @asyncio.coroutine - def post(self, request): + async def post(self, request): """Handle Dialogflow.""" hass = request.app['hass'] - message = yield from request.json() + message = await request.json() _LOGGER.debug("Received Dialogflow request: %s", message) try: - response = yield from async_handle_message(hass, message) + response = await async_handle_message(hass, message) return b'' if response is None else self.json(response) except DialogFlowError as err: @@ -93,8 +90,7 @@ def dialogflow_error_response(hass, message, error): return dialogflow_response.as_dict() -@asyncio.coroutine -def async_handle_message(hass, message): +async def async_handle_message(hass, message): """Handle a DialogFlow message.""" req = message.get('result') action_incomplete = req['actionIncomplete'] @@ -110,7 +106,7 @@ def async_handle_message(hass, message): raise DialogFlowError( "You have not defined an action in your Dialogflow intent.") - intent_response = yield from intent.async_handle( + intent_response = await intent.async_handle( hass, DOMAIN, action, {key: {'value': value} for key, value in parameters.items()}) diff --git a/homeassistant/components/fan/mqtt.py b/homeassistant/components/fan/mqtt.py index 95ff587c613..6fa506edec6 100644 --- a/homeassistant/components/fan/mqtt.py +++ b/homeassistant/components/fan/mqtt.py @@ -4,7 +4,6 @@ Support for MQTT fans. For more details about this platform, please refer to the documentation https://home-assistant.io/components/fan.mqtt/ """ -import asyncio import logging import voluptuous as vol @@ -19,6 +18,7 @@ from homeassistant.components.mqtt import ( CONF_PAYLOAD_AVAILABLE, CONF_PAYLOAD_NOT_AVAILABLE, CONF_QOS, CONF_RETAIN, MqttAvailability) import homeassistant.helpers.config_validation as cv +from homeassistant.helpers.typing import HomeAssistantType, ConfigType from homeassistant.components.fan import (SPEED_LOW, SPEED_MEDIUM, SPEED_HIGH, FanEntity, SUPPORT_SET_SPEED, SUPPORT_OSCILLATE, @@ -77,8 +77,8 @@ PLATFORM_SCHEMA = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend({ }).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema) -@asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +async def async_setup_platform(hass: HomeAssistantType, config: ConfigType, + async_add_devices, discovery_info=None): """Set up the MQTT fan platform.""" if discovery_info is not None: config = PLATFORM_SCHEMA(discovery_info) @@ -149,10 +149,9 @@ class MqttFan(MqttAvailability, FanEntity): self._supported_features |= (topic[CONF_SPEED_STATE_TOPIC] is not None and SUPPORT_SET_SPEED) - @asyncio.coroutine - def async_added_to_hass(self): + async def async_added_to_hass(self): """Subscribe to MQTT events.""" - yield from super().async_added_to_hass() + await super().async_added_to_hass() templates = {} for key, tpl in list(self._templates.items()): @@ -173,7 +172,7 @@ class MqttFan(MqttAvailability, FanEntity): self.async_schedule_update_ha_state() if self._topic[CONF_STATE_TOPIC] is not None: - yield from mqtt.async_subscribe( + await mqtt.async_subscribe( self.hass, self._topic[CONF_STATE_TOPIC], state_received, self._qos) @@ -190,7 +189,7 @@ class MqttFan(MqttAvailability, FanEntity): self.async_schedule_update_ha_state() if self._topic[CONF_SPEED_STATE_TOPIC] is not None: - yield from mqtt.async_subscribe( + await mqtt.async_subscribe( self.hass, self._topic[CONF_SPEED_STATE_TOPIC], speed_received, self._qos) self._speed = SPEED_OFF @@ -206,7 +205,7 @@ class MqttFan(MqttAvailability, FanEntity): self.async_schedule_update_ha_state() if self._topic[CONF_OSCILLATION_STATE_TOPIC] is not None: - yield from mqtt.async_subscribe( + await mqtt.async_subscribe( self.hass, self._topic[CONF_OSCILLATION_STATE_TOPIC], oscillation_received, self._qos) self._oscillation = False @@ -251,8 +250,7 @@ class MqttFan(MqttAvailability, FanEntity): """Return the oscillation state.""" return self._oscillation - @asyncio.coroutine - def async_turn_on(self, speed: str = None, **kwargs) -> None: + async def async_turn_on(self, speed: str = None, **kwargs) -> None: """Turn on the entity. This method is a coroutine. @@ -261,10 +259,9 @@ class MqttFan(MqttAvailability, FanEntity): self.hass, self._topic[CONF_COMMAND_TOPIC], self._payload[STATE_ON], self._qos, self._retain) if speed: - yield from self.async_set_speed(speed) + await self.async_set_speed(speed) - @asyncio.coroutine - def async_turn_off(self, **kwargs) -> None: + async def async_turn_off(self, **kwargs) -> None: """Turn off the entity. This method is a coroutine. @@ -273,8 +270,7 @@ class MqttFan(MqttAvailability, FanEntity): self.hass, self._topic[CONF_COMMAND_TOPIC], self._payload[STATE_OFF], self._qos, self._retain) - @asyncio.coroutine - def async_set_speed(self, speed: str) -> None: + async def async_set_speed(self, speed: str) -> None: """Set the speed of the fan. This method is a coroutine. @@ -299,8 +295,7 @@ class MqttFan(MqttAvailability, FanEntity): self._speed = speed self.async_schedule_update_ha_state() - @asyncio.coroutine - def async_oscillate(self, oscillating: bool) -> None: + async def async_oscillate(self, oscillating: bool) -> None: """Set oscillation. This method is a coroutine. diff --git a/homeassistant/components/google_assistant/__init__.py b/homeassistant/components/google_assistant/__init__.py index 676654c2c91..1c6d11a7c99 100644 --- a/homeassistant/components/google_assistant/__init__.py +++ b/homeassistant/components/google_assistant/__init__.py @@ -70,8 +70,7 @@ def request_sync(hass): hass.services.call(DOMAIN, SERVICE_REQUEST_SYNC) -@asyncio.coroutine -def async_setup(hass: HomeAssistant, yaml_config: Dict[str, Any]): +async def async_setup(hass: HomeAssistant, yaml_config: Dict[str, Any]): """Activate Google Actions component.""" config = yaml_config.get(DOMAIN, {}) agent_user_id = config.get(CONF_AGENT_USER_ID) @@ -79,20 +78,19 @@ def async_setup(hass: HomeAssistant, yaml_config: Dict[str, Any]): hass.http.register_view(GoogleAssistantAuthView(hass, config)) async_register_http(hass, config) - @asyncio.coroutine - def request_sync_service_handler(call): + async def request_sync_service_handler(call): """Handle request sync service calls.""" websession = async_get_clientsession(hass) try: with async_timeout.timeout(5, loop=hass.loop): - res = yield from websession.post( + res = await websession.post( REQUEST_SYNC_BASE_URL, params={'key': api_key}, json={'agent_user_id': agent_user_id}) _LOGGER.info("Submitted request_sync request to Google") res.raise_for_status() except aiohttp.ClientResponseError: - body = yield from res.read() + body = await res.read() _LOGGER.error( 'request_sync request failed: %d %s', res.status, body) except (asyncio.TimeoutError, aiohttp.ClientError): diff --git a/homeassistant/components/google_assistant/auth.py b/homeassistant/components/google_assistant/auth.py index 1ed27403797..a21dd0e6738 100644 --- a/homeassistant/components/google_assistant/auth.py +++ b/homeassistant/components/google_assistant/auth.py @@ -1,6 +1,5 @@ """Google Assistant OAuth View.""" -import asyncio import logging # Typing imports @@ -44,8 +43,7 @@ class GoogleAssistantAuthView(HomeAssistantView): self.client_id = cfg.get(CONF_CLIENT_ID) self.access_token = cfg.get(CONF_ACCESS_TOKEN) - @asyncio.coroutine - def get(self, request: Request) -> Response: + async def get(self, request: Request) -> Response: """Handle oauth token request.""" query = request.query redirect_uri = query.get('redirect_uri') diff --git a/homeassistant/components/google_assistant/http.py b/homeassistant/components/google_assistant/http.py index 0caea3aadf4..0ea5f7d9fa4 100644 --- a/homeassistant/components/google_assistant/http.py +++ b/homeassistant/components/google_assistant/http.py @@ -4,7 +4,6 @@ Support for Google Actions Smart Home Control. For more details about this component, please refer to the documentation at https://home-assistant.io/components/google_assistant/ """ -import asyncio import logging from aiohttp.hdrs import AUTHORIZATION @@ -77,14 +76,13 @@ class GoogleAssistantView(HomeAssistantView): self.access_token = access_token self.gass_config = gass_config - @asyncio.coroutine - def post(self, request: Request) -> Response: + async def post(self, request: Request) -> Response: """Handle Google Assistant requests.""" auth = request.headers.get(AUTHORIZATION, None) if 'Bearer {}'.format(self.access_token) != auth: return self.json_message("missing authorization", status_code=401) - message = yield from request.json() # type: dict - result = yield from async_handle_message( + message = await request.json() # type: dict + result = await async_handle_message( request.app['hass'], self.gass_config, message) return self.json(result) diff --git a/homeassistant/components/group/__init__.py b/homeassistant/components/group/__init__.py index 67ad8066aff..f70a2d29351 100644 --- a/homeassistant/components/group/__init__.py +++ b/homeassistant/components/group/__init__.py @@ -245,34 +245,31 @@ def get_entity_ids(hass, entity_id, domain_filter=None): if ent_id.startswith(domain_filter)] -@asyncio.coroutine -def async_setup(hass, config): +async def async_setup(hass, config): """Set up all groups found defined in the configuration.""" component = hass.data.get(DOMAIN) if component is None: component = hass.data[DOMAIN] = EntityComponent(_LOGGER, DOMAIN, hass) - yield from _async_process_config(hass, config, component) + await _async_process_config(hass, config, component) - @asyncio.coroutine - def reload_service_handler(service): + async def reload_service_handler(service): """Remove all user-defined groups and load new ones from config.""" auto = list(filter(lambda e: not e.user_defined, component.entities)) - conf = yield from component.async_prepare_reload() + conf = await component.async_prepare_reload() if conf is None: return - yield from _async_process_config(hass, conf, component) + await _async_process_config(hass, conf, component) - yield from component.async_add_entities(auto) + await component.async_add_entities(auto) hass.services.async_register( DOMAIN, SERVICE_RELOAD, reload_service_handler, schema=RELOAD_SERVICE_SCHEMA) - @asyncio.coroutine - def groups_service_handler(service): + async def groups_service_handler(service): """Handle dynamic group service functions.""" object_id = service.data[ATTR_OBJECT_ID] entity_id = ENTITY_ID_FORMAT.format(object_id) @@ -287,7 +284,7 @@ def async_setup(hass, config): ATTR_VISIBLE, ATTR_ICON, ATTR_VIEW, ATTR_CONTROL ) if service.data.get(attr) is not None} - yield from Group.async_create_group( + await Group.async_create_group( hass, service.data.get(ATTR_NAME, object_id), object_id=object_id, entity_ids=entity_ids, @@ -308,11 +305,11 @@ def async_setup(hass, config): if ATTR_ADD_ENTITIES in service.data: delta = service.data[ATTR_ADD_ENTITIES] entity_ids = set(group.tracking) | set(delta) - yield from group.async_update_tracked_entity_ids(entity_ids) + await group.async_update_tracked_entity_ids(entity_ids) if ATTR_ENTITIES in service.data: entity_ids = service.data[ATTR_ENTITIES] - yield from group.async_update_tracked_entity_ids(entity_ids) + await group.async_update_tracked_entity_ids(entity_ids) if ATTR_NAME in service.data: group.name = service.data[ATTR_NAME] @@ -335,13 +332,13 @@ def async_setup(hass, config): need_update = True if need_update: - yield from group.async_update_ha_state() + await group.async_update_ha_state() return # remove group if service.service == SERVICE_REMOVE: - yield from component.async_remove_entity(entity_id) + await component.async_remove_entity(entity_id) hass.services.async_register( DOMAIN, SERVICE_SET, groups_service_handler, @@ -351,8 +348,7 @@ def async_setup(hass, config): DOMAIN, SERVICE_REMOVE, groups_service_handler, schema=REMOVE_SERVICE_SCHEMA) - @asyncio.coroutine - def visibility_service_handler(service): + async def visibility_service_handler(service): """Change visibility of a group.""" visible = service.data.get(ATTR_VISIBLE) @@ -363,7 +359,7 @@ def async_setup(hass, config): tasks.append(group.async_update_ha_state()) if tasks: - yield from asyncio.wait(tasks, loop=hass.loop) + await asyncio.wait(tasks, loop=hass.loop) hass.services.async_register( DOMAIN, SERVICE_SET_VISIBILITY, visibility_service_handler, @@ -372,8 +368,7 @@ def async_setup(hass, config): return True -@asyncio.coroutine -def _async_process_config(hass, config, component): +async def _async_process_config(hass, config, component): """Process group configuration.""" for object_id, conf in config.get(DOMAIN, {}).items(): name = conf.get(CONF_NAME, object_id) @@ -384,7 +379,7 @@ def _async_process_config(hass, config, component): # Don't create tasks and await them all. The order is important as # groups get a number based on creation order. - yield from Group.async_create_group( + await Group.async_create_group( hass, name, entity_ids, icon=icon, view=view, control=control, object_id=object_id) @@ -428,10 +423,9 @@ class Group(Entity): hass.loop).result() @staticmethod - @asyncio.coroutine - def async_create_group(hass, name, entity_ids=None, user_defined=True, - visible=True, icon=None, view=False, control=None, - object_id=None): + async def async_create_group(hass, name, entity_ids=None, + user_defined=True, visible=True, icon=None, + view=False, control=None, object_id=None): """Initialize a group. This method must be run in the event loop. @@ -453,7 +447,7 @@ class Group(Entity): component = hass.data[DOMAIN] = \ EntityComponent(_LOGGER, DOMAIN, hass) - yield from component.async_add_entities([group], True) + await component.async_add_entities([group], True) return group @@ -520,17 +514,16 @@ class Group(Entity): self.async_update_tracked_entity_ids(entity_ids), self.hass.loop ).result() - @asyncio.coroutine - def async_update_tracked_entity_ids(self, entity_ids): + async def async_update_tracked_entity_ids(self, entity_ids): """Update the member entity IDs. This method must be run in the event loop. """ - yield from self.async_stop() + await self.async_stop() self.tracking = tuple(ent_id.lower() for ent_id in entity_ids) self.group_on, self.group_off = None, None - yield from self.async_update_ha_state(True) + await self.async_update_ha_state(True) self.async_start() @callback @@ -544,8 +537,7 @@ class Group(Entity): self.hass, self.tracking, self._async_state_changed_listener ) - @asyncio.coroutine - def async_stop(self): + async def async_stop(self): """Unregister the group from Home Assistant. This method must be run in the event loop. @@ -554,27 +546,24 @@ class Group(Entity): self._async_unsub_state_changed() self._async_unsub_state_changed = None - @asyncio.coroutine - def async_update(self): + async def async_update(self): """Query all members and determine current group state.""" self._state = STATE_UNKNOWN self._async_update_group_state() - @asyncio.coroutine - def async_added_to_hass(self): + async def async_added_to_hass(self): """Callback when added to HASS.""" if self.tracking: self.async_start() - @asyncio.coroutine - def async_will_remove_from_hass(self): + async def async_will_remove_from_hass(self): """Callback when removed from HASS.""" if self._async_unsub_state_changed: self._async_unsub_state_changed() self._async_unsub_state_changed = None - @asyncio.coroutine - def _async_state_changed_listener(self, entity_id, old_state, new_state): + async def _async_state_changed_listener(self, entity_id, old_state, + new_state): """Respond to a member state changing. This method must be run in the event loop. @@ -584,7 +573,7 @@ class Group(Entity): return self._async_update_group_state(new_state) - yield from self.async_update_ha_state() + await self.async_update_ha_state() @property def _tracking_states(self): diff --git a/homeassistant/components/history.py b/homeassistant/components/history.py index b5ac37b1451..c27e394ce28 100644 --- a/homeassistant/components/history.py +++ b/homeassistant/components/history.py @@ -4,7 +4,6 @@ Provide pre-made queries on top of the recorder component. For more details about this component, please refer to the documentation at https://home-assistant.io/components/history/ """ -import asyncio from collections import defaultdict from datetime import timedelta from itertools import groupby @@ -259,8 +258,7 @@ def get_state(hass, utc_point_in_time, entity_id, run=None): return states[0] if states else None -@asyncio.coroutine -def async_setup(hass, config): +async def async_setup(hass, config): """Set up the history hooks.""" filters = Filters() conf = config.get(DOMAIN, {}) @@ -275,7 +273,7 @@ def async_setup(hass, config): use_include_order = conf.get(CONF_ORDER) hass.http.register_view(HistoryPeriodView(filters, use_include_order)) - yield from hass.components.frontend.async_register_built_in_panel( + await hass.components.frontend.async_register_built_in_panel( 'history', 'history', 'mdi:poll-box') return True @@ -293,8 +291,7 @@ class HistoryPeriodView(HomeAssistantView): self.filters = filters self.use_include_order = use_include_order - @asyncio.coroutine - def get(self, request, datetime=None): + async def get(self, request, datetime=None): """Return history over a period of time.""" timer_start = time.perf_counter() if datetime: @@ -330,7 +327,7 @@ class HistoryPeriodView(HomeAssistantView): hass = request.app['hass'] - result = yield from hass.async_add_job( + result = await hass.async_add_job( get_significant_states, hass, start_time, end_time, entity_ids, self.filters, include_start_time_state) result = list(result.values()) @@ -353,8 +350,7 @@ class HistoryPeriodView(HomeAssistantView): sorted_result.extend(result) result = sorted_result - response = yield from hass.async_add_job(self.json, result) - return response + return await hass.async_add_job(self.json, result) class Filters(object): diff --git a/homeassistant/components/history_graph.py b/homeassistant/components/history_graph.py index e6977d60c30..fa7d615dce2 100644 --- a/homeassistant/components/history_graph.py +++ b/homeassistant/components/history_graph.py @@ -4,7 +4,6 @@ Support to graphs card in the UI. For more details about this component, please refer to the documentation at https://home-assistant.io/components/history_graph/ """ -import asyncio import logging import voluptuous as vol @@ -39,8 +38,7 @@ CONFIG_SCHEMA = vol.Schema({ }, extra=vol.ALLOW_EXTRA) -@asyncio.coroutine -def async_setup(hass, config): +async def async_setup(hass, config): """Load graph configurations.""" component = EntityComponent( _LOGGER, DOMAIN, hass) @@ -51,7 +49,7 @@ def async_setup(hass, config): graph = HistoryGraphEntity(name, cfg) graphs.append(graph) - yield from component.async_add_entities(graphs) + await component.async_add_entities(graphs) return True diff --git a/homeassistant/components/input_boolean.py b/homeassistant/components/input_boolean.py index 56761b5af4e..9c8435614a2 100644 --- a/homeassistant/components/input_boolean.py +++ b/homeassistant/components/input_boolean.py @@ -65,8 +65,7 @@ def toggle(hass, entity_id): hass.services.call(DOMAIN, SERVICE_TOGGLE, {ATTR_ENTITY_ID: entity_id}) -@asyncio.coroutine -def async_setup(hass, config): +async def async_setup(hass, config): """Set up an input boolean.""" component = EntityComponent(_LOGGER, DOMAIN, hass) @@ -85,8 +84,7 @@ def async_setup(hass, config): if not entities: return False - @asyncio.coroutine - def async_handler_service(service): + async def async_handler_service(service): """Handle a calls to the input boolean services.""" target_inputs = component.async_extract_from_service(service) @@ -99,7 +97,7 @@ def async_setup(hass, config): tasks = [getattr(input_b, attr)() for input_b in target_inputs] if tasks: - yield from asyncio.wait(tasks, loop=hass.loop) + await asyncio.wait(tasks, loop=hass.loop) hass.services.async_register( DOMAIN, SERVICE_TURN_OFF, async_handler_service, @@ -111,7 +109,7 @@ def async_setup(hass, config): DOMAIN, SERVICE_TOGGLE, async_handler_service, schema=SERVICE_SCHEMA) - yield from component.async_add_entities(entities) + await component.async_add_entities(entities) return True @@ -145,24 +143,21 @@ class InputBoolean(ToggleEntity): """Return true if entity is on.""" return self._state - @asyncio.coroutine - def async_added_to_hass(self): + async def async_added_to_hass(self): """Call when entity about to be added to hass.""" # If not None, we got an initial value. if self._state is not None: return - state = yield from async_get_last_state(self.hass, self.entity_id) + state = await async_get_last_state(self.hass, self.entity_id) self._state = state and state.state == STATE_ON - @asyncio.coroutine - def async_turn_on(self, **kwargs): + async def async_turn_on(self, **kwargs): """Turn the entity on.""" self._state = True - yield from self.async_update_ha_state() + await self.async_update_ha_state() - @asyncio.coroutine - def async_turn_off(self, **kwargs): + async def async_turn_off(self, **kwargs): """Turn the entity off.""" self._state = False - yield from self.async_update_ha_state() + await self.async_update_ha_state() diff --git a/homeassistant/components/light/mqtt_json.py b/homeassistant/components/light/mqtt_json.py index a0bfc5a0787..ca5c76e905f 100644 --- a/homeassistant/components/light/mqtt_json.py +++ b/homeassistant/components/light/mqtt_json.py @@ -4,7 +4,6 @@ Support for MQTT JSON lights. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/light.mqtt_json/ """ -import asyncio import logging import json import voluptuous as vol @@ -26,6 +25,7 @@ from homeassistant.components.mqtt import ( CONF_PAYLOAD_AVAILABLE, CONF_PAYLOAD_NOT_AVAILABLE, CONF_QOS, CONF_RETAIN, MqttAvailability) import homeassistant.helpers.config_validation as cv +from homeassistant.helpers.typing import HomeAssistantType, ConfigType import homeassistant.util.color as color_util _LOGGER = logging.getLogger(__name__) @@ -79,8 +79,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema) -@asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +async def async_setup_platform(hass: HomeAssistantType, config: ConfigType, + async_add_devices, discovery_info=None): """Set up a MQTT JSON Light.""" if discovery_info is not None: config = PLATFORM_SCHEMA(discovery_info) @@ -173,10 +173,9 @@ class MqttJson(MqttAvailability, Light): self._supported_features |= (xy and SUPPORT_COLOR) self._supported_features |= (hs and SUPPORT_COLOR) - @asyncio.coroutine - def async_added_to_hass(self): + async def async_added_to_hass(self): """Subscribe to MQTT events.""" - yield from super().async_added_to_hass() + await super().async_added_to_hass() @callback def state_received(topic, payload, qos): @@ -257,7 +256,7 @@ class MqttJson(MqttAvailability, Light): self.async_schedule_update_ha_state() if self._topic[CONF_STATE_TOPIC] is not None: - yield from mqtt.async_subscribe( + await mqtt.async_subscribe( self.hass, self._topic[CONF_STATE_TOPIC], state_received, self._qos) @@ -316,8 +315,7 @@ class MqttJson(MqttAvailability, Light): """Flag supported features.""" return self._supported_features - @asyncio.coroutine - def async_turn_on(self, **kwargs): + async def async_turn_on(self, **kwargs): """Turn the device on. This method is a coroutine. @@ -404,8 +402,7 @@ class MqttJson(MqttAvailability, Light): if should_update: self.async_schedule_update_ha_state() - @asyncio.coroutine - def async_turn_off(self, **kwargs): + async def async_turn_off(self, **kwargs): """Turn the device off. This method is a coroutine. diff --git a/homeassistant/components/logbook.py b/homeassistant/components/logbook.py index 1c3e8ed1f19..8bab6fe0440 100644 --- a/homeassistant/components/logbook.py +++ b/homeassistant/components/logbook.py @@ -4,7 +4,6 @@ Event parser and human readable log generator. For more details about this component, please refer to the documentation at https://home-assistant.io/components/logbook/ """ -import asyncio import logging from datetime import timedelta from itertools import groupby @@ -88,8 +87,7 @@ def async_log_entry(hass, name, message, domain=None, entity_id=None): hass.bus.async_fire(EVENT_LOGBOOK_ENTRY, data) -@asyncio.coroutine -def setup(hass, config): +async def setup(hass, config): """Listen for download events to download files.""" @callback def log_message(service): @@ -105,7 +103,7 @@ def setup(hass, config): hass.http.register_view(LogbookView(config.get(DOMAIN, {}))) - yield from hass.components.frontend.async_register_built_in_panel( + await hass.components.frontend.async_register_built_in_panel( 'logbook', 'logbook', 'mdi:format-list-bulleted-type') hass.services.async_register( @@ -124,8 +122,7 @@ class LogbookView(HomeAssistantView): """Initialize the logbook view.""" self.config = config - @asyncio.coroutine - def get(self, request, datetime=None): + async def get(self, request, datetime=None): """Retrieve logbook entries.""" if datetime: datetime = dt_util.parse_datetime(datetime) @@ -144,8 +141,7 @@ class LogbookView(HomeAssistantView): return self.json(list( _get_events(hass, self.config, start_day, end_day))) - response = yield from hass.async_add_job(json_events) - return response + return await hass.async_add_job(json_events) class Entry(object): diff --git a/homeassistant/components/logger.py b/homeassistant/components/logger.py index c2309401977..6e8995a0444 100644 --- a/homeassistant/components/logger.py +++ b/homeassistant/components/logger.py @@ -4,7 +4,6 @@ Component that will help set the level of logging for components. For more details about this component, please refer to the documentation at https://home-assistant.io/components/logger/ """ -import asyncio import logging from collections import OrderedDict @@ -73,8 +72,7 @@ class HomeAssistantLogFilter(logging.Filter): return record.levelno >= default -@asyncio.coroutine -def async_setup(hass, config): +async def async_setup(hass, config): """Set up the logger component.""" logfilter = {} @@ -116,8 +114,7 @@ def async_setup(hass, config): if LOGGER_LOGS in config.get(DOMAIN): set_log_levels(config.get(DOMAIN)[LOGGER_LOGS]) - @asyncio.coroutine - def async_service_handler(service): + async def async_service_handler(service): """Handle logger services.""" set_log_levels(service.data) diff --git a/homeassistant/components/map.py b/homeassistant/components/map.py index b8293f64fc0..30cb00af69e 100644 --- a/homeassistant/components/map.py +++ b/homeassistant/components/map.py @@ -4,14 +4,11 @@ Provides a map panel for showing device locations. For more details about this component, please refer to the documentation at https://home-assistant.io/components/map/ """ -import asyncio - DOMAIN = 'map' -@asyncio.coroutine -def async_setup(hass, config): +async def async_setup(hass, config): """Register the built-in map panel.""" - yield from hass.components.frontend.async_register_built_in_panel( + await hass.components.frontend.async_register_built_in_panel( 'map', 'map', 'mdi:account-location') return True diff --git a/homeassistant/components/media_player/__init__.py b/homeassistant/components/media_player/__init__.py index 615c758cd1a..20fd3b875c8 100644 --- a/homeassistant/components/media_player/__init__.py +++ b/homeassistant/components/media_player/__init__.py @@ -361,18 +361,16 @@ def set_shuffle(hass, shuffle, entity_id=None): hass.services.call(DOMAIN, SERVICE_SHUFFLE_SET, data) -@asyncio.coroutine -def async_setup(hass, config): +async def async_setup(hass, config): """Track states and offer events for media_players.""" component = EntityComponent( logging.getLogger(__name__), DOMAIN, hass, SCAN_INTERVAL) hass.http.register_view(MediaPlayerImageView(component)) - yield from component.async_setup(config) + await component.async_setup(config) - @asyncio.coroutine - def async_service_handler(service): + async def async_service_handler(service): """Map services to methods on MediaPlayerDevice.""" method = SERVICE_TO_METHOD.get(service.service) if not method: @@ -400,13 +398,13 @@ def async_setup(hass, config): update_tasks = [] for player in target_players: - yield from getattr(player, method['method'])(**params) + await getattr(player, method['method'])(**params) if not player.should_poll: continue update_tasks.append(player.async_update_ha_state(True)) if update_tasks: - yield from asyncio.wait(update_tasks, loop=hass.loop) + await asyncio.wait(update_tasks, loop=hass.loop) for service in SERVICE_TO_METHOD: schema = SERVICE_TO_METHOD[service].get( @@ -490,14 +488,13 @@ class MediaPlayerDevice(Entity): return None - @asyncio.coroutine - def async_get_media_image(self): + async def async_get_media_image(self): """Fetch media image of current playing image.""" url = self.media_image_url if url is None: return None, None - return (yield from _async_fetch_image(self.hass, url)) + return await _async_fetch_image(self.hass, url) @property def media_title(self): @@ -808,34 +805,31 @@ class MediaPlayerDevice(Entity): return self.async_turn_on() return self.async_turn_off() - @asyncio.coroutine - def async_volume_up(self): + async def async_volume_up(self): """Turn volume up for media player. This method is a coroutine. """ if hasattr(self, 'volume_up'): # pylint: disable=no-member - yield from self.hass.async_add_job(self.volume_up) + await self.hass.async_add_job(self.volume_up) return if self.volume_level < 1: - yield from self.async_set_volume_level( - min(1, self.volume_level + .1)) + await self.async_set_volume_level(min(1, self.volume_level + .1)) - @asyncio.coroutine - def async_volume_down(self): + async def async_volume_down(self): """Turn volume down for media player. This method is a coroutine. """ if hasattr(self, 'volume_down'): # pylint: disable=no-member - yield from self.hass.async_add_job(self.volume_down) + await self.hass.async_add_job(self.volume_down) return if self.volume_level > 0: - yield from self.async_set_volume_level( + await self.async_set_volume_level( max(0, self.volume_level - .1)) def async_media_play_pause(self): @@ -879,8 +873,7 @@ class MediaPlayerDevice(Entity): return state_attr -@asyncio.coroutine -def _async_fetch_image(hass, url): +async def _async_fetch_image(hass, url): """Fetch image. Images are cached in memory (the images are typically 10-100kB in size). @@ -891,7 +884,7 @@ def _async_fetch_image(hass, url): if url not in cache_images: cache_images[url] = {CACHE_LOCK: asyncio.Lock(loop=hass.loop)} - with (yield from cache_images[url][CACHE_LOCK]): + async with cache_images[url][CACHE_LOCK]: if CACHE_CONTENT in cache_images[url]: return cache_images[url][CACHE_CONTENT] @@ -899,10 +892,10 @@ def _async_fetch_image(hass, url): websession = async_get_clientsession(hass) try: with async_timeout.timeout(10, loop=hass.loop): - response = yield from websession.get(url) + response = await websession.get(url) if response.status == 200: - content = yield from response.read() + content = await response.read() content_type = response.headers.get(CONTENT_TYPE) if content_type: content_type = content_type.split(';')[0] @@ -928,8 +921,7 @@ class MediaPlayerImageView(HomeAssistantView): """Initialize a media player view.""" self.component = component - @asyncio.coroutine - def get(self, request, entity_id): + async def get(self, request, entity_id): """Start a get request.""" player = self.component.get_entity(entity_id) if player is None: @@ -942,7 +934,7 @@ class MediaPlayerImageView(HomeAssistantView): if not authenticated: return web.Response(status=401) - data, content_type = yield from player.async_get_media_image() + data, content_type = await player.async_get_media_image() if data is None: return web.Response(status=500) diff --git a/homeassistant/components/media_player/universal.py b/homeassistant/components/media_player/universal.py index 27a0714527d..fa4f03f1179 100644 --- a/homeassistant/components/media_player/universal.py +++ b/homeassistant/components/media_player/universal.py @@ -4,7 +4,6 @@ Combination of multiple media players into one for a universal controller. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/media_player.universal/ """ -import asyncio import logging # pylint: disable=import-error from copy import copy @@ -63,8 +62,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }, extra=vol.REMOVE_EXTRA) -@asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +async def async_setup_platform(hass, config, async_add_devices, + discovery_info=None): """Set up the universal media players.""" player = UniversalMediaPlayer( hass, @@ -99,8 +98,7 @@ class UniversalMediaPlayer(MediaPlayerDevice): if state_template is not None: self._state_template.hass = hass - @asyncio.coroutine - def async_added_to_hass(self): + async def async_added_to_hass(self): """Subscribe to children and template state changes. This method must be run in the event loop and returns a coroutine. @@ -144,15 +142,14 @@ class UniversalMediaPlayer(MediaPlayerDevice): active_child = self._child_state return active_child.attributes.get(attr_name) if active_child else None - @asyncio.coroutine - def _async_call_service(self, service_name, service_data=None, - allow_override=False): + async def _async_call_service(self, service_name, service_data=None, + allow_override=False): """Call either a specified or active child's service.""" if service_data is None: service_data = {} if allow_override and service_name in self._cmds: - yield from async_call_from_config( + await async_call_from_config( self.hass, self._cmds[service_name], variables=service_data, blocking=True, validate_config=False) @@ -165,7 +162,7 @@ class UniversalMediaPlayer(MediaPlayerDevice): service_data[ATTR_ENTITY_ID] = active_child.entity_id - yield from self.hass.services.async_call( + await self.hass.services.async_call( DOMAIN, service_name, service_data, blocking=True) @property @@ -506,8 +503,7 @@ class UniversalMediaPlayer(MediaPlayerDevice): return self._async_call_service( SERVICE_SHUFFLE_SET, data, allow_override=True) - @asyncio.coroutine - def async_update(self): + async def async_update(self): """Update state in HA.""" for child_name in self._children: child_state = self.hass.states.get(child_name) diff --git a/homeassistant/components/recorder/__init__.py b/homeassistant/components/recorder/__init__.py index 8e69c2cfcd8..9b5bea043f4 100644 --- a/homeassistant/components/recorder/__init__.py +++ b/homeassistant/components/recorder/__init__.py @@ -111,8 +111,7 @@ def run_information(hass, point_in_time: Optional[datetime] = None): return res -@asyncio.coroutine -def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: +async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: """Set up the recorder.""" conf = config.get(DOMAIN, {}) keep_days = conf.get(CONF_PURGE_KEEP_DAYS) @@ -131,8 +130,7 @@ def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: instance.async_initialize() instance.start() - @asyncio.coroutine - def async_handle_purge_service(service): + async def async_handle_purge_service(service): """Handle calls to the purge service.""" instance.do_adhoc_purge(**service.data) @@ -140,7 +138,7 @@ def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: DOMAIN, SERVICE_PURGE, async_handle_purge_service, schema=SERVICE_PURGE_SCHEMA) - return (yield from instance.async_db_ready) + return await instance.async_db_ready PurgeTask = namedtuple('PurgeTask', ['keep_days', 'repack']) diff --git a/homeassistant/components/sensor/mqtt.py b/homeassistant/components/sensor/mqtt.py index c4f64e9e015..d7d66a3a145 100644 --- a/homeassistant/components/sensor/mqtt.py +++ b/homeassistant/components/sensor/mqtt.py @@ -4,7 +4,6 @@ Support for MQTT sensors. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/sensor.mqtt/ """ -import asyncio import logging import json from datetime import timedelta @@ -22,6 +21,7 @@ from homeassistant.const import ( from homeassistant.helpers.entity import Entity import homeassistant.components.mqtt as mqtt import homeassistant.helpers.config_validation as cv +from homeassistant.helpers.typing import HomeAssistantType, ConfigType from homeassistant.helpers.event import async_track_point_in_utc_time from homeassistant.util import dt as dt_util @@ -48,8 +48,8 @@ PLATFORM_SCHEMA = mqtt.MQTT_RO_PLATFORM_SCHEMA.extend({ }).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema) -@asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +async def async_setup_platform(hass: HomeAssistantType, config: ConfigType, + async_add_devices, discovery_info=None): """Set up MQTT Sensor.""" if discovery_info is not None: config = PLATFORM_SCHEMA(discovery_info) @@ -100,10 +100,9 @@ class MqttSensor(MqttAvailability, Entity): self._unique_id = unique_id self._attributes = None - @asyncio.coroutine - def async_added_to_hass(self): + async def async_added_to_hass(self): """Subscribe to MQTT events.""" - yield from super().async_added_to_hass() + await super().async_added_to_hass() @callback def message_received(topic, payload, qos): @@ -142,8 +141,8 @@ class MqttSensor(MqttAvailability, Entity): self._state = payload self.async_schedule_update_ha_state() - yield from mqtt.async_subscribe( - self.hass, self._state_topic, message_received, self._qos) + await mqtt.async_subscribe(self.hass, self._state_topic, + message_received, self._qos) @callback def value_is_expired(self, *_): diff --git a/homeassistant/components/sensor/wunderground.py b/homeassistant/components/sensor/wunderground.py index 7938b17e4d6..bbee167d4b0 100644 --- a/homeassistant/components/sensor/wunderground.py +++ b/homeassistant/components/sensor/wunderground.py @@ -639,9 +639,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ ADDED_ENTITY_IDS_KEY = 'wunderground_added_entity_ids' -@asyncio.coroutine -def async_setup_platform(hass: HomeAssistantType, config: ConfigType, - async_add_devices, discovery_info=None): +async def async_setup_platform(hass: HomeAssistantType, config: ConfigType, + async_add_devices, discovery_info=None): """Set up the WUnderground sensor.""" hass.data.setdefault(ADDED_ENTITY_IDS_KEY, set()) @@ -656,7 +655,7 @@ def async_setup_platform(hass: HomeAssistantType, config: ConfigType, for variable in config[CONF_MONITORED_CONDITIONS]: sensors.append(WUndergroundSensor(hass, rest, variable, namespace)) - yield from rest.async_update() + await rest.async_update() if not rest.data: raise PlatformNotReady diff --git a/homeassistant/components/switch/mqtt.py b/homeassistant/components/switch/mqtt.py index f3bd0bef012..15dc6f1d0f4 100644 --- a/homeassistant/components/switch/mqtt.py +++ b/homeassistant/components/switch/mqtt.py @@ -4,7 +4,6 @@ Support for MQTT switches. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/switch.mqtt/ """ -import asyncio import logging import voluptuous as vol @@ -39,8 +38,8 @@ PLATFORM_SCHEMA = mqtt.MQTT_RW_PLATFORM_SCHEMA.extend({ }).extend(mqtt.MQTT_AVAILABILITY_SCHEMA.schema) -@asyncio.coroutine -def async_setup_platform(hass, config, async_add_devices, discovery_info=None): +async def async_setup_platform(hass, config, async_add_devices, + discovery_info=None): """Set up the MQTT switch.""" if discovery_info is not None: config = PLATFORM_SCHEMA(discovery_info) @@ -88,10 +87,9 @@ class MqttSwitch(MqttAvailability, SwitchDevice): self._optimistic = optimistic self._template = value_template - @asyncio.coroutine - def async_added_to_hass(self): + async def async_added_to_hass(self): """Subscribe to MQTT events.""" - yield from super().async_added_to_hass() + await super().async_added_to_hass() @callback def state_message_received(topic, payload, qos): @@ -110,7 +108,7 @@ class MqttSwitch(MqttAvailability, SwitchDevice): # Force into optimistic mode. self._optimistic = True else: - yield from mqtt.async_subscribe( + await mqtt.async_subscribe( self.hass, self._state_topic, state_message_received, self._qos) @@ -139,8 +137,7 @@ class MqttSwitch(MqttAvailability, SwitchDevice): """Return the icon.""" return self._icon - @asyncio.coroutine - def async_turn_on(self, **kwargs): + async def async_turn_on(self, **kwargs): """Turn the device on. This method is a coroutine. @@ -153,8 +150,7 @@ class MqttSwitch(MqttAvailability, SwitchDevice): self._state = True self.async_schedule_update_ha_state() - @asyncio.coroutine - def async_turn_off(self, **kwargs): + async def async_turn_off(self, **kwargs): """Turn the device off. This method is a coroutine. diff --git a/homeassistant/components/timer/__init__.py b/homeassistant/components/timer/__init__.py index 84d2d3f349d..5a363e84d7b 100644 --- a/homeassistant/components/timer/__init__.py +++ b/homeassistant/components/timer/__init__.py @@ -122,8 +122,7 @@ def async_finish(hass, entity_id): DOMAIN, SERVICE_FINISH, {ATTR_ENTITY_ID: entity_id})) -@asyncio.coroutine -def async_setup(hass, config): +async def async_setup(hass, config): """Set up a timer.""" component = EntityComponent(_LOGGER, DOMAIN, hass) @@ -142,8 +141,7 @@ def async_setup(hass, config): if not entities: return False - @asyncio.coroutine - def async_handler_service(service): + async def async_handler_service(service): """Handle a call to the timer services.""" target_timers = component.async_extract_from_service(service) @@ -162,7 +160,7 @@ def async_setup(hass, config): timer.async_start(service.data.get(ATTR_DURATION)) ) if tasks: - yield from asyncio.wait(tasks, loop=hass.loop) + await asyncio.wait(tasks, loop=hass.loop) hass.services.async_register( DOMAIN, SERVICE_START, async_handler_service, @@ -177,7 +175,7 @@ def async_setup(hass, config): DOMAIN, SERVICE_FINISH, async_handler_service, schema=SERVICE_SCHEMA) - yield from component.async_add_entities(entities) + await component.async_add_entities(entities) return True @@ -224,19 +222,17 @@ class Timer(Entity): ATTR_REMAINING: str(self._remaining) } - @asyncio.coroutine - def async_added_to_hass(self): + async def async_added_to_hass(self): """Call when entity is about to be added to Home Assistant.""" # If not None, we got an initial value. if self._state is not None: return restore_state = self._hass.helpers.restore_state - state = yield from restore_state.async_get_last_state(self.entity_id) + state = await restore_state.async_get_last_state(self.entity_id) self._state = state and state.state == state - @asyncio.coroutine - def async_start(self, duration): + async def async_start(self, duration): """Start a timer.""" if self._listener: self._listener() @@ -260,10 +256,9 @@ class Timer(Entity): self._listener = async_track_point_in_utc_time(self._hass, self.async_finished, self._end) - yield from self.async_update_ha_state() + await self.async_update_ha_state() - @asyncio.coroutine - def async_pause(self): + async def async_pause(self): """Pause a timer.""" if self._listener is None: return @@ -273,10 +268,9 @@ class Timer(Entity): self._remaining = self._end - dt_util.utcnow() self._state = STATUS_PAUSED self._end = None - yield from self.async_update_ha_state() + await self.async_update_ha_state() - @asyncio.coroutine - def async_cancel(self): + async def async_cancel(self): """Cancel a timer.""" if self._listener: self._listener() @@ -286,10 +280,9 @@ class Timer(Entity): self._remaining = timedelta() self._hass.bus.async_fire(EVENT_TIMER_CANCELLED, {"entity_id": self.entity_id}) - yield from self.async_update_ha_state() + await self.async_update_ha_state() - @asyncio.coroutine - def async_finish(self): + async def async_finish(self): """Reset and updates the states, fire finished event.""" if self._state != STATUS_ACTIVE: return @@ -299,10 +292,9 @@ class Timer(Entity): self._remaining = timedelta() self._hass.bus.async_fire(EVENT_TIMER_FINISHED, {"entity_id": self.entity_id}) - yield from self.async_update_ha_state() + await self.async_update_ha_state() - @asyncio.coroutine - def async_finished(self, time): + async def async_finished(self, time): """Reset and updates the states, fire finished event.""" if self._state != STATUS_ACTIVE: return @@ -312,4 +304,4 @@ class Timer(Entity): self._remaining = timedelta() self._hass.bus.async_fire(EVENT_TIMER_FINISHED, {"entity_id": self.entity_id}) - yield from self.async_update_ha_state() + await self.async_update_ha_state() diff --git a/homeassistant/components/tts/google.py b/homeassistant/components/tts/google.py index 084a7229212..bf03ec1adad 100644 --- a/homeassistant/components/tts/google.py +++ b/homeassistant/components/tts/google.py @@ -39,8 +39,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ }) -@asyncio.coroutine -def async_get_engine(hass, config): +async def async_get_engine(hass, config): """Set up Google speech component.""" return GoogleProvider(hass, config[CONF_LANG]) @@ -70,8 +69,7 @@ class GoogleProvider(Provider): """Return list of supported languages.""" return SUPPORT_LANGUAGES - @asyncio.coroutine - def async_get_tts_audio(self, message, language, options=None): + async def async_get_tts_audio(self, message, language, options=None): """Load TTS from google.""" from gtts_token import gtts_token @@ -81,7 +79,7 @@ class GoogleProvider(Provider): data = b'' for idx, part in enumerate(message_parts): - part_token = yield from self.hass.async_add_job( + part_token = await self.hass.async_add_job( token.calculate_token, part) url_param = { @@ -97,7 +95,7 @@ class GoogleProvider(Provider): try: with async_timeout.timeout(10, loop=self.hass.loop): - request = yield from websession.get( + request = await websession.get( GOOGLE_SPEECH_URL, params=url_param, headers=self.headers ) @@ -106,7 +104,7 @@ class GoogleProvider(Provider): _LOGGER.error("Error %d on load url %s", request.status, request.url) return (None, None) - data += yield from request.read() + data += await request.read() except (asyncio.TimeoutError, aiohttp.ClientError): _LOGGER.error("Timeout for google speech.") diff --git a/homeassistant/components/updater.py b/homeassistant/components/updater.py index f7bf9774e42..9ccf280ed04 100644 --- a/homeassistant/components/updater.py +++ b/homeassistant/components/updater.py @@ -72,8 +72,7 @@ def _load_uuid(hass, filename=UPDATER_UUID_FILE): return _create_uuid(hass, filename) -@asyncio.coroutine -def async_setup(hass, config): +async def async_setup(hass, config): """Set up the updater component.""" if 'dev' in current_version: # This component only makes sense in release versions @@ -81,16 +80,15 @@ def async_setup(hass, config): config = config.get(DOMAIN, {}) if config.get(CONF_REPORTING): - huuid = yield from hass.async_add_job(_load_uuid, hass) + huuid = await hass.async_add_job(_load_uuid, hass) else: huuid = None include_components = config.get(CONF_COMPONENT_REPORTING) - @asyncio.coroutine - def check_new_version(now): + async def check_new_version(now): """Check if a new version is available and report if one is.""" - result = yield from get_newest_version(hass, huuid, include_components) + result = await get_newest_version(hass, huuid, include_components) if result is None: return @@ -125,8 +123,7 @@ def async_setup(hass, config): return True -@asyncio.coroutine -def get_system_info(hass, include_components): +async def get_system_info(hass, include_components): """Return info about the system.""" info_object = { 'arch': platform.machine(), @@ -151,7 +148,7 @@ def get_system_info(hass, include_components): info_object['os_version'] = platform.release() elif platform.system() == 'Linux': import distro - linux_dist = yield from hass.async_add_job( + linux_dist = await hass.async_add_job( distro.linux_distribution, False) info_object['distribution'] = linux_dist[0] info_object['os_version'] = linux_dist[1] @@ -160,11 +157,10 @@ def get_system_info(hass, include_components): return info_object -@asyncio.coroutine -def get_newest_version(hass, huuid, include_components): +async def get_newest_version(hass, huuid, include_components): """Get the newest Home Assistant version.""" if huuid: - info_object = yield from get_system_info(hass, include_components) + info_object = await get_system_info(hass, include_components) info_object['huuid'] = huuid else: info_object = {} @@ -172,7 +168,7 @@ def get_newest_version(hass, huuid, include_components): session = async_get_clientsession(hass) try: with async_timeout.timeout(5, loop=hass.loop): - req = yield from session.post(UPDATER_URL, json=info_object) + req = await session.post(UPDATER_URL, json=info_object) _LOGGER.info(("Submitted analytics to Home Assistant servers. " "Information submitted includes %s"), info_object) except (asyncio.TimeoutError, aiohttp.ClientError): @@ -181,7 +177,7 @@ def get_newest_version(hass, huuid, include_components): return None try: - res = yield from req.json() + res = await req.json() except ValueError: _LOGGER.error("Received invalid JSON from Home Assistant Update") return None diff --git a/homeassistant/util/logging.py b/homeassistant/util/logging.py index f7306cae98b..10b43445184 100644 --- a/homeassistant/util/logging.py +++ b/homeassistant/util/logging.py @@ -49,17 +49,16 @@ class AsyncHandler(object): """Wrap close to handler.""" self.emit(None) - @asyncio.coroutine - def async_close(self, blocking=False): + async def async_close(self, blocking=False): """Close the handler. When blocking=True, will wait till closed. """ - yield from self._queue.put(None) + await self._queue.put(None) if blocking: while self._thread.is_alive(): - yield from asyncio.sleep(0, loop=self.loop) + await asyncio.sleep(0, loop=self.loop) def emit(self, record): """Process a record.""" diff --git a/tests/test_bootstrap.py b/tests/test_bootstrap.py index c109ae30aad..3e4d4739779 100644 --- a/tests/test_bootstrap.py +++ b/tests/test_bootstrap.py @@ -40,9 +40,9 @@ def test_from_config_file(hass): assert components == hass.config.components -@asyncio.coroutine @patch('homeassistant.bootstrap.async_enable_logging', Mock()) @patch('homeassistant.bootstrap.async_register_signal_handling', Mock()) +@asyncio.coroutine def test_home_assistant_core_config_validation(hass): """Test if we pass in wrong information for HA conf.""" # Extensive HA conf validation testing is done