mirror of
https://github.com/home-assistant/core.git
synced 2026-08-28 10:16:02 -05:00
Use service helper in Sonarr (#174273)
This commit is contained in:
@@ -7,11 +7,10 @@ from typing import Any, cast
|
||||
from aiopyarr import exceptions
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
from homeassistant.const import CONF_URL
|
||||
from homeassistant.core import HomeAssistant, ServiceCall, SupportsResponse, callback
|
||||
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||
from homeassistant.helpers import selector
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import selector, service
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from .const import (
|
||||
@@ -100,24 +99,6 @@ SERVICE_GET_WANTED_SCHEMA = SERVICE_BASE_SCHEMA.extend(
|
||||
)
|
||||
|
||||
|
||||
def _get_config_entry_from_service_data(call: ServiceCall) -> SonarrConfigEntry:
|
||||
"""Return config entry for entry id."""
|
||||
config_entry_id: str = call.data[ATTR_ENTRY_ID]
|
||||
if not (entry := call.hass.config_entries.async_get_entry(config_entry_id)):
|
||||
raise ServiceValidationError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="integration_not_found",
|
||||
translation_placeholders={"target": config_entry_id},
|
||||
)
|
||||
if entry.state is not ConfigEntryState.LOADED:
|
||||
raise ServiceValidationError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="not_loaded",
|
||||
translation_placeholders={"target": entry.title},
|
||||
)
|
||||
return cast(SonarrConfigEntry, entry)
|
||||
|
||||
|
||||
async def _handle_api_errors[_T](func: Callable[[], Awaitable[_T]]) -> _T:
|
||||
"""Handle API errors and raise HomeAssistantError with user-friendly messages."""
|
||||
try:
|
||||
@@ -130,9 +111,11 @@ async def _handle_api_errors[_T](func: Callable[[], Awaitable[_T]]) -> _T:
|
||||
raise HomeAssistantError(f"Sonarr API error: {ex}") from ex
|
||||
|
||||
|
||||
async def _async_get_series(service: ServiceCall) -> dict[str, Any]:
|
||||
async def _async_get_series(call: ServiceCall) -> dict[str, Any]:
|
||||
"""Get all Sonarr series."""
|
||||
entry = _get_config_entry_from_service_data(service)
|
||||
entry: SonarrConfigEntry = service.async_get_config_entry(
|
||||
call.hass, DOMAIN, call.data[ATTR_ENTRY_ID]
|
||||
)
|
||||
|
||||
api_client = entry.runtime_data.status.api_client
|
||||
series_list = await _handle_api_errors(api_client.async_get_series)
|
||||
@@ -143,11 +126,13 @@ async def _async_get_series(service: ServiceCall) -> dict[str, Any]:
|
||||
return {ATTR_SHOWS: shows}
|
||||
|
||||
|
||||
async def _async_get_episodes(service: ServiceCall) -> dict[str, Any]:
|
||||
async def _async_get_episodes(call: ServiceCall) -> dict[str, Any]:
|
||||
"""Get episodes for a specific series."""
|
||||
entry = _get_config_entry_from_service_data(service)
|
||||
series_id: int = service.data[CONF_SERIES_ID]
|
||||
season_number: int | None = service.data.get(CONF_SEASON_NUMBER)
|
||||
entry: SonarrConfigEntry = service.async_get_config_entry(
|
||||
call.hass, DOMAIN, call.data[ATTR_ENTRY_ID]
|
||||
)
|
||||
series_id: int = call.data[CONF_SERIES_ID]
|
||||
season_number: int | None = call.data.get(CONF_SEASON_NUMBER)
|
||||
|
||||
api_client = entry.runtime_data.status.api_client
|
||||
episodes = await _handle_api_errors(
|
||||
@@ -159,10 +144,12 @@ async def _async_get_episodes(service: ServiceCall) -> dict[str, Any]:
|
||||
return {ATTR_EPISODES: formatted_episodes}
|
||||
|
||||
|
||||
async def _async_get_queue(service: ServiceCall) -> dict[str, Any]:
|
||||
async def _async_get_queue(call: ServiceCall) -> dict[str, Any]:
|
||||
"""Get Sonarr queue."""
|
||||
entry = _get_config_entry_from_service_data(service)
|
||||
max_items: int = service.data[CONF_MAX_ITEMS]
|
||||
entry: SonarrConfigEntry = service.async_get_config_entry(
|
||||
call.hass, DOMAIN, call.data[ATTR_ENTRY_ID]
|
||||
)
|
||||
max_items: int = call.data[CONF_MAX_ITEMS]
|
||||
|
||||
api_client = entry.runtime_data.status.api_client
|
||||
# 0 means no limit - use a large page size to get all items
|
||||
@@ -179,10 +166,12 @@ async def _async_get_queue(service: ServiceCall) -> dict[str, Any]:
|
||||
return {ATTR_SHOWS: shows}
|
||||
|
||||
|
||||
async def _async_get_diskspace(service: ServiceCall) -> dict[str, Any]:
|
||||
async def _async_get_diskspace(call: ServiceCall) -> dict[str, Any]:
|
||||
"""Get Sonarr diskspace information."""
|
||||
entry = _get_config_entry_from_service_data(service)
|
||||
space_unit: str = service.data[CONF_SPACE_UNIT]
|
||||
entry: SonarrConfigEntry = service.async_get_config_entry(
|
||||
call.hass, DOMAIN, call.data[ATTR_ENTRY_ID]
|
||||
)
|
||||
space_unit: str = call.data[CONF_SPACE_UNIT]
|
||||
|
||||
api_client = entry.runtime_data.status.api_client
|
||||
disks = await _handle_api_errors(api_client.async_get_diskspace)
|
||||
@@ -190,10 +179,12 @@ async def _async_get_diskspace(service: ServiceCall) -> dict[str, Any]:
|
||||
return {ATTR_DISKS: format_diskspace(disks, space_unit)}
|
||||
|
||||
|
||||
async def _async_get_upcoming(service: ServiceCall) -> dict[str, Any]:
|
||||
async def _async_get_upcoming(call: ServiceCall) -> dict[str, Any]:
|
||||
"""Get Sonarr upcoming episodes."""
|
||||
entry = _get_config_entry_from_service_data(service)
|
||||
days: int = service.data[CONF_DAYS]
|
||||
entry: SonarrConfigEntry = service.async_get_config_entry(
|
||||
call.hass, DOMAIN, call.data[ATTR_ENTRY_ID]
|
||||
)
|
||||
days: int = call.data[CONF_DAYS]
|
||||
|
||||
api_client = entry.runtime_data.status.api_client
|
||||
|
||||
@@ -213,10 +204,12 @@ async def _async_get_upcoming(service: ServiceCall) -> dict[str, Any]:
|
||||
return {ATTR_EPISODES: episodes}
|
||||
|
||||
|
||||
async def _async_get_wanted(service: ServiceCall) -> dict[str, Any]:
|
||||
async def _async_get_wanted(call: ServiceCall) -> dict[str, Any]:
|
||||
"""Get Sonarr wanted/missing episodes."""
|
||||
entry = _get_config_entry_from_service_data(service)
|
||||
max_items: int = service.data[CONF_MAX_ITEMS]
|
||||
entry: SonarrConfigEntry = service.async_get_config_entry(
|
||||
call.hass, DOMAIN, call.data[ATTR_ENTRY_ID]
|
||||
)
|
||||
max_items: int = call.data[CONF_MAX_ITEMS]
|
||||
|
||||
api_client = entry.runtime_data.status.api_client
|
||||
# 0 means no limit - use a large page size to get all items
|
||||
|
||||
@@ -58,14 +58,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"exceptions": {
|
||||
"integration_not_found": {
|
||||
"message": "Config entry for integration \"{target}\" not found."
|
||||
},
|
||||
"not_loaded": {
|
||||
"message": "Config entry \"{target}\" is not loaded."
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
|
||||
@@ -66,7 +66,7 @@ async def test_services_config_entry_not_loaded_state(
|
||||
return_response=True,
|
||||
)
|
||||
|
||||
assert exc_info.value.translation_key == "not_loaded"
|
||||
assert exc_info.value.translation_key == "service_config_entry_not_loaded"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -94,7 +94,7 @@ async def test_services_integration_not_found(
|
||||
return_response=True,
|
||||
)
|
||||
|
||||
assert exc_info.value.translation_key == "integration_not_found"
|
||||
assert exc_info.value.translation_key == "service_config_entry_not_found"
|
||||
|
||||
|
||||
async def test_service_get_series(
|
||||
@@ -168,7 +168,7 @@ async def test_services_entry_not_loaded(
|
||||
return_response=True,
|
||||
)
|
||||
|
||||
assert exc_info.value.translation_key == "not_loaded"
|
||||
assert exc_info.value.translation_key == "service_config_entry_not_loaded"
|
||||
|
||||
|
||||
async def test_service_get_queue_empty(
|
||||
|
||||
Reference in New Issue
Block a user