Remove yaml import from feedreader integration (#132278)
* Remove yaml import from feedreader integration * Update homeassistant/components/feedreader/config_flow.py Co-authored-by: epenet <6771947+epenet@users.noreply.github.com> * Drop _max_entries class attribute --------- Co-authored-by: epenet <6771947+epenet@users.noreply.github.com>pull/132419/head
parent
e5851c20e9
commit
3a2460f9f9
|
@ -2,17 +2,12 @@
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
||||
from homeassistant.const import CONF_SCAN_INTERVAL, CONF_URL, Platform
|
||||
from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_URL, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.util.hass_dict import HassKey
|
||||
|
||||
from .const import CONF_MAX_ENTRIES, DEFAULT_MAX_ENTRIES, DEFAULT_SCAN_INTERVAL, DOMAIN
|
||||
from .const import CONF_MAX_ENTRIES, DOMAIN
|
||||
from .coordinator import FeedReaderCoordinator, StoredData
|
||||
|
||||
type FeedReaderConfigEntry = ConfigEntry[FeedReaderCoordinator]
|
||||
|
@ -21,60 +16,6 @@ CONF_URLS = "urls"
|
|||
|
||||
MY_KEY: HassKey[StoredData] = HassKey(DOMAIN)
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema(
|
||||
vol.All(
|
||||
cv.deprecated(DOMAIN),
|
||||
{
|
||||
DOMAIN: vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_URLS): vol.All(cv.ensure_list, [cv.url]),
|
||||
vol.Optional(
|
||||
CONF_SCAN_INTERVAL, default=DEFAULT_SCAN_INTERVAL
|
||||
): cv.time_period,
|
||||
vol.Optional(
|
||||
CONF_MAX_ENTRIES, default=DEFAULT_MAX_ENTRIES
|
||||
): cv.positive_int,
|
||||
}
|
||||
)
|
||||
},
|
||||
),
|
||||
extra=vol.ALLOW_EXTRA,
|
||||
)
|
||||
|
||||
|
||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
||||
"""Set up the Feedreader component."""
|
||||
if DOMAIN in config:
|
||||
for url in config[DOMAIN][CONF_URLS]:
|
||||
hass.async_create_task(
|
||||
hass.config_entries.flow.async_init(
|
||||
DOMAIN,
|
||||
context={"source": SOURCE_IMPORT},
|
||||
data={
|
||||
CONF_URL: url,
|
||||
CONF_MAX_ENTRIES: config[DOMAIN][CONF_MAX_ENTRIES],
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
async_create_issue(
|
||||
hass,
|
||||
HOMEASSISTANT_DOMAIN,
|
||||
f"deprecated_yaml_{DOMAIN}",
|
||||
breaks_in_ha_version="2025.1.0",
|
||||
is_fixable=False,
|
||||
is_persistent=False,
|
||||
issue_domain=DOMAIN,
|
||||
severity=IssueSeverity.WARNING,
|
||||
translation_key="deprecated_yaml",
|
||||
translation_placeholders={
|
||||
"domain": DOMAIN,
|
||||
"integration_title": "Feedreader",
|
||||
},
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: FeedReaderConfigEntry) -> bool:
|
||||
"""Set up Feedreader from a config entry."""
|
||||
|
|
|
@ -11,7 +11,6 @@ import feedparser
|
|||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import (
|
||||
SOURCE_IMPORT,
|
||||
ConfigEntry,
|
||||
ConfigFlow,
|
||||
ConfigFlowResult,
|
||||
|
@ -20,13 +19,11 @@ from homeassistant.config_entries import (
|
|||
from homeassistant.const import CONF_URL
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
|
||||
from homeassistant.helpers.selector import (
|
||||
TextSelector,
|
||||
TextSelectorConfig,
|
||||
TextSelectorType,
|
||||
)
|
||||
from homeassistant.util import slugify
|
||||
|
||||
from .const import CONF_MAX_ENTRIES, DEFAULT_MAX_ENTRIES, DOMAIN
|
||||
|
||||
|
@ -42,7 +39,6 @@ class FeedReaderConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||
"""Handle a config flow."""
|
||||
|
||||
VERSION = 1
|
||||
_max_entries: int | None = None
|
||||
|
||||
@staticmethod
|
||||
@callback
|
||||
|
@ -75,21 +71,6 @@ class FeedReaderConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||
errors=errors,
|
||||
)
|
||||
|
||||
def abort_on_import_error(self, url: str, error: str) -> ConfigFlowResult:
|
||||
"""Abort import flow on error."""
|
||||
async_create_issue(
|
||||
self.hass,
|
||||
DOMAIN,
|
||||
f"import_yaml_error_{DOMAIN}_{error}_{slugify(url)}",
|
||||
breaks_in_ha_version="2025.1.0",
|
||||
is_fixable=False,
|
||||
issue_domain=DOMAIN,
|
||||
severity=IssueSeverity.WARNING,
|
||||
translation_key=f"import_yaml_error_{error}",
|
||||
translation_placeholders={"url": url},
|
||||
)
|
||||
return self.async_abort(reason=error)
|
||||
|
||||
async def async_step_user(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
|
@ -104,8 +85,6 @@ class FeedReaderConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||
if feed.bozo:
|
||||
LOGGER.debug("feed bozo_exception: %s", feed.bozo_exception)
|
||||
if isinstance(feed.bozo_exception, urllib.error.URLError):
|
||||
if self.context["source"] == SOURCE_IMPORT:
|
||||
return self.abort_on_import_error(user_input[CONF_URL], "url_error")
|
||||
return self.show_user_form(user_input, {"base": "url_error"})
|
||||
|
||||
feed_title = html.unescape(feed["feed"]["title"])
|
||||
|
@ -113,14 +92,9 @@ class FeedReaderConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||
return self.async_create_entry(
|
||||
title=feed_title,
|
||||
data=user_input,
|
||||
options={CONF_MAX_ENTRIES: self._max_entries or DEFAULT_MAX_ENTRIES},
|
||||
options={CONF_MAX_ENTRIES: DEFAULT_MAX_ENTRIES},
|
||||
)
|
||||
|
||||
async def async_step_import(self, import_data: dict[str, Any]) -> ConfigFlowResult:
|
||||
"""Handle an import flow."""
|
||||
self._max_entries = import_data[CONF_MAX_ENTRIES]
|
||||
return await self.async_step_user({CONF_URL: import_data[CONF_URL]})
|
||||
|
||||
async def async_step_reconfigure(
|
||||
self, user_input: dict[str, Any] | None = None
|
||||
) -> ConfigFlowResult:
|
||||
|
|
|
@ -5,7 +5,6 @@ import urllib
|
|||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.feedreader import CONF_URLS
|
||||
from homeassistant.components.feedreader.const import (
|
||||
CONF_MAX_ENTRIES,
|
||||
DEFAULT_MAX_ENTRIES,
|
||||
|
@ -13,10 +12,8 @@ from homeassistant.components.feedreader.const import (
|
|||
)
|
||||
from homeassistant.config_entries import SOURCE_USER
|
||||
from homeassistant.const import CONF_URL
|
||||
from homeassistant.core import DOMAIN as HOMEASSISTANT_DOMAIN, HomeAssistant
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.data_entry_flow import FlowResultType
|
||||
from homeassistant.helpers import issue_registry as ir
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
||||
from . import create_mock_entry
|
||||
from .const import FEED_TITLE, URL, VALID_CONFIG_DEFAULT
|
||||
|
@ -95,65 +92,6 @@ async def test_user_errors(
|
|||
assert result["options"][CONF_MAX_ENTRIES] == DEFAULT_MAX_ENTRIES
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("data", "expected_data", "expected_options"),
|
||||
[
|
||||
({CONF_URLS: [URL]}, {CONF_URL: URL}, {CONF_MAX_ENTRIES: DEFAULT_MAX_ENTRIES}),
|
||||
(
|
||||
{CONF_URLS: [URL], CONF_MAX_ENTRIES: 5},
|
||||
{CONF_URL: URL},
|
||||
{CONF_MAX_ENTRIES: 5},
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_import(
|
||||
hass: HomeAssistant,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
data,
|
||||
expected_data,
|
||||
expected_options,
|
||||
feedparser,
|
||||
setup_entry,
|
||||
) -> None:
|
||||
"""Test starting an import flow."""
|
||||
config_entries = hass.config_entries.async_entries(DOMAIN)
|
||||
assert not config_entries
|
||||
|
||||
assert await async_setup_component(hass, DOMAIN, {DOMAIN: data})
|
||||
|
||||
config_entries = hass.config_entries.async_entries(DOMAIN)
|
||||
assert config_entries
|
||||
assert len(config_entries) == 1
|
||||
assert config_entries[0].title == FEED_TITLE
|
||||
assert config_entries[0].data == expected_data
|
||||
assert config_entries[0].options == expected_options
|
||||
|
||||
assert issue_registry.async_get_issue(
|
||||
HOMEASSISTANT_DOMAIN, "deprecated_yaml_feedreader"
|
||||
)
|
||||
|
||||
|
||||
async def test_import_errors(
|
||||
hass: HomeAssistant,
|
||||
issue_registry: ir.IssueRegistry,
|
||||
feedparser,
|
||||
setup_entry,
|
||||
feed_one_event,
|
||||
) -> None:
|
||||
"""Test starting an import flow which results in an URL error."""
|
||||
config_entries = hass.config_entries.async_entries(DOMAIN)
|
||||
assert not config_entries
|
||||
|
||||
# raise URLError
|
||||
feedparser.side_effect = urllib.error.URLError("Test")
|
||||
feedparser.return_value = None
|
||||
assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_URLS: [URL]}})
|
||||
assert issue_registry.async_get_issue(
|
||||
DOMAIN,
|
||||
"import_yaml_error_feedreader_url_error_http_some_rss_local_rss_feed_xml",
|
||||
)
|
||||
|
||||
|
||||
async def test_reconfigure(hass: HomeAssistant, feedparser) -> None:
|
||||
"""Test starting a reconfigure flow."""
|
||||
entry = create_mock_entry(VALID_CONFIG_DEFAULT)
|
||||
|
|
Loading…
Reference in New Issue