Example #1
0
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()
Example #3
0
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()
Example #4
0
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()
Example #5
0
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()
Example #6
0
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()
Example #7
0
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)
Example #9
0
    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)
Example #10
0
    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))
Example #11
0
    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)
Example #13
0
    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))
Example #14
0
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
Example #15
0
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
Example #16
0
    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)
Example #17
0
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
Example #18
0
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()
Example #19
0
    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
Example #20
0
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
Example #21
0
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()
Example #22
0
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()
Example #23
0
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
Example #24
0
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
Example #25
0
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)