Add entity_platform helper function to create issues when platform setup is not supported by integration (#171105)

Co-authored-by: Erik Montnemery <erik@montnemery.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Petro31
2026-05-19 21:08:03 +02:00
committed by GitHub
co-authored by Erik Montnemery Copilot Autofix powered by AI
parent f823ef639a
commit 3fee05db71
39 changed files with 357 additions and 408 deletions
@@ -7,12 +7,6 @@
"message": "Timeout trying to execute command: {command}"
}
},
"issues": {
"platform_yaml_not_supported": {
"description": "Platform YAML setup is not supported.\nChange from configuring it using the `{platform}:` key to using the `command_line:` key directly in configuration.yaml and restart Home Assistant to resolve the issue.\nTo see the detailed documentation, select Learn more.",
"title": "Platform YAML is not supported in Command Line"
}
},
"services": {
"reload": {
"description": "Reloads command line configuration from the YAML-configuration.",
@@ -4,7 +4,9 @@ import asyncio
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import TemplateError
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
from homeassistant.helpers.entity_platform import (
async_create_platform_config_not_supported_issue,
)
from homeassistant.helpers.template import Template
from .const import DOMAIN, LOGGER
@@ -98,13 +100,11 @@ def create_platform_yaml_not_supported_issue(
hass: HomeAssistant, platform_domain: str
) -> None:
"""Create an issue when platform yaml is used."""
async_create_issue(
async_create_platform_config_not_supported_issue(
hass,
DOMAIN,
f"{platform_domain}_platform_yaml_not_supported",
is_fixable=False,
severity=IssueSeverity.ERROR,
translation_key="platform_yaml_not_supported",
translation_placeholders={"platform": platform_domain},
platform_domain,
yaml_config_under_integration_supported=True,
learn_more_url="https://www.home-assistant.io/integrations/command_line/",
logger=LOGGER,
)
@@ -91,6 +91,11 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the Compensation sensor."""
hass.data[DATA_COMPENSATION] = {}
# Exit early if no compensations are configured using the compensation: key in configuration.yaml.
# This allows us to create an issue if platform: compensation is present in the sensor: section.
if DOMAIN not in config:
return True
for compensation, conf in config[DOMAIN].items():
_LOGGER.debug("Setup %s.%s", DOMAIN, compensation)
@@ -8,6 +8,7 @@ import numpy as np
from homeassistant.components.sensor import (
ATTR_STATE_CLASS,
CONF_STATE_CLASS,
DOMAIN as SENSOR_DOMAIN,
SensorEntity,
)
from homeassistant.const import (
@@ -31,7 +32,10 @@ from homeassistant.core import (
State,
callback,
)
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.entity_platform import (
AddEntitiesCallback,
async_create_platform_config_not_supported_issue,
)
from homeassistant.helpers.event import async_track_state_change_event
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
@@ -41,6 +45,7 @@ from .const import (
CONF_PRECISION,
DATA_COMPENSATION,
DEFAULT_NAME,
DOMAIN,
)
_LOGGER = logging.getLogger(__name__)
@@ -58,6 +63,14 @@ async def async_setup_platform(
) -> None:
"""Set up the Compensation sensor."""
if discovery_info is None:
async_create_platform_config_not_supported_issue(
hass,
DOMAIN,
SENSOR_DOMAIN,
yaml_config_under_integration_supported=True,
learn_more_url="https://www.home-assistant.io/integrations/compensation/",
logger=_LOGGER,
)
return
compensation: str = discovery_info[CONF_COMPENSATION]
@@ -167,10 +167,6 @@
"description": "Please do the following steps:\n- Adopt your configuration to support template rendering to native python types.\n- Remove the `legacy_templates` key from the `homeassistant` configuration in your configuration.yaml file.\n- Restart Home Assistant to fix this issue.",
"title": "The support for legacy templates is being removed"
},
"no_platform_setup": {
"description": "It's not possible to configure {platform} {domain} by adding `{platform_key}` to the {domain} configuration. Please check the documentation for more information on how to set up this integration.\n\nTo resolve this:\n1. Remove `{platform_key}` occurrences from the `{domain}:` configuration in your YAML configuration file.\n2. Restart Home Assistant.\n\nExample that should be removed:\n{yaml_example}",
"title": "Unused YAML configuration for the {platform} integration"
},
"orphaned_ignored_config_entry": {
"fix_flow": {
"abort": {
@@ -189,10 +185,18 @@
},
"title": "Orphaned ignored config entry for {domain}"
},
"platform_config_not_supported": {
"description": "Configuring the {integration_domain} integration by adding `{platform_key}` under the `{platform_domain}:` key is not supported. The {integration_domain} integration must be configured under its own `{integration_domain}:` key instead.\n\nTo resolve this:\n\n1. Remove the following from your YAML configuration file:\n\n{yaml_example}\n\n2. Move the configuration under the `{integration_domain}:` key instead.\n\n3. Restart Home Assistant.\n\nTo see the detailed documentation, select Learn more.",
"title": "Unsupported YAML configuration for the {integration_domain} integration"
},
"platform_only": {
"description": "The {domain} integration does not support configuration under its own key, it must be configured under its supported platforms.\n\nTo resolve this:\n\n1. Remove `{domain}:` from your YAML configuration file.\n\n2. Restart Home Assistant.",
"title": "The {domain} integration does not support YAML configuration under its own key"
},
"platform_setup_not_supported": {
"description": "It's not possible to configure {integration_domain} {platform_domain} by adding `{platform_key}` to the {platform_domain} configuration. Please check the documentation for more information on how to set up this integration.\n\nTo resolve this:\n\n1. Remove `{platform_key}` occurrences from the `{platform_domain}:` configuration in your YAML configuration file.\n\n2. Restart Home Assistant.",
"title": "Unused YAML configuration for the {integration_domain} integration"
},
"storage_corruption": {
"fix_flow": {
"step": {
+14 -3
View File
@@ -1,11 +1,11 @@
"""Support for getting data from websites with scraping."""
import logging
from typing import Any, cast
from typing import Any
import voluptuous as vol
from homeassistant.components.sensor import CONF_STATE_CLASS
from homeassistant.components.sensor import CONF_STATE_CLASS, DOMAIN as SENSOR_DOMAIN
from homeassistant.const import (
CONF_ATTRIBUTE,
CONF_DEVICE_CLASS,
@@ -21,6 +21,7 @@ from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
from homeassistant.helpers.entity_platform import (
AddConfigEntryEntitiesCallback,
AddEntitiesCallback,
async_create_platform_config_not_supported_issue,
)
from homeassistant.helpers.template import _SENTINEL, Template
from homeassistant.helpers.trigger_template_entity import (
@@ -59,7 +60,17 @@ async def async_setup_platform(
discovery_info: DiscoveryInfoType | None = None,
) -> None:
"""Set up the Web scrape sensor."""
discovery_info = cast(DiscoveryInfoType, discovery_info)
if discovery_info is None:
async_create_platform_config_not_supported_issue(
hass,
DOMAIN,
SENSOR_DOMAIN,
yaml_config_under_integration_supported=True,
learn_more_url="https://www.home-assistant.io/integrations/scrape/",
logger=_LOGGER,
)
return
coordinator: ScrapeCoordinator = discovery_info["coordinator"]
sensors_config: list[ConfigType] = discovery_info["configs"]
+6 -7
View File
@@ -8,7 +8,7 @@ from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import scoped_session
from homeassistant.components.recorder import CONF_DB_URL, get_instance
from homeassistant.components.sensor import CONF_STATE_CLASS
from homeassistant.components.sensor import CONF_STATE_CLASS, DOMAIN as SENSOR_DOMAIN
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
CONF_DEVICE_CLASS,
@@ -25,8 +25,8 @@ from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
from homeassistant.helpers.entity_platform import (
AddConfigEntryEntitiesCallback,
AddEntitiesCallback,
async_create_platform_config_not_supported_issue,
)
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
from homeassistant.helpers.template import Template
from homeassistant.helpers.trigger_template_entity import (
CONF_AVAILABILITY,
@@ -69,14 +69,13 @@ async def async_setup_platform(
) -> None:
"""Set up the SQL sensor from yaml."""
if (conf := discovery_info) is None:
async_create_issue(
async_create_platform_config_not_supported_issue(
hass,
DOMAIN,
"sensor_platform_yaml_not_supported",
is_fixable=False,
severity=IssueSeverity.WARNING,
translation_key="platform_yaml_not_supported",
SENSOR_DOMAIN,
yaml_config_under_integration_supported=True,
learn_more_url="https://www.home-assistant.io/integrations/sql/",
logger=_LOGGER,
)
return
@@ -66,10 +66,6 @@
"entity_id_query_does_full_table_scan": {
"description": "The query `{query}` contains the keyword `entity_id` but does not reference the `states_meta` table. This will cause a full table scan and database instability. Please check the documentation and use `states_meta.entity_id` instead.",
"title": "SQL query does full table scan"
},
"platform_yaml_not_supported": {
"description": "Platform YAML setup is not supported.\nChange from configuring it in the `sensor:` key to using the `sql:` key directly in configuration.yaml.\nTo see the detailed documentation, select Learn more.",
"title": "Platform YAML is not supported in SQL"
}
},
"options": {
@@ -19,6 +19,8 @@ CONF_TURN_ON = "turn_on"
DOMAIN = "template"
DOCUMENTATION_URL = "https://www.home-assistant.io/integrations/template/"
PLATFORM_STORAGE_KEY = "template_platforms"
PLATFORMS = [
+9 -2
View File
@@ -32,6 +32,7 @@ from homeassistant.helpers.entity import Entity
from homeassistant.helpers.entity_platform import (
AddConfigEntryEntitiesCallback,
AddEntitiesCallback,
async_create_platform_config_not_supported_issue,
async_get_platforms,
)
from homeassistant.helpers.issue_registry import IssueSeverity
@@ -50,6 +51,7 @@ from .const import (
CONF_AVAILABILITY_TEMPLATE,
CONF_DEFAULT_ENTITY_ID,
CONF_PICTURE,
DOCUMENTATION_URL,
DOMAIN,
PLATFORMS,
)
@@ -372,8 +374,13 @@ async def async_setup_template_platform(
None,
)
else:
_LOGGER.warning(
"Template %s entities can only be configured under template:", domain
async_create_platform_config_not_supported_issue(
hass,
DOMAIN,
domain,
yaml_config_under_integration_supported=True,
learn_more_url=DOCUMENTATION_URL,
logger=_LOGGER,
)
return
+10 -3
View File
@@ -41,6 +41,7 @@ from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.entity_platform import (
AddConfigEntryEntitiesCallback,
AddEntitiesCallback,
async_create_platform_config_not_supported_issue,
)
from homeassistant.helpers.restore_state import ExtraStoredData, RestoreEntity
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
@@ -51,7 +52,8 @@ from homeassistant.util.unit_conversion import (
TemperatureConverter,
)
from . import TriggerUpdateCoordinator, validators as template_validators
from . import DOMAIN, TriggerUpdateCoordinator, validators as template_validators
from .const import DOCUMENTATION_URL
from .entity import AbstractTemplateEntity
from .helpers import (
async_setup_template_entry,
@@ -242,8 +244,13 @@ async def async_setup_platform(
# Rewrite the configuration options to modern keys.
if discovery_info is None:
_LOGGER.warning(
"Template weather entities can only be configured under template:"
async_create_platform_config_not_supported_issue(
hass,
DOMAIN,
WEATHER_DOMAIN,
yaml_config_under_integration_supported=True,
learn_more_url=DOCUMENTATION_URL,
logger=_LOGGER,
)
return
@@ -2,7 +2,7 @@
import logging
from homeassistant.components.select import SelectEntity
from homeassistant.components.select import DOMAIN as SELECT_DOMAIN, SelectEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_NAME, CONF_UNIQUE_ID
from homeassistant.core import HomeAssistant
@@ -11,11 +11,12 @@ from homeassistant.helpers.device_registry import DeviceEntry
from homeassistant.helpers.entity_platform import (
AddConfigEntryEntitiesCallback,
AddEntitiesCallback,
async_create_platform_config_not_supported_issue,
)
from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from .const import CONF_METER, CONF_SOURCE_SENSOR, CONF_TARIFFS, DATA_UTILITY
from .const import CONF_METER, CONF_SOURCE_SENSOR, CONF_TARIFFS, DATA_UTILITY, DOMAIN
_LOGGER = logging.getLogger(__name__)
@@ -53,9 +54,13 @@ async def async_setup_platform(
) -> None:
"""Set up the utility meter select."""
if discovery_info is None:
_LOGGER.error(
"This platform is not available to configure "
"from 'select:' in configuration.yaml"
async_create_platform_config_not_supported_issue(
hass,
DOMAIN,
SELECT_DOMAIN,
yaml_config_under_integration_supported=True,
learn_more_url="https://www.home-assistant.io/integrations/utility_meter/",
logger=_LOGGER,
)
return
@@ -15,6 +15,7 @@ from homeassistant.components.sensor import (
ATTR_LAST_RESET,
DEVICE_CLASS_STATE_CLASSES,
DEVICE_CLASS_UNITS,
DOMAIN as SENSOR_DOMAIN,
RestoreSensor,
SensorDeviceClass,
SensorExtraStoredData,
@@ -46,6 +47,7 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.entity_platform import (
AddConfigEntryEntitiesCallback,
AddEntitiesCallback,
async_create_platform_config_not_supported_issue,
)
from homeassistant.helpers.event import (
async_track_point_in_time,
@@ -75,6 +77,7 @@ from .const import (
DAILY,
DATA_TARIFF_SENSORS,
DATA_UTILITY,
DOMAIN,
HOURLY,
MONTHLY,
QUARTER_HOURLY,
@@ -212,9 +215,13 @@ async def async_setup_platform(
) -> None:
"""Set up the utility meter sensor."""
if discovery_info is None:
_LOGGER.error(
"This platform is not available to configure "
"from 'sensor:' in configuration.yaml"
async_create_platform_config_not_supported_issue(
hass,
DOMAIN,
SENSOR_DOMAIN,
yaml_config_under_integration_supported=True,
learn_more_url="https://www.home-assistant.io/integrations/utility_meter/",
logger=_LOGGER,
)
return
+62 -26
View File
@@ -66,6 +66,61 @@ PLATFORM_NOT_READY_BASE_WAIT_TIME = 30 # seconds
_LOGGER = getLogger(__name__)
@callback
def async_create_platform_config_not_supported_issue(
hass: HomeAssistant,
integration_domain: str,
platform_domain: str,
*,
yaml_config_under_integration_supported: bool = False,
learn_more_url: str | None = None,
logger: Logger = _LOGGER,
) -> None:
"""Create a repair issue for an unsupported YAML platform configuration.
Raised when an integration is configured via the legacy
<platform_domain>: - platform: <integration_domain> schema.
Set yaml_config_under_integration_supported=False if the integration does
not support YAML configuration for this platform and the config should be
removed. Set it to True if the integration supports YAML configuration
under its own <integration_domain>: key and the config should be moved
there.
"""
if yaml_config_under_integration_supported:
logger.error(
"Configuring the %s integration under the %s platform key is not"
" supported, it must be configured under its own %s key instead",
integration_domain,
platform_domain,
integration_domain,
)
else:
logger.error(
"The %s platform for the %s integration does not support platform"
" setup, please remove it from your config",
integration_domain,
platform_domain,
)
platform_key = f"platform: {integration_domain}"
yaml_example = f"```yaml\n{platform_domain}:\n - {platform_key}\n```"
async_create_issue(
hass,
HOMEASSISTANT_DOMAIN,
f"platform_integration_no_support_{platform_domain}_{integration_domain}",
is_fixable=False,
issue_domain=integration_domain,
learn_more_url=learn_more_url,
severity=IssueSeverity.ERROR,
translation_key=f"platform_{'config' if yaml_config_under_integration_supported else 'setup'}_not_supported",
translation_placeholders={
"platform_domain": platform_domain,
"integration_domain": integration_domain,
"platform_key": platform_key,
"yaml_example": yaml_example,
},
)
class AddEntitiesCallback(Protocol):
"""Protocol type for EntityPlatform.add_entities callback."""
@@ -315,14 +370,6 @@ class EntityPlatform:
if not hasattr(platform, "async_setup_platform") and not hasattr(
platform, "setup_platform"
):
self.logger.error(
(
"The %s platform for the %s integration does not support platform"
" setup. Please remove it from your config."
),
self.platform_name,
self.domain,
)
learn_more_url = None
if self.platform:
if "custom_components" in self.platform.__file__: # type: ignore[attr-defined]
@@ -337,25 +384,14 @@ class EntityPlatform:
)
else:
learn_more_url = f"https://www.home-assistant.io/integrations/{self.platform_name}/"
platform_key = f"platform: {self.platform_name}"
yaml_example = f"```yaml\n{self.domain}:\n - {platform_key}\n```"
async_create_issue(
self.hass,
HOMEASSISTANT_DOMAIN,
f"platform_integration_no_support_{self.domain}_{self.platform_name}",
is_fixable=False,
issue_domain=self.platform_name,
learn_more_url=learn_more_url,
severity=IssueSeverity.ERROR,
translation_key="no_platform_setup",
translation_placeholders={
"domain": self.domain,
"platform": self.platform_name,
"platform_key": platform_key,
"yaml_example": yaml_example,
},
)
async_create_platform_config_not_supported_issue(
self.hass,
self.platform_name,
self.domain,
learn_more_url=learn_more_url,
logger=self.logger,
)
return
@callback
+45
View File
@@ -100,6 +100,7 @@ from homeassistant.helpers.entity_platform import (
)
from homeassistant.helpers.json import JSONEncoder, _orjson_default_encoder, json_dumps
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.setup import async_setup_component
from homeassistant.util import dt as dt_util, ulid as ulid_util, uuid as uuid_util
from homeassistant.util.async_ import (
_SHUTDOWN_RUN_CALLBACK_THREADSAFE,
@@ -2026,3 +2027,47 @@ def get_sensor_display_state(
numerical_value = float(value)
value = f"{numerical_value:z.{precision}f}"
return value
async def assert_platform_setup_creates_issue(
hass: HomeAssistant,
platform_domain: str,
integration_domain: str,
issue_registry: ir.IssueRegistry,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Assert that setting up a platform creates an issue."""
caplog.clear()
with assert_setup_component(1, platform_domain):
assert await async_setup_component(
hass,
platform_domain,
{platform_domain: {"platform": integration_domain}},
)
await hass.async_block_till_done()
await hass.async_start()
await hass.async_block_till_done()
assert len(hass.states.async_all(platform_domain)) == 0
assert (
f"Configuring the {integration_domain} integration under the {platform_domain} platform key is not"
f" supported, it must be configured under its own {integration_domain} key instead"
in caplog.text
)
issue = issue_registry.async_get_issue(
"homeassistant",
f"platform_integration_no_support_{platform_domain}_{integration_domain}",
)
assert issue
assert issue.issue_domain == integration_domain
assert issue.learn_more_url is not None
assert issue.translation_key == "platform_config_not_supported"
assert issue.severity == ir.IssueSeverity.ERROR
assert issue.translation_placeholders == {
"platform_domain": platform_domain,
"integration_domain": integration_domain,
"platform_key": f"platform: {integration_domain}",
"yaml_example": f"```yaml\n{platform_domain}:\n - platform: {integration_domain}\n```",
}
@@ -9,7 +9,6 @@ from freezegun.api import FrozenDateTimeFactory
import pytest
from homeassistant import setup
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
from homeassistant.components.command_line.binary_sensor import CommandBinarySensor
from homeassistant.components.command_line.const import DOMAIN
from homeassistant.components.homeassistant import (
@@ -18,7 +17,7 @@ from homeassistant.components.homeassistant import (
)
from homeassistant.const import ATTR_ENTITY_ID, STATE_OFF, STATE_ON, STATE_UNAVAILABLE
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er, issue_registry as ir
from homeassistant.helpers import entity_registry as er
from homeassistant.util import dt as dt_util
from . import mock_asyncio_subprocess_run
@@ -55,33 +54,6 @@ async def test_setup_integration_yaml(
assert entity_state.name == "Test"
async def test_setup_platform_yaml(
hass: HomeAssistant, issue_registry: ir.IssueRegistry
) -> None:
"""Test setting up the platform with platform yaml."""
await setup.async_setup_component(
hass,
"binary_sensor",
{
"binary_sensor": {
"platform": "command_line",
"command": "echo 1",
"payload_on": "1",
"payload_off": "0",
}
},
)
await hass.async_block_till_done()
assert len(hass.states.async_all()) == 0
issue = issue_registry.async_get_issue(
DOMAIN, "binary_sensor_platform_yaml_not_supported"
)
assert issue is not None
assert issue.severity == ir.IssueSeverity.ERROR
assert issue.translation_placeholders == {"platform": BINARY_SENSOR_DOMAIN}
@pytest.mark.parametrize(
"get_config",
[
+1 -25
View File
@@ -29,7 +29,7 @@ from homeassistant.const import (
STATE_UNAVAILABLE,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er, issue_registry as ir
from homeassistant.helpers import entity_registry as er
from homeassistant.util import dt as dt_util
from . import mock_asyncio_subprocess_run
@@ -37,30 +37,6 @@ from . import mock_asyncio_subprocess_run
from tests.common import async_fire_time_changed
async def test_setup_platform_yaml(
hass: HomeAssistant, issue_registry: ir.IssueRegistry
) -> None:
"""Test setting up the platform with platform yaml."""
await setup.async_setup_component(
hass,
"cover",
{
"cover": {
"platform": "command_line",
"command": "echo 1",
"payload_on": "1",
"payload_off": "0",
}
},
)
await hass.async_block_till_done()
assert len(hass.states.async_all()) == 0
issue = issue_registry.async_get_issue(DOMAIN, "cover_platform_yaml_not_supported")
assert issue is not None
assert issue.severity == ir.IssueSeverity.ERROR
assert issue.translation_placeholders == {"platform": COVER_DOMAIN}
async def test_no_poll_when_cover_has_no_command_state(hass: HomeAssistant) -> None:
"""Test that the cover does not polls when there's no state command."""
+32 -1
View File
@@ -9,9 +9,40 @@ from homeassistant import config as hass_config
from homeassistant.components.command_line.const import DOMAIN
from homeassistant.const import SERVICE_RELOAD, STATE_ON, STATE_OPEN
from homeassistant.core import HomeAssistant
from homeassistant.helpers import issue_registry as ir
from homeassistant.util import dt as dt_util
from tests.common import async_fire_time_changed, get_fixture_path
from tests.common import (
assert_platform_setup_creates_issue,
async_fire_time_changed,
get_fixture_path,
)
@pytest.mark.parametrize(
"platform_domain",
[
"binary_sensor",
"cover",
"notify",
"sensor",
"switch",
],
)
async def test_platform_config_creates_issue(
hass: HomeAssistant,
platform_domain: str,
issue_registry: ir.IssueRegistry,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test invalid platform config creates issue and logs a warning."""
await assert_platform_setup_creates_issue(
hass,
platform_domain,
DOMAIN,
issue_registry,
caplog,
)
async def test_setup_config(hass: HomeAssistant, load_yaml_integration: None) -> None:
@@ -13,31 +13,6 @@ from homeassistant.components.command_line import DOMAIN
from homeassistant.components.notify import DOMAIN as NOTIFY_DOMAIN
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers import issue_registry as ir
async def test_setup_platform_yaml(
hass: HomeAssistant, issue_registry: ir.IssueRegistry
) -> None:
"""Test setting up the platform with platform yaml."""
await setup.async_setup_component(
hass,
"notify",
{
"notify": {
"platform": "command_line",
"command": "echo 1",
"payload_on": "1",
"payload_off": "0",
}
},
)
await hass.async_block_till_done()
assert len(hass.states.async_all()) == 0
issue = issue_registry.async_get_issue(DOMAIN, "notify_platform_yaml_not_supported")
assert issue is not None
assert issue.severity == ir.IssueSeverity.ERROR
assert issue.translation_placeholders == {"platform": NOTIFY_DOMAIN}
@pytest.mark.parametrize(
+1 -26
View File
@@ -15,10 +15,9 @@ from homeassistant.components.homeassistant import (
DOMAIN as HA_DOMAIN,
SERVICE_UPDATE_ENTITY,
)
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.const import ATTR_ENTITY_ID, STATE_UNAVAILABLE, STATE_UNKNOWN
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er, issue_registry as ir
from homeassistant.helpers import entity_registry as er
from homeassistant.util import dt as dt_util
from . import mock_asyncio_subprocess_run
@@ -26,30 +25,6 @@ from . import mock_asyncio_subprocess_run
from tests.common import async_fire_time_changed
async def test_setup_platform_yaml(
hass: HomeAssistant, issue_registry: ir.IssueRegistry
) -> None:
"""Test setting up the platform with platform yaml."""
await setup.async_setup_component(
hass,
"sensor",
{
"sensor": {
"platform": "command_line",
"command": "echo 1",
"payload_on": "1",
"payload_off": "0",
}
},
)
await hass.async_block_till_done()
assert len(hass.states.async_all()) == 0
issue = issue_registry.async_get_issue(DOMAIN, "sensor_platform_yaml_not_supported")
assert issue is not None
assert issue.severity == ir.IssueSeverity.ERROR
assert issue.translation_placeholders == {"platform": SENSOR_DOMAIN}
@pytest.mark.parametrize(
"get_config",
[
+1 -25
View File
@@ -27,7 +27,7 @@ from homeassistant.const import (
STATE_UNAVAILABLE,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er, issue_registry as ir
from homeassistant.helpers import entity_registry as er
from homeassistant.util import dt as dt_util
from . import mock_asyncio_subprocess_run
@@ -35,30 +35,6 @@ from . import mock_asyncio_subprocess_run
from tests.common import async_fire_time_changed
async def test_setup_platform_yaml(
hass: HomeAssistant, issue_registry: ir.IssueRegistry
) -> None:
"""Test setting up the platform with platform yaml."""
await setup.async_setup_component(
hass,
"switch",
{
"switch": {
"platform": "command_line",
"command": "echo 1",
"payload_on": "1",
"payload_off": "0",
}
},
)
await hass.async_block_till_done()
assert len(hass.states.async_all()) == 0
issue = issue_registry.async_get_issue(DOMAIN, "switch_platform_yaml_not_supported")
assert issue is not None
assert issue.severity == ir.IssueSeverity.ERROR
assert issue.translation_placeholders == {"platform": SWITCH_DOMAIN}
async def test_state_integration_yaml(hass: HomeAssistant) -> None:
"""Test with none state."""
with tempfile.TemporaryDirectory() as tempdirname:
+22 -1
View File
@@ -10,6 +10,7 @@ from homeassistant.components.compensation.const import CONF_PRECISION, DOMAIN
from homeassistant.components.compensation.sensor import ATTR_COEFFICIENTS
from homeassistant.components.sensor import (
ATTR_STATE_CLASS,
DOMAIN as SENSOR_DOMAIN,
SensorDeviceClass,
SensorStateClass,
)
@@ -24,9 +25,14 @@ from homeassistant.const import (
UnitOfTemperature,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import issue_registry as ir
from homeassistant.setup import async_setup_component
from tests.common import assert_setup_component, get_fixture_path
from tests.common import (
assert_platform_setup_creates_issue,
assert_setup_component,
get_fixture_path,
)
TEST_OBJECT_ID = "test_compensation"
TEST_ENTITY_ID = "sensor.test_compensation"
@@ -47,6 +53,21 @@ TEST_CONFIG = {
}
async def test_platform_config_creates_issue(
hass: HomeAssistant,
issue_registry: ir.IssueRegistry,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test invalid platform config creates issue and logs a warning."""
await assert_platform_setup_creates_issue(
hass,
SENSOR_DOMAIN,
DOMAIN,
issue_registry,
caplog,
)
async def async_setup_compensation(hass: HomeAssistant, config: dict[str, Any]) -> None:
"""Do setup of a compensation integration sensor."""
with assert_setup_component(1, DOMAIN):
+22 -2
View File
@@ -16,6 +16,7 @@ from homeassistant.components.scrape.const import (
)
from homeassistant.components.sensor import (
CONF_STATE_CLASS,
DOMAIN as SENSOR_DOMAIN,
SensorDeviceClass,
SensorStateClass,
)
@@ -35,7 +36,7 @@ from homeassistant.const import (
UnitOfTemperature,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers import entity_registry as er, issue_registry as ir
from homeassistant.helpers.trigger_template_entity import (
CONF_AVAILABILITY,
CONF_PICTURE,
@@ -45,11 +46,30 @@ from homeassistant.util import dt as dt_util
from . import MockRestData, return_integration_config
from tests.common import MockConfigEntry, async_fire_time_changed
from tests.common import (
MockConfigEntry,
assert_platform_setup_creates_issue,
async_fire_time_changed,
)
DOMAIN = "scrape"
async def test_platform_config_creates_issue(
hass: HomeAssistant,
issue_registry: ir.IssueRegistry,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test invalid platform config creates issue and logs a warning."""
await assert_platform_setup_creates_issue(
hass,
SENSOR_DOMAIN,
DOMAIN,
issue_registry,
caplog,
)
async def test_scrape_sensor(hass: HomeAssistant) -> None:
"""Test Scrape sensor minimal."""
config = {
+17 -23
View File
@@ -13,6 +13,7 @@ from sqlalchemy.exc import SQLAlchemyError
from homeassistant.components.recorder import CONF_DB_URL, Recorder
from homeassistant.components.sensor import (
CONF_STATE_CLASS,
DOMAIN as SENSOR_DOMAIN,
SensorDeviceClass,
SensorStateClass,
)
@@ -50,7 +51,11 @@ from . import (
init_integration,
)
from tests.common import MockConfigEntry, async_fire_time_changed
from tests.common import (
MockConfigEntry,
assert_platform_setup_creates_issue,
async_fire_time_changed,
)
async def test_query_basic(recorder_mock: Recorder, hass: HomeAssistant) -> None:
@@ -432,30 +437,19 @@ async def test_templates_with_yaml(
async def test_config_from_old_yaml(
recorder_mock: Recorder, hass: HomeAssistant, issue_registry: ir.IssueRegistry
recorder_mock: Recorder,
hass: HomeAssistant,
issue_registry: ir.IssueRegistry,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test the SQL sensor from old yaml config does not create any entity."""
config = {
"sensor": {
"platform": "sql",
CONF_DB_URL: "sqlite://",
"queries": [
{
CONF_NAME: "count_tables",
CONF_QUERY: "SELECT 5 as value",
CONF_COLUMN_NAME: "value",
}
],
}
}
assert await async_setup_component(hass, "sensor", config)
await hass.async_block_till_done()
state = hass.states.get("sensor.count_tables")
assert not state
issue = issue_registry.async_get_issue(DOMAIN, "sensor_platform_yaml_not_supported")
assert issue is not None
assert issue.severity == ir.IssueSeverity.WARNING
await assert_platform_setup_creates_issue(
hass,
SENSOR_DOMAIN,
DOMAIN,
issue_registry,
caplog,
)
@pytest.mark.parametrize(
@@ -350,19 +350,6 @@ async def test_template_syntax_error(
assert (msg) in caplog_setup_text
@pytest.mark.parametrize(
("count", "state_template", "style"),
[(1, "{{ states('sensor.test_state') }}", ConfigurationStyle.LEGACY)],
)
@pytest.mark.usefixtures("setup_state_panel")
async def test_legacy_template_creates_warning(
hass: HomeAssistant, caplog_setup_text
) -> None:
"""Test legacy YAML configuration logs a warning."""
assert len(hass.states.async_all("alarm_control_panel")) == 0
assert "entities can only be configured under template:" in caplog_setup_text
@pytest.mark.parametrize(
("count", "state_template", "attribute", "attribute_template"),
[(1, "disarmed", "name", '{{ "Template Alarm Panel" }}')],
@@ -234,19 +234,6 @@ async def test_setup_invalid_sensors(hass: HomeAssistant, count: int) -> None:
assert len(hass.states.async_entity_ids("binary_sensor")) == count
@pytest.mark.parametrize(
("count", "state_template", "style", "extra_config"),
[(1, "{{ states('sensor.test_state') }}", ConfigurationStyle.LEGACY, {})],
)
@pytest.mark.usefixtures("setup_binary_sensor")
async def test_legacy_template_creates_warning(
hass: HomeAssistant, caplog_setup_text
) -> None:
"""Test legacy YAML configuration logs a warning."""
assert len(hass.states.async_all("binary_sensor")) == 0
assert "entities can only be configured under template:" in caplog_setup_text
@pytest.mark.parametrize(
("state_template", "expected_result"),
[
+23
View File
@@ -6,6 +6,7 @@ import voluptuous as vol
from homeassistant.components.template import DOMAIN
from homeassistant.components.template.config import (
CONFIG_SECTION_SCHEMA,
PLATFORMS,
async_validate_config_section,
)
from homeassistant.core import HomeAssistant
@@ -14,6 +15,28 @@ from homeassistant.helpers.script_variables import ScriptVariables
from homeassistant.helpers.template import Template
from homeassistant.setup import async_setup_component
from tests.common import assert_platform_setup_creates_issue
@pytest.mark.parametrize(
"platform_domain",
PLATFORMS,
)
async def test_platform_config_creates_issue(
hass: HomeAssistant,
platform_domain: str,
issue_registry: ir.IssueRegistry,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test invalid platform config creates issue and logs a warning."""
await assert_platform_setup_creates_issue(
hass,
platform_domain,
DOMAIN,
issue_registry,
caplog,
)
@pytest.mark.parametrize(
"config",
-20
View File
@@ -161,26 +161,6 @@ async def setup_empty_action(
)
@pytest.mark.parametrize(
("count", "state_template", "style", "config"),
[
(
1,
"{{ states('sensor.test_state') }}",
ConfigurationStyle.LEGACY,
COVER_ACTIONS,
)
],
)
@pytest.mark.usefixtures("setup_state_cover")
async def test_legacy_template_creates_warning(
hass: HomeAssistant, caplog_setup_text
) -> None:
"""Test legacy YAML configuration logs a warning."""
assert len(hass.states.async_all("cover")) == 0
assert "entities can only be configured under template:" in caplog_setup_text
@pytest.mark.parametrize(
("count", "state_template", "config"),
[(1, "{{ states.sensor.test_state.state }}", COVER_ACTIONS)],
-15
View File
@@ -113,21 +113,6 @@ async def setup_single_attribute_state_event(
)
async def test_legacy_platform_config(hass: HomeAssistant) -> None:
"""Test a legacy platform does not create event entities."""
with assert_setup_component(1, event.DOMAIN):
assert await async_setup_component(
hass,
event.DOMAIN,
{"event": {"platform": "template", "events": {TEST_EVENT.object_id: {}}}},
)
await hass.async_block_till_done()
await hass.async_start()
await hass.async_block_till_done()
assert hass.states.async_all("event") == []
@pytest.mark.freeze_time(TEST_FROZEN_INPUT)
async def test_setup_config_entry(
hass: HomeAssistant,
-20
View File
@@ -172,26 +172,6 @@ async def setup_single_attribute_state_fan(
)
@pytest.mark.parametrize(
("count", "state_template", "style", "extra_config"),
[
(
1,
"{{ states('sensor.test_state') }}",
ConfigurationStyle.LEGACY,
OPTIMISTIC_ON_OFF_ACTIONS,
)
],
)
@pytest.mark.usefixtures("setup_state_fan")
async def test_legacy_template_creates_warning(
hass: HomeAssistant, caplog_setup_text
) -> None:
"""Test legacy YAML configuration logs a warning."""
assert len(hass.states.async_all("fan")) == 0
assert "entities can only be configured under template:" in caplog_setup_text
@pytest.mark.parametrize(
("count", "state_template", "extra_config"),
[(1, "{{ 'on' }}", OPTIMISTIC_ON_OFF_ACTIONS)],
-13
View File
@@ -343,19 +343,6 @@ async def setup_light_with_transition_template(
)
@pytest.mark.parametrize(
("count", "state_template", "style", "extra_config"),
[(1, "{{ states('sensor.test_state') }}", ConfigurationStyle.LEGACY, {})],
)
@pytest.mark.usefixtures("setup_state_light")
async def test_legacy_template_creates_warning(
hass: HomeAssistant, caplog_setup_text
) -> None:
"""Test legacy YAML configuration logs a warning."""
assert len(hass.states.async_all("light")) == 0
assert "entities can only be configured under template:" in caplog_setup_text
@pytest.mark.parametrize(
("count", "state_template", "extra_config"),
[(1, "{{states.test['big.fat...']}}", {})],
-13
View File
@@ -132,19 +132,6 @@ async def setup_state_lock_with_attribute(
)
@pytest.mark.parametrize(
("count", "state_template", "style"),
[(1, "{{ states('sensor.test_state') }}", ConfigurationStyle.LEGACY)],
)
@pytest.mark.usefixtures("setup_state_lock")
async def test_legacy_template_creates_warning(
hass: HomeAssistant, caplog_setup_text
) -> None:
"""Test legacy YAML configuration logs a warning."""
assert len(hass.states.async_all("lock")) == 0
assert "entities can only be configured under template:" in caplog_setup_text
@pytest.mark.parametrize(
("count", "state_template"), [(1, "{{ states.sensor.test_state.state }}")]
)
-13
View File
@@ -125,19 +125,6 @@ async def setup_attributes_state_sensor(
)
@pytest.mark.parametrize(
("count", "state_template", "style", "config"),
[(1, "{{ states('sensor.test_state') }}", ConfigurationStyle.LEGACY, {})],
)
@pytest.mark.usefixtures("setup_state_sensor")
async def test_legacy_template_creates_warning(
hass: HomeAssistant, caplog_setup_text
) -> None:
"""Test legacy YAML configuration logs a warning."""
assert len(hass.states.async_all("sensor")) == 0
assert "entities can only be configured under template:" in caplog_setup_text
@pytest.mark.parametrize(
"config_entry_extra_options",
[
-13
View File
@@ -149,19 +149,6 @@ async def setup_single_attribute_optimistic_switch(
)
@pytest.mark.parametrize(
("count", "state_template", "style"),
[(1, "{{ states('sensor.test_state') }}", ConfigurationStyle.LEGACY)],
)
@pytest.mark.usefixtures("setup_state_switch")
async def test_legacy_template_creates_warning(
hass: HomeAssistant, caplog_setup_text
) -> None:
"""Test legacy YAML configuration logs a warning."""
assert len(hass.states.async_all("switch")) == 0
assert "entities can only be configured under template:" in caplog_setup_text
@pytest.mark.parametrize(("count", "state_template"), [(1, "{{ True }}")])
@pytest.mark.parametrize(
"style",
-15
View File
@@ -125,21 +125,6 @@ async def setup_single_attribute_update(
)
async def test_legacy_platform_config(hass: HomeAssistant) -> None:
"""Test a legacy platform does not create update entities."""
with assert_setup_component(1, update.DOMAIN):
assert await async_setup_component(
hass,
update.DOMAIN,
{"update": {"platform": "template", "updates": {"anything": {}}}},
)
await hass.async_block_till_done()
await hass.async_start()
await hass.async_block_till_done()
assert hass.states.async_all("update") == []
async def test_setup_config_entry(
hass: HomeAssistant,
snapshot: SnapshotAssertion,
-13
View File
@@ -191,19 +191,6 @@ async def setup_attributes_state_vacuum(
)
@pytest.mark.parametrize(
("count", "state_template", "style"),
[(1, "{{ states('sensor.test_state') }}", ConfigurationStyle.LEGACY)],
)
@pytest.mark.usefixtures("setup_state_vacuum")
async def test_legacy_template_creates_warning(
hass: HomeAssistant, caplog_setup_text
) -> None:
"""Test legacy YAML configuration logs a warning."""
assert len(hass.states.async_all("vacuum")) == 0
assert "entities can only be configured under template:" in caplog_setup_text
@pytest.mark.parametrize("count", [1])
@pytest.mark.parametrize(
("style", "state_template", "extra_config", "parm1", "parm2"),
-13
View File
@@ -106,19 +106,6 @@ async def setup_weather(
await setup_entity(hass, TEST_WEATHER, style, 1, config)
@pytest.mark.parametrize(
("style", "config"),
[(ConfigurationStyle.LEGACY, TEST_LEGACY_REQUIRED)],
)
@pytest.mark.usefixtures("setup_weather")
async def test_legacy_template_creates_warning(
hass: HomeAssistant, caplog_setup_text
) -> None:
"""Test legacy YAML configuration logs a warning."""
assert len(hass.states.async_all("weather")) == 0
assert "entities can only be configured under template:" in caplog_setup_text
@pytest.mark.parametrize(
"style", [ConfigurationStyle.MODERN, ConfigurationStyle.TRIGGER]
)
+30 -2
View File
@@ -28,12 +28,20 @@ from homeassistant.const import (
UnitOfEnergy,
)
from homeassistant.core import Event, HomeAssistant, State, callback
from homeassistant.helpers import device_registry as dr, entity_registry as er
from homeassistant.helpers import (
device_registry as dr,
entity_registry as er,
issue_registry as ir,
)
from homeassistant.helpers.event import async_track_entity_registry_updated_event
from homeassistant.setup import async_setup_component
from homeassistant.util import dt as dt_util
from tests.common import MockConfigEntry, mock_restore_cache
from tests.common import (
MockConfigEntry,
assert_platform_setup_creates_issue,
mock_restore_cache,
)
@pytest.fixture
@@ -116,6 +124,26 @@ def track_entity_registry_actions(hass: HomeAssistant, entity_id: str) -> list[s
return events
@pytest.mark.parametrize(
"platform_domain",
["select", "sensor"],
)
async def test_platform_config_creates_issue(
hass: HomeAssistant,
platform_domain: str,
issue_registry: ir.IssueRegistry,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test invalid platform config creates issue and logs a warning."""
await assert_platform_setup_creates_issue(
hass,
platform_domain,
DOMAIN,
issue_registry,
caplog,
)
async def test_restore_state(hass: HomeAssistant) -> None:
"""Test utility sensor restore state."""
config = {
+5 -4
View File
@@ -1612,7 +1612,8 @@ async def test_platform_with_no_setup(
assert (
"The mock-platform platform for the mock-integration"
" integration does not support platform setup." in caplog.text
" integration does not support platform setup, please remove it from your config"
in caplog.text
)
issue = issue_registry.async_get_issue(
domain="homeassistant",
@@ -1621,10 +1622,10 @@ async def test_platform_with_no_setup(
assert issue
assert issue.issue_domain == "mock-platform"
assert issue.learn_more_url is None
assert issue.translation_key == "no_platform_setup"
assert issue.translation_key == "platform_setup_not_supported"
assert issue.translation_placeholders == {
"domain": "mock-integration",
"platform": "mock-platform",
"platform_domain": "mock-integration",
"integration_domain": "mock-platform",
"platform_key": "platform: mock-platform",
"yaml_example": "```yaml\nmock-integration:\n - platform: mock-platform\n```",
}