diff --git a/homeassistant/components/config/config_entries.py b/homeassistant/components/config/config_entries.py index ebfa095372a..7c4dcbd1602 100644 --- a/homeassistant/components/config/config_entries.py +++ b/homeassistant/components/config/config_entries.py @@ -97,10 +97,10 @@ class ConfigManagerFlowIndexView(HomeAssistantView): flow for flow in hass.config_entries.flow.async_progress() if flow['source'] != config_entries.SOURCE_USER]) - @asyncio.coroutine @RequestDataValidator(vol.Schema({ vol.Required('domain'): str, })) + @asyncio.coroutine def post(self, request, data): """Handle a POST request.""" hass = request.app['hass'] @@ -139,8 +139,8 @@ class ConfigManagerFlowResourceView(HomeAssistantView): return self.json(result) - @asyncio.coroutine @RequestDataValidator(vol.Schema(dict), allow_empty=True) + @asyncio.coroutine def post(self, request, flow_id, data): """Handle a POST request.""" hass = request.app['hass'] diff --git a/homeassistant/config.py b/homeassistant/config.py index 6507e2a74f6..1c8ca10f8c6 100644 --- a/homeassistant/config.py +++ b/homeassistant/config.py @@ -260,8 +260,7 @@ def create_default_config(config_dir, detect_location=True): return None -@asyncio.coroutine -def async_hass_config_yaml(hass): +async def async_hass_config_yaml(hass): """Load YAML from a Home Assistant configuration file. This function allow a component inside the asyncio loop to reload its @@ -274,7 +273,7 @@ def async_hass_config_yaml(hass): conf = load_yaml_config_file(path) return conf - conf = yield from hass.async_add_job(_load_hass_yaml_config) + conf = await hass.async_add_job(_load_hass_yaml_config) return conf @@ -373,8 +372,7 @@ def async_log_exception(ex, domain, config, hass): _LOGGER.error(message) -@asyncio.coroutine -def async_process_ha_core_config(hass, config): +async def async_process_ha_core_config(hass, config): """Process the [homeassistant] section from the configuration. This method is a coroutine. @@ -461,7 +459,7 @@ def async_process_ha_core_config(hass, config): # If we miss some of the needed values, auto detect them if None in (hac.latitude, hac.longitude, hac.units, hac.time_zone): - info = yield from hass.async_add_job( + info = await hass.async_add_job( loc_util.detect_location_info) if info is None: @@ -487,7 +485,7 @@ def async_process_ha_core_config(hass, config): if hac.elevation is None and hac.latitude is not None and \ hac.longitude is not None: - elevation = yield from hass.async_add_job( + elevation = await hass.async_add_job( loc_util.elevation, hac.latitude, hac.longitude) hac.elevation = elevation discovered.append(('elevation', elevation)) @@ -648,21 +646,20 @@ def async_process_component_config(hass, config, domain): return config -@asyncio.coroutine -def async_check_ha_config_file(hass): +async def async_check_ha_config_file(hass): """Check if Home Assistant configuration file is valid. This method is a coroutine. """ - proc = yield from asyncio.create_subprocess_exec( + proc = await asyncio.create_subprocess_exec( sys.executable, '-m', 'homeassistant', '--script', 'check_config', '--config', hass.config.config_dir, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.STDOUT, loop=hass.loop) # Wait for the subprocess exit - log, _ = yield from proc.communicate() - exit_code = yield from proc.wait() + log, _ = await proc.communicate() + exit_code = await proc.wait() # Convert to ASCII log = RE_ASCII.sub('', log.decode()) diff --git a/homeassistant/config_entries.py b/homeassistant/config_entries.py index 7b5d23d284f..63eff4e1f77 100644 --- a/homeassistant/config_entries.py +++ b/homeassistant/config_entries.py @@ -76,7 +76,7 @@ If the user input passes validation, you can again return one of the three return values. If you want to navigate the user to the next step, return the return value of that step: - return (await self.async_step_account()) + return await self.async_step_account() ### Abort @@ -110,7 +110,7 @@ should follow the same return values as a normal step. If the result of the step is to show a form, the user will be able to continue the flow from the config panel. """ -import asyncio + import logging import os import uuid @@ -176,14 +176,13 @@ class ConfigEntry: # State of the entry (LOADED, NOT_LOADED) self.state = state - @asyncio.coroutine - def async_setup(self, hass, *, component=None): + async def async_setup(self, hass, *, component=None): """Set up an entry.""" if component is None: component = getattr(hass.components, self.domain) try: - result = yield from component.async_setup_entry(hass, self) + result = await component.async_setup_entry(hass, self) if not isinstance(result, bool): _LOGGER.error('%s.async_config_entry did not return boolean', @@ -199,8 +198,7 @@ class ConfigEntry: else: self.state = ENTRY_STATE_SETUP_ERROR - @asyncio.coroutine - def async_unload(self, hass): + async def async_unload(self, hass): """Unload an entry. Returns if unload is possible and was successful. @@ -213,7 +211,7 @@ class ConfigEntry: return False try: - result = yield from component.async_unload_entry(hass, self) + result = await component.async_unload_entry(hass, self) if not isinstance(result, bool): _LOGGER.error('%s.async_unload_entry did not return boolean', @@ -293,8 +291,7 @@ class ConfigEntries: return list(self._entries) return [entry for entry in self._entries if entry.domain == domain] - @asyncio.coroutine - def async_remove(self, entry_id): + async def async_remove(self, entry_id): """Remove an entry.""" found = None for index, entry in enumerate(self._entries): @@ -308,25 +305,23 @@ class ConfigEntries: entry = self._entries.pop(found) self._async_schedule_save() - unloaded = yield from entry.async_unload(self.hass) + unloaded = await entry.async_unload(self.hass) return { 'require_restart': not unloaded } - @asyncio.coroutine - def async_load(self): + async def async_load(self): """Load the config.""" path = self.hass.config.path(PATH_CONFIG) if not os.path.isfile(path): self._entries = [] return - entries = yield from self.hass.async_add_job(load_json, path) + entries = await self.hass.async_add_job(load_json, path) self._entries = [ConfigEntry(**entry) for entry in entries] - @asyncio.coroutine - def _async_add_entry(self, entry): + async def _async_add_entry(self, entry): """Add an entry.""" self._entries.append(entry) self._async_schedule_save() @@ -334,10 +329,10 @@ class ConfigEntries: # Setup entry if entry.domain in self.hass.config.components: # Component already set up, just need to call setup_entry - yield from entry.async_setup(self.hass) + await entry.async_setup(self.hass) else: # Setting up component will also load the entries - yield from async_setup_component( + await async_setup_component( self.hass, entry.domain, self._hass_config) @callback @@ -350,13 +345,12 @@ class ConfigEntries: SAVE_DELAY, self.hass.async_add_job, self._async_save ) - @asyncio.coroutine - def _async_save(self): + async def _async_save(self): """Save the entity registry to a file.""" self._sched_save = None data = [entry.as_dict() for entry in self._entries] - yield from self.hass.async_add_job( + await self.hass.async_add_job( save_json, self.hass.config.path(PATH_CONFIG), data) @@ -379,8 +373,7 @@ class FlowManager: 'source': flow.source, } for flow in self._progress.values()] - @asyncio.coroutine - def async_init(self, domain, *, source=SOURCE_USER, data=None): + async def async_init(self, domain, *, source=SOURCE_USER, data=None): """Start a configuration flow.""" handler = HANDLERS.get(domain) @@ -393,7 +386,7 @@ class FlowManager: raise self.hass.helpers.UnknownHandler # Make sure requirements and dependencies of component are resolved - yield from async_process_deps_reqs( + await async_process_deps_reqs( self.hass, self._hass_config, domain, component) flow_id = uuid.uuid4().hex @@ -408,10 +401,9 @@ class FlowManager: else: step = source - return (yield from self._async_handle_step(flow, step, data)) + return await self._async_handle_step(flow, step, data) - @asyncio.coroutine - def async_configure(self, flow_id, user_input=None): + async def async_configure(self, flow_id, user_input=None): """Start or continue a configuration flow.""" flow = self._progress.get(flow_id) @@ -423,8 +415,8 @@ class FlowManager: if data_schema is not None and user_input is not None: user_input = data_schema(user_input) - return (yield from self._async_handle_step( - flow, step_id, user_input)) + return await self._async_handle_step( + flow, step_id, user_input) @callback def async_abort(self, flow_id): @@ -432,8 +424,7 @@ class FlowManager: if self._progress.pop(flow_id, None) is None: raise UnknownFlow - @asyncio.coroutine - def _async_handle_step(self, flow, step_id, user_input): + async def _async_handle_step(self, flow, step_id, user_input): """Handle a step of a flow.""" method = "async_step_{}".format(step_id) @@ -442,7 +433,7 @@ class FlowManager: raise UnknownStep("Handler {} doesn't support step {}".format( flow.__class__.__name__, step_id)) - result = yield from getattr(flow, method)(user_input) + result = await getattr(flow, method)(user_input) if result['type'] not in (RESULT_TYPE_FORM, RESULT_TYPE_CREATE_ENTRY, RESULT_TYPE_ABORT): @@ -466,7 +457,7 @@ class FlowManager: data=result.pop('data'), source=flow.source ) - yield from self._async_add_entry(entry) + await self._async_add_entry(entry) return result diff --git a/homeassistant/helpers/aiohttp_client.py b/homeassistant/helpers/aiohttp_client.py index 239aaea64a0..5a6e0eae1e3 100644 --- a/homeassistant/helpers/aiohttp_client.py +++ b/homeassistant/helpers/aiohttp_client.py @@ -106,29 +106,28 @@ def async_aiohttp_proxy_web(hass, request, web_coro, buffer_size=102400, req.close() -@asyncio.coroutine @bind_hass -def async_aiohttp_proxy_stream(hass, request, stream, content_type, - buffer_size=102400, timeout=10): +async def async_aiohttp_proxy_stream(hass, request, stream, content_type, + buffer_size=102400, timeout=10): """Stream a stream to aiohttp web response.""" response = web.StreamResponse() response.content_type = content_type - yield from response.prepare(request) + await response.prepare(request) try: while True: with async_timeout.timeout(timeout, loop=hass.loop): - data = yield from stream.read(buffer_size) + data = await stream.read(buffer_size) if not data: - yield from response.write_eof() + await response.write_eof() break response.write(data) except (asyncio.TimeoutError, aiohttp.ClientError): # Something went wrong fetching data, close connection gracefully - yield from response.write_eof() + await response.write_eof() except asyncio.CancelledError: # The user closed the connection diff --git a/homeassistant/helpers/entity.py b/homeassistant/helpers/entity.py index 9168c459f74..a3c6e7a944b 100644 --- a/homeassistant/helpers/entity.py +++ b/homeassistant/helpers/entity.py @@ -332,11 +332,10 @@ class Entity(object): if self.parallel_updates: self.parallel_updates.release() - @asyncio.coroutine - def async_remove(self): + async def async_remove(self): """Remove entity from Home Assistant.""" if self.platform is not None: - yield from self.platform.async_remove_entity(self.entity_id) + await self.platform.async_remove_entity(self.entity_id) else: self.hass.states.async_remove(self.entity_id) diff --git a/homeassistant/helpers/entity_component.py b/homeassistant/helpers/entity_component.py index 2dcde6fdeda..f086437c10d 100644 --- a/homeassistant/helpers/entity_component.py +++ b/homeassistant/helpers/entity_component.py @@ -75,8 +75,7 @@ class EntityComponent(object): """ self.hass.add_job(self.async_setup(config)) - @asyncio.coroutine - def async_setup(self, config): + async def async_setup(self, config): """Set up a full entity component. Loads the platforms from the config and will listen for supported @@ -92,14 +91,13 @@ class EntityComponent(object): tasks.append(self._async_setup_platform(p_type, p_config)) if tasks: - yield from asyncio.wait(tasks, loop=self.hass.loop) + await asyncio.wait(tasks, loop=self.hass.loop) # Generic discovery listener for loading platform dynamically # Refer to: homeassistant.components.discovery.load_platform() - @asyncio.coroutine - def component_platform_discovered(platform, info): + async def component_platform_discovered(platform, info): """Handle the loading of a platform.""" - yield from self._async_setup_platform(platform, {}, info) + await self._async_setup_platform(platform, {}, info) discovery.async_listen_platform( self.hass, self.domain, component_platform_discovered) @@ -120,11 +118,10 @@ class EntityComponent(object): return [entity for entity in self.entities if entity.available and entity.entity_id in entity_ids] - @asyncio.coroutine - def _async_setup_platform(self, platform_type, platform_config, - discovery_info=None): + async def _async_setup_platform(self, platform_type, platform_config, + discovery_info=None): """Set up a platform for this component.""" - platform = yield from async_prepare_setup_platform( + platform = await async_prepare_setup_platform( self.hass, self.config, self.domain, platform_type) if platform is None: @@ -156,7 +153,7 @@ class EntityComponent(object): else: entity_platform = self._platforms[key] - yield from entity_platform.async_setup( + await entity_platform.async_setup( platform, platform_config, discovery_info) @callback @@ -177,8 +174,7 @@ class EntityComponent(object): visible=False, entity_ids=ids ) - @asyncio.coroutine - def _async_reset(self): + async def _async_reset(self): """Remove entities and reset the entity component to initial values. This method must be run in the event loop. @@ -187,7 +183,7 @@ class EntityComponent(object): in self._platforms.values()] if tasks: - yield from asyncio.wait(tasks, loop=self.hass.loop) + await asyncio.wait(tasks, loop=self.hass.loop) self._platforms = { self.domain: self._platforms[self.domain] @@ -197,21 +193,19 @@ class EntityComponent(object): if self.group_name is not None: self.hass.components.group.async_remove(slugify(self.group_name)) - @asyncio.coroutine - def async_remove_entity(self, entity_id): + async def async_remove_entity(self, entity_id): """Remove an entity managed by one of the platforms.""" for platform in self._platforms.values(): if entity_id in platform.entities: - yield from platform.async_remove_entity(entity_id) + await platform.async_remove_entity(entity_id) - @asyncio.coroutine - def async_prepare_reload(self): + async def async_prepare_reload(self): """Prepare reloading this entity component. This method must be run in the event loop. """ try: - conf = yield from \ + conf = await \ conf_util.async_hass_config_yaml(self.hass) except HomeAssistantError as err: self.logger.error(err) @@ -223,5 +217,5 @@ class EntityComponent(object): if conf is None: return None - yield from self._async_reset() + await self._async_reset() return conf diff --git a/homeassistant/helpers/entity_platform.py b/homeassistant/helpers/entity_platform.py index f627ccd24b1..d28212a34d1 100644 --- a/homeassistant/helpers/entity_platform.py +++ b/homeassistant/helpers/entity_platform.py @@ -51,9 +51,8 @@ class EntityPlatform(object): self.parallel_updates = asyncio.Semaphore( parallel_updates, loop=hass.loop) - @asyncio.coroutine - def async_setup(self, platform, platform_config, discovery_info=None, - tries=0): + async def async_setup(self, platform, platform_config, discovery_info=None, + tries=0): """Setup the platform.""" logger = self.logger hass = self.hass @@ -78,7 +77,7 @@ class EntityPlatform(object): None, platform.setup_platform, hass, platform_config, self._schedule_add_entities, discovery_info ) - yield from asyncio.wait_for( + await asyncio.wait_for( asyncio.shield(task, loop=hass.loop), SLOW_SETUP_MAX_WAIT, loop=hass.loop) @@ -88,7 +87,7 @@ class EntityPlatform(object): self._tasks.clear() if pending: - yield from asyncio.wait( + await asyncio.wait( pending, loop=self.hass.loop) hass.config.components.add(full_name) @@ -142,8 +141,7 @@ class EntityPlatform(object): self.async_add_entities(list(new_entities), update_before_add), self.hass.loop).result() - @asyncio.coroutine - def async_add_entities(self, new_entities, update_before_add=False): + async def async_add_entities(self, new_entities, update_before_add=False): """Add entities for a single platform async. This method must be run in the event loop. @@ -155,14 +153,14 @@ class EntityPlatform(object): hass = self.hass component_entities = set(hass.states.async_entity_ids(self.domain)) - registry = yield from async_get_registry(hass) + registry = await async_get_registry(hass) tasks = [ self._async_add_entity(entity, update_before_add, component_entities, registry) for entity in new_entities] - yield from asyncio.wait(tasks, loop=self.hass.loop) + await asyncio.wait(tasks, loop=self.hass.loop) self.async_entities_added_callback() if self._async_unsub_polling is not None or \ @@ -174,9 +172,8 @@ class EntityPlatform(object): self.hass, self._update_entity_states, self.scan_interval ) - @asyncio.coroutine - def _async_add_entity(self, entity, update_before_add, component_entities, - registry): + async def _async_add_entity(self, entity, update_before_add, + component_entities, registry): """Helper method to add an entity to the platform.""" if entity is None: raise ValueError('Entity cannot be None') @@ -188,7 +185,7 @@ class EntityPlatform(object): # Update properties before we generate the entity_id if update_before_add: try: - yield from entity.async_device_update(warning=False) + await entity.async_device_update(warning=False) except Exception: # pylint: disable=broad-except self.logger.exception( "%s: Error on device update!", self.platform_name) @@ -258,12 +255,11 @@ class EntityPlatform(object): component_entities.add(entity.entity_id) if hasattr(entity, 'async_added_to_hass'): - yield from entity.async_added_to_hass() + await entity.async_added_to_hass() - yield from entity.async_update_ha_state() + await entity.async_update_ha_state() - @asyncio.coroutine - def async_reset(self): + async def async_reset(self): """Remove all entities and reset data. This method must be run in the event loop. @@ -274,16 +270,15 @@ class EntityPlatform(object): tasks = [self._async_remove_entity(entity_id) for entity_id in self.entities] - yield from asyncio.wait(tasks, loop=self.hass.loop) + await asyncio.wait(tasks, loop=self.hass.loop) if self._async_unsub_polling is not None: self._async_unsub_polling() self._async_unsub_polling = None - @asyncio.coroutine - def async_remove_entity(self, entity_id): + async def async_remove_entity(self, entity_id): """Remove entity id from platform.""" - yield from self._async_remove_entity(entity_id) + await self._async_remove_entity(entity_id) # Clean up polling job if no longer needed if (self._async_unsub_polling is not None and @@ -292,18 +287,16 @@ class EntityPlatform(object): self._async_unsub_polling() self._async_unsub_polling = None - @asyncio.coroutine - def _async_remove_entity(self, entity_id): + async def _async_remove_entity(self, entity_id): """Remove entity id from platform.""" entity = self.entities.pop(entity_id) if hasattr(entity, 'async_will_remove_from_hass'): - yield from entity.async_will_remove_from_hass() + await entity.async_will_remove_from_hass() self.hass.states.async_remove(entity_id) - @asyncio.coroutine - def _update_entity_states(self, now): + async def _update_entity_states(self, now): """Update the states of all the polling entities. To protect from flooding the executor, we will update async entities @@ -318,7 +311,7 @@ class EntityPlatform(object): self.scan_interval) return - with (yield from self._process_updates): + with (await self._process_updates): tasks = [] for entity in self.entities.values(): if not entity.should_poll: @@ -326,4 +319,4 @@ class EntityPlatform(object): tasks.append(entity.async_update_ha_state(True)) if tasks: - yield from asyncio.wait(tasks, loop=self.hass.loop) + await asyncio.wait(tasks, loop=self.hass.loop) diff --git a/homeassistant/helpers/entity_registry.py b/homeassistant/helpers/entity_registry.py index c6eafa91335..b5a9c309119 100644 --- a/homeassistant/helpers/entity_registry.py +++ b/homeassistant/helpers/entity_registry.py @@ -10,7 +10,7 @@ timer. After initializing, call EntityRegistry.async_ensure_loaded to load the data from disk. """ -import asyncio + from collections import OrderedDict from itertools import chain import logging @@ -150,8 +150,7 @@ class EntityRegistry: return new - @asyncio.coroutine - def async_ensure_loaded(self): + async def async_ensure_loaded(self): """Load the registry from disk.""" if self.entities is not None: return @@ -159,16 +158,15 @@ class EntityRegistry: if self._load_task is None: self._load_task = self.hass.async_add_job(self._async_load) - yield from self._load_task + await self._load_task - @asyncio.coroutine - def _async_load(self): + async def _async_load(self): """Load the entity registry.""" path = self.hass.config.path(PATH_REGISTRY) entities = OrderedDict() if os.path.isfile(path): - data = yield from self.hass.async_add_job(load_yaml, path) + data = await self.hass.async_add_job(load_yaml, path) for entity_id, info in data.items(): entities[entity_id] = RegistryEntry( @@ -192,8 +190,7 @@ class EntityRegistry: SAVE_DELAY, self.hass.async_add_job, self._async_save ) - @asyncio.coroutine - def _async_save(self): + async def _async_save(self): """Save the entity registry to a file.""" self._sched_save = None data = OrderedDict() @@ -205,7 +202,7 @@ class EntityRegistry: 'name': entry.name, } - yield from self.hass.async_add_job( + await self.hass.async_add_job( save_yaml, self.hass.config.path(PATH_REGISTRY), data) diff --git a/homeassistant/helpers/intent.py b/homeassistant/helpers/intent.py index bf2773d32b8..dfbce4e82a5 100644 --- a/homeassistant/helpers/intent.py +++ b/homeassistant/helpers/intent.py @@ -1,5 +1,4 @@ """Module to coordinate user intentions.""" -import asyncio import logging import re @@ -41,9 +40,9 @@ def async_register(hass, handler): intents[handler.intent_type] = handler -@asyncio.coroutine @bind_hass -def async_handle(hass, platform, intent_type, slots=None, text_input=None): +async def async_handle(hass, platform, intent_type, slots=None, + text_input=None): """Handle an intent.""" handler = hass.data.get(DATA_KEY, {}).get(intent_type) @@ -54,7 +53,7 @@ def async_handle(hass, platform, intent_type, slots=None, text_input=None): try: _LOGGER.info("Triggering intent handler %s", handler) - result = yield from handler.async_handle(intent) + result = await handler.async_handle(intent) return result except vol.Invalid as err: raise InvalidSlotInfo( @@ -114,8 +113,7 @@ class IntentHandler: return self._slot_schema(slots) - @asyncio.coroutine - def async_handle(self, intent_obj): + async def async_handle(self, intent_obj): """Handle the intent.""" raise NotImplementedError() @@ -153,8 +151,7 @@ class ServiceIntentHandler(IntentHandler): self.service = service self.speech = speech - @asyncio.coroutine - def async_handle(self, intent_obj): + async def async_handle(self, intent_obj): """Handle the hass intent.""" hass = intent_obj.hass slots = self.async_validate_slots(intent_obj.slots) @@ -175,7 +172,7 @@ class ServiceIntentHandler(IntentHandler): _LOGGER.error("Could not find entity id matching %s", name) return response - yield from hass.services.async_call( + await hass.services.async_call( self.domain, self.service, { ATTR_ENTITY_ID: entity_id }) diff --git a/homeassistant/helpers/restore_state.py b/homeassistant/helpers/restore_state.py index a2940f06022..aac00b07d7a 100644 --- a/homeassistant/helpers/restore_state.py +++ b/homeassistant/helpers/restore_state.py @@ -49,9 +49,8 @@ def _load_restore_cache(hass: HomeAssistant): _LOGGER.debug('Created cache with %s', list(hass.data[DATA_RESTORE_CACHE])) -@asyncio.coroutine @bind_hass -def async_get_last_state(hass, entity_id: str): +async def async_get_last_state(hass, entity_id: str): """Restore state.""" if DATA_RESTORE_CACHE in hass.data: return hass.data[DATA_RESTORE_CACHE].get(entity_id) @@ -66,7 +65,7 @@ def async_get_last_state(hass, entity_id: str): try: with async_timeout.timeout(RECORDER_TIMEOUT, loop=hass.loop): - connected = yield from wait_connection_ready(hass) + connected = await wait_connection_ready(hass) except asyncio.TimeoutError: return None @@ -76,25 +75,24 @@ def async_get_last_state(hass, entity_id: str): if _LOCK not in hass.data: hass.data[_LOCK] = asyncio.Lock(loop=hass.loop) - with (yield from hass.data[_LOCK]): + with (await hass.data[_LOCK]): if DATA_RESTORE_CACHE not in hass.data: - yield from hass.async_add_job( + await hass.async_add_job( _load_restore_cache, hass) return hass.data.get(DATA_RESTORE_CACHE, {}).get(entity_id) -@asyncio.coroutine -def async_restore_state(entity, extract_info): +async def async_restore_state(entity, extract_info): """Call entity.async_restore_state with cached info.""" if entity.hass.state not in (CoreState.starting, CoreState.not_running): _LOGGER.debug("Not restoring state for %s: Hass is not starting: %s", entity.entity_id, entity.hass.state) return - state = yield from async_get_last_state(entity.hass, entity.entity_id) + state = await async_get_last_state(entity.hass, entity.entity_id) if not state: return - yield from entity.async_restore_state(**extract_info(state)) + await entity.async_restore_state(**extract_info(state)) diff --git a/homeassistant/helpers/script.py b/homeassistant/helpers/script.py index 7a989267572..6530cb62485 100644 --- a/homeassistant/helpers/script.py +++ b/homeassistant/helpers/script.py @@ -1,5 +1,5 @@ """Helpers to execute scripts.""" -import asyncio + import logging from itertools import islice from typing import Optional, Sequence @@ -68,8 +68,7 @@ class Script(): run_coroutine_threadsafe( self.async_run(variables), self.hass.loop).result() - @asyncio.coroutine - def async_run(self, variables: Optional[Sequence] = None) -> None: + async def async_run(self, variables: Optional[Sequence] = None) -> None: """Run script. This method is a coroutine. @@ -151,7 +150,7 @@ class Script(): self._async_fire_event(action, variables) else: - yield from self._async_call_service(action, variables) + await self._async_call_service(action, variables) self._cur = -1 self.last_action = None @@ -172,15 +171,14 @@ class Script(): if self._change_listener: self.hass.async_add_job(self._change_listener) - @asyncio.coroutine - def _async_call_service(self, action, variables): + async def _async_call_service(self, action, variables): """Call the service specified in the action. This method is a coroutine. """ self.last_action = action.get(CONF_ALIAS, 'call service') self._log("Executing step %s" % self.last_action) - yield from service.async_call_from_config( + await service.async_call_from_config( self.hass, action, True, variables, validate_config=False) def _async_fire_event(self, action, variables): diff --git a/homeassistant/helpers/service.py b/homeassistant/helpers/service.py index b89b1689c9e..7118cab211a 100644 --- a/homeassistant/helpers/service.py +++ b/homeassistant/helpers/service.py @@ -1,5 +1,4 @@ """Service calling related helpers.""" -import asyncio import logging # pylint: disable=unused-import from typing import Optional # NOQA @@ -36,10 +35,9 @@ def call_from_config(hass, config, blocking=False, variables=None, validate_config), hass.loop).result() -@asyncio.coroutine @bind_hass -def async_call_from_config(hass, config, blocking=False, variables=None, - validate_config=True): +async def async_call_from_config(hass, config, blocking=False, variables=None, + validate_config=True): """Call a service based on a config hash.""" if validate_config: try: @@ -79,7 +77,7 @@ def async_call_from_config(hass, config, blocking=False, variables=None, if CONF_SERVICE_ENTITY_ID in config: service_data[ATTR_ENTITY_ID] = config[CONF_SERVICE_ENTITY_ID] - yield from hass.services.async_call( + await hass.services.async_call( domain, service_name, service_data, blocking) @@ -115,9 +113,8 @@ def extract_entity_ids(hass, service_call, expand_group=True): return service_ent_id -@asyncio.coroutine @bind_hass -def async_get_all_descriptions(hass): +async def async_get_all_descriptions(hass): """Return descriptions (i.e. user documentation) for all service calls.""" if SERVICE_DESCRIPTION_CACHE not in hass.data: hass.data[SERVICE_DESCRIPTION_CACHE] = {} @@ -156,7 +153,7 @@ def async_get_all_descriptions(hass): break if missing: - loaded = yield from hass.async_add_job(load_services_files, missing) + loaded = await hass.async_add_job(load_services_files, missing) # Build response catch_all_yaml_file = domain_yaml_file(ha.DOMAIN) diff --git a/homeassistant/helpers/state.py b/homeassistant/helpers/state.py index 255f760ebff..6be0dbae914 100644 --- a/homeassistant/helpers/state.py +++ b/homeassistant/helpers/state.py @@ -130,9 +130,8 @@ def reproduce_state(hass, states, blocking=False): async_reproduce_state(hass, states, blocking), hass.loop).result() -@asyncio.coroutine @bind_hass -def async_reproduce_state(hass, states, blocking=False): +async def async_reproduce_state(hass, states, blocking=False): """Reproduce given state.""" if isinstance(states, State): states = [states] @@ -193,16 +192,15 @@ def async_reproduce_state(hass, states, blocking=False): hass.services.async_call(service_domain, service, data, blocking) ) - @asyncio.coroutine - def async_handle_service_calls(coro_list): + async def async_handle_service_calls(coro_list): """Handle service calls by domain sequence.""" for coro in coro_list: - yield from coro + await coro execute_tasks = [async_handle_service_calls(coro_list) for coro_list in domain_tasks.values()] if execute_tasks: - yield from asyncio.wait(execute_tasks, loop=hass.loop) + await asyncio.wait(execute_tasks, loop=hass.loop) def state_as_number(state): diff --git a/homeassistant/requirements.py b/homeassistant/requirements.py index aaf83870147..df5a098f901 100644 --- a/homeassistant/requirements.py +++ b/homeassistant/requirements.py @@ -11,8 +11,7 @@ CONSTRAINT_FILE = 'package_constraints.txt' _LOGGER = logging.getLogger(__name__) -@asyncio.coroutine -def async_process_requirements(hass, name, requirements): +async def async_process_requirements(hass, name, requirements): """Install the requirements for a component or platform. This method is a coroutine. @@ -24,9 +23,9 @@ def async_process_requirements(hass, name, requirements): pip_install = partial(pkg_util.install_package, **pip_kwargs(hass.config.config_dir)) - with (yield from pip_lock): + async with pip_lock: for req in requirements: - ret = yield from hass.async_add_job(pip_install, req) + ret = await hass.async_add_job(pip_install, req) if not ret: _LOGGER.error("Not initializing %s because could not install " "requirement %s", name, req) diff --git a/homeassistant/scripts/benchmark/__init__.py b/homeassistant/scripts/benchmark/__init__.py index 834334b8a90..331b9992627 100644 --- a/homeassistant/scripts/benchmark/__init__.py +++ b/homeassistant/scripts/benchmark/__init__.py @@ -50,8 +50,7 @@ def benchmark(func): @benchmark -@asyncio.coroutine -def async_million_events(hass): +async def async_million_events(hass): """Run a million events.""" count = 0 event_name = 'benchmark_event' @@ -73,15 +72,14 @@ def async_million_events(hass): start = timer() - yield from event.wait() + await event.wait() return timer() - start @benchmark -@asyncio.coroutine # pylint: disable=invalid-name -def async_million_time_changed_helper(hass): +async def async_million_time_changed_helper(hass): """Run a million events through time changed helper.""" count = 0 event = asyncio.Event(loop=hass.loop) @@ -105,15 +103,14 @@ def async_million_time_changed_helper(hass): start = timer() - yield from event.wait() + await event.wait() return timer() - start @benchmark -@asyncio.coroutine # pylint: disable=invalid-name -def async_million_state_changed_helper(hass): +async def async_million_state_changed_helper(hass): """Run a million events through state changed helper.""" count = 0 entity_id = 'light.kitchen' @@ -141,7 +138,7 @@ def async_million_state_changed_helper(hass): start = timer() - yield from event.wait() + await event.wait() return timer() - start diff --git a/homeassistant/scripts/check_config.py b/homeassistant/scripts/check_config.py index ec55b1d70c5..a062c1724ae 100644 --- a/homeassistant/scripts/check_config.py +++ b/homeassistant/scripts/check_config.py @@ -1,5 +1,5 @@ """Script to ensure a configuration file exists.""" -import asyncio + import argparse import logging import os @@ -46,8 +46,7 @@ C_HEAD = 'bold' ERROR_STR = 'General Errors' -@asyncio.coroutine -def mock_coro(*args): +async def mock_coro(*args): """Coroutine that returns None.""" return None @@ -181,8 +180,7 @@ def check(config_path): # pylint: disable=unused-variable def mock_get(comp_name): """Mock hass.loader.get_component to replace setup & setup_platform.""" - @asyncio.coroutine - def mock_async_setup(*args): + async def mock_async_setup(*args): """Mock setup, only record the component name & config.""" assert comp_name not in res['components'], \ "Components should contain a list of platforms" diff --git a/homeassistant/setup.py b/homeassistant/setup.py index 5a8681e82fd..5be1547242e 100644 --- a/homeassistant/setup.py +++ b/homeassistant/setup.py @@ -30,9 +30,8 @@ def setup_component(hass: core.HomeAssistant, domain: str, async_setup_component(hass, domain, config), loop=hass.loop).result() -@asyncio.coroutine -def async_setup_component(hass: core.HomeAssistant, domain: str, - config: Optional[Dict] = None) -> bool: +async def async_setup_component(hass: core.HomeAssistant, domain: str, + config: Optional[Dict] = None) -> bool: """Set up a component and all its dependencies. This method is a coroutine. @@ -43,7 +42,7 @@ def async_setup_component(hass: core.HomeAssistant, domain: str, setup_tasks = hass.data.get(DATA_SETUP) if setup_tasks is not None and domain in setup_tasks: - return (yield from setup_tasks[domain]) + return await setup_tasks[domain] if config is None: config = {} @@ -54,11 +53,10 @@ def async_setup_component(hass: core.HomeAssistant, domain: str, task = setup_tasks[domain] = hass.async_add_job( _async_setup_component(hass, domain, config)) - return (yield from task) + return await task -@asyncio.coroutine -def _async_process_dependencies(hass, config, name, dependencies): +async def _async_process_dependencies(hass, config, name, dependencies): """Ensure all dependencies are set up.""" blacklisted = [dep for dep in dependencies if dep in loader.DEPENDENCY_BLACKLIST] @@ -75,7 +73,7 @@ def _async_process_dependencies(hass, config, name, dependencies): if not tasks: return True - results = yield from asyncio.gather(*tasks, loop=hass.loop) + results = await asyncio.gather(*tasks, loop=hass.loop) failed = [dependencies[idx] for idx, res in enumerate(results) if not res] @@ -89,9 +87,8 @@ def _async_process_dependencies(hass, config, name, dependencies): return True -@asyncio.coroutine -def _async_setup_component(hass: core.HomeAssistant, - domain: str, config) -> bool: +async def _async_setup_component(hass: core.HomeAssistant, + domain: str, config) -> bool: """Set up a component for Home Assistant. This method is a coroutine. @@ -123,7 +120,7 @@ def _async_setup_component(hass: core.HomeAssistant, return False try: - yield from async_process_deps_reqs(hass, config, domain, component) + await async_process_deps_reqs(hass, config, domain, component) except HomeAssistantError as err: log_error(str(err)) return False @@ -142,9 +139,9 @@ def _async_setup_component(hass: core.HomeAssistant, try: if hasattr(component, 'async_setup'): - result = yield from component.async_setup(hass, processed_config) + result = await component.async_setup(hass, processed_config) else: - result = yield from hass.async_add_job( + result = await hass.async_add_job( component.setup, hass, processed_config) except Exception: # pylint: disable=broad-except _LOGGER.exception("Error during setup of component %s", domain) @@ -166,7 +163,7 @@ def _async_setup_component(hass: core.HomeAssistant, return False for entry in hass.config_entries.async_entries(domain): - yield from entry.async_setup(hass, component=component) + await entry.async_setup(hass, component=component) hass.config.components.add(component.DOMAIN) @@ -181,9 +178,8 @@ def _async_setup_component(hass: core.HomeAssistant, return True -@asyncio.coroutine -def async_prepare_setup_platform(hass: core.HomeAssistant, config, domain: str, - platform_name: str) \ +async def async_prepare_setup_platform(hass: core.HomeAssistant, config, + domain: str, platform_name: str) \ -> Optional[ModuleType]: """Load a platform and makes sure dependencies are setup. @@ -209,7 +205,7 @@ def async_prepare_setup_platform(hass: core.HomeAssistant, config, domain: str, return platform try: - yield from async_process_deps_reqs( + await async_process_deps_reqs( hass, config, platform_path, platform) except HomeAssistantError as err: log_error(str(err)) @@ -218,8 +214,7 @@ def async_prepare_setup_platform(hass: core.HomeAssistant, config, domain: str, return platform -@asyncio.coroutine -def async_process_deps_reqs(hass, config, name, module): +async def async_process_deps_reqs(hass, config, name, module): """Process all dependencies and requirements for a module. Module is a Python module of either a component or platform. @@ -232,14 +227,14 @@ def async_process_deps_reqs(hass, config, name, module): return if hasattr(module, 'DEPENDENCIES'): - dep_success = yield from _async_process_dependencies( + dep_success = await _async_process_dependencies( hass, config, name, module.DEPENDENCIES) if not dep_success: raise HomeAssistantError("Could not setup all dependencies.") if not hass.config.skip_pip and hasattr(module, 'REQUIREMENTS'): - req_success = yield from requirements.async_process_requirements( + req_success = await requirements.async_process_requirements( hass, name, module.REQUIREMENTS) if not req_success: diff --git a/homeassistant/util/package.py b/homeassistant/util/package.py index e8149a85262..75e12f41a90 100644 --- a/homeassistant/util/package.py +++ b/homeassistant/util/package.py @@ -88,17 +88,17 @@ def get_user_site(deps_dir: str) -> str: return lib_dir -@asyncio.coroutine -def async_get_user_site(deps_dir: str, loop: asyncio.AbstractEventLoop) -> str: +async def async_get_user_site(deps_dir: str, + loop: asyncio.AbstractEventLoop) -> str: """Return user local library path. This function is a coroutine. """ args, env = _get_user_site(deps_dir) - process = yield from asyncio.create_subprocess_exec( + process = await asyncio.create_subprocess_exec( *args, loop=loop, stdin=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.DEVNULL, env=env) - stdout, _ = yield from process.communicate() + stdout, _ = await process.communicate() lib_dir = stdout.decode().strip() return lib_dir diff --git a/script/test b/script/test index 2f3f3557094..14fc357eb12 100755 --- a/script/test +++ b/script/test @@ -3,4 +3,4 @@ cd "$(dirname "$0")/.." -tox -e py34 +tox -e py35 diff --git a/tests/util/test_logging.py b/tests/util/test_logging.py index 94c8568dc47..c67b2aea448 100644 --- a/tests/util/test_logging.py +++ b/tests/util/test_logging.py @@ -6,7 +6,6 @@ import threading import homeassistant.util.logging as logging_util -@asyncio.coroutine def test_sensitive_data_filter(): """Test the logging sensitive data filter.""" log_filter = logging_util.HideSensitiveDataFilter('mock_sensitive')