Handle circular setup dependency
This commit is contained in:
parent
4c538c718b
commit
1bfea626ff
3 changed files with 63 additions and 40 deletions
|
@ -1,13 +1,4 @@
|
|||
"""
|
||||
homeassistant.bootstrap
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Provides methods to bootstrap a home assistant instance.
|
||||
|
||||
Each method will return a tuple (bus, statemachine).
|
||||
|
||||
After bootstrapping you can add your own components or
|
||||
start by calling homeassistant.start_home_assistant(bus)
|
||||
"""
|
||||
"""Provides methods to bootstrap a home assistant instance."""
|
||||
|
||||
import logging
|
||||
import logging.handlers
|
||||
|
@ -15,6 +6,7 @@ import os
|
|||
import shutil
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
from threading import RLock
|
||||
|
||||
import homeassistant.components as core_components
|
||||
import homeassistant.components.group as group
|
||||
|
@ -32,6 +24,8 @@ from homeassistant.helpers import event_decorators, service
|
|||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
_SETUP_LOCK = RLock()
|
||||
_CURRENT_SETUP = []
|
||||
|
||||
ATTR_COMPONENT = 'component'
|
||||
|
||||
|
@ -79,10 +73,21 @@ def _handle_requirements(hass, component, name):
|
|||
|
||||
def _setup_component(hass, domain, config):
|
||||
"""Setup a component for Home Assistant."""
|
||||
# pylint: disable=too-many-return-statements
|
||||
if domain in hass.config.components:
|
||||
return True
|
||||
component = loader.get_component(domain)
|
||||
|
||||
with _SETUP_LOCK:
|
||||
# It might have been loaded while waiting for lock
|
||||
if domain in hass.config.components:
|
||||
return True
|
||||
|
||||
if domain in _CURRENT_SETUP:
|
||||
_LOGGER.error('Attempt made to setup %s during setup of %s',
|
||||
domain, domain)
|
||||
return False
|
||||
|
||||
component = loader.get_component(domain)
|
||||
missing_deps = [dep for dep in getattr(component, 'DEPENDENCIES', [])
|
||||
if dep not in hass.config.components]
|
||||
|
||||
|
@ -95,6 +100,8 @@ def _setup_component(hass, domain, config):
|
|||
if not _handle_requirements(hass, component, domain):
|
||||
return False
|
||||
|
||||
_CURRENT_SETUP.append(domain)
|
||||
|
||||
try:
|
||||
if not component.setup(hass, config):
|
||||
_LOGGER.error('component %s failed to initialize', domain)
|
||||
|
@ -102,6 +109,8 @@ def _setup_component(hass, domain, config):
|
|||
except Exception: # pylint: disable=broad-except
|
||||
_LOGGER.exception('Error during setup of component %s', domain)
|
||||
return False
|
||||
finally:
|
||||
_CURRENT_SETUP.remove(domain)
|
||||
|
||||
hass.config.components.append(component.DOMAIN)
|
||||
|
||||
|
|
|
@ -146,7 +146,7 @@ class MockModule(object):
|
|||
self.DEPENDENCIES = dependencies
|
||||
# Setup a mock setup if none given.
|
||||
if setup is None:
|
||||
self.setup = lambda hass, config: False
|
||||
self.setup = lambda hass, config: True
|
||||
else:
|
||||
self.setup = setup
|
||||
|
||||
|
|
|
@ -9,13 +9,13 @@ import os
|
|||
import tempfile
|
||||
import unittest
|
||||
|
||||
from homeassistant import bootstrap
|
||||
from homeassistant import bootstrap, loader
|
||||
from homeassistant.const import (__version__, CONF_LATITUDE, CONF_LONGITUDE,
|
||||
CONF_NAME, CONF_CUSTOMIZE)
|
||||
import homeassistant.util.dt as dt_util
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
from tests.common import get_test_home_assistant
|
||||
from tests.common import get_test_home_assistant, MockModule
|
||||
|
||||
|
||||
class TestBootstrap(unittest.TestCase):
|
||||
|
@ -102,3 +102,17 @@ class TestBootstrap(unittest.TestCase):
|
|||
state = hass.states.get('test.test')
|
||||
|
||||
self.assertTrue(state.attributes['hidden'])
|
||||
|
||||
def test_handle_setup_circular_dependency(self):
|
||||
hass = get_test_home_assistant()
|
||||
|
||||
loader.set_component('comp_b', MockModule('comp_b', ['comp_a']))
|
||||
|
||||
def setup_a(hass, config):
|
||||
bootstrap.setup_component(hass, 'comp_b')
|
||||
return True
|
||||
|
||||
loader.set_component('comp_a', MockModule('comp_a', setup=setup_a))
|
||||
|
||||
bootstrap.setup_component(hass, 'comp_a')
|
||||
self.assertEqual(['comp_a'], hass.config.components)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue