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() flow for flow in hass.config_entries.flow.async_progress()
if flow['source'] != config_entries.SOURCE_USER]) if flow['source'] != config_entries.SOURCE_USER])
@asyncio.coroutine
@RequestDataValidator(vol.Schema({ @RequestDataValidator(vol.Schema({
vol.Required('domain'): str, vol.Required('domain'): str,
})) }))
@asyncio.coroutine
def post(self, request, data): def post(self, request, data):
"""Handle a POST request.""" """Handle a POST request."""
hass = request.app['hass'] hass = request.app['hass']
@ -139,8 +139,8 @@ class ConfigManagerFlowResourceView(HomeAssistantView):
return self.json(result) return self.json(result)
@asyncio.coroutine
@RequestDataValidator(vol.Schema(dict), allow_empty=True) @RequestDataValidator(vol.Schema(dict), allow_empty=True)
@asyncio.coroutine
def post(self, request, flow_id, data): def post(self, request, flow_id, data):
"""Handle a POST request.""" """Handle a POST request."""
hass = request.app['hass'] hass = request.app['hass']

View File

@ -260,8 +260,7 @@ def create_default_config(config_dir, detect_location=True):
return None return None
@asyncio.coroutine async def async_hass_config_yaml(hass):
def async_hass_config_yaml(hass):
"""Load YAML from a Home Assistant configuration file. """Load YAML from a Home Assistant configuration file.
This function allow a component inside the asyncio loop to reload its 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) conf = load_yaml_config_file(path)
return conf 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 return conf
@ -373,8 +372,7 @@ def async_log_exception(ex, domain, config, hass):
_LOGGER.error(message) _LOGGER.error(message)
@asyncio.coroutine async def async_process_ha_core_config(hass, config):
def async_process_ha_core_config(hass, config):
"""Process the [homeassistant] section from the configuration. """Process the [homeassistant] section from the configuration.
This method is a coroutine. 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 we miss some of the needed values, auto detect them
if None in (hac.latitude, hac.longitude, hac.units, if None in (hac.latitude, hac.longitude, hac.units,
hac.time_zone): hac.time_zone):
info = yield from hass.async_add_job( info = await hass.async_add_job(
loc_util.detect_location_info) loc_util.detect_location_info)
if info is None: 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 \ if hac.elevation is None and hac.latitude is not None and \
hac.longitude is not None: 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) loc_util.elevation, hac.latitude, hac.longitude)
hac.elevation = elevation hac.elevation = elevation
discovered.append(('elevation', elevation)) discovered.append(('elevation', elevation))
@ -648,21 +646,20 @@ def async_process_component_config(hass, config, domain):
return config return config
@asyncio.coroutine async def async_check_ha_config_file(hass):
def async_check_ha_config_file(hass):
"""Check if Home Assistant configuration file is valid. """Check if Home Assistant configuration file is valid.
This method is a coroutine. This method is a coroutine.
""" """
proc = yield from asyncio.create_subprocess_exec( proc = await asyncio.create_subprocess_exec(
sys.executable, '-m', 'homeassistant', '--script', sys.executable, '-m', 'homeassistant', '--script',
'check_config', '--config', hass.config.config_dir, 'check_config', '--config', hass.config.config_dir,
stdout=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.STDOUT, loop=hass.loop) stderr=asyncio.subprocess.STDOUT, loop=hass.loop)
# Wait for the subprocess exit # Wait for the subprocess exit
log, _ = yield from proc.communicate() log, _ = await proc.communicate()
exit_code = yield from proc.wait() exit_code = await proc.wait()
# Convert to ASCII # Convert to ASCII
log = RE_ASCII.sub('', log.decode()) 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 values. If you want to navigate the user to the next step, return the
return value of that step: return value of that step:
return (await self.async_step_account()) return await self.async_step_account()
### Abort ### 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 If the result of the step is to show a form, the user will be able to continue
the flow from the config panel. the flow from the config panel.
""" """
import asyncio
import logging import logging
import os import os
import uuid import uuid
@ -176,14 +176,13 @@ class ConfigEntry:
# State of the entry (LOADED, NOT_LOADED) # State of the entry (LOADED, NOT_LOADED)
self.state = state self.state = state
@asyncio.coroutine async def async_setup(self, hass, *, component=None):
def async_setup(self, hass, *, component=None):
"""Set up an entry.""" """Set up an entry."""
if component is None: if component is None:
component = getattr(hass.components, self.domain) component = getattr(hass.components, self.domain)
try: try:
result = yield from component.async_setup_entry(hass, self) result = await component.async_setup_entry(hass, self)
if not isinstance(result, bool): if not isinstance(result, bool):
_LOGGER.error('%s.async_config_entry did not return boolean', _LOGGER.error('%s.async_config_entry did not return boolean',
@ -199,8 +198,7 @@ class ConfigEntry:
else: else:
self.state = ENTRY_STATE_SETUP_ERROR self.state = ENTRY_STATE_SETUP_ERROR
@asyncio.coroutine async def async_unload(self, hass):
def async_unload(self, hass):
"""Unload an entry. """Unload an entry.
Returns if unload is possible and was successful. Returns if unload is possible and was successful.
@ -213,7 +211,7 @@ class ConfigEntry:
return False return False
try: try:
result = yield from component.async_unload_entry(hass, self) result = await component.async_unload_entry(hass, self)
if not isinstance(result, bool): if not isinstance(result, bool):
_LOGGER.error('%s.async_unload_entry did not return boolean', _LOGGER.error('%s.async_unload_entry did not return boolean',
@ -293,8 +291,7 @@ class ConfigEntries:
return list(self._entries) return list(self._entries)
return [entry for entry in self._entries if entry.domain == domain] return [entry for entry in self._entries if entry.domain == domain]
@asyncio.coroutine async def async_remove(self, entry_id):
def async_remove(self, entry_id):
"""Remove an entry.""" """Remove an entry."""
found = None found = None
for index, entry in enumerate(self._entries): for index, entry in enumerate(self._entries):
@ -308,25 +305,23 @@ class ConfigEntries:
entry = self._entries.pop(found) entry = self._entries.pop(found)
self._async_schedule_save() self._async_schedule_save()
unloaded = yield from entry.async_unload(self.hass) unloaded = await entry.async_unload(self.hass)
return { return {
'require_restart': not unloaded 'require_restart': not unloaded
} }
@asyncio.coroutine async def async_load(self):
def async_load(self):
"""Load the config.""" """Load the config."""
path = self.hass.config.path(PATH_CONFIG) path = self.hass.config.path(PATH_CONFIG)
if not os.path.isfile(path): if not os.path.isfile(path):
self._entries = [] self._entries = []
return 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] self._entries = [ConfigEntry(**entry) for entry in entries]
@asyncio.coroutine async def _async_add_entry(self, entry):
def _async_add_entry(self, entry):
"""Add an entry.""" """Add an entry."""
self._entries.append(entry) self._entries.append(entry)
self._async_schedule_save() self._async_schedule_save()
@ -334,10 +329,10 @@ class ConfigEntries:
# Setup entry # Setup entry
if entry.domain in self.hass.config.components: if entry.domain in self.hass.config.components:
# Component already set up, just need to call setup_entry # Component already set up, just need to call setup_entry
yield from entry.async_setup(self.hass) await entry.async_setup(self.hass)
else: else:
# Setting up component will also load the entries # Setting up component will also load the entries
yield from async_setup_component( await async_setup_component(
self.hass, entry.domain, self._hass_config) self.hass, entry.domain, self._hass_config)
@callback @callback
@ -350,13 +345,12 @@ class ConfigEntries:
SAVE_DELAY, self.hass.async_add_job, self._async_save SAVE_DELAY, self.hass.async_add_job, self._async_save
) )
@asyncio.coroutine async def _async_save(self):
def _async_save(self):
"""Save the entity registry to a file.""" """Save the entity registry to a file."""
self._sched_save = None self._sched_save = None
data = [entry.as_dict() for entry in self._entries] 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) save_json, self.hass.config.path(PATH_CONFIG), data)
@ -379,8 +373,7 @@ class FlowManager:
'source': flow.source, 'source': flow.source,
} for flow in self._progress.values()] } for flow in self._progress.values()]
@asyncio.coroutine async def async_init(self, domain, *, source=SOURCE_USER, data=None):
def async_init(self, domain, *, source=SOURCE_USER, data=None):
"""Start a configuration flow.""" """Start a configuration flow."""
handler = HANDLERS.get(domain) handler = HANDLERS.get(domain)
@ -393,7 +386,7 @@ class FlowManager:
raise self.hass.helpers.UnknownHandler raise self.hass.helpers.UnknownHandler
# Make sure requirements and dependencies of component are resolved # 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) self.hass, self._hass_config, domain, component)
flow_id = uuid.uuid4().hex flow_id = uuid.uuid4().hex
@ -408,10 +401,9 @@ class FlowManager:
else: else:
step = source step = source
return (yield from self._async_handle_step(flow, step, data)) return await self._async_handle_step(flow, step, data)
@asyncio.coroutine async def async_configure(self, flow_id, user_input=None):
def async_configure(self, flow_id, user_input=None):
"""Start or continue a configuration flow.""" """Start or continue a configuration flow."""
flow = self._progress.get(flow_id) flow = self._progress.get(flow_id)
@ -423,8 +415,8 @@ class FlowManager:
if data_schema is not None and user_input is not None: if data_schema is not None and user_input is not None:
user_input = data_schema(user_input) user_input = data_schema(user_input)
return (yield from self._async_handle_step( return await self._async_handle_step(
flow, step_id, user_input)) flow, step_id, user_input)
@callback @callback
def async_abort(self, flow_id): def async_abort(self, flow_id):
@ -432,8 +424,7 @@ class FlowManager:
if self._progress.pop(flow_id, None) is None: if self._progress.pop(flow_id, None) is None:
raise UnknownFlow raise UnknownFlow
@asyncio.coroutine async def _async_handle_step(self, flow, step_id, user_input):
def _async_handle_step(self, flow, step_id, user_input):
"""Handle a step of a flow.""" """Handle a step of a flow."""
method = "async_step_{}".format(step_id) method = "async_step_{}".format(step_id)
@ -442,7 +433,7 @@ class FlowManager:
raise UnknownStep("Handler {} doesn't support step {}".format( raise UnknownStep("Handler {} doesn't support step {}".format(
flow.__class__.__name__, step_id)) 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, if result['type'] not in (RESULT_TYPE_FORM, RESULT_TYPE_CREATE_ENTRY,
RESULT_TYPE_ABORT): RESULT_TYPE_ABORT):
@ -466,7 +457,7 @@ class FlowManager:
data=result.pop('data'), data=result.pop('data'),
source=flow.source source=flow.source
) )
yield from self._async_add_entry(entry) await self._async_add_entry(entry)
return result return result

View File

@ -106,29 +106,28 @@ def async_aiohttp_proxy_web(hass, request, web_coro, buffer_size=102400,
req.close() req.close()
@asyncio.coroutine
@bind_hass @bind_hass
def async_aiohttp_proxy_stream(hass, request, stream, content_type, async def async_aiohttp_proxy_stream(hass, request, stream, content_type,
buffer_size=102400, timeout=10): buffer_size=102400, timeout=10):
"""Stream a stream to aiohttp web response.""" """Stream a stream to aiohttp web response."""
response = web.StreamResponse() response = web.StreamResponse()
response.content_type = content_type response.content_type = content_type
yield from response.prepare(request) await response.prepare(request)
try: try:
while True: while True:
with async_timeout.timeout(timeout, loop=hass.loop): with async_timeout.timeout(timeout, loop=hass.loop):
data = yield from stream.read(buffer_size) data = await stream.read(buffer_size)
if not data: if not data:
yield from response.write_eof() await response.write_eof()
break break
response.write(data) response.write(data)
except (asyncio.TimeoutError, aiohttp.ClientError): except (asyncio.TimeoutError, aiohttp.ClientError):
# Something went wrong fetching data, close connection gracefully # Something went wrong fetching data, close connection gracefully
yield from response.write_eof() await response.write_eof()
except asyncio.CancelledError: except asyncio.CancelledError:
# The user closed the connection # The user closed the connection

View File

@ -332,11 +332,10 @@ class Entity(object):
if self.parallel_updates: if self.parallel_updates:
self.parallel_updates.release() self.parallel_updates.release()
@asyncio.coroutine async def async_remove(self):
def async_remove(self):
"""Remove entity from Home Assistant.""" """Remove entity from Home Assistant."""
if self.platform is not None: 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: else:
self.hass.states.async_remove(self.entity_id) 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)) self.hass.add_job(self.async_setup(config))
@asyncio.coroutine async def async_setup(self, config):
def async_setup(self, config):
"""Set up a full entity component. """Set up a full entity component.
Loads the platforms from the config and will listen for supported 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)) tasks.append(self._async_setup_platform(p_type, p_config))
if tasks: 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 # Generic discovery listener for loading platform dynamically
# Refer to: homeassistant.components.discovery.load_platform() # Refer to: homeassistant.components.discovery.load_platform()
@asyncio.coroutine async def component_platform_discovered(platform, info):
def component_platform_discovered(platform, info):
"""Handle the loading of a platform.""" """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( discovery.async_listen_platform(
self.hass, self.domain, component_platform_discovered) self.hass, self.domain, component_platform_discovered)
@ -120,11 +118,10 @@ class EntityComponent(object):
return [entity for entity in self.entities return [entity for entity in self.entities
if entity.available and entity.entity_id in entity_ids] if entity.available and entity.entity_id in entity_ids]
@asyncio.coroutine async def _async_setup_platform(self, platform_type, platform_config,
def _async_setup_platform(self, platform_type, platform_config, discovery_info=None):
discovery_info=None):
"""Set up a platform for this component.""" """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) self.hass, self.config, self.domain, platform_type)
if platform is None: if platform is None:
@ -156,7 +153,7 @@ class EntityComponent(object):
else: else:
entity_platform = self._platforms[key] entity_platform = self._platforms[key]
yield from entity_platform.async_setup( await entity_platform.async_setup(
platform, platform_config, discovery_info) platform, platform_config, discovery_info)
@callback @callback
@ -177,8 +174,7 @@ class EntityComponent(object):
visible=False, entity_ids=ids visible=False, entity_ids=ids
) )
@asyncio.coroutine async def _async_reset(self):
def _async_reset(self):
"""Remove entities and reset the entity component to initial values. """Remove entities and reset the entity component to initial values.
This method must be run in the event loop. This method must be run in the event loop.
@ -187,7 +183,7 @@ class EntityComponent(object):
in self._platforms.values()] in self._platforms.values()]
if tasks: if tasks:
yield from asyncio.wait(tasks, loop=self.hass.loop) await asyncio.wait(tasks, loop=self.hass.loop)
self._platforms = { self._platforms = {
self.domain: self._platforms[self.domain] self.domain: self._platforms[self.domain]
@ -197,21 +193,19 @@ class EntityComponent(object):
if self.group_name is not None: if self.group_name is not None:
self.hass.components.group.async_remove(slugify(self.group_name)) self.hass.components.group.async_remove(slugify(self.group_name))
@asyncio.coroutine async def async_remove_entity(self, entity_id):
def async_remove_entity(self, entity_id):
"""Remove an entity managed by one of the platforms.""" """Remove an entity managed by one of the platforms."""
for platform in self._platforms.values(): for platform in self._platforms.values():
if entity_id in platform.entities: if entity_id in platform.entities:
yield from platform.async_remove_entity(entity_id) await platform.async_remove_entity(entity_id)
@asyncio.coroutine async def async_prepare_reload(self):
def async_prepare_reload(self):
"""Prepare reloading this entity component. """Prepare reloading this entity component.
This method must be run in the event loop. This method must be run in the event loop.
""" """
try: try:
conf = yield from \ conf = await \
conf_util.async_hass_config_yaml(self.hass) conf_util.async_hass_config_yaml(self.hass)
except HomeAssistantError as err: except HomeAssistantError as err:
self.logger.error(err) self.logger.error(err)
@ -223,5 +217,5 @@ class EntityComponent(object):
if conf is None: if conf is None:
return None return None
yield from self._async_reset() await self._async_reset()
return conf return conf

View File

@ -51,9 +51,8 @@ class EntityPlatform(object):
self.parallel_updates = asyncio.Semaphore( self.parallel_updates = asyncio.Semaphore(
parallel_updates, loop=hass.loop) parallel_updates, loop=hass.loop)
@asyncio.coroutine async def async_setup(self, platform, platform_config, discovery_info=None,
def async_setup(self, platform, platform_config, discovery_info=None, tries=0):
tries=0):
"""Setup the platform.""" """Setup the platform."""
logger = self.logger logger = self.logger
hass = self.hass hass = self.hass
@ -78,7 +77,7 @@ class EntityPlatform(object):
None, platform.setup_platform, hass, platform_config, None, platform.setup_platform, hass, platform_config,
self._schedule_add_entities, discovery_info self._schedule_add_entities, discovery_info
) )
yield from asyncio.wait_for( await asyncio.wait_for(
asyncio.shield(task, loop=hass.loop), asyncio.shield(task, loop=hass.loop),
SLOW_SETUP_MAX_WAIT, loop=hass.loop) SLOW_SETUP_MAX_WAIT, loop=hass.loop)
@ -88,7 +87,7 @@ class EntityPlatform(object):
self._tasks.clear() self._tasks.clear()
if pending: if pending:
yield from asyncio.wait( await asyncio.wait(
pending, loop=self.hass.loop) pending, loop=self.hass.loop)
hass.config.components.add(full_name) hass.config.components.add(full_name)
@ -142,8 +141,7 @@ class EntityPlatform(object):
self.async_add_entities(list(new_entities), update_before_add), self.async_add_entities(list(new_entities), update_before_add),
self.hass.loop).result() self.hass.loop).result()
@asyncio.coroutine async def async_add_entities(self, new_entities, update_before_add=False):
def async_add_entities(self, new_entities, update_before_add=False):
"""Add entities for a single platform async. """Add entities for a single platform async.
This method must be run in the event loop. This method must be run in the event loop.
@ -155,14 +153,14 @@ class EntityPlatform(object):
hass = self.hass hass = self.hass
component_entities = set(hass.states.async_entity_ids(self.domain)) component_entities = set(hass.states.async_entity_ids(self.domain))
registry = yield from async_get_registry(hass) registry = await async_get_registry(hass)
tasks = [ tasks = [
self._async_add_entity(entity, update_before_add, self._async_add_entity(entity, update_before_add,
component_entities, registry) component_entities, registry)
for entity in new_entities] 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() self.async_entities_added_callback()
if self._async_unsub_polling is not None or \ 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 self.hass, self._update_entity_states, self.scan_interval
) )
@asyncio.coroutine async def _async_add_entity(self, entity, update_before_add,
def _async_add_entity(self, entity, update_before_add, component_entities, component_entities, registry):
registry):
"""Helper method to add an entity to the platform.""" """Helper method to add an entity to the platform."""
if entity is None: if entity is None:
raise ValueError('Entity cannot be None') raise ValueError('Entity cannot be None')
@ -188,7 +185,7 @@ class EntityPlatform(object):
# Update properties before we generate the entity_id # Update properties before we generate the entity_id
if update_before_add: if update_before_add:
try: try:
yield from entity.async_device_update(warning=False) await entity.async_device_update(warning=False)
except Exception: # pylint: disable=broad-except except Exception: # pylint: disable=broad-except
self.logger.exception( self.logger.exception(
"%s: Error on device update!", self.platform_name) "%s: Error on device update!", self.platform_name)
@ -258,12 +255,11 @@ class EntityPlatform(object):
component_entities.add(entity.entity_id) component_entities.add(entity.entity_id)
if hasattr(entity, 'async_added_to_hass'): 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 async def async_reset(self):
def async_reset(self):
"""Remove all entities and reset data. """Remove all entities and reset data.
This method must be run in the event loop. This method must be run in the event loop.
@ -274,16 +270,15 @@ class EntityPlatform(object):
tasks = [self._async_remove_entity(entity_id) tasks = [self._async_remove_entity(entity_id)
for entity_id in self.entities] 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: if self._async_unsub_polling is not None:
self._async_unsub_polling() self._async_unsub_polling()
self._async_unsub_polling = None self._async_unsub_polling = None
@asyncio.coroutine async def async_remove_entity(self, entity_id):
def async_remove_entity(self, entity_id):
"""Remove entity id from platform.""" """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 # Clean up polling job if no longer needed
if (self._async_unsub_polling is not None and if (self._async_unsub_polling is not None and
@ -292,18 +287,16 @@ class EntityPlatform(object):
self._async_unsub_polling() self._async_unsub_polling()
self._async_unsub_polling = None self._async_unsub_polling = None
@asyncio.coroutine async def _async_remove_entity(self, entity_id):
def _async_remove_entity(self, entity_id):
"""Remove entity id from platform.""" """Remove entity id from platform."""
entity = self.entities.pop(entity_id) entity = self.entities.pop(entity_id)
if hasattr(entity, 'async_will_remove_from_hass'): 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) self.hass.states.async_remove(entity_id)
@asyncio.coroutine async def _update_entity_states(self, now):
def _update_entity_states(self, now):
"""Update the states of all the polling entities. """Update the states of all the polling entities.
To protect from flooding the executor, we will update async entities To protect from flooding the executor, we will update async entities
@ -318,7 +311,7 @@ class EntityPlatform(object):
self.scan_interval) self.scan_interval)
return return
with (yield from self._process_updates): with (await self._process_updates):
tasks = [] tasks = []
for entity in self.entities.values(): for entity in self.entities.values():
if not entity.should_poll: if not entity.should_poll:
@ -326,4 +319,4 @@ class EntityPlatform(object):
tasks.append(entity.async_update_ha_state(True)) tasks.append(entity.async_update_ha_state(True))
if tasks: 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 After initializing, call EntityRegistry.async_ensure_loaded to load the data
from disk. from disk.
""" """
import asyncio
from collections import OrderedDict from collections import OrderedDict
from itertools import chain from itertools import chain
import logging import logging
@ -150,8 +150,7 @@ class EntityRegistry:
return new return new
@asyncio.coroutine async def async_ensure_loaded(self):
def async_ensure_loaded(self):
"""Load the registry from disk.""" """Load the registry from disk."""
if self.entities is not None: if self.entities is not None:
return return
@ -159,16 +158,15 @@ class EntityRegistry:
if self._load_task is None: if self._load_task is None:
self._load_task = self.hass.async_add_job(self._async_load) self._load_task = self.hass.async_add_job(self._async_load)
yield from self._load_task await self._load_task
@asyncio.coroutine async def _async_load(self):
def _async_load(self):
"""Load the entity registry.""" """Load the entity registry."""
path = self.hass.config.path(PATH_REGISTRY) path = self.hass.config.path(PATH_REGISTRY)
entities = OrderedDict() entities = OrderedDict()
if os.path.isfile(path): 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(): for entity_id, info in data.items():
entities[entity_id] = RegistryEntry( entities[entity_id] = RegistryEntry(
@ -192,8 +190,7 @@ class EntityRegistry:
SAVE_DELAY, self.hass.async_add_job, self._async_save SAVE_DELAY, self.hass.async_add_job, self._async_save
) )
@asyncio.coroutine async def _async_save(self):
def _async_save(self):
"""Save the entity registry to a file.""" """Save the entity registry to a file."""
self._sched_save = None self._sched_save = None
data = OrderedDict() data = OrderedDict()
@ -205,7 +202,7 @@ class EntityRegistry:
'name': entry.name, '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) save_yaml, self.hass.config.path(PATH_REGISTRY), data)

View File

@ -1,5 +1,4 @@
"""Module to coordinate user intentions.""" """Module to coordinate user intentions."""
import asyncio
import logging import logging
import re import re
@ -41,9 +40,9 @@ def async_register(hass, handler):
intents[handler.intent_type] = handler intents[handler.intent_type] = handler
@asyncio.coroutine
@bind_hass @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.""" """Handle an intent."""
handler = hass.data.get(DATA_KEY, {}).get(intent_type) 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: try:
_LOGGER.info("Triggering intent handler %s", handler) _LOGGER.info("Triggering intent handler %s", handler)
result = yield from handler.async_handle(intent) result = await handler.async_handle(intent)
return result return result
except vol.Invalid as err: except vol.Invalid as err:
raise InvalidSlotInfo( raise InvalidSlotInfo(
@ -114,8 +113,7 @@ class IntentHandler:
return self._slot_schema(slots) return self._slot_schema(slots)
@asyncio.coroutine async def async_handle(self, intent_obj):
def async_handle(self, intent_obj):
"""Handle the intent.""" """Handle the intent."""
raise NotImplementedError() raise NotImplementedError()
@ -153,8 +151,7 @@ class ServiceIntentHandler(IntentHandler):
self.service = service self.service = service
self.speech = speech self.speech = speech
@asyncio.coroutine async def async_handle(self, intent_obj):
def async_handle(self, intent_obj):
"""Handle the hass intent.""" """Handle the hass intent."""
hass = intent_obj.hass hass = intent_obj.hass
slots = self.async_validate_slots(intent_obj.slots) 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) _LOGGER.error("Could not find entity id matching %s", name)
return response return response
yield from hass.services.async_call( await hass.services.async_call(
self.domain, self.service, { self.domain, self.service, {
ATTR_ENTITY_ID: entity_id 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])) _LOGGER.debug('Created cache with %s', list(hass.data[DATA_RESTORE_CACHE]))
@asyncio.coroutine
@bind_hass @bind_hass
def async_get_last_state(hass, entity_id: str): async def async_get_last_state(hass, entity_id: str):
"""Restore state.""" """Restore state."""
if DATA_RESTORE_CACHE in hass.data: if DATA_RESTORE_CACHE in hass.data:
return hass.data[DATA_RESTORE_CACHE].get(entity_id) return hass.data[DATA_RESTORE_CACHE].get(entity_id)
@ -66,7 +65,7 @@ def async_get_last_state(hass, entity_id: str):
try: try:
with async_timeout.timeout(RECORDER_TIMEOUT, loop=hass.loop): 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: except asyncio.TimeoutError:
return None return None
@ -76,25 +75,24 @@ def async_get_last_state(hass, entity_id: str):
if _LOCK not in hass.data: if _LOCK not in hass.data:
hass.data[_LOCK] = asyncio.Lock(loop=hass.loop) 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: if DATA_RESTORE_CACHE not in hass.data:
yield from hass.async_add_job( await hass.async_add_job(
_load_restore_cache, hass) _load_restore_cache, hass)
return hass.data.get(DATA_RESTORE_CACHE, {}).get(entity_id) return hass.data.get(DATA_RESTORE_CACHE, {}).get(entity_id)
@asyncio.coroutine async def async_restore_state(entity, extract_info):
def async_restore_state(entity, extract_info):
"""Call entity.async_restore_state with cached info.""" """Call entity.async_restore_state with cached info."""
if entity.hass.state not in (CoreState.starting, CoreState.not_running): if entity.hass.state not in (CoreState.starting, CoreState.not_running):
_LOGGER.debug("Not restoring state for %s: Hass is not starting: %s", _LOGGER.debug("Not restoring state for %s: Hass is not starting: %s",
entity.entity_id, entity.hass.state) entity.entity_id, entity.hass.state)
return 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: if not state:
return 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.""" """Helpers to execute scripts."""
import asyncio
import logging import logging
from itertools import islice from itertools import islice
from typing import Optional, Sequence from typing import Optional, Sequence
@ -68,8 +68,7 @@ class Script():
run_coroutine_threadsafe( run_coroutine_threadsafe(
self.async_run(variables), self.hass.loop).result() self.async_run(variables), self.hass.loop).result()
@asyncio.coroutine async def async_run(self, variables: Optional[Sequence] = None) -> None:
def async_run(self, variables: Optional[Sequence] = None) -> None:
"""Run script. """Run script.
This method is a coroutine. This method is a coroutine.
@ -151,7 +150,7 @@ class Script():
self._async_fire_event(action, variables) self._async_fire_event(action, variables)
else: else:
yield from self._async_call_service(action, variables) await self._async_call_service(action, variables)
self._cur = -1 self._cur = -1
self.last_action = None self.last_action = None
@ -172,15 +171,14 @@ class Script():
if self._change_listener: if self._change_listener:
self.hass.async_add_job(self._change_listener) self.hass.async_add_job(self._change_listener)
@asyncio.coroutine async def _async_call_service(self, action, variables):
def _async_call_service(self, action, variables):
"""Call the service specified in the action. """Call the service specified in the action.
This method is a coroutine. This method is a coroutine.
""" """
self.last_action = action.get(CONF_ALIAS, 'call service') self.last_action = action.get(CONF_ALIAS, 'call service')
self._log("Executing step %s" % self.last_action) 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) self.hass, action, True, variables, validate_config=False)
def _async_fire_event(self, action, variables): def _async_fire_event(self, action, variables):

View File

@ -1,5 +1,4 @@
"""Service calling related helpers.""" """Service calling related helpers."""
import asyncio
import logging import logging
# pylint: disable=unused-import # pylint: disable=unused-import
from typing import Optional # NOQA from typing import Optional # NOQA
@ -36,10 +35,9 @@ def call_from_config(hass, config, blocking=False, variables=None,
validate_config), hass.loop).result() validate_config), hass.loop).result()
@asyncio.coroutine
@bind_hass @bind_hass
def async_call_from_config(hass, config, blocking=False, variables=None, async def async_call_from_config(hass, config, blocking=False, variables=None,
validate_config=True): validate_config=True):
"""Call a service based on a config hash.""" """Call a service based on a config hash."""
if validate_config: if validate_config:
try: try:
@ -79,7 +77,7 @@ def async_call_from_config(hass, config, blocking=False, variables=None,
if CONF_SERVICE_ENTITY_ID in config: if CONF_SERVICE_ENTITY_ID in config:
service_data[ATTR_ENTITY_ID] = config[CONF_SERVICE_ENTITY_ID] 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) domain, service_name, service_data, blocking)
@ -115,9 +113,8 @@ def extract_entity_ids(hass, service_call, expand_group=True):
return service_ent_id return service_ent_id
@asyncio.coroutine
@bind_hass @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.""" """Return descriptions (i.e. user documentation) for all service calls."""
if SERVICE_DESCRIPTION_CACHE not in hass.data: if SERVICE_DESCRIPTION_CACHE not in hass.data:
hass.data[SERVICE_DESCRIPTION_CACHE] = {} hass.data[SERVICE_DESCRIPTION_CACHE] = {}
@ -156,7 +153,7 @@ def async_get_all_descriptions(hass):
break break
if missing: 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 # Build response
catch_all_yaml_file = domain_yaml_file(ha.DOMAIN) 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() async_reproduce_state(hass, states, blocking), hass.loop).result()
@asyncio.coroutine
@bind_hass @bind_hass
def async_reproduce_state(hass, states, blocking=False): async def async_reproduce_state(hass, states, blocking=False):
"""Reproduce given state.""" """Reproduce given state."""
if isinstance(states, State): if isinstance(states, State):
states = [states] states = [states]
@ -193,16 +192,15 @@ def async_reproduce_state(hass, states, blocking=False):
hass.services.async_call(service_domain, service, data, blocking) hass.services.async_call(service_domain, service, data, blocking)
) )
@asyncio.coroutine async def async_handle_service_calls(coro_list):
def async_handle_service_calls(coro_list):
"""Handle service calls by domain sequence.""" """Handle service calls by domain sequence."""
for coro in coro_list: for coro in coro_list:
yield from coro await coro
execute_tasks = [async_handle_service_calls(coro_list) execute_tasks = [async_handle_service_calls(coro_list)
for coro_list in domain_tasks.values()] for coro_list in domain_tasks.values()]
if execute_tasks: 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): def state_as_number(state):

View File

@ -11,8 +11,7 @@ CONSTRAINT_FILE = 'package_constraints.txt'
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@asyncio.coroutine async def async_process_requirements(hass, name, requirements):
def async_process_requirements(hass, name, requirements):
"""Install the requirements for a component or platform. """Install the requirements for a component or platform.
This method is a coroutine. This method is a coroutine.
@ -24,9 +23,9 @@ def async_process_requirements(hass, name, requirements):
pip_install = partial(pkg_util.install_package, pip_install = partial(pkg_util.install_package,
**pip_kwargs(hass.config.config_dir)) **pip_kwargs(hass.config.config_dir))
with (yield from pip_lock): async with pip_lock:
for req in requirements: 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: if not ret:
_LOGGER.error("Not initializing %s because could not install " _LOGGER.error("Not initializing %s because could not install "
"requirement %s", name, req) "requirement %s", name, req)

View File

@ -50,8 +50,7 @@ def benchmark(func):
@benchmark @benchmark
@asyncio.coroutine async def async_million_events(hass):
def async_million_events(hass):
"""Run a million events.""" """Run a million events."""
count = 0 count = 0
event_name = 'benchmark_event' event_name = 'benchmark_event'
@ -73,15 +72,14 @@ def async_million_events(hass):
start = timer() start = timer()
yield from event.wait() await event.wait()
return timer() - start return timer() - start
@benchmark @benchmark
@asyncio.coroutine
# pylint: disable=invalid-name # 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.""" """Run a million events through time changed helper."""
count = 0 count = 0
event = asyncio.Event(loop=hass.loop) event = asyncio.Event(loop=hass.loop)
@ -105,15 +103,14 @@ def async_million_time_changed_helper(hass):
start = timer() start = timer()
yield from event.wait() await event.wait()
return timer() - start return timer() - start
@benchmark @benchmark
@asyncio.coroutine
# pylint: disable=invalid-name # 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.""" """Run a million events through state changed helper."""
count = 0 count = 0
entity_id = 'light.kitchen' entity_id = 'light.kitchen'
@ -141,7 +138,7 @@ def async_million_state_changed_helper(hass):
start = timer() start = timer()
yield from event.wait() await event.wait()
return timer() - start return timer() - start

View File

@ -1,5 +1,5 @@
"""Script to ensure a configuration file exists.""" """Script to ensure a configuration file exists."""
import asyncio
import argparse import argparse
import logging import logging
import os import os
@ -46,8 +46,7 @@ C_HEAD = 'bold'
ERROR_STR = 'General Errors' ERROR_STR = 'General Errors'
@asyncio.coroutine async def mock_coro(*args):
def mock_coro(*args):
"""Coroutine that returns None.""" """Coroutine that returns None."""
return None return None
@ -181,8 +180,7 @@ def check(config_path):
# pylint: disable=unused-variable # pylint: disable=unused-variable
def mock_get(comp_name): def mock_get(comp_name):
"""Mock hass.loader.get_component to replace setup & setup_platform.""" """Mock hass.loader.get_component to replace setup & setup_platform."""
@asyncio.coroutine async def mock_async_setup(*args):
def mock_async_setup(*args):
"""Mock setup, only record the component name & config.""" """Mock setup, only record the component name & config."""
assert comp_name not in res['components'], \ assert comp_name not in res['components'], \
"Components should contain a list of platforms" "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() async_setup_component(hass, domain, config), loop=hass.loop).result()
@asyncio.coroutine async def async_setup_component(hass: core.HomeAssistant, domain: str,
def async_setup_component(hass: core.HomeAssistant, domain: str, config: Optional[Dict] = None) -> bool:
config: Optional[Dict] = None) -> bool:
"""Set up a component and all its dependencies. """Set up a component and all its dependencies.
This method is a coroutine. 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) setup_tasks = hass.data.get(DATA_SETUP)
if setup_tasks is not None and domain in setup_tasks: 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: if config is None:
config = {} config = {}
@ -54,11 +53,10 @@ def async_setup_component(hass: core.HomeAssistant, domain: str,
task = setup_tasks[domain] = hass.async_add_job( task = setup_tasks[domain] = hass.async_add_job(
_async_setup_component(hass, domain, config)) _async_setup_component(hass, domain, config))
return (yield from task) return await task
@asyncio.coroutine async def _async_process_dependencies(hass, config, name, dependencies):
def _async_process_dependencies(hass, config, name, dependencies):
"""Ensure all dependencies are set up.""" """Ensure all dependencies are set up."""
blacklisted = [dep for dep in dependencies blacklisted = [dep for dep in dependencies
if dep in loader.DEPENDENCY_BLACKLIST] if dep in loader.DEPENDENCY_BLACKLIST]
@ -75,7 +73,7 @@ def _async_process_dependencies(hass, config, name, dependencies):
if not tasks: if not tasks:
return True 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 failed = [dependencies[idx] for idx, res
in enumerate(results) if not res] in enumerate(results) if not res]
@ -89,9 +87,8 @@ def _async_process_dependencies(hass, config, name, dependencies):
return True return True
@asyncio.coroutine async def _async_setup_component(hass: core.HomeAssistant,
def _async_setup_component(hass: core.HomeAssistant, domain: str, config) -> bool:
domain: str, config) -> bool:
"""Set up a component for Home Assistant. """Set up a component for Home Assistant.
This method is a coroutine. This method is a coroutine.
@ -123,7 +120,7 @@ def _async_setup_component(hass: core.HomeAssistant,
return False return False
try: try:
yield from async_process_deps_reqs(hass, config, domain, component) await async_process_deps_reqs(hass, config, domain, component)
except HomeAssistantError as err: except HomeAssistantError as err:
log_error(str(err)) log_error(str(err))
return False return False
@ -142,9 +139,9 @@ def _async_setup_component(hass: core.HomeAssistant,
try: try:
if hasattr(component, 'async_setup'): if hasattr(component, 'async_setup'):
result = yield from component.async_setup(hass, processed_config) result = await component.async_setup(hass, processed_config)
else: else:
result = yield from hass.async_add_job( result = await hass.async_add_job(
component.setup, hass, processed_config) component.setup, hass, processed_config)
except Exception: # pylint: disable=broad-except except Exception: # pylint: disable=broad-except
_LOGGER.exception("Error during setup of component %s", domain) _LOGGER.exception("Error during setup of component %s", domain)
@ -166,7 +163,7 @@ def _async_setup_component(hass: core.HomeAssistant,
return False return False
for entry in hass.config_entries.async_entries(domain): 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) hass.config.components.add(component.DOMAIN)
@ -181,9 +178,8 @@ def _async_setup_component(hass: core.HomeAssistant,
return True return True
@asyncio.coroutine async def async_prepare_setup_platform(hass: core.HomeAssistant, config,
def async_prepare_setup_platform(hass: core.HomeAssistant, config, domain: str, domain: str, platform_name: str) \
platform_name: str) \
-> Optional[ModuleType]: -> Optional[ModuleType]:
"""Load a platform and makes sure dependencies are setup. """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 return platform
try: try:
yield from async_process_deps_reqs( await async_process_deps_reqs(
hass, config, platform_path, platform) hass, config, platform_path, platform)
except HomeAssistantError as err: except HomeAssistantError as err:
log_error(str(err)) log_error(str(err))
@ -218,8 +214,7 @@ def async_prepare_setup_platform(hass: core.HomeAssistant, config, domain: str,
return platform return platform
@asyncio.coroutine async def async_process_deps_reqs(hass, config, name, module):
def async_process_deps_reqs(hass, config, name, module):
"""Process all dependencies and requirements for a module. """Process all dependencies and requirements for a module.
Module is a Python module of either a component or platform. 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 return
if hasattr(module, 'DEPENDENCIES'): if hasattr(module, 'DEPENDENCIES'):
dep_success = yield from _async_process_dependencies( dep_success = await _async_process_dependencies(
hass, config, name, module.DEPENDENCIES) hass, config, name, module.DEPENDENCIES)
if not dep_success: if not dep_success:
raise HomeAssistantError("Could not setup all dependencies.") raise HomeAssistantError("Could not setup all dependencies.")
if not hass.config.skip_pip and hasattr(module, 'REQUIREMENTS'): 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) hass, name, module.REQUIREMENTS)
if not req_success: if not req_success:

View File

@ -88,17 +88,17 @@ def get_user_site(deps_dir: str) -> str:
return lib_dir return lib_dir
@asyncio.coroutine async def async_get_user_site(deps_dir: str,
def async_get_user_site(deps_dir: str, loop: asyncio.AbstractEventLoop) -> str: loop: asyncio.AbstractEventLoop) -> str:
"""Return user local library path. """Return user local library path.
This function is a coroutine. This function is a coroutine.
""" """
args, env = _get_user_site(deps_dir) 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, *args, loop=loop, stdin=asyncio.subprocess.PIPE,
stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.DEVNULL, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.DEVNULL,
env=env) env=env)
stdout, _ = yield from process.communicate() stdout, _ = await process.communicate()
lib_dir = stdout.decode().strip() lib_dir = stdout.decode().strip()
return lib_dir return lib_dir

View File

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

View File

@ -6,7 +6,6 @@ import threading
import homeassistant.util.logging as logging_util import homeassistant.util.logging as logging_util
@asyncio.coroutine
def test_sensitive_data_filter(): def test_sensitive_data_filter():
"""Test the logging sensitive data filter.""" """Test the logging sensitive data filter."""
log_filter = logging_util.HideSensitiveDataFilter('mock_sensitive') log_filter = logging_util.HideSensitiveDataFilter('mock_sensitive')