Remove deprecated services in SABnzbd (#144405)

Co-authored-by: Franck Nijhof <git@frenck.dev>
This commit is contained in:
Joost Lekkerkerker 2025-05-08 20:02:24 +02:00 committed by GitHub
parent 04867f6ecc
commit cb6847b64c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 11 additions and 276 deletions

View File

@ -2,148 +2,18 @@
from __future__ import annotations
from collections.abc import Callable, Coroutine
import logging
from typing import Any
import voluptuous as vol
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant, ServiceCall, callback
from homeassistant.exceptions import ConfigEntryNotReady, HomeAssistantError
from homeassistant.helpers import config_validation as cv, issue_registry as ir
from homeassistant.helpers.typing import ConfigType
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from .const import (
ATTR_API_KEY,
ATTR_SPEED,
DEFAULT_SPEED_LIMIT,
DOMAIN,
SERVICE_PAUSE,
SERVICE_RESUME,
SERVICE_SET_SPEED,
)
from .coordinator import SabnzbdConfigEntry, SabnzbdUpdateCoordinator
from .helpers import get_client
PLATFORMS = [Platform.BINARY_SENSOR, Platform.BUTTON, Platform.NUMBER, Platform.SENSOR]
_LOGGER = logging.getLogger(__name__)
SERVICES = (
SERVICE_PAUSE,
SERVICE_RESUME,
SERVICE_SET_SPEED,
)
SERVICE_BASE_SCHEMA = vol.Schema(
{
vol.Required(ATTR_API_KEY): cv.string,
}
)
SERVICE_SPEED_SCHEMA = SERVICE_BASE_SCHEMA.extend(
{
vol.Optional(ATTR_SPEED, default=DEFAULT_SPEED_LIMIT): cv.string,
}
)
CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
@callback
def async_get_entry_for_service_call(
hass: HomeAssistant, call: ServiceCall
) -> SabnzbdConfigEntry:
"""Get the entry ID related to a service call (by device ID)."""
call_data_api_key = call.data[ATTR_API_KEY]
for entry in hass.config_entries.async_entries(DOMAIN):
if entry.data[ATTR_API_KEY] == call_data_api_key:
return entry
raise ValueError(f"No api for API key: {call_data_api_key}")
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the SabNzbd Component."""
@callback
def extract_api(
func: Callable[
[ServiceCall, SabnzbdUpdateCoordinator], Coroutine[Any, Any, None]
],
) -> Callable[[ServiceCall], Coroutine[Any, Any, None]]:
"""Define a decorator to get the correct api for a service call."""
async def wrapper(call: ServiceCall) -> None:
"""Wrap the service function."""
config_entry = async_get_entry_for_service_call(hass, call)
coordinator = config_entry.runtime_data
try:
await func(call, coordinator)
except Exception as err:
raise HomeAssistantError(
f"Error while executing {func.__name__}: {err}"
) from err
return wrapper
@extract_api
async def async_pause_queue(
call: ServiceCall, coordinator: SabnzbdUpdateCoordinator
) -> None:
ir.async_create_issue(
hass,
DOMAIN,
"pause_action_deprecated",
is_fixable=False,
severity=ir.IssueSeverity.WARNING,
breaks_in_ha_version="2025.6",
translation_key="pause_action_deprecated",
)
await coordinator.sab_api.pause_queue()
@extract_api
async def async_resume_queue(
call: ServiceCall, coordinator: SabnzbdUpdateCoordinator
) -> None:
ir.async_create_issue(
hass,
DOMAIN,
"resume_action_deprecated",
is_fixable=False,
severity=ir.IssueSeverity.WARNING,
breaks_in_ha_version="2025.6",
translation_key="resume_action_deprecated",
)
await coordinator.sab_api.resume_queue()
@extract_api
async def async_set_queue_speed(
call: ServiceCall, coordinator: SabnzbdUpdateCoordinator
) -> None:
ir.async_create_issue(
hass,
DOMAIN,
"set_speed_action_deprecated",
is_fixable=False,
severity=ir.IssueSeverity.WARNING,
breaks_in_ha_version="2025.6",
translation_key="set_speed_action_deprecated",
)
speed = call.data.get(ATTR_SPEED)
await coordinator.sab_api.set_speed_limit(speed)
for service, method, schema in (
(SERVICE_PAUSE, async_pause_queue, SERVICE_BASE_SCHEMA),
(SERVICE_RESUME, async_resume_queue, SERVICE_BASE_SCHEMA),
(SERVICE_SET_SPEED, async_set_queue_speed, SERVICE_SPEED_SCHEMA),
):
hass.services.async_register(DOMAIN, service, method, schema=schema)
return True
async def async_setup_entry(hass: HomeAssistant, entry: SabnzbdConfigEntry) -> bool:
"""Set up the SabNzbd Component."""

View File

@ -1,12 +1,3 @@
"""Constants for the Sabnzbd component."""
DOMAIN = "sabnzbd"
ATTR_SPEED = "speed"
ATTR_API_KEY = "api_key"
DEFAULT_SPEED_LIMIT = "100"
SERVICE_PAUSE = "pause"
SERVICE_RESUME = "resume"
SERVICE_SET_SPEED = "set_speed"

View File

@ -13,16 +13,5 @@
"default": "mdi:speedometer"
}
}
},
"services": {
"pause": {
"service": "mdi:pause"
},
"resume": {
"service": "mdi:play"
},
"set_speed": {
"service": "mdi:speedometer"
}
}
}

View File

@ -1,6 +1,9 @@
rules:
# Bronze
action-setup: done
action-setup:
status: exempt
comment: |
The integration does not provide any actions.
appropriate-polling: done
brands: done
common-modules: done
@ -10,7 +13,7 @@ rules:
docs-actions:
status: exempt
comment: |
The integration has deprecated the actions, thus the documentation has been removed.
The integration does not provide any actions.
docs-high-level-description: done
docs-installation-instructions: done
docs-removal-instructions: done
@ -26,10 +29,7 @@ rules:
unique-config-entry: done
# Silver
action-exceptions:
status: todo
comment: |
Raise ServiceValidationError in async_get_entry_for_service_call.
action-exceptions: done
config-entry-unloading: done
docs-configuration-parameters:
status: exempt

View File

@ -1,23 +0,0 @@
pause:
fields:
api_key:
required: true
selector:
text:
resume:
fields:
api_key:
required: true
selector:
text:
set_speed:
fields:
api_key:
required: true
selector:
text:
speed:
example: 100
default: 100
selector:
text:

View File

@ -32,7 +32,7 @@
"name": "[%key:common::action::pause%]"
},
"resume": {
"name": "[%key:component::sabnzbd::services::resume::name%]"
"name": "Resume"
}
},
"number": {
@ -76,56 +76,6 @@
}
}
},
"services": {
"pause": {
"name": "[%key:common::action::pause%]",
"description": "Pauses downloads.",
"fields": {
"api_key": {
"name": "SABnzbd API key",
"description": "The SABnzbd API key to pause downloads."
}
}
},
"resume": {
"name": "Resume",
"description": "Resumes downloads.",
"fields": {
"api_key": {
"name": "[%key:component::sabnzbd::services::pause::fields::api_key::name%]",
"description": "The SABnzbd API key to resume downloads."
}
}
},
"set_speed": {
"name": "Set speed",
"description": "Sets the download speed limit.",
"fields": {
"api_key": {
"name": "[%key:component::sabnzbd::services::pause::fields::api_key::name%]",
"description": "The SABnzbd API key to set speed limit."
},
"speed": {
"name": "Speed",
"description": "Speed limit. If specified as a number with no units, will be interpreted as a percent. If units are provided (e.g., 500K) will be interpreted absolutely."
}
}
}
},
"issues": {
"pause_action_deprecated": {
"title": "SABnzbd pause action deprecated",
"description": "The 'Pause' action is deprecated and will be removed in a future version. Please use the 'Pause' button instead. To remove this issue, please adjust automations accordingly and restart Home Assistant."
},
"resume_action_deprecated": {
"title": "SABnzbd resume action deprecated",
"description": "The 'Resume' action is deprecated and will be removed in a future version. Please use the 'Resume' button instead. To remove this issue, please adjust automations accordingly and restart Home Assistant."
},
"set_speed_action_deprecated": {
"title": "SABnzbd set_speed action deprecated",
"description": "The 'Set speed' action is deprecated and will be removed in a future version. Please use the 'Speedlimit' number entity instead. To remove this issue, please adjust automations accordingly and restart Home Assistant."
}
},
"exceptions": {
"service_call_exception": {
"message": "Unable to send command to SABnzbd due to a connection error, try again later"

View File

@ -5,7 +5,7 @@ from unittest.mock import AsyncMock, patch
import pytest
from homeassistant.components.sabnzbd import DOMAIN
from homeassistant.components.sabnzbd.const import DOMAIN
from homeassistant.const import CONF_API_KEY, CONF_URL
from homeassistant.core import HomeAssistant
from homeassistant.setup import async_setup_component

View File

@ -6,7 +6,7 @@ from pysabnzbd import SabnzbdApiException
import pytest
from homeassistant import config_entries
from homeassistant.components.sabnzbd import DOMAIN
from homeassistant.components.sabnzbd.const import DOMAIN
from homeassistant.config_entries import SOURCE_USER
from homeassistant.const import CONF_API_KEY, CONF_URL
from homeassistant.core import HomeAssistant

View File

@ -1,42 +0,0 @@
"""Tests for the SABnzbd Integration."""
import pytest
from homeassistant.components.sabnzbd.const import (
ATTR_API_KEY,
DOMAIN,
SERVICE_PAUSE,
SERVICE_RESUME,
SERVICE_SET_SPEED,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import issue_registry as ir
@pytest.mark.parametrize(
("service", "issue_id"),
[
(SERVICE_RESUME, "resume_action_deprecated"),
(SERVICE_PAUSE, "pause_action_deprecated"),
(SERVICE_SET_SPEED, "set_speed_action_deprecated"),
],
)
@pytest.mark.usefixtures("setup_integration")
async def test_deprecated_service_creates_issue(
hass: HomeAssistant,
issue_registry: ir.IssueRegistry,
service: str,
issue_id: str,
) -> None:
"""Test that deprecated actions creates an issue."""
await hass.services.async_call(
DOMAIN,
service,
{ATTR_API_KEY: "edc3eee7330e4fdda04489e3fbc283d0"},
blocking=True,
)
issue = issue_registry.async_get_issue(domain=DOMAIN, issue_id=issue_id)
assert issue
assert issue.severity == ir.IssueSeverity.WARNING
assert issue.breaks_in_ha_version == "2025.6"