Removing asyncio.coroutine syntax from HASS core (#12509)

* changed asyncio.coroutine syntax to new async def/await

* removed py34 from tox environment

* reverted some changes within entity.py

* -

* reverted changes within bootstrap.py

* reverted changes within discovery.py

* switched decorators

* Reverted change within aiohttp_client.py

* reverted change within logging.py

* switched decorators

* Await lock properly

* removed asyncio.coroutine from test
This commit is contained in:
Julius Mittenzwei 2018-02-25 12:38:46 +01:00 committed by Paulus Schoutsen
parent eacfbc048a
commit 16cb7388ee
20 changed files with 148 additions and 202 deletions

View File

@ -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']

View File

@ -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())

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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
})

View File

@ -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))

View File

@ -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):

View File

@ -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)

View File

@ -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):

View File

@ -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)

View File

@ -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

View File

@ -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"

View File

@ -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:

View File

@ -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

View File

@ -3,4 +3,4 @@
cd "$(dirname "$0")/.."
tox -e py34
tox -e py35

View File

@ -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')