diff --git a/homeassistant/helpers/network.py b/homeassistant/helpers/network.py index 58ca191feb0..df95c0834bc 100644 --- a/homeassistant/helpers/network.py +++ b/homeassistant/helpers/network.py @@ -40,7 +40,11 @@ def get_supervisor_network_url( hass: HomeAssistant, *, allow_ssl: bool = False ) -> str | None: """Get URL for home assistant within supervisor network.""" - if hass.config.api is None or not hass.components.hassio.is_hassio(): + # Local import to avoid circular dependencies + # pylint: disable-next=import-outside-toplevel + from homeassistant.components.hassio import is_hassio + + if hass.config.api is None or not is_hassio(hass): return None scheme = "http" @@ -170,14 +174,17 @@ def get_url( and request_host is not None and hass.config.api is not None ): + # Local import to avoid circular dependencies + # pylint: disable-next=import-outside-toplevel + from homeassistant.components.hassio import get_host_info, is_hassio + scheme = "https" if hass.config.api.use_ssl else "http" current_url = yarl.URL.build( scheme=scheme, host=request_host, port=hass.config.api.port ) known_hostnames = ["localhost"] - if hass.components.hassio.is_hassio(): - host_info = hass.components.hassio.get_host_info() + if is_hassio(hass) and (host_info := get_host_info(hass)): known_hostnames.extend( [host_info["hostname"], f"{host_info['hostname']}.local"] ) diff --git a/homeassistant/helpers/system_info.py b/homeassistant/helpers/system_info.py index 8af04c11c18..31097ec923e 100644 --- a/homeassistant/helpers/system_info.py +++ b/homeassistant/helpers/system_info.py @@ -30,7 +30,11 @@ cached_get_user = cache(getuser) @bind_hass async def async_get_system_info(hass: HomeAssistant) -> dict[str, Any]: """Return info about the system.""" - is_hassio = hass.components.hassio.is_hassio() + # Local import to avoid circular dependencies + # pylint: disable-next=import-outside-toplevel + from homeassistant.components import hassio + + is_hassio = hassio.is_hassio(hass) info_object = { "installation_type": "Unknown", @@ -68,11 +72,11 @@ async def async_get_system_info(hass: HomeAssistant) -> dict[str, Any]: # Enrich with Supervisor information if is_hassio: - if not (info := hass.components.hassio.get_info()): + if not (info := hassio.get_info(hass)): _LOGGER.warning("No Home Assistant Supervisor info available") info = {} - host = hass.components.hassio.get_host_info() or {} + host = hassio.get_host_info(hass) or {} info_object["supervisor"] = info.get("supervisor") info_object["host_os"] = host.get("operating_system") info_object["docker_version"] = info.get("docker") diff --git a/tests/components/hassio/test_init.py b/tests/components/hassio/test_init.py index 7d0943b3677..a6f94152af0 100644 --- a/tests/components/hassio/test_init.py +++ b/tests/components/hassio/test_init.py @@ -15,7 +15,9 @@ from homeassistant.components.hassio import ( DOMAIN, STORAGE_KEY, async_get_addon_store_info, + get_core_info, hostname_from_addon_slug, + is_hassio, ) from homeassistant.components.hassio.const import REQUEST_REFRESH_DELAY from homeassistant.components.hassio.handler import HassioAPIError @@ -246,8 +248,8 @@ async def test_setup_api_ping( assert result assert aioclient_mock.call_count == 19 - assert hass.components.hassio.get_core_info()["version_latest"] == "1.0.0" - assert hass.components.hassio.is_hassio() + assert get_core_info(hass)["version_latest"] == "1.0.0" + assert is_hassio(hass) async def test_setup_api_panel( @@ -465,7 +467,7 @@ async def test_warn_when_cannot_connect( result = await async_setup_component(hass, "hassio", {}) assert result - assert hass.components.hassio.is_hassio() + assert is_hassio(hass) assert "Not connected with the supervisor / system too busy!" in caplog.text diff --git a/tests/helpers/test_network.py b/tests/helpers/test_network.py index b8fbfc9346b..37603a99a8b 100644 --- a/tests/helpers/test_network.py +++ b/tests/helpers/test_network.py @@ -565,6 +565,11 @@ async def test_get_request_host(hass: HomeAssistant) -> None: assert _get_request_host() == "example.com" +@patch("homeassistant.components.hassio.is_hassio", Mock(return_value=True)) +@patch( + "homeassistant.components.hassio.get_host_info", + Mock(return_value={"hostname": "homeassistant"}), +) async def test_get_current_request_url_with_known_host( hass: HomeAssistant, current_request ) -> None: @@ -595,10 +600,6 @@ async def test_get_current_request_url_with_known_host( # Ensure hostname from Supervisor is accepted transparently mock_component(hass, "hassio") - hass.components.hassio.is_hassio = Mock(return_value=True) - hass.components.hassio.get_host_info = Mock( - return_value={"hostname": "homeassistant"} - ) with patch( "homeassistant.helpers.network._get_request_host", @@ -623,6 +624,14 @@ async def test_get_current_request_url_with_known_host( get_url(hass, require_current_request=True) +@patch( + "homeassistant.components.hassio.is_hassio", + Mock(return_value={"hostname": "homeassistant"}), +) +@patch( + "homeassistant.components.hassio.get_host_info", + Mock(return_value={"hostname": "hellohost"}), +) async def test_is_internal_request(hass: HomeAssistant, mock_current_request) -> None: """Test if accessing an instance on its internal URL.""" # Test with internal URL: http://example.local:8123 @@ -662,16 +671,9 @@ async def test_is_internal_request(hass: HomeAssistant, mock_current_request) -> assert is_internal_request(hass), mock_current_request.return_value.url # Test for matching against HassOS hostname - with patch.object( - hass.components.hassio, "is_hassio", return_value=True - ), patch.object( - hass.components.hassio, - "get_host_info", - return_value={"hostname": "hellohost"}, - ): - for allowed in ("hellohost", "hellohost.local"): - mock_current_request.return_value = Mock(url=f"http://{allowed}:8123") - assert is_internal_request(hass), mock_current_request.return_value.url + for allowed in ("hellohost", "hellohost.local"): + mock_current_request.return_value = Mock(url=f"http://{allowed}:8123") + assert is_internal_request(hass), mock_current_request.return_value.url async def test_is_hass_url(hass: HomeAssistant) -> None: