Move config_per_platform and extract_domain_configs to config.py (#104989)

This commit is contained in:
Erik Montnemery 2023-12-04 12:48:49 +01:00 committed by GitHub
parent 53becaa976
commit 95f7db1970
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 138 additions and 51 deletions

View file

@ -11,7 +11,7 @@ from voluptuous.humanize import humanize_error
from homeassistant.components import blueprint from homeassistant.components import blueprint
from homeassistant.components.trace import TRACE_CONFIG_SCHEMA from homeassistant.components.trace import TRACE_CONFIG_SCHEMA
from homeassistant.config import config_without_domain from homeassistant.config import config_per_platform, config_without_domain
from homeassistant.const import ( from homeassistant.const import (
CONF_ALIAS, CONF_ALIAS,
CONF_CONDITION, CONF_CONDITION,
@ -21,7 +21,7 @@ from homeassistant.const import (
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_per_platform, config_validation as cv, script from homeassistant.helpers import config_validation as cv, script
from homeassistant.helpers.condition import async_validate_conditions_config from homeassistant.helpers.condition import async_validate_conditions_config
from homeassistant.helpers.trigger import async_validate_trigger_config from homeassistant.helpers.trigger import async_validate_trigger_config
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType

View file

@ -14,7 +14,11 @@ import voluptuous as vol
from homeassistant import util from homeassistant import util
from homeassistant.backports.functools import cached_property from homeassistant.backports.functools import cached_property
from homeassistant.components import zone from homeassistant.components import zone
from homeassistant.config import async_log_schema_error, load_yaml_config_file from homeassistant.config import (
async_log_schema_error,
config_per_platform,
load_yaml_config_file,
)
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_ENTITY_ID,
ATTR_GPS_ACCURACY, ATTR_GPS_ACCURACY,
@ -33,7 +37,6 @@ from homeassistant.const import (
from homeassistant.core import Event, HomeAssistant, ServiceCall, callback from homeassistant.core import Event, HomeAssistant, ServiceCall, callback
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import ( from homeassistant.helpers import (
config_per_platform,
config_validation as cv, config_validation as cv,
discovery, discovery,
entity_registry as er, entity_registry as er,

View file

@ -30,11 +30,7 @@ from homeassistant.core import (
callback, callback,
) )
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
from homeassistant.helpers import ( from homeassistant.helpers import config_validation as cv, entity_platform
config_per_platform,
config_validation as cv,
entity_platform,
)
from homeassistant.helpers.entity_platform import AddEntitiesCallback, EntityPlatform from homeassistant.helpers.entity_platform import AddEntitiesCallback, EntityPlatform
from homeassistant.helpers.service import ( from homeassistant.helpers.service import (
async_extract_entity_ids, async_extract_entity_ids,
@ -208,7 +204,7 @@ async def async_setup_platform(
await platform.async_reset() await platform.async_reset()
# Extract only the config for the Home Assistant platform, ignore the rest. # Extract only the config for the Home Assistant platform, ignore the rest.
for p_type, p_config in config_per_platform(conf, SCENE_DOMAIN): for p_type, p_config in conf_util.config_per_platform(conf, SCENE_DOMAIN):
if p_type != HA_DOMAIN: if p_type != HA_DOMAIN:
continue continue

View file

@ -13,13 +13,10 @@ from aiohttp.web_exceptions import HTTPNotFound
from homeassistant.components import frontend from homeassistant.components import frontend
from homeassistant.components.http import HomeAssistantView from homeassistant.components.http import HomeAssistantView
from homeassistant.config import config_per_platform
from homeassistant.core import Event, HomeAssistant, callback from homeassistant.core import Event, HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import ( from homeassistant.helpers import config_validation as cv, discovery
config_per_platform,
config_validation as cv,
discovery,
)
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity_component import EntityComponent from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType

View file

@ -6,10 +6,11 @@ from collections.abc import Callable, Coroutine, Mapping
from functools import partial from functools import partial
from typing import Any, Protocol, cast from typing import Any, Protocol, cast
from homeassistant.config import config_per_platform
from homeassistant.const import CONF_DESCRIPTION, CONF_NAME from homeassistant.const import CONF_DESCRIPTION, CONF_NAME
from homeassistant.core import HomeAssistant, ServiceCall, callback from homeassistant.core import HomeAssistant, ServiceCall, callback
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_per_platform, discovery from homeassistant.helpers import discovery
from homeassistant.helpers.service import async_set_service_schema from homeassistant.helpers.service import async_set_service_schema
from homeassistant.helpers.template import Template from homeassistant.helpers.template import Template
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType

View file

@ -13,7 +13,7 @@ from homeassistant.components.blueprint import (
is_blueprint_instance_config, is_blueprint_instance_config,
) )
from homeassistant.components.trace import TRACE_CONFIG_SCHEMA from homeassistant.components.trace import TRACE_CONFIG_SCHEMA
from homeassistant.config import config_without_domain from homeassistant.config import config_per_platform, config_without_domain
from homeassistant.const import ( from homeassistant.const import (
CONF_ALIAS, CONF_ALIAS,
CONF_DEFAULT, CONF_DEFAULT,
@ -30,7 +30,7 @@ from homeassistant.const import (
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import config_per_platform, config_validation as cv from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.script import ( from homeassistant.helpers.script import (
SCRIPT_MODE_SINGLE, SCRIPT_MODE_SINGLE,
async_validate_actions_config, async_validate_actions_config,

View file

@ -6,8 +6,9 @@ from collections.abc import AsyncIterable, Coroutine
import logging import logging
from typing import Any from typing import Any
from homeassistant.config import config_per_platform
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import config_per_platform, discovery from homeassistant.helpers import discovery
from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.typing import ConfigType
from homeassistant.setup import async_prepare_setup_platform from homeassistant.setup import async_prepare_setup_platform

View file

@ -18,6 +18,7 @@ from homeassistant.components.media_player import (
SERVICE_PLAY_MEDIA, SERVICE_PLAY_MEDIA,
MediaType, MediaType,
) )
from homeassistant.config import config_per_platform
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_ENTITY_ID,
CONF_DESCRIPTION, CONF_DESCRIPTION,
@ -25,7 +26,7 @@ from homeassistant.const import (
CONF_PLATFORM, CONF_PLATFORM,
) )
from homeassistant.core import HomeAssistant, ServiceCall, callback from homeassistant.core import HomeAssistant, ServiceCall, callback
from homeassistant.helpers import config_per_platform, discovery from homeassistant.helpers import discovery
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.service import async_set_service_schema from homeassistant.helpers.service import async_set_service_schema
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType

View file

@ -2,7 +2,7 @@
from __future__ import annotations from __future__ import annotations
from collections import OrderedDict from collections import OrderedDict
from collections.abc import Callable, Sequence from collections.abc import Callable, Iterable, Sequence
from contextlib import suppress from contextlib import suppress
from dataclasses import dataclass from dataclasses import dataclass
from enum import StrEnum from enum import StrEnum
@ -48,6 +48,7 @@ from .const import (
CONF_MEDIA_DIRS, CONF_MEDIA_DIRS,
CONF_NAME, CONF_NAME,
CONF_PACKAGES, CONF_PACKAGES,
CONF_PLATFORM,
CONF_TEMPERATURE_UNIT, CONF_TEMPERATURE_UNIT,
CONF_TIME_ZONE, CONF_TIME_ZONE,
CONF_TYPE, CONF_TYPE,
@ -58,12 +59,7 @@ from .const import (
from .core import DOMAIN as CONF_CORE, ConfigSource, HomeAssistant, callback from .core import DOMAIN as CONF_CORE, ConfigSource, HomeAssistant, callback
from .exceptions import ConfigValidationError, HomeAssistantError from .exceptions import ConfigValidationError, HomeAssistantError
from .generated.currencies import HISTORIC_CURRENCIES from .generated.currencies import HISTORIC_CURRENCIES
from .helpers import ( from .helpers import config_validation as cv, issue_registry as ir
config_per_platform,
config_validation as cv,
extract_domain_configs,
issue_registry as ir,
)
from .helpers.entity_values import EntityValues from .helpers.entity_values import EntityValues
from .helpers.typing import ConfigType from .helpers.typing import ConfigType
from .loader import ComponentProtocol, Integration, IntegrationNotFound from .loader import ComponentProtocol, Integration, IntegrationNotFound
@ -1222,6 +1218,41 @@ def async_handle_component_errors(
) )
def config_per_platform(
config: ConfigType, domain: str
) -> Iterable[tuple[str | None, ConfigType]]:
"""Break a component config into different platforms.
For example, will find 'switch', 'switch 2', 'switch 3', .. etc
Async friendly.
"""
for config_key in extract_domain_configs(config, domain):
if not (platform_config := config[config_key]):
continue
if not isinstance(platform_config, list):
platform_config = [platform_config]
item: ConfigType
platform: str | None
for item in platform_config:
try:
platform = item.get(CONF_PLATFORM)
except AttributeError:
platform = None
yield platform, item
def extract_domain_configs(config: ConfigType, domain: str) -> Sequence[str]:
"""Extract keys from config for given domain name.
Async friendly.
"""
pattern = re.compile(rf"^{domain}(| .+)$")
return [key for key in config if pattern.match(key)]
async def async_process_component_config( # noqa: C901 async def async_process_component_config( # noqa: C901
hass: HomeAssistant, hass: HomeAssistant,
config: ConfigType, config: ConfigType,

View file

@ -2,11 +2,8 @@
from __future__ import annotations from __future__ import annotations
from collections.abc import Iterable, Sequence from collections.abc import Iterable, Sequence
import re
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from homeassistant.const import CONF_PLATFORM
if TYPE_CHECKING: if TYPE_CHECKING:
from .typing import ConfigType from .typing import ConfigType
@ -19,22 +16,23 @@ def config_per_platform(
For example, will find 'switch', 'switch 2', 'switch 3', .. etc For example, will find 'switch', 'switch 2', 'switch 3', .. etc
Async friendly. Async friendly.
""" """
for config_key in extract_domain_configs(config, domain): # pylint: disable-next=import-outside-toplevel
if not (platform_config := config[config_key]): from homeassistant import config as ha_config
continue
if not isinstance(platform_config, list): # pylint: disable-next=import-outside-toplevel
platform_config = [platform_config] from .deprecation import _print_deprecation_warning
item: ConfigType _print_deprecation_warning(
platform: str | None config_per_platform,
for item in platform_config: "config.config_per_platform",
try: "function",
platform = item.get(CONF_PLATFORM) "called",
except AttributeError: "2024.6",
platform = None )
return ha_config.config_per_platform(config, domain)
yield platform, item
config_per_platform.__name__ = "helpers.config_per_platform"
def extract_domain_configs(config: ConfigType, domain: str) -> Sequence[str]: def extract_domain_configs(config: ConfigType, domain: str) -> Sequence[str]:
@ -42,5 +40,20 @@ def extract_domain_configs(config: ConfigType, domain: str) -> Sequence[str]:
Async friendly. Async friendly.
""" """
pattern = re.compile(rf"^{domain}(| .+)$") # pylint: disable-next=import-outside-toplevel
return [key for key in config if pattern.match(key)] from homeassistant import config as ha_config
# pylint: disable-next=import-outside-toplevel
from .deprecation import _print_deprecation_warning
_print_deprecation_warning(
extract_domain_configs,
"config.extract_domain_configs",
"function",
"called",
"2024.6",
)
return ha_config.extract_domain_configs(config, domain)
extract_domain_configs.__name__ = "helpers.extract_domain_configs"

View file

@ -32,7 +32,7 @@ from homeassistant.exceptions import HomeAssistantError
from homeassistant.loader import async_get_integration, bind_hass from homeassistant.loader import async_get_integration, bind_hass
from homeassistant.setup import async_prepare_setup_platform from homeassistant.setup import async_prepare_setup_platform
from . import config_per_platform, config_validation as cv, discovery, entity, service from . import config_validation as cv, discovery, entity, service
from .entity_platform import EntityPlatform from .entity_platform import EntityPlatform
from .typing import ConfigType, DiscoveryInfoType from .typing import ConfigType, DiscoveryInfoType
@ -148,7 +148,7 @@ class EntityComponent(Generic[_EntityT]):
self.config = config self.config = config
# Look in config for Domain, Domain 2, Domain 3 etc and load them # Look in config for Domain, Domain 2, Domain 3 etc and load them
for p_type, p_config in config_per_platform(config, self.domain): for p_type, p_config in conf_util.config_per_platform(config, self.domain):
if p_type is not None: if p_type is not None:
self.hass.async_create_task( self.hass.async_create_task(
self.async_setup_platform(p_type, p_config), self.async_setup_platform(p_type, p_config),

View file

@ -13,7 +13,6 @@ from homeassistant.exceptions import HomeAssistantError
from homeassistant.loader import async_get_integration from homeassistant.loader import async_get_integration
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from . import config_per_platform
from .entity import Entity from .entity import Entity
from .entity_component import EntityComponent from .entity_component import EntityComponent
from .entity_platform import EntityPlatform, async_get_platforms from .entity_platform import EntityPlatform, async_get_platforms
@ -69,7 +68,7 @@ async def _resetup_platform(
root_config: dict[str, list[ConfigType]] = {platform_domain: []} root_config: dict[str, list[ConfigType]] = {platform_domain: []}
# Extract only the config for template, ignore the rest. # Extract only the config for template, ignore the rest.
for p_type, p_config in config_per_platform(conf, platform_domain): for p_type, p_config in conf_util.config_per_platform(conf, platform_domain):
if p_type != integration_domain: if p_type != integration_domain:
continue continue

View file

@ -2,10 +2,12 @@
from collections import OrderedDict from collections import OrderedDict
import pytest
from homeassistant import helpers from homeassistant import helpers
def test_extract_domain_configs() -> None: def test_extract_domain_configs(caplog: pytest.LogCaptureFixture) -> None:
"""Test the extraction of domain configuration.""" """Test the extraction of domain configuration."""
config = { config = {
"zone": None, "zone": None,
@ -19,8 +21,13 @@ def test_extract_domain_configs() -> None:
helpers.extract_domain_configs(config, "zone") helpers.extract_domain_configs(config, "zone")
) )
assert (
"helpers.extract_domain_configs is a deprecated function which will be removed "
"in HA Core 2024.6. Use config.extract_domain_configs instead" in caplog.text
)
def test_config_per_platform() -> None:
def test_config_per_platform(caplog: pytest.LogCaptureFixture) -> None:
"""Test config per platform method.""" """Test config per platform method."""
config = OrderedDict( config = OrderedDict(
[ [
@ -36,3 +43,8 @@ def test_config_per_platform() -> None:
(None, 1), (None, 1),
("hello 2", config["zone Hallo"][1]), ("hello 2", config["zone Hallo"][1]),
] == list(helpers.config_per_platform(config, "zone")) ] == list(helpers.config_per_platform(config, "zone"))
assert (
"helpers.config_per_platform is a deprecated function which will be removed "
"in HA Core 2024.6. Use config.config_per_platform instead" in caplog.text
)

View file

@ -2207,3 +2207,36 @@ async def test_yaml_error(
if record.levelno == logging.ERROR if record.levelno == logging.ERROR
] ]
assert error_records == snapshot assert error_records == snapshot
def test_extract_domain_configs() -> None:
"""Test the extraction of domain configuration."""
config = {
"zone": None,
"zoner": None,
"zone ": None,
"zone Hallo": None,
"zone 100": None,
}
assert {"zone", "zone Hallo", "zone 100"} == set(
config_util.extract_domain_configs(config, "zone")
)
def test_config_per_platform() -> None:
"""Test config per platform method."""
config = OrderedDict(
[
("zone", {"platform": "hello"}),
("zoner", None),
("zone Hallo", [1, {"platform": "hello 2"}]),
("zone 100", None),
]
)
assert [
("hello", config["zone"]),
(None, 1),
("hello 2", config["zone Hallo"][1]),
] == list(config_util.config_per_platform(config, "zone"))