End deprecation for config entry import for folder watcher (#128056)

This commit is contained in:
G Johansson 2024-10-09 21:25:55 +02:00 committed by GitHub
parent 2a171fb08c
commit 9bbbb2cd3c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 54 additions and 135 deletions

View File

@ -4,9 +4,8 @@ from __future__ import annotations
import logging import logging
import os import os
from typing import Any, cast from typing import cast
import voluptuous as vol
from watchdog.events import ( from watchdog.events import (
FileClosedEvent, FileClosedEvent,
FileCreatedEvent, FileCreatedEvent,
@ -19,69 +18,17 @@ from watchdog.events import (
) )
from watchdog.observers import Observer from watchdog.observers import Observer
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP from homeassistant.const import EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP
from homeassistant.core import Event, HomeAssistant from homeassistant.core import Event, HomeAssistant
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.dispatcher import dispatcher_send from homeassistant.helpers.dispatcher import dispatcher_send
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
from homeassistant.helpers.typing import ConfigType
from .const import CONF_FOLDER, CONF_PATTERNS, DEFAULT_PATTERN, DOMAIN, PLATFORMS from .const import CONF_FOLDER, CONF_PATTERNS, DOMAIN, PLATFORMS
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
CONFIG_SCHEMA = vol.Schema(
{
DOMAIN: vol.All(
cv.ensure_list,
[
vol.Schema(
{
vol.Required(CONF_FOLDER): cv.isdir,
vol.Optional(CONF_PATTERNS, default=[DEFAULT_PATTERN]): vol.All(
cv.ensure_list, [cv.string]
),
}
)
],
)
},
extra=vol.ALLOW_EXTRA,
)
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the folder watcher."""
if DOMAIN in config:
conf: list[dict[str, Any]] = config[DOMAIN]
for watcher in conf:
path: str = watcher[CONF_FOLDER]
if not hass.config.is_allowed_path(path):
async_create_issue(
hass,
DOMAIN,
f"import_failed_not_allowed_path_{path}",
is_fixable=False,
is_persistent=False,
severity=IssueSeverity.ERROR,
translation_key="import_failed_not_allowed_path",
translation_placeholders={
"path": path,
"config_variable": "allowlist_external_dirs",
},
)
continue
hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_IMPORT}, data=watcher
)
)
return True
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Folder watcher from a config entry.""" """Set up Folder watcher from a config entry."""

View File

@ -8,10 +8,8 @@ from typing import Any
import voluptuous as vol import voluptuous as vol
from homeassistant.components.homeassistant import DOMAIN as HOMEASSISTANT_DOMAIN
from homeassistant.config_entries import ConfigFlowResult from homeassistant.config_entries import ConfigFlowResult
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers.issue_registry import IssueSeverity, async_create_issue
from homeassistant.helpers.schema_config_entry_flow import ( from homeassistant.helpers.schema_config_entry_flow import (
SchemaCommonFlowHandler, SchemaCommonFlowHandler,
SchemaConfigFlowHandler, SchemaConfigFlowHandler,
@ -46,28 +44,6 @@ async def validate_setup(
return user_input return user_input
async def validate_import_setup(
handler: SchemaCommonFlowHandler, user_input: dict[str, Any]
) -> dict[str, Any]:
"""Create issue on successful import."""
async_create_issue(
handler.parent_handler.hass,
HOMEASSISTANT_DOMAIN,
f"deprecated_yaml_{DOMAIN}",
breaks_in_ha_version="2024.11.0",
is_fixable=False,
is_persistent=False,
issue_domain=DOMAIN,
severity=IssueSeverity.WARNING,
translation_key="deprecated_yaml",
translation_placeholders={
"domain": DOMAIN,
"integration_title": "Folder Watcher",
},
)
return user_input
OPTIONS_SCHEMA = vol.Schema( OPTIONS_SCHEMA = vol.Schema(
{ {
vol.Optional(CONF_PATTERNS, default=[DEFAULT_PATTERN]): SelectSelector( vol.Optional(CONF_PATTERNS, default=[DEFAULT_PATTERN]): SelectSelector(
@ -88,9 +64,6 @@ DATA_SCHEMA = vol.Schema(
CONFIG_FLOW = { CONFIG_FLOW = {
"user": SchemaFlowFormStep(schema=DATA_SCHEMA, validate_user_input=validate_setup), "user": SchemaFlowFormStep(schema=DATA_SCHEMA, validate_user_input=validate_setup),
"import": SchemaFlowFormStep(
schema=DATA_SCHEMA, validate_user_input=validate_import_setup
),
} }
OPTIONS_FLOW = { OPTIONS_FLOW = {
"init": SchemaFlowFormStep(schema=OPTIONS_SCHEMA), "init": SchemaFlowFormStep(schema=OPTIONS_SCHEMA),

View File

@ -148,39 +148,3 @@ async def test_form_already_configured(hass: HomeAssistant, tmp_path: Path) -> N
assert result["type"] == FlowResultType.ABORT assert result["type"] == FlowResultType.ABORT
assert result["reason"] == "already_configured" assert result["reason"] == "already_configured"
async def test_import(hass: HomeAssistant, tmp_path: Path) -> None:
"""Test import flow."""
path = tmp_path.as_posix()
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_IMPORT},
data={CONF_FOLDER: path, CONF_PATTERNS: ["*"]},
)
await hass.async_block_till_done()
assert result["type"] == FlowResultType.CREATE_ENTRY
assert result["title"] == f"Folder Watcher {path}"
assert result["options"] == {CONF_FOLDER: path, CONF_PATTERNS: ["*"]}
async def test_import_already_configured(hass: HomeAssistant, tmp_path: Path) -> None:
"""Test we abort import when entry is already configured."""
path = tmp_path.as_posix()
entry = MockConfigEntry(
domain=DOMAIN,
title=f"Folder Watcher {path}",
data={CONF_FOLDER: path},
)
entry.add_to_hass(hass)
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_IMPORT},
data={CONF_FOLDER: path},
)
assert result["type"] == FlowResultType.ABORT
assert result["reason"] == "already_configured"

View File

@ -1,33 +1,68 @@
"""The tests for the folder_watcher component.""" """The tests for the folder_watcher component."""
import os from pathlib import Path
from types import SimpleNamespace from types import SimpleNamespace
from unittest.mock import Mock, patch from unittest.mock import Mock, patch
from freezegun.api import FrozenDateTimeFactory
from homeassistant.components import folder_watcher from homeassistant.components import folder_watcher
from homeassistant.components.folder_watcher.const import DOMAIN
from homeassistant.config_entries import SOURCE_USER, ConfigEntryState
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component from homeassistant.helpers import issue_registry as ir
from tests.common import MockConfigEntry
async def test_invalid_path_setup(hass: HomeAssistant) -> None: async def test_invalid_path_setup(
hass: HomeAssistant,
tmp_path: Path,
freezer: FrozenDateTimeFactory,
issue_registry: ir.IssueRegistry,
) -> None:
"""Test that an invalid path is not set up.""" """Test that an invalid path is not set up."""
assert not await async_setup_component( freezer.move_to("2022-04-19 10:31:02+00:00")
hass, path = tmp_path.as_posix()
folder_watcher.DOMAIN, config_entry = MockConfigEntry(
{folder_watcher.DOMAIN: {folder_watcher.CONF_FOLDER: "invalid_path"}}, domain=DOMAIN,
source=SOURCE_USER,
title=f"Folder Watcher {path!s}",
data={},
options={"folder": str(path), "patterns": ["*"]},
entry_id="1",
) )
config_entry.add_to_hass(hass)
async def test_valid_path_setup(hass: HomeAssistant) -> None: await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
assert config_entry.state is ConfigEntryState.SETUP_ERROR
assert len(issue_registry.issues) == 1
async def test_valid_path_setup(
hass: HomeAssistant, tmp_path: Path, freezer: FrozenDateTimeFactory
) -> None:
"""Test that a valid path is setup.""" """Test that a valid path is setup."""
cwd = os.path.join(os.path.dirname(__file__)) freezer.move_to("2022-04-19 10:31:02+00:00")
hass.config.allowlist_external_dirs = {cwd} path = tmp_path.as_posix()
with patch.object(folder_watcher, "Watcher"): hass.config.allowlist_external_dirs = {path}
assert await async_setup_component( config_entry = MockConfigEntry(
hass, domain=DOMAIN,
folder_watcher.DOMAIN, source=SOURCE_USER,
{folder_watcher.DOMAIN: {folder_watcher.CONF_FOLDER: cwd}}, title=f"Folder Watcher {path!s}",
) data={},
options={"folder": str(path), "patterns": ["*"]},
entry_id="1",
)
config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
assert config_entry.state is ConfigEntryState.LOADED
def test_event() -> None: def test_event() -> None: