Skip to content

Commit 612c1b8

Browse files
committed
Add addon availability API
1 parent 441429f commit 612c1b8

File tree

3 files changed

+157
-0
lines changed

3 files changed

+157
-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: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
"""Store client for supervisor."""
22

3+
import re
4+
35
from .client import _SupervisorComponentClient
46
from .const import ResponseType
7+
from .exceptions import (
8+
AddonNotSupportedArchitectureError,
9+
AddonNotSupportedError,
10+
AddonNotSupportedHomeAssistantVersionError,
11+
AddonNotSupportedMachineTypeError,
12+
SupervisorBadRequestError,
13+
)
514
from .models.addons import (
615
Repository,
716
StoreAddon,
@@ -12,6 +21,19 @@
1221
StoreInfo,
1322
)
1423

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

1638
class StoreClient(_SupervisorComponentClient):
1739
"""Handles store access in Supervisor."""
@@ -45,6 +67,37 @@ async def addon_documentation(self, addon: str) -> str:
4567
)
4668
return result.data
4769

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

tests/test_store.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
"""Tests for store supervisor client."""
22

33
from aioresponses import aioresponses
4+
import pytest
45
from yarl import URL
56

67
from aiohasupervisor import SupervisorClient
8+
from aiohasupervisor.exceptions import (
9+
AddonNotSupportedArchitectureError,
10+
AddonNotSupportedError,
11+
AddonNotSupportedHomeAssistantVersionError,
12+
AddonNotSupportedMachineTypeError,
13+
)
714
from aiohasupervisor.models import StoreAddonUpdate, StoreAddRepository
815

916
from . import load_fixture
@@ -132,6 +139,59 @@ async def test_store_addon_update(
132139
}
133140

134141

142+
async def test_store_addon_availability(
143+
responses: aioresponses, supervisor_client: SupervisorClient
144+
) -> None:
145+
"""Test store addon availability API."""
146+
responses.get(
147+
f"{SUPERVISOR_URL}/store/addons/core_mosquitto/availability", status=200
148+
)
149+
150+
assert (await supervisor_client.store.addon_availability("core_mosquitto")) is None
151+
152+
153+
@pytest.mark.parametrize(
154+
("error_msg", "exc_type"),
155+
[
156+
(
157+
"Add-on core_mosquitto not supported on this platform, "
158+
"supported architectures: i386",
159+
AddonNotSupportedArchitectureError,
160+
),
161+
(
162+
"Add-on core_mosquitto not supported on this machine, "
163+
"supported machine types: odroid-n2",
164+
AddonNotSupportedMachineTypeError,
165+
),
166+
(
167+
"Add-on core_mosquitto not supported on this system, "
168+
"requires Home Assistant version 2023.1.1 or greater",
169+
AddonNotSupportedHomeAssistantVersionError,
170+
),
171+
(
172+
"Add-on core_mosquitto not supported on this system, "
173+
"requires <something new> to be <something else>",
174+
AddonNotSupportedError,
175+
),
176+
],
177+
)
178+
async def test_store_addon_availability_error(
179+
responses: aioresponses,
180+
supervisor_client: SupervisorClient,
181+
error_msg: str,
182+
exc_type: type[AddonNotSupportedError],
183+
) -> None:
184+
"""Test store addon availability API error."""
185+
responses.get(
186+
f"{SUPERVISOR_URL}/store/addons/core_mosquitto/availability",
187+
status=400,
188+
body=f'{{"result": "error", "message": "{error_msg}"}}',
189+
)
190+
191+
with pytest.raises(exc_type):
192+
await supervisor_client.store.addon_availability("core_mosquitto")
193+
194+
135195
async def test_store_reload(
136196
responses: aioresponses, supervisor_client: SupervisorClient
137197
) -> None:

0 commit comments

Comments
 (0)