def main(): """ Starts Home Assistant. Will create demo config if no config found. """ # Do we want to run the tests? if ARG_RUN_TESTS in sys.argv: sys.argv.remove(ARG_RUN_TESTS) import unittest unittest.main(module='homeassistant.test') # Within Docker we load the config from a different path if ARG_DOCKER in sys.argv: config_path = '/config/home-assistant.conf' else: config_path = 'config/home-assistant.conf' # Ensure a config file exists to make first time usage easier if not os.path.isfile(config_path): with open(config_path, 'w') as conf: conf.write("[http]\n") conf.write("api_password=password\n\n") conf.write("[demo]\n") hass = bootstrap.from_config_file(config_path) hass.start() hass.block_till_stopped()
def main(): """ Starts Home Assistant. """ args = get_arguments() config_dir = os.path.join(os.getcwd(), args.config) ensure_config_path(config_dir) if args.demo_mode: hass = bootstrap.from_config_dict({ 'frontend': {}, 'demo': {} }, config_dir=config_dir) else: config_file = ensure_config_file(config_dir) hass = bootstrap.from_config_file(config_file) if args.open_ui: def open_browser(event): """ Open the webinterface in a browser. """ if hass.config.api is not None: import webbrowser webbrowser.open(hass.config.api.base_url) hass.bus.listen_once(EVENT_HOMEASSISTANT_START, open_browser) hass.start() hass.block_till_stopped()
def main(): """ Starts Home Assistant. """ validate_python() validate_dependencies() bootstrap = ensure_path_and_load_bootstrap() validate_git_submodules() args = get_arguments() config_dir = os.path.join(os.getcwd(), args.config) config_path = ensure_config_path(config_dir) if args.demo_mode: from homeassistant.components import http, demo # Demo mode only requires http and demo components. hass = bootstrap.from_config_dict({http.DOMAIN: {}, demo.DOMAIN: {}}) else: hass = bootstrap.from_config_file(config_path) if args.open_ui: from homeassistant.const import EVENT_HOMEASSISTANT_START def open_browser(event): """ Open the webinterface in a browser. """ if hass.local_api is not None: import webbrowser webbrowser.open(hass.local_api.base_url) hass.bus.listen_once(EVENT_HOMEASSISTANT_START, open_browser) hass.start() hass.block_till_stopped()
def main(): """ Starts Home Assistant. """ validate_python() args = get_arguments() config_dir = os.path.join(os.getcwd(), args.config) ensure_config_path(config_dir) # os x launchd functions if args.install_osx: install_osx() return if args.uninstall_osx: uninstall_osx() return if args.restart_osx: uninstall_osx() install_osx() return # daemon functions if args.pid_file: check_pid(args.pid_file) if args.daemon: daemonize() if args.pid_file: write_pid(args.pid_file) if args.demo_mode: config = { 'frontend': {}, 'demo': {} } hass = bootstrap.from_config_dict( config, config_dir=config_dir, daemon=args.daemon, verbose=args.verbose, skip_pip=args.skip_pip, log_rotate_days=args.log_rotate_days) else: config_file = ensure_config_file(config_dir) print('Config directory:', config_dir) hass = bootstrap.from_config_file( config_file, daemon=args.daemon, verbose=args.verbose, skip_pip=args.skip_pip, log_rotate_days=args.log_rotate_days) if args.open_ui: def open_browser(event): """ Open the webinterface in a browser. """ if hass.config.api is not None: import webbrowser webbrowser.open(hass.config.api.base_url) hass.bus.listen_once(EVENT_HOMEASSISTANT_START, open_browser) hass.start() hass.block_till_stopped()
def setup_and_run_hass(config_dir: str, args: argparse.Namespace) -> Optional[int]: """Set up HASS and run.""" from homeassistant import bootstrap # Run a simple daemon runner process on Windows to handle restarts if os.name == 'nt' and '--runner' not in sys.argv: nt_args = cmdline() + ['--runner'] while True: try: subprocess.check_call(nt_args) sys.exit(0) except subprocess.CalledProcessError as exc: if exc.returncode != RESTART_EXIT_CODE: sys.exit(exc.returncode) if args.demo_mode: config = { 'frontend': {}, 'demo': {} } hass = bootstrap.from_config_dict( config, config_dir=config_dir, verbose=args.verbose, skip_pip=args.skip_pip, log_rotate_days=args.log_rotate_days, log_file=args.log_file, log_no_color=args.log_no_color) else: config_file = ensure_config_file(config_dir) print('Config directory:', config_dir) hass = bootstrap.from_config_file( config_file, verbose=args.verbose, skip_pip=args.skip_pip, log_rotate_days=args.log_rotate_days, log_file=args.log_file, log_no_color=args.log_no_color) if hass is None: return None if args.open_ui: # Imported here to avoid importing asyncio before monkey patch from homeassistant.util.async_ import run_callback_threadsafe def open_browser(event): """Open the webinterface in a browser.""" if hass.config.api is not None: import webbrowser webbrowser.open(hass.config.api.base_url) run_callback_threadsafe( hass.loop, hass.bus.async_listen_once, EVENT_HOMEASSISTANT_START, open_browser ) return hass.start()
def main(): """ Starts Home Assistant. Will create demo config if no config found. """ parser = argparse.ArgumentParser() parser.add_argument( '-c', '--config', metavar='path_to_config_dir', default="config", help="Directory that contains the Home Assistant configuration") args = parser.parse_args() # Validate that all core dependencies are installed import_fail = False for module in ['requests']: try: importlib.import_module(module) except ImportError: import_fail = True print( 'Fatal Error: Unable to find dependency {}'.format(module)) if import_fail: print(("Install dependencies by running: " "pip3 install -r requirements.txt")) exit() # Test if configuration directory exists config_dir = os.path.join(os.getcwd(), args.config) if not os.path.isdir(config_dir): print(('Fatal Error: Unable to find specified configuration ' 'directory {} ').format(config_dir)) sys.exit() config_path = os.path.join(config_dir, 'home-assistant.conf') # Ensure a config file exists to make first time usage easier if not os.path.isfile(config_path): try: with open(config_path, 'w') as conf: conf.write("[http]\n") conf.write("api_password=password\n\n") conf.write("[demo]\n") except IOError: print(('Fatal Error: No configuration file found and unable ' 'to write a default one to {}').format(config_path)) sys.exit() hass = bootstrap.from_config_file(config_path) hass.start() hass.block_till_stopped()
def setup_and_run_hass(config_dir: str, args: argparse.Namespace) -> Optional[int]: """Set up HASS and run.""" from homeassistant import bootstrap # Run a simple daemon runner process on Windows to handle restarts if os.name == 'nt' and '--runner' not in sys.argv: nt_args = cmdline() + ['--runner'] while True: try: subprocess.check_call(nt_args) sys.exit(0) except subprocess.CalledProcessError as exc: if exc.returncode != RESTART_EXIT_CODE: sys.exit(exc.returncode) if args.demo_mode: config = { 'frontend': {}, 'demo': {} } # type: Dict[str, Any] hass = bootstrap.from_config_dict( config, config_dir=config_dir, verbose=args.verbose, skip_pip=args.skip_pip, log_rotate_days=args.log_rotate_days, log_file=args.log_file, log_no_color=args.log_no_color) else: config_file = ensure_config_file(config_dir) print('Config directory:', config_dir) hass = bootstrap.from_config_file( config_file, verbose=args.verbose, skip_pip=args.skip_pip, log_rotate_days=args.log_rotate_days, log_file=args.log_file, log_no_color=args.log_no_color) if hass is None: return None if args.open_ui: # Imported here to avoid importing asyncio before monkey patch from homeassistant.util.async_ import run_callback_threadsafe def open_browser(event): """Open the webinterface in a browser.""" if hass.config.api is not None: import webbrowser webbrowser.open(hass.config.api.base_url) run_callback_threadsafe( hass.loop, hass.bus.async_listen_once, EVENT_HOMEASSISTANT_START, open_browser ) return hass.start()
def test_from_config_file(self, mock_detect): """Test with configuration file.""" components = ['browser', 'conversation', 'script'] with tempfile.NamedTemporaryFile() as fp: for comp in components: fp.write('{}:\n'.format(comp).encode('utf-8')) fp.flush() self.hass = bootstrap.from_config_file(fp.name) components.append('group') assert sorted(components) == sorted(self.hass.config.components)
def test_from_config_file(self): components = ['browser', 'conversation', 'script'] with tempfile.NamedTemporaryFile() as fp: for comp in components: fp.write('{}:\n'.format(comp).encode('utf-8')) fp.flush() hass = bootstrap.from_config_file(fp.name) components.append('group') self.assertEqual(sorted(components), sorted(hass.config.components))
def test_from_config_file(self, mock_upgrade, mock_detect): """Test with configuration file.""" components = ['browser', 'conversation', 'script'] files = { 'config.yaml': ''.join('{}:\n'.format(comp) for comp in components) } with mock.patch('os.path.isfile', mock.Mock(return_value=True)), \ mock.patch('os.access', mock.Mock(return_value=True)), \ patch_yaml_files(files, True): self.hass = bootstrap.from_config_file('config.yaml') components.append('group') assert sorted(components) == sorted(self.hass.config.components)
def test_from_config_file(self): components = ['browser', 'conversation', 'script'] with tempfile.NamedTemporaryFile() as fp: for comp in components: fp.write('{}:\n'.format(comp).encode('utf-8')) fp.flush() with mock.patch('homeassistant.util.location.detect_location_info', mock_detect_location_info): hass = bootstrap.from_config_file(fp.name) components.append('group') self.assertEqual(sorted(components), sorted(hass.config.components))
def setup_and_run_hass(config_dir: str, args: argparse.Namespace) -> Optional[int]: """Setup HASS and run.""" from homeassistant import bootstrap # Run a simple daemon runner process on Windows to handle restarts if os.name == 'nt' and '--runner' not in sys.argv: nt_args = cmdline() + ['--runner'] while True: try: subprocess.check_call(nt_args) sys.exit(0) except subprocess.CalledProcessError as exc: if exc.returncode != RESTART_EXIT_CODE: sys.exit(exc.returncode) if args.demo_mode: config = {'frontend': {}, 'demo': {}} hass = bootstrap.from_config_dict(config, config_dir=config_dir, verbose=args.verbose, skip_pip=args.skip_pip, log_rotate_days=args.log_rotate_days) else: config_file = ensure_config_file(config_dir) print('Config directory:', config_dir) hass = bootstrap.from_config_file(config_file, verbose=args.verbose, skip_pip=args.skip_pip, log_rotate_days=args.log_rotate_days) if hass is None: return None if args.open_ui: def open_browser(event): """Open the webinterface in a browser.""" if hass.config.api is not None: import webbrowser webbrowser.open(hass.config.api.base_url) hass.bus.listen_once(EVENT_HOMEASSISTANT_START, open_browser) hass.start() exit_code = int(hass.block_till_stopped()) return exit_code
def setup_and_run_hass(config_dir, args): """Setup HASS and run.""" from homeassistant import bootstrap # Run a simple daemon runner process on Windows to handle restarts if os.name == 'nt' and '--runner' not in sys.argv: args = cmdline() + ['--runner'] while True: try: subprocess.check_call(args) sys.exit(0) except subprocess.CalledProcessError as exc: if exc.returncode != RESTART_EXIT_CODE: sys.exit(exc.returncode) if args.demo_mode: config = { 'frontend': {}, 'demo': {} } hass = bootstrap.from_config_dict( config, config_dir=config_dir, verbose=args.verbose, skip_pip=args.skip_pip, log_rotate_days=args.log_rotate_days) else: config_file = ensure_config_file(config_dir) print('Config directory:', config_dir) hass = bootstrap.from_config_file( config_file, verbose=args.verbose, skip_pip=args.skip_pip, log_rotate_days=args.log_rotate_days) if hass is None: return if args.open_ui: def open_browser(event): """Open the webinterface in a browser.""" if hass.config.api is not None: import webbrowser webbrowser.open(hass.config.api.base_url) hass.bus.listen_once(EVENT_HOMEASSISTANT_START, open_browser) print('Starting Home-Assistant') hass.start() exit_code = int(hass.block_till_stopped()) return exit_code
def test_from_config_file(self, mock_detect): """Test with configuration file.""" components = ['browser', 'conversation', 'script'] files = { 'config.yaml': ''.join( '{}:\n'.format(comp) for comp in components ) } with mock.patch('os.path.isfile', mock.Mock(return_value=True)), \ mock.patch('os.access', mock.Mock(return_value=True)), \ patch_yaml_files(files, True): self.hass = bootstrap.from_config_file('config.yaml') components.append('group') assert sorted(components) == sorted(self.hass.config.components)
def setup_and_run_hass(config_dir, args, top_process=False): """Setup HASS and run. Block until stopped. Will assume it is running in a subprocess unless top_process is set to true. """ from homeassistant import bootstrap if args.demo_mode: config = {'frontend': {}, 'demo': {}} hass = bootstrap.from_config_dict(config, config_dir=config_dir, daemon=args.daemon, verbose=args.verbose, skip_pip=args.skip_pip, log_rotate_days=args.log_rotate_days) else: config_file = ensure_config_file(config_dir) print('Config directory:', config_dir) hass = bootstrap.from_config_file(config_file, daemon=args.daemon, verbose=args.verbose, skip_pip=args.skip_pip, log_rotate_days=args.log_rotate_days) if hass is None: return if args.open_ui: def open_browser(event): """Open the webinterface in a browser.""" if hass.config.api is not None: import webbrowser webbrowser.open(hass.config.api.base_url) hass.bus.listen_once(EVENT_HOMEASSISTANT_START, open_browser) hass.start() exit_code = int(hass.block_till_stopped()) if not top_process: sys.exit(exit_code) return exit_code
def main(): """ Starts Home Assistant. """ validate_python() args = get_arguments() config_dir = os.path.join(os.getcwd(), args.config) ensure_config_path(config_dir) # daemon functions if args.pid_file: check_pid(args.pid_file) if args.daemon: daemonize() if args.pid_file: write_pid(args.pid_file) if args.demo_mode: config = { 'frontend': {}, 'demo': {} } hass = bootstrap.from_config_dict( config, config_dir=config_dir, daemon=args.daemon, verbose=args.verbose, skip_pip=args.skip_pip, log_rotate_days=args.log_rotate_days) else: config_file = ensure_config_file(config_dir) print('Config directory:', config_dir) hass = bootstrap.from_config_file( config_file, daemon=args.daemon, verbose=args.verbose, skip_pip=args.skip_pip, log_rotate_days=args.log_rotate_days) if args.open_ui: def open_browser(event): """ Open the webinterface in a browser. """ if hass.config.api is not None: import webbrowser webbrowser.open(hass.config.api.base_url) hass.bus.listen_once(EVENT_HOMEASSISTANT_START, open_browser) hass.start() hass.block_till_stopped()
def test_from_config_file(self, mock_upgrade, mock_detect, mock_signal): """Test with configuration file.""" components = set(['browser', 'conversation', 'script']) files = { 'config.yaml': ''.join( '{}:\n'.format(comp) for comp in components ) } with mock.patch('os.path.isfile', mock.Mock(return_value=True)), \ mock.patch('os.access', mock.Mock(return_value=True)), \ mock.patch('homeassistant.bootstrap.async_enable_logging', mock.Mock(return_value=True)), \ patch_yaml_files(files, True): self.hass = bootstrap.from_config_file('config.yaml') components.add('group') assert components == self.hass.config.components
def setup_and_run_hass(config_dir, args, top_process=False): """Setup HASS and run. Block until stopped. Will assume it is running in a subprocess unless top_process is set to true. """ from homeassistant import bootstrap if args.demo_mode: config = { 'frontend': {}, 'demo': {} } hass = bootstrap.from_config_dict( config, config_dir=config_dir, daemon=args.daemon, verbose=args.verbose, skip_pip=args.skip_pip, log_rotate_days=args.log_rotate_days) else: config_file = ensure_config_file(config_dir) print('Config directory:', config_dir) hass = bootstrap.from_config_file( config_file, daemon=args.daemon, verbose=args.verbose, skip_pip=args.skip_pip, log_rotate_days=args.log_rotate_days) if hass is None: return if args.open_ui: def open_browser(event): """Open the webinterface in a browser.""" if hass.config.api is not None: import webbrowser webbrowser.open(hass.config.api.base_url) hass.bus.listen_once(EVENT_HOMEASSISTANT_START, open_browser) hass.start() exit_code = int(hass.block_till_stopped()) if not top_process: sys.exit(exit_code) return exit_code
def main(): """ Starts Home Assistant. """ validate_python() validate_dependencies() # Windows needs this to pick up new modules importlib.invalidate_caches() bootstrap = ensure_path_and_load_bootstrap() validate_git_submodules() args = get_arguments() config_dir = os.path.join(os.getcwd(), args.config) config_path = ensure_config_path(config_dir) if args.demo_mode: from homeassistant.components import frontend, demo hass = bootstrap.from_config_dict({ frontend.DOMAIN: {}, demo.DOMAIN: {} }) else: hass = bootstrap.from_config_file(config_path) if args.open_ui: from homeassistant.const import EVENT_HOMEASSISTANT_START def open_browser(event): """ Open the webinterface in a browser. """ if hass.config.api is not None: import webbrowser webbrowser.open(hass.config.api.base_url) hass.bus.listen_once(EVENT_HOMEASSISTANT_START, open_browser) hass.start() hass.block_till_stopped()
def main(): """ Starts Home Assistant. Will create demo config if no config found. """ tasks = ['serve', 'test'] parser = argparse.ArgumentParser() parser.add_argument( '-c', '--config', metavar='path_to_config_dir', default="config", help="Directory that contains the Home Assistant configuration") parser.add_argument('-t', '--task', default=tasks[0], choices=tasks, help="Task to execute. Defaults to serve.") args = parser.parse_args() if args.task == tasks[1]: # unittest does not like our command line arguments, remove them sys.argv[1:] = [] import unittest unittest.main(module='homeassistant.test') else: # Validate that all core dependencies are installed import_fail = False for module in ['requests']: try: importlib.import_module(module) except ImportError: import_fail = True print( 'Fatal Error: Unable to find dependency {}'.format(module)) if import_fail: print(("Install dependencies by running: " "pip3 install -r requirements.txt")) exit() # Test if configuration directory exists config_dir = os.path.join(os.getcwd(), args.config) if not os.path.isdir(config_dir): print(('Fatal Error: Unable to find specified configuration ' 'directory {} ').format(config_dir)) sys.exit() config_path = os.path.join(config_dir, 'home-assistant.conf') # Ensure a config file exists to make first time usage easier if not os.path.isfile(config_path): try: with open(config_path, 'w') as conf: conf.write("[http]\n") conf.write("api_password=password\n\n") conf.write("[demo]\n") except IOError: print(('Fatal Error: No configuration file found and unable ' 'to write a default one to {}').format(config_path)) sys.exit() hass = bootstrap.from_config_file(config_path) hass.start() hass.block_till_stopped()
def check(config_path): """Perform a check by mocking hass load functions.""" res = { 'yaml_files': OrderedDict(), # yaml_files loaded 'secrets': OrderedDict(), # secret cache and secrets loaded 'except': OrderedDict(), # exceptions raised (with config) 'components': OrderedDict(), # successful components 'secret_cache': OrderedDict(), } # pylint: disable=unused-variable def mock_load(filename): """Mock hass.util.load_yaml to save config files.""" res['yaml_files'][filename] = True return MOCKS['load'][1](filename) # pylint: disable=unused-variable def mock_get(comp_name): """Mock hass.loader.get_component to replace setup & setup_platform.""" def mock_setup(*kwargs): """Mock setup, only record the component name & config.""" assert comp_name not in res['components'], \ "Components should contain a list of platforms" res['components'][comp_name] = kwargs[1].get(comp_name) return True module = MOCKS['get'][1](comp_name) if module is None: # Ensure list res['except'][ERROR_STR] = res['except'].get(ERROR_STR, []) res['except'][ERROR_STR].append('{} not found: {}'.format( 'Platform' if '.' in comp_name else 'Component', comp_name)) return None # Test if platform/component and overwrite setup if '.' in comp_name: module.setup_platform = mock_setup if hasattr(module, 'async_setup_platform'): del module.async_setup_platform else: module.setup = mock_setup if hasattr(module, 'async_setup'): del module.async_setup return module # pylint: disable=unused-variable def mock_secrets(ldr, node): """Mock _get_secrets.""" try: val = MOCKS['secrets'][1](ldr, node) except HomeAssistantError: val = None res['secrets'][node.value] = val return val def mock_except(ex, domain, config, # pylint: disable=unused-variable hass=None): """Mock bootstrap.log_exception.""" MOCKS['except'][1](ex, domain, config, hass) res['except'][domain] = config.get(domain, config) # Patches to skip functions for sil in SILENCE: PATCHES[sil] = patch(sil) # Patches with local mock functions for key, val in MOCKS.items(): # The * in the key is removed to find the mock_function (side_effect) # This allows us to use one side_effect to patch multiple locations mock_function = locals()['mock_' + key.replace('*', '')] PATCHES[key] = patch(val[0], side_effect=mock_function) # Start all patches for pat in PATCHES.values(): pat.start() # Ensure !secrets point to the patched function yaml.yaml.SafeLoader.add_constructor('!secret', yaml._secret_yaml) try: bootstrap.from_config_file(config_path, skip_pip=True) res['secret_cache'] = dict(yaml.__SECRET_CACHE) except Exception as err: # pylint: disable=broad-except print(color('red', 'Fatal error while loading config:'), str(err)) finally: # Stop all patches for pat in PATCHES.values(): pat.stop() # Ensure !secrets point to the original function yaml.yaml.SafeLoader.add_constructor('!secret', yaml._secret_yaml) bootstrap.clear_secret_cache() return res
def check(config_path): """Perform a check by mocking hass load functions.""" res = { 'yaml_files': OrderedDict(), # yaml_files loaded 'secrets': OrderedDict(), # secret cache and secrets loaded 'except': OrderedDict(), # exceptions raised (with config) 'components': OrderedDict(), # successful components 'secret_cache': OrderedDict(), } # pylint: disable=unused-variable def mock_load(filename): """Mock hass.util.load_yaml to save config files.""" res['yaml_files'][filename] = True return MOCKS['load'][1](filename) # pylint: disable=unused-variable def mock_get(comp_name): """Mock hass.loader.get_component to replace setup & setup_platform.""" def mock_setup(*kwargs): """Mock setup, only record the component name & config.""" assert comp_name not in res['components'], \ "Components should contain a list of platforms" res['components'][comp_name] = kwargs[1].get(comp_name) return True module = MOCKS['get'][1](comp_name) if module is None: # Ensure list msg = '{} not found: {}'.format( 'Platform' if '.' in comp_name else 'Component', comp_name) res['except'].setdefault(ERROR_STR, []).append(msg) return None # Test if platform/component and overwrite setup if '.' in comp_name: module.setup_platform = mock_setup if hasattr(module, 'async_setup_platform'): del module.async_setup_platform else: module.setup = mock_setup if hasattr(module, 'async_setup'): del module.async_setup return module # pylint: disable=unused-variable def mock_secrets(ldr, node): """Mock _get_secrets.""" try: val = MOCKS['secrets'][1](ldr, node) except HomeAssistantError: val = None res['secrets'][node.value] = val return val def mock_except( ex, domain, config, # pylint: disable=unused-variable hass=None): """Mock config.log_exception.""" MOCKS['except'][1](ex, domain, config, hass) res['except'][domain] = config.get(domain, config) def mock_package_error( # pylint: disable=unused-variable package, component, config, message): """Mock config_util._log_pkg_error.""" MOCKS['package_error'][1](package, component, config, message) pkg_key = 'homeassistant.packages.{}'.format(package) res['except'][pkg_key] = config.get('homeassistant', {}) \ .get('packages', {}).get(package) def mock_logger_exception(msg, *params): """Log logger.exceptions.""" res['except'].setdefault(ERROR_STR, []).append(msg % params) MOCKS['logger_exception'][1](msg, *params) # Patches to skip functions for sil in SILENCE: PATCHES[sil] = patch(sil) # Patches with local mock functions for key, val in MOCKS.items(): # The * in the key is removed to find the mock_function (side_effect) # This allows us to use one side_effect to patch multiple locations mock_function = locals()['mock_' + key.replace('*', '')] PATCHES[key] = patch(val[0], side_effect=mock_function) # Start all patches for pat in PATCHES.values(): pat.start() # Ensure !secrets point to the patched function yaml.yaml.SafeLoader.add_constructor('!secret', yaml._secret_yaml) try: with patch('homeassistant.util.logging.AsyncHandler._process'): bootstrap.from_config_file(config_path, skip_pip=True) res['secret_cache'] = dict(yaml.__SECRET_CACHE) except Exception as err: # pylint: disable=broad-except print(color('red', 'Fatal error while loading config:'), str(err)) res['except'].setdefault(ERROR_STR, []).append(err) finally: # Stop all patches for pat in PATCHES.values(): pat.stop() # Ensure !secrets point to the original function yaml.yaml.SafeLoader.add_constructor('!secret', yaml._secret_yaml) bootstrap.clear_secret_cache() return res
def check(config_path): """Perform a check by mocking hass load functions.""" res = { 'yaml_files': {}, # yaml_files loaded 'secrets': {}, # secret cache and secrets loaded 'except': {}, # exceptions raised (with config) 'components': {}, # successful components 'secret_cache': {}, } def mock_load(filename): # pylint: disable=unused-variable """Mock hass.util.load_yaml to save config files.""" res['yaml_files'][filename] = True return MOCKS['load'][1](filename) def mock_get(comp_name): # pylint: disable=unused-variable """Mock hass.loader.get_component to replace setup & setup_platform.""" def mock_setup(*kwargs): """Mock setup, only record the component name & config.""" assert comp_name not in res['components'], \ "Components should contain a list of platforms" res['components'][comp_name] = kwargs[1].get(comp_name) return True module = MOCKS['get'][1](comp_name) if module is None: # Ensure list res['except'][ERROR_STR] = res['except'].get(ERROR_STR, []) res['except'][ERROR_STR].append('{} not found: {}'.format( 'Platform' if '.' in comp_name else 'Component', comp_name)) return None # Test if platform/component and overwrite setup if '.' in comp_name: module.setup_platform = mock_setup else: module.setup = mock_setup return module def mock_secrets(ldr, node): # pylint: disable=unused-variable """Mock _get_secrets.""" try: val = MOCKS['secrets'][1](ldr, node) except HomeAssistantError: val = None res['secrets'][node.value] = val return val def mock_except(ex, domain, config): # pylint: disable=unused-variable """Mock bootstrap.log_exception.""" MOCKS['except'][1](ex, domain, config) res['except'][domain] = config.get(domain, config) # Patches to skip functions for sil in SILENCE: PATCHES[sil] = patch(sil) # Patches with local mock functions for key, val in MOCKS.items(): # The * in the key is removed to find the mock_function (side_effect) # This allows us to use one side_effect to patch multiple locations mock_function = locals()['mock_' + key.replace('*', '')] PATCHES[key] = patch(val[0], side_effect=mock_function) # Start all patches for pat in PATCHES.values(): pat.start() # Ensure !secrets point to the patched function yaml.yaml.SafeLoader.add_constructor('!secret', yaml._secret_yaml) try: bootstrap.from_config_file(config_path, skip_pip=True) res['secret_cache'] = yaml.__SECRET_CACHE return res finally: # Stop all patches for pat in PATCHES.values(): pat.stop() # Ensure !secrets point to the original function yaml.yaml.SafeLoader.add_constructor('!secret', yaml._secret_yaml)