Remove deprecated platform yaml in Scrape (#90272)

* Deprecate platform yaml

* typing

* DiscoveryInfoType
This commit is contained in:
G Johansson 2023-03-27 08:05:30 +02:00 committed by GitHub
parent c3717f8182
commit 624860da0e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 8 additions and 208 deletions

View File

@ -1,44 +1,23 @@
"""Support for getting data from websites with scraping.""" """Support for getting data from websites with scraping."""
from __future__ import annotations from __future__ import annotations
from datetime import timedelta
import logging import logging
from typing import Any from typing import Any, cast
import voluptuous as vol import voluptuous as vol
from homeassistant.components.rest import RESOURCE_SCHEMA, create_rest_data_from_config from homeassistant.components.sensor import SensorDeviceClass
from homeassistant.components.sensor import (
CONF_STATE_CLASS,
DEVICE_CLASSES_SCHEMA,
PLATFORM_SCHEMA as PARENT_PLATFORM_SCHEMA,
STATE_CLASSES_SCHEMA,
SensorDeviceClass,
)
from homeassistant.components.sensor.helpers import async_parse_date_datetime from homeassistant.components.sensor.helpers import async_parse_date_datetime
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ( from homeassistant.const import (
CONF_ATTRIBUTE, CONF_ATTRIBUTE,
CONF_AUTHENTICATION,
CONF_DEVICE_CLASS,
CONF_HEADERS,
CONF_NAME, CONF_NAME,
CONF_PASSWORD,
CONF_RESOURCE,
CONF_SCAN_INTERVAL,
CONF_UNIQUE_ID, CONF_UNIQUE_ID,
CONF_UNIT_OF_MEASUREMENT,
CONF_USERNAME,
CONF_VALUE_TEMPLATE, CONF_VALUE_TEMPLATE,
CONF_VERIFY_SSL,
HTTP_BASIC_AUTHENTICATION,
HTTP_DIGEST_AUTHENTICATION,
) )
from homeassistant.core import HomeAssistant, callback from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import PlatformNotReady from homeassistant.exceptions import PlatformNotReady
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
from homeassistant.helpers.template import Template from homeassistant.helpers.template import Template
from homeassistant.helpers.template_entity import ( from homeassistant.helpers.template_entity import (
TEMPLATE_SENSOR_BASE_SCHEMA, TEMPLATE_SENSOR_BASE_SCHEMA,
@ -47,43 +26,11 @@ from homeassistant.helpers.template_entity import (
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.helpers.update_coordinator import CoordinatorEntity from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import ( from .const import CONF_INDEX, CONF_SELECT, DOMAIN
CONF_INDEX,
CONF_SELECT,
DEFAULT_NAME,
DEFAULT_SCAN_INTERVAL,
DEFAULT_VERIFY_SSL,
DOMAIN,
)
from .coordinator import ScrapeCoordinator from .coordinator import ScrapeCoordinator
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
PLATFORM_SCHEMA = PARENT_PLATFORM_SCHEMA.extend(
{
# Linked to the loading of the page (can be linked to RestData)
vol.Optional(CONF_AUTHENTICATION): vol.In(
[HTTP_BASIC_AUTHENTICATION, HTTP_DIGEST_AUTHENTICATION]
),
vol.Optional(CONF_HEADERS): vol.Schema({cv.string: cv.string}),
vol.Optional(CONF_PASSWORD): cv.string,
vol.Required(CONF_RESOURCE): cv.string,
vol.Optional(CONF_USERNAME): cv.string,
vol.Optional(CONF_VERIFY_SSL, default=DEFAULT_VERIFY_SSL): cv.boolean,
# Linked to the parsing of the page (specific to scrape)
vol.Optional(CONF_ATTRIBUTE): cv.string,
vol.Optional(CONF_INDEX, default=0): cv.positive_int,
vol.Required(CONF_SELECT): cv.string,
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
# Linked to the sensor definition (can be linked to TemplateSensor)
vol.Optional(CONF_DEVICE_CLASS): DEVICE_CLASSES_SCHEMA,
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
vol.Optional(CONF_STATE_CLASS): STATE_CLASSES_SCHEMA,
vol.Optional(CONF_UNIQUE_ID): cv.string,
vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string,
}
)
async def async_setup_platform( async def async_setup_platform(
hass: HomeAssistant, hass: HomeAssistant,
@ -92,33 +39,9 @@ async def async_setup_platform(
discovery_info: DiscoveryInfoType | None = None, discovery_info: DiscoveryInfoType | None = None,
) -> None: ) -> None:
"""Set up the Web scrape sensor.""" """Set up the Web scrape sensor."""
coordinator: ScrapeCoordinator discovery_info = cast(DiscoveryInfoType, discovery_info)
sensors_config: list[ConfigType] coordinator: ScrapeCoordinator = discovery_info["coordinator"]
if discovery_info is None: sensors_config: list[ConfigType] = discovery_info["configs"]
async_create_issue(
hass,
DOMAIN,
"moved_yaml",
breaks_in_ha_version="2022.12.0",
is_fixable=False,
severity=IssueSeverity.WARNING,
translation_key="moved_yaml",
)
resource_config = vol.Schema(RESOURCE_SCHEMA, extra=vol.REMOVE_EXTRA)(config)
rest = create_rest_data_from_config(hass, resource_config)
scan_interval: timedelta = config.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL)
coordinator = ScrapeCoordinator(hass, rest, scan_interval)
sensors_config = [
vol.Schema(TEMPLATE_SENSOR_BASE_SCHEMA.schema, extra=vol.ALLOW_EXTRA)(
config
)
]
else:
coordinator = discovery_info["coordinator"]
sensors_config = discovery_info["configs"]
await coordinator.async_refresh() await coordinator.async_refresh()
if coordinator.data is None: if coordinator.data is None:

View File

@ -121,11 +121,5 @@
} }
} }
} }
},
"issues": {
"moved_yaml": {
"title": "The Scrape YAML configuration has been moved",
"description": "Configuring Scrape using YAML has been moved to integration key.\n\nYour existing YAML configuration will be working for 2 more versions.\n\nMigrate your YAML configuration to the integration key according to the documentation."
}
} }
} }

View File

@ -29,65 +29,13 @@ def return_integration_config(
return config return config
def return_config(
select,
name,
*,
attribute=None,
index=None,
template=None,
uom=None,
device_class=None,
state_class=None,
authentication=None,
username=None,
password=None,
headers=None,
unique_id=None,
remove_platform=False,
) -> dict[str, dict[str, Any]]:
"""Return config."""
config = {
"platform": "scrape",
"resource": "https://www.home-assistant.io",
"select": select,
"name": name,
"index": 0,
"verify_ssl": True,
}
if remove_platform:
config.pop("platform")
if attribute:
config["attribute"] = attribute
if index:
config["index"] = index
if template:
config["value_template"] = template
if uom:
config["unit_of_measurement"] = uom
if device_class:
config["device_class"] = device_class
if state_class:
config["state_class"] = state_class
if authentication:
config["authentication"] = authentication
if username:
config["username"] = username
config["password"] = password
if headers:
config["headers"] = headers
if unique_id:
config["unique_id"] = unique_id
return config
class MockRestData: class MockRestData:
"""Mock RestData.""" """Mock RestData."""
def __init__( def __init__(
self, self,
payload, payload,
): ) -> None:
"""Init RestDataMock.""" """Init RestDataMock."""
self.data: str | None = None self.data: str | None = None
self.payload = payload self.payload = payload

View File

@ -9,7 +9,6 @@ import pytest
from homeassistant.components.scrape.const import DEFAULT_SCAN_INTERVAL from homeassistant.components.scrape.const import DEFAULT_SCAN_INTERVAL
from homeassistant.components.sensor import ( from homeassistant.components.sensor import (
CONF_STATE_CLASS, CONF_STATE_CLASS,
DOMAIN as SENSOR_DOMAIN,
SensorDeviceClass, SensorDeviceClass,
SensorStateClass, SensorStateClass,
) )
@ -24,7 +23,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er from homeassistant.helpers import entity_registry as er
from homeassistant.setup import async_setup_component from homeassistant.setup import async_setup_component
from . import MockRestData, return_config, return_integration_config from . import MockRestData, return_integration_config
from tests.common import MockConfigEntry, async_fire_time_changed from tests.common import MockConfigEntry, async_fire_time_changed
@ -53,70 +52,6 @@ async def test_scrape_sensor(hass: HomeAssistant) -> None:
assert state.state == "Current Version: 2021.12.10" assert state.state == "Current Version: 2021.12.10"
async def test_scrape_sensor_platform_yaml(hass: HomeAssistant) -> None:
"""Test Scrape sensor load from sensor platform."""
config = {
SENSOR_DOMAIN: [
return_config(
select=".return",
name="Auth page",
username="user@secret.com",
password="12345678",
authentication="digest",
),
return_config(
select=".return",
name="Auth page2",
username="user@secret.com",
password="12345678",
template="{{value}}",
),
]
}
mocker = MockRestData("test_scrape_sensor_authentication")
with patch(
"homeassistant.components.rest.RestData",
return_value=mocker,
):
assert await async_setup_component(hass, SENSOR_DOMAIN, config)
await hass.async_block_till_done()
state = hass.states.get("sensor.auth_page")
assert state.state == "secret text"
state2 = hass.states.get("sensor.auth_page2")
assert state2.state == "secret text"
async def test_scrape_sensor_platform_yaml_no_data(
hass: HomeAssistant, caplog: pytest.LogCaptureFixture
) -> None:
"""Test Scrape sensor load from sensor platform fetching no data."""
config = {
SENSOR_DOMAIN: [
return_config(
select=".return",
name="Auth page",
username="user@secret.com",
password="12345678",
authentication="digest",
),
]
}
mocker = MockRestData("test_scrape_sensor_no_data")
with patch(
"homeassistant.components.rest.RestData",
return_value=mocker,
):
assert await async_setup_component(hass, SENSOR_DOMAIN, config)
await hass.async_block_till_done()
state = hass.states.get("sensor.auth_page")
assert not state
assert "Platform scrape not ready yet: None; Retrying in background" in caplog.text
async def test_scrape_sensor_value_template(hass: HomeAssistant) -> None: async def test_scrape_sensor_value_template(hass: HomeAssistant) -> None:
"""Test Scrape sensor with value template.""" """Test Scrape sensor with value template."""
config = { config = {