Skip to content

Commit a6fe784

Browse files
committed
Add addon availability API
1 parent 7bbea79 commit a6fe784

File tree

3 files changed

+155
-0
lines changed

3 files changed

+155
-0
lines changed

aiohasupervisor/exceptions.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,47 @@ class SupervisorServiceUnavailableError(SupervisorError):
4444

4545
class SupervisorResponseError(SupervisorError):
4646
"""Unusable response received from Supervisor with the wrong type or encoding."""
47+
48+
49+
class AddonNotSupportedError(SupervisorError):
50+
"""Addon is not supported on this system."""
51+
52+
53+
class AddonNotSupportedArchitectureError(AddonNotSupportedError):
54+
"""Addon is not supported on this system due to its architecture."""
55+
56+
def __init__(
57+
self, addon: str, architectures: str, job_id: str | None = None
58+
) -> None:
59+
"""Initialize exception."""
60+
super().__init__(
61+
f"Add-on {addon} not supported on this platform, "
62+
f"supported architectures: {architectures}",
63+
job_id,
64+
)
65+
66+
67+
class AddonNotSupportedMachineTypeError(AddonNotSupportedError):
68+
"""Addon is not supported on this system due to its machine type."""
69+
70+
def __init__(
71+
self, addon: str, machine_types: str, job_id: str | None = None
72+
) -> None:
73+
"""Initialize exception."""
74+
super().__init__(
75+
f"Add-on {addon} not supported on this machine, "
76+
f"supported machine types: {machine_types}",
77+
job_id,
78+
)
79+
80+
81+
class AddonNotSupportedHomeAssistantVersionError(AddonNotSupportedError):
82+
"""Addon is not supported on this system due to its version of Home Assistant."""
83+
84+
def __init__(self, addon: str, version: str, job_id: str | None = None) -> None:
85+
"""Initialize exception."""
86+
super().__init__(
87+
f"Add-on {addon} not supported on this system, "
88+
f"requires Home Assistant version {version} or greater",
89+
job_id,
90+
)

aiohasupervisor/store.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
"""Store client for supervisor."""
22

3+
import re
34
from typing import Any
45

56
from .client import _SupervisorComponentClient
67
from .const import ResponseType
8+
from .exceptions import (
9+
AddonNotSupportedArchitectureError,
10+
AddonNotSupportedError,
11+
AddonNotSupportedHomeAssistantVersionError,
12+
AddonNotSupportedMachineTypeError,
13+
SupervisorBadRequestError,
14+
)
715
from .models.addons import (
816
Repository,
917
StoreAddon,
@@ -15,6 +23,19 @@
1523
StoreInfo,
1624
)
1725

26+
RE_ADDON_UNAVAILABLE_ARCHITECTURE = re.compile(
27+
r"^Add\-on (?P<addon>\w+) not supported on this platform, "
28+
r"supported architectures: (?P<architectures>.*)$"
29+
)
30+
RE_ADDON_UNAVAILABLE_MACHINE_TYPE = re.compile(
31+
r"^Add\-on (?P<addon>\w+) not supported on this machine, "
32+
r"supported machine types: (?P<machine_types>.*)$"
33+
)
34+
RE_ADDON_UNAVAILABLE_HOME_ASSISTANT = re.compile(
35+
r"^Add\-on (?P<addon>\w+) not supported on this system, "
36+
r"requires Home Assistant version (?P<version>\S+) or greater$"
37+
)
38+
1839

1940
class StoreClient(_SupervisorComponentClient):
2041
"""Handles store access in Supervisor."""
@@ -48,6 +69,37 @@ async def addon_documentation(self, addon: str) -> str:
4869
)
4970
return result.data
5071

72+
async def addon_availability(self, addon: str) -> None:
73+
"""Determine if latest version of addon can be installed on this system.
74+
75+
No return means it can be. If not, raises one of the following errors:
76+
- AddonUnavailableHomeAssistantVersionError
77+
- AddonUnavailableArchitectureError
78+
- AddonUnavailableMachineTypeError
79+
80+
If Supervisor adds a new reason an add-on can be restricted from being
81+
installed on some systems in the future, older versions of this client
82+
will raise the generic AddonNotSupportedError for that reason.
83+
"""
84+
try:
85+
await self._client.get(
86+
f"store/addons/{addon}/availability", response_type=ResponseType.NONE
87+
)
88+
except SupervisorBadRequestError as err:
89+
if match := RE_ADDON_UNAVAILABLE_ARCHITECTURE.match(str(err)):
90+
raise AddonNotSupportedArchitectureError(
91+
match.group("addon"), match.group("architectures"), err.job_id
92+
) from None
93+
if match := RE_ADDON_UNAVAILABLE_HOME_ASSISTANT.match(str(err)):
94+
raise AddonNotSupportedHomeAssistantVersionError(
95+
match.group("addon"), match.group("version"), err.job_id
96+
) from None
97+
if match := RE_ADDON_UNAVAILABLE_MACHINE_TYPE.match(str(err)):
98+
raise AddonNotSupportedMachineTypeError(
99+
match.group("addon"), match.group("machine_types"), err.job_id
100+
) from None
101+
raise AddonNotSupportedError(str(err), err.job_id) from None
102+
51103
async def install_addon(
52104
self, addon: str, options: StoreAddonInstall | None = None
53105
) -> None:

tests/test_store.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
from yarl import URL
66

77
from aiohasupervisor import SupervisorClient
8+
from aiohasupervisor.exceptions import (
9+
AddonNotSupportedArchitectureError,
10+
AddonNotSupportedError,
11+
AddonNotSupportedHomeAssistantVersionError,
12+
AddonNotSupportedMachineTypeError,
13+
)
814
from aiohasupervisor.models import StoreAddonUpdate, StoreAddRepository
915
from aiohasupervisor.models.addons import StoreAddonInstall
1016

@@ -169,6 +175,59 @@ async def test_store_addon_update(
169175
)
170176

171177

178+
async def test_store_addon_availability(
179+
responses: aioresponses, supervisor_client: SupervisorClient
180+
) -> None:
181+
"""Test store addon availability API."""
182+
responses.get(
183+
f"{SUPERVISOR_URL}/store/addons/core_mosquitto/availability", status=200
184+
)
185+
186+
assert (await supervisor_client.store.addon_availability("core_mosquitto")) is None
187+
188+
189+
@pytest.mark.parametrize(
190+
("error_msg", "exc_type"),
191+
[
192+
(
193+
"Add-on core_mosquitto not supported on this platform, "
194+
"supported architectures: i386",
195+
AddonNotSupportedArchitectureError,
196+
),
197+
(
198+
"Add-on core_mosquitto not supported on this machine, "
199+
"supported machine types: odroid-n2",
200+
AddonNotSupportedMachineTypeError,
201+
),
202+
(
203+
"Add-on core_mosquitto not supported on this system, "
204+
"requires Home Assistant version 2023.1.1 or greater",
205+
AddonNotSupportedHomeAssistantVersionError,
206+
),
207+
(
208+
"Add-on core_mosquitto not supported on this system, "
209+
"requires <something new> to be <something else>",
210+
AddonNotSupportedError,
211+
),
212+
],
213+
)
214+
async def test_store_addon_availability_error(
215+
responses: aioresponses,
216+
supervisor_client: SupervisorClient,
217+
error_msg: str,
218+
exc_type: type[AddonNotSupportedError],
219+
) -> None:
220+
"""Test store addon availability API error."""
221+
responses.get(
222+
f"{SUPERVISOR_URL}/store/addons/core_mosquitto/availability",
223+
status=400,
224+
body=f'{{"result": "error", "message": "{error_msg}"}}',
225+
)
226+
227+
with pytest.raises(exc_type):
228+
await supervisor_client.store.addon_availability("core_mosquitto")
229+
230+
172231
async def test_store_reload(
173232
responses: aioresponses, supervisor_client: SupervisorClient
174233
) -> None:

0 commit comments

Comments
 (0)