Allow components with empty list config (i.e. person) in packages (#25827)

* Fix #23424

* mypy Lists
This commit is contained in:
Johann Kellerman 2019-08-11 01:30:33 +02:00 committed by Paulus Schoutsen
parent ce0edf8360
commit 8b9d0593b1
3 changed files with 20 additions and 25 deletions

View file

@ -631,10 +631,9 @@ def _recursive_merge(conf: Dict[str, Any], package: Dict[str, Any]) -> Union[boo
error = _recursive_merge(conf=conf[key], package=pack_conf) error = _recursive_merge(conf=conf[key], package=pack_conf)
elif isinstance(pack_conf, list): elif isinstance(pack_conf, list):
if not pack_conf: conf[key] = cv.remove_falsy(
continue cv.ensure_list(conf.get(key)) + cv.ensure_list(pack_conf)
conf[key] = cv.ensure_list(conf.get(key)) )
conf[key].extend(cv.ensure_list(pack_conf))
else: else:
if conf.get(key) is not None: if conf.get(key) is not None:
@ -669,22 +668,17 @@ async def merge_packages_config(
_log_pkg_error(pack_name, comp_name, config, str(ex)) _log_pkg_error(pack_name, comp_name, config, str(ex))
continue continue
if hasattr(component, "PLATFORM_SCHEMA"): merge_list = hasattr(component, "PLATFORM_SCHEMA")
if not comp_conf:
continue # Ensure we dont add Falsy items to list
config[comp_name] = cv.ensure_list(config.get(comp_name))
config[comp_name].extend(cv.ensure_list(comp_conf))
continue
if hasattr(component, "CONFIG_SCHEMA"): if not merge_list and hasattr(component, "CONFIG_SCHEMA"):
merge_type, _ = _identify_config_schema(component) merge_type, _ = _identify_config_schema(component)
merge_list = merge_type == "list"
if merge_type == "list": if merge_list:
if not comp_conf: config[comp_name] = cv.remove_falsy(
continue # Ensure we dont add Falsy items to list cv.ensure_list(config.get(comp_name)) + cv.ensure_list(comp_conf)
config[comp_name] = cv.ensure_list(config.get(comp_name)) )
config[comp_name].extend(cv.ensure_list(comp_conf)) continue
continue
if comp_conf is None: if comp_conf is None:
comp_conf = OrderedDict() comp_conf = OrderedDict()

View file

@ -11,7 +11,7 @@ from datetime import (
) )
from socket import _GLOBAL_DEFAULT_TIMEOUT from socket import _GLOBAL_DEFAULT_TIMEOUT
from numbers import Number from numbers import Number
from typing import Any, Union, TypeVar, Callable, Sequence, Dict, Optional from typing import Any, Union, TypeVar, Callable, List, Dict, Optional
from urllib.parse import urlparse from urllib.parse import urlparse
from uuid import UUID from uuid import UUID
@ -191,7 +191,7 @@ def isdir(value: Any) -> str:
return dir_in return dir_in
def ensure_list(value: Union[T, Sequence[T], None]) -> Sequence[T]: def ensure_list(value: Union[T, List[T], None]) -> List[T]:
"""Wrap value in list if it is not one.""" """Wrap value in list if it is not one."""
if value is None: if value is None:
return [] return []
@ -207,7 +207,7 @@ def entity_id(value: Any) -> str:
raise vol.Invalid("Entity ID {} is an invalid entity id".format(value)) raise vol.Invalid("Entity ID {} is an invalid entity id".format(value))
def entity_ids(value: Union[str, Sequence]) -> Sequence[str]: def entity_ids(value: Union[str, List]) -> List[str]:
"""Validate Entity IDs.""" """Validate Entity IDs."""
if value is None: if value is None:
raise vol.Invalid("Entity IDs can not be None") raise vol.Invalid("Entity IDs can not be None")
@ -234,7 +234,7 @@ def entity_domain(domain: str):
def entities_domain(domain: str): def entities_domain(domain: str):
"""Validate that entities belong to domain.""" """Validate that entities belong to domain."""
def validate(values: Union[str, Sequence]) -> Sequence[str]: def validate(values: Union[str, List]) -> List[str]:
"""Test if entity domain is domain.""" """Test if entity domain is domain."""
values = entity_ids(values) values = entity_ids(values)
for ent_id in values: for ent_id in values:
@ -370,7 +370,7 @@ def positive_timedelta(value: timedelta) -> timedelta:
return value return value
def remove_falsy(value: Sequence[T]) -> Sequence[T]: def remove_falsy(value: List[T]) -> List[T]:
"""Remove falsy values from a list.""" """Remove falsy values from a list."""
return [v for v in value if v] return [v for v in value if v]
@ -562,7 +562,7 @@ def uuid4_hex(value):
return result.hex return result.hex
def ensure_list_csv(value: Any) -> Sequence: def ensure_list_csv(value: Any) -> List:
"""Ensure that input is a list or make one from comma-separated string.""" """Ensure that input is a list or make one from comma-separated string."""
if isinstance(value, str): if isinstance(value, str):
return [member.strip() for member in value.split(",")] return [member.strip() for member in value.split(",")]

View file

@ -735,7 +735,7 @@ async def test_merge_once_only_lists(hass):
"""Test if we have a merge for a comp that may occur only once. Lists.""" """Test if we have a merge for a comp that may occur only once. Lists."""
packages = { packages = {
"pack_2": { "pack_2": {
"api": {"list_1": ["item_2", "item_3"], "list_2": ["item_1"], "list_3": []} "api": {"list_1": ["item_2", "item_3"], "list_2": ["item_4"], "list_3": []}
} }
} }
config = { config = {
@ -745,7 +745,8 @@ async def test_merge_once_only_lists(hass):
await config_util.merge_packages_config(hass, config, packages) await config_util.merge_packages_config(hass, config, packages)
assert config["api"] == { assert config["api"] == {
"list_1": ["item_1", "item_2", "item_3"], "list_1": ["item_1", "item_2", "item_3"],
"list_2": ["item_1"], "list_2": ["item_4"],
"list_3": [],
} }