diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py index 179c819f611..e0664ee5b6e 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -27,7 +27,6 @@ from homeassistant.helpers import ( event_decorators, service, config_per_platform, extract_domain_configs) _LOGGER = logging.getLogger(__name__) -_CURRENT_SETUP = [] ATTR_COMPONENT = 'component' @@ -102,30 +101,37 @@ def _async_setup_component(hass: core.HomeAssistant, """ # pylint: disable=too-many-return-statements,too-many-branches # pylint: disable=too-many-statements - if not hasattr(hass, 'setup_lock'): - hass.setup_lock = asyncio.Lock(loop=hass.loop) - if domain in hass.config.components: return True - did_lock = False - if not hass.setup_lock.locked(): - yield from hass.setup_lock.acquire() - did_lock = True + setup_lock = hass.data.get('setup_lock') + if setup_lock is None: + setup_lock = hass.data['setup_lock'] = asyncio.Lock(loop=hass.loop) + + setup_progress = hass.data.get('setup_progress') + if setup_progress is None: + setup_progress = hass.data['setup_progress'] = [] + + if domain in setup_progress: + _LOGGER.error('Attempt made to setup %s during setup of %s', + domain, domain) + return False try: - if domain in _CURRENT_SETUP: - _LOGGER.error('Attempt made to setup %s during setup of %s', - domain, domain) - return False + # Used to indicate to discovery that a setup is ongoing and allow it + # to wait till it is done. + did_lock = False + if not setup_lock.locked(): + yield from setup_lock.acquire() + did_lock = True + setup_progress.append(domain) config = yield from async_prepare_setup_component(hass, config, domain) if config is None: return False component = loader.get_component(domain) - _CURRENT_SETUP.append(domain) try: if hasattr(component, 'async_setup'): @@ -133,20 +139,18 @@ def _async_setup_component(hass: core.HomeAssistant, else: result = yield from hass.loop.run_in_executor( None, component.setup, hass, config) - - if result is False: - _LOGGER.error('component %s failed to initialize', domain) - return False - elif result is not True: - _LOGGER.error('component %s did not return boolean if setup ' - 'was successful. Disabling component.', domain) - loader.set_component(domain, None) - return False except Exception: # pylint: disable=broad-except _LOGGER.exception('Error during setup of component %s', domain) return False - finally: - _CURRENT_SETUP.remove(domain) + + if result is False: + _LOGGER.error('component %s failed to initialize', domain) + return False + elif result is not True: + _LOGGER.error('component %s did not return boolean if setup ' + 'was successful. Disabling component.', domain) + loader.set_component(domain, None) + return False hass.config.components.append(component.DOMAIN) @@ -162,8 +166,9 @@ def _async_setup_component(hass: core.HomeAssistant, return True finally: + setup_progress.remove(domain) if did_lock: - hass.setup_lock.release() + setup_lock.release() def prepare_setup_component(hass: core.HomeAssistant, config: dict, diff --git a/homeassistant/core.py b/homeassistant/core.py index f6743a40ef5..d8720f26cd5 100644 --- a/homeassistant/core.py +++ b/homeassistant/core.py @@ -141,6 +141,8 @@ class HomeAssistant(object): self.services = ServiceRegistry(self.bus, self.add_job, self.loop) self.states = StateMachine(self.bus, self.loop) self.config = Config() # type: Config + # This is a dictionary that any component can store any data on. + self.data = {} self.state = CoreState.not_running self.exit_code = None self._websession = None diff --git a/homeassistant/helpers/discovery.py b/homeassistant/helpers/discovery.py index de432804e9c..551aabc1573 100644 --- a/homeassistant/helpers/discovery.py +++ b/homeassistant/helpers/discovery.py @@ -113,9 +113,10 @@ def async_load_platform(hass, component, platform, discovered=None, This method is a coroutine. """ did_lock = False - if hasattr(hass, 'setup_lock') and hass.setup_lock.locked(): + setup_lock = hass.data.get('setup_lock') + if setup_lock and setup_lock.locked(): did_lock = True - yield from hass.setup_lock.acquire() + yield from setup_lock.acquire() try: # No need to fire event if we could not setup component @@ -123,7 +124,7 @@ def async_load_platform(hass, component, platform, discovered=None, hass, component, hass_config) finally: if did_lock: - hass.setup_lock.release() + setup_lock.release() if not res: return diff --git a/homeassistant/remote.py b/homeassistant/remote.py index 94ac2899c69..42afa91170c 100644 --- a/homeassistant/remote.py +++ b/homeassistant/remote.py @@ -134,9 +134,11 @@ class HomeAssistant(ha.HomeAssistant): self.services = ha.ServiceRegistry(self.bus, self.add_job, self.loop) self.states = StateMachine(self.bus, self.loop, self.remote_api) self.config = ha.Config() - self._websession = None - + # This is a dictionary that any component can store any data on. + self.data = {} self.state = ha.CoreState.not_running + self.exit_code = None + self._websession = None self.config.api = local_api def start(self): diff --git a/tests/helpers/test_discovery.py b/tests/helpers/test_discovery.py index 6851874ca37..a81db2074fb 100644 --- a/tests/helpers/test_discovery.py +++ b/tests/helpers/test_discovery.py @@ -138,7 +138,7 @@ class TestHelpersDiscovery: # We wait for the setup_lock to finish run_coroutine_threadsafe( - self.hass.setup_lock.acquire(), self.hass.loop).result() + self.hass.data['setup_lock'].acquire(), self.hass.loop).result() self.hass.block_till_done()