Use enums for downloader service names and arguments (#183979)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
epenet
2026-10-02 09:35:30 +02:00
committed by GitHub
co-authored by Claude Opus 5.5
parent 880c8e51f5
commit a0de5d63f4
3 changed files with 36 additions and 33 deletions
@@ -7,13 +7,6 @@ LOGGER = logging.getLogger(__package__)
DOMAIN = "downloader"
DEFAULT_NAME = "Downloader"
CONF_DOWNLOAD_DIR = "download_dir"
ATTR_FILENAME = "filename"
ATTR_SUBDIR = "subdir"
ATTR_URL = "url"
ATTR_OVERWRITE = "overwrite"
ATTR_HEADERS = "headers"
DOWNLOAD_FAILED_EVENT = "download_failed"
DOWNLOAD_COMPLETED_EVENT = "download_completed"
SERVICE_DOWNLOAD_FILE = "download_file"
+32 -19
View File
@@ -1,5 +1,6 @@
"""Support for functionality to download files."""
from enum import StrEnum
from http import HTTPStatus
import os
import re
@@ -14,30 +15,40 @@ from homeassistant.helpers.service import async_register_admin_service
from homeassistant.util import raise_if_invalid_filename, raise_if_invalid_path
from .const import (
ATTR_FILENAME,
ATTR_HEADERS,
ATTR_OVERWRITE,
ATTR_SUBDIR,
ATTR_URL,
CONF_DOWNLOAD_DIR,
DOMAIN,
DOWNLOAD_COMPLETED_EVENT,
DOWNLOAD_FAILED_EVENT,
LOGGER,
SERVICE_DOWNLOAD_FILE,
)
class DownloaderService(StrEnum):
"""Store keys for Downloader services."""
DOWNLOAD_FILE = "download_file"
class DownloaderServiceArgument(StrEnum):
"""Store keys for Downloader service arguments."""
FILENAME = "filename"
HEADERS = "headers"
OVERWRITE = "overwrite"
SUBDIR = "subdir"
URL = "url"
async def download_file(service: ServiceCall) -> None:
"""Download file specified in the URL."""
entry = service.hass.config_entries.async_loaded_entries(DOMAIN)[0]
download_path = entry.data[CONF_DOWNLOAD_DIR]
url: str = service.data[ATTR_URL]
subdir: str | None = service.data.get(ATTR_SUBDIR)
target_filename: str | None = service.data.get(ATTR_FILENAME)
overwrite: bool = service.data[ATTR_OVERWRITE]
headers: dict[str, str] = service.data[ATTR_HEADERS]
url: str = service.data[DownloaderServiceArgument.URL]
subdir: str | None = service.data.get(DownloaderServiceArgument.SUBDIR)
target_filename: str | None = service.data.get(DownloaderServiceArgument.FILENAME)
overwrite: bool = service.data[DownloaderServiceArgument.OVERWRITE]
headers: dict[str, str] = service.data[DownloaderServiceArgument.HEADERS]
if subdir:
# Check the path
@@ -163,17 +174,19 @@ def async_setup_services(hass: HomeAssistant) -> None:
async_register_admin_service(
hass,
DOMAIN,
SERVICE_DOWNLOAD_FILE,
DownloaderService.DOWNLOAD_FILE,
download_file,
schema=probatio.Schema(
{
probatio.Optional(ATTR_FILENAME): cv.string,
probatio.Optional(ATTR_SUBDIR): cv.string,
probatio.Required(ATTR_URL): cv.url,
probatio.Optional(ATTR_OVERWRITE, default=False): cv.boolean,
probatio.Optional(ATTR_HEADERS, default=dict): probatio.Schema(
{cv.string: cv.string}
),
probatio.Optional(DownloaderServiceArgument.FILENAME): cv.string,
probatio.Optional(DownloaderServiceArgument.SUBDIR): cv.string,
probatio.Required(DownloaderServiceArgument.URL): cv.url,
probatio.Optional(
DownloaderServiceArgument.OVERWRITE, default=False
): cv.boolean,
probatio.Optional(
DownloaderServiceArgument.HEADERS, default=dict
): probatio.Schema({cv.string: cv.string}),
}
),
)
+4 -7
View File
@@ -4,11 +4,8 @@ from pathlib import Path
import pytest
from homeassistant.components.downloader.const import (
CONF_DOWNLOAD_DIR,
DOMAIN,
SERVICE_DOWNLOAD_FILE,
)
from homeassistant.components.downloader.const import CONF_DOWNLOAD_DIR, DOMAIN
from homeassistant.components.downloader.services import DownloaderService
from homeassistant.config_entries import ConfigEntryState
from homeassistant.core import HomeAssistant
@@ -29,7 +26,7 @@ async def test_config_entry_setup(
"""Test config entry setup."""
config_entry = setup_integration
assert hass.services.has_service(DOMAIN, SERVICE_DOWNLOAD_FILE)
assert hass.services.has_service(DOMAIN, DownloaderService.DOWNLOAD_FILE)
assert config_entry.state is ConfigEntryState.LOADED
@@ -67,5 +64,5 @@ async def test_config_entry_setup_not_existing_directory(
"""Test config entry setup without existing download directory."""
await hass.config_entries.async_setup(mock_config_entry.entry_id)
assert not hass.services.has_service(DOMAIN, SERVICE_DOWNLOAD_FILE)
assert not hass.services.has_service(DOMAIN, DownloaderService.DOWNLOAD_FILE)
assert mock_config_entry.state is ConfigEntryState.SETUP_ERROR