diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py index a7476162265..2ba0681c2d6 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -22,6 +22,7 @@ from homeassistant.const import ( CONF_CUSTOMIZE, CONF_LATITUDE, CONF_LONGITUDE, CONF_NAME, CONF_TEMPERATURE_UNIT, CONF_TIME_ZONE, EVENT_COMPONENT_LOADED, TEMP_CELCIUS, TEMP_FAHRENHEIT, PLATFORM_FORMAT, __version__) +from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import ( event_decorators, service, config_per_platform, extract_domain_configs) from homeassistant.helpers.entity import Entity @@ -293,7 +294,10 @@ def from_config_file(config_path, hass=None, verbose=False, daemon=False, enable_logging(hass, verbose, daemon, log_rotate_days) - config_dict = config_util.load_yaml_config_file(config_path) + try: + config_dict = config_util.load_yaml_config_file(config_path) + except HomeAssistantError: + return None return from_config_dict(config_dict, hass, enable_log=False, skip_pip=skip_pip) diff --git a/homeassistant/components/device_tracker/__init__.py b/homeassistant/components/device_tracker/__init__.py index 240ac532e5c..1866e972e28 100644 --- a/homeassistant/components/device_tracker/__init__.py +++ b/homeassistant/components/device_tracker/__init__.py @@ -204,6 +204,7 @@ class DeviceTracker(object): return # If no device can be found, create it + dev_id = util.ensure_unique_string(dev_id, self.devices.keys()) device = Device( self.hass, self.consider_home, self.home_range, self.track_new, dev_id, mac, (host_name or dev_id).replace('_', ' ')) diff --git a/homeassistant/const.py b/homeassistant/const.py index 9bb3d3fba7a..349a820dfc1 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ # coding: utf-8 """Constants used by Home Assistant components.""" -__version__ = "0.17.1" +__version__ = "0.17.2" REQUIRED_PYTHON_VER = (3, 4) PLATFORM_FORMAT = '{}.{}' diff --git a/homeassistant/util/yaml.py b/homeassistant/util/yaml.py index b60d81fae55..1c9ff8c1c16 100644 --- a/homeassistant/util/yaml.py +++ b/homeassistant/util/yaml.py @@ -29,10 +29,9 @@ def load_yaml(fname): # If configuration file is empty YAML returns None # We convert that to an empty dict return yaml.load(conf_file, Loader=SafeLineLoader) or {} - except yaml.YAMLError: - error = 'Error reading YAML configuration file {}'.format(fname) - _LOGGER.exception(error) - raise HomeAssistantError(error) + except yaml.YAMLError as exc: + _LOGGER.error(exc) + raise HomeAssistantError(exc) def _include_yaml(loader, node): @@ -55,9 +54,12 @@ def _ordered_dict(loader, node): line = getattr(node, '__line__', 'unknown') if key in seen: fname = getattr(loader.stream, 'name', '') - raise yaml.YAMLError("ERROR: duplicate key: \"{}\"" - " in {} line {} and {}" - .format(key, fname, seen[key], line)) + first_mark = yaml.Mark(fname, 0, seen[key], -1, None, None) + second_mark = yaml.Mark(fname, 0, line, -1, None, None) + raise yaml.MarkedYAMLError( + context="duplicate key: \"{}\"".format(key), + context_mark=first_mark, problem_mark=second_mark, + ) seen[key] = line return OrderedDict(nodes) diff --git a/tests/components/device_tracker/test_init.py b/tests/components/device_tracker/test_init.py index 8cd3df96198..fb6b5240f95 100644 --- a/tests/components/device_tracker/test_init.py +++ b/tests/components/device_tracker/test_init.py @@ -197,3 +197,16 @@ class TestComponentsDeviceTracker(unittest.TestCase): mock_see.assert_called_once_with( mac=mac, dev_id=dev_id, host_name=host_name, location_name=location_name, gps=gps) + + def test_not_write_duplicate_yaml_keys(self): + """Test that the device tracker will not generate invalid YAML.""" + self.assertTrue(device_tracker.setup(self.hass, {})) + + device_tracker.see(self.hass, 'mac_1', host_name='hello') + device_tracker.see(self.hass, 'mac_2', host_name='hello') + + self.hass.pool.block_till_done() + + config = device_tracker.load_config(self.yaml_devices, self.hass, + timedelta(seconds=0), 0) + assert len(config) == 2