Coverage for custom_components/ha_repl_server/rest.py: 76%
19 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-10-05 13:50 +0000
« prev ^ index » next coverage.py v7.15.4, created at 2026-10-05 13:50 +0000
1"""`hass_api` - an already-connected homeassistant_api.AsyncClient, bound in
2custom mode alongside `hass`/`obj` for parity with API client mode (see
3../../src/homeassistant_repl/rest.py). Duplicated rather than imported
4across the packaging boundary for the same reason as objtree.py/paths.py -
5this component is deployed via HACS with its own `manifest.json`
6requirements, not as a dependent of the PyPI homeassistant_repl package.
8Named `hass_api`, not `api`: `obj.mode("api")` already uses "api" for the
9cached/read-only view `obj` can switch into, and the two are easy to
10conflate in a transcript otherwise.
12There's no notion of "the current admin's token" inside hass itself, so
13this only resolves via the add-on supervisor proxy or an explicit
14$HASS_SERVER/$HASS_TOKEN - see __init__.py for what happens when neither is
15set (a warning, not a failed setup).
16"""
18from __future__ import annotations
20import os
22from homeassistant_api import AsyncClient
23from homeassistant_api.errors import HomeassistantAPIError
26class HassApiUnavailable(Exception):
27 """No usable $SUPERVISOR_TOKEN or $HASS_SERVER/$HASS_TOKEN, or the API
28 didn't respond/authenticate."""
31async def connect_hass_api() -> AsyncClient:
32 if token := os.environ.get("SUPERVISOR_TOKEN"): 32 ↛ 33line 32 didn't jump to line 33 because the condition on line 32 was never true
33 url = "http://supervisor/core/api"
34 elif (server := os.environ.get("HASS_SERVER")) and (
35 token := os.environ.get("HASS_TOKEN")
36 ):
37 url = server.rstrip("/") + "/api"
38 else:
39 raise HassApiUnavailable("no $SUPERVISOR_TOKEN or $HASS_SERVER/$HASS_TOKEN set")
40 client = AsyncClient(url, token)
41 try:
42 running = await client.check_api_running()
43 except (HomeassistantAPIError, OSError) as err:
44 raise HassApiUnavailable(f"cannot reach {url}: {err}") from err
45 if not running: 45 ↛ 46line 45 didn't jump to line 46 because the condition on line 45 was never true
46 raise HassApiUnavailable(f"{url} is not running")
47 return client