diff --git a/Dockerfile.dev b/Dockerfile.dev index 5a3f1a2ae6480b..4c037799567b73 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -1,15 +1,7 @@ -FROM mcr.microsoft.com/devcontainers/python:1-3.13 +FROM mcr.microsoft.com/vscode/devcontainers/base:debian SHELL ["/bin/bash", "-o", "pipefail", "-c"] -# Uninstall pre-installed formatting and linting tools -# They would conflict with our pinned versions -RUN \ - pipx uninstall pydocstyle \ - && pipx uninstall pycodestyle \ - && pipx uninstall mypy \ - && pipx uninstall pylint - RUN \ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \ && apt-get update \ @@ -32,21 +24,18 @@ RUN \ libxml2 \ git \ cmake \ + autoconf \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* # Add go2rtc binary COPY --from=ghcr.io/alexxit/go2rtc:latest /usr/local/bin/go2rtc /bin/go2rtc -# Install uv -RUN pip3 install uv - WORKDIR /usr/src -# Setup hass-release -RUN git clone --depth 1 https://github.com/home-assistant/hass-release \ - && uv pip install --system -e hass-release/ \ - && chown -R vscode /usr/src/hass-release/data +COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv + +RUN uv python install 3.13.2 USER vscode ENV VIRTUAL_ENV="/home/vscode/.local/ha-venv" @@ -55,6 +44,10 @@ ENV PATH="$VIRTUAL_ENV/bin:$PATH" WORKDIR /tmp +# Setup hass-release +RUN git clone --depth 1 https://github.com/home-assistant/hass-release ~/hass-release \ + && uv pip install -e ~/hass-release/ + # Install Python dependencies from requirements COPY requirements.txt ./ COPY homeassistant/package_constraints.txt homeassistant/package_constraints.txt @@ -65,4 +58,4 @@ RUN uv pip install -r requirements_test.txt WORKDIR /workspaces # Set the default shell to bash instead of sh -ENV SHELL /bin/bash +ENV SHELL=/bin/bash diff --git a/homeassistant/components/alexa_devices/config_flow.py b/homeassistant/components/alexa_devices/config_flow.py index 961f2760065449..aa9bbb4ae5e356 100644 --- a/homeassistant/components/alexa_devices/config_flow.py +++ b/homeassistant/components/alexa_devices/config_flow.py @@ -6,7 +6,7 @@ from typing import Any from aioamazondevices.api import AmazonEchoApi -from aioamazondevices.exceptions import CannotAuthenticate, CannotConnect +from aioamazondevices.exceptions import CannotAuthenticate, CannotConnect, WrongCountry import voluptuous as vol from homeassistant.config_entries import ConfigFlow, ConfigFlowResult @@ -57,6 +57,8 @@ async def async_step_user( errors["base"] = "cannot_connect" except CannotAuthenticate: errors["base"] = "invalid_auth" + except WrongCountry: + errors["base"] = "wrong_country" else: await self.async_set_unique_id(data["customer_info"]["user_id"]) self._abort_if_unique_id_configured() diff --git a/homeassistant/components/alexa_devices/manifest.json b/homeassistant/components/alexa_devices/manifest.json index cdf942e836d9b4..2e74561b7553e0 100644 --- a/homeassistant/components/alexa_devices/manifest.json +++ b/homeassistant/components/alexa_devices/manifest.json @@ -8,5 +8,5 @@ "iot_class": "cloud_polling", "loggers": ["aioamazondevices"], "quality_scale": "bronze", - "requirements": ["aioamazondevices==3.1.22"] + "requirements": ["aioamazondevices==3.2.1"] } diff --git a/homeassistant/components/alexa_devices/strings.json b/homeassistant/components/alexa_devices/strings.json index 89ab5b7056eb5c..03a6cc3de64303 100644 --- a/homeassistant/components/alexa_devices/strings.json +++ b/homeassistant/components/alexa_devices/strings.json @@ -44,6 +44,7 @@ "error": { "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", "invalid_auth": "[%key:common::config_flow::error::invalid_auth%]", + "wrong_country": "Wrong country selected. Please select the country where your Amazon account is registered.", "unknown": "[%key:common::config_flow::error::unknown%]" } }, diff --git a/homeassistant/components/bluetooth/manifest.json b/homeassistant/components/bluetooth/manifest.json index f212f4bdc1701e..33914f3457f760 100644 --- a/homeassistant/components/bluetooth/manifest.json +++ b/homeassistant/components/bluetooth/manifest.json @@ -19,7 +19,7 @@ "bleak-retry-connector==3.9.0", "bluetooth-adapters==0.21.4", "bluetooth-auto-recovery==1.5.2", - "bluetooth-data-tools==1.28.1", + "bluetooth-data-tools==1.28.2", "dbus-fast==2.43.0", "habluetooth==3.49.0" ] diff --git a/homeassistant/components/google_generative_ai_conversation/config_flow.py b/homeassistant/components/google_generative_ai_conversation/config_flow.py index 1b1444e81b14d6..ade326cf71bbab 100644 --- a/homeassistant/components/google_generative_ai_conversation/config_flow.py +++ b/homeassistant/components/google_generative_ai_conversation/config_flow.py @@ -330,13 +330,14 @@ async def google_generative_ai_config_option_schema( api_models = [api_model async for api_model in api_models_pager] models = [ SelectOptionDict( - label=api_model.display_name, + label=api_model.name.lstrip("models/"), value=api_model.name, ) - for api_model in sorted(api_models, key=lambda x: x.display_name or "") + for api_model in sorted( + api_models, key=lambda x: x.name.lstrip("models/") or "" + ) if ( - api_model.display_name - and api_model.name + api_model.name and ("tts" in api_model.name) == (subentry_type == "tts") and "vision" not in api_model.name and api_model.supported_actions diff --git a/homeassistant/components/ld2410_ble/manifest.json b/homeassistant/components/ld2410_ble/manifest.json index ba5ca3bdba4f3f..1efe4e05682244 100644 --- a/homeassistant/components/ld2410_ble/manifest.json +++ b/homeassistant/components/ld2410_ble/manifest.json @@ -20,5 +20,5 @@ "documentation": "https://www.home-assistant.io/integrations/ld2410_ble", "integration_type": "device", "iot_class": "local_push", - "requirements": ["bluetooth-data-tools==1.28.1", "ld2410-ble==0.1.1"] + "requirements": ["bluetooth-data-tools==1.28.2", "ld2410-ble==0.1.1"] } diff --git a/homeassistant/components/led_ble/manifest.json b/homeassistant/components/led_ble/manifest.json index 49daafeca255ce..3a73c28cdf6d16 100644 --- a/homeassistant/components/led_ble/manifest.json +++ b/homeassistant/components/led_ble/manifest.json @@ -35,5 +35,5 @@ "dependencies": ["bluetooth_adapters"], "documentation": "https://www.home-assistant.io/integrations/led_ble", "iot_class": "local_polling", - "requirements": ["bluetooth-data-tools==1.28.1", "led-ble==1.1.7"] + "requirements": ["bluetooth-data-tools==1.28.2", "led-ble==1.1.7"] } diff --git a/homeassistant/components/matter/manifest.json b/homeassistant/components/matter/manifest.json index 48f0bfa2e67752..9db0dfc9881973 100644 --- a/homeassistant/components/matter/manifest.json +++ b/homeassistant/components/matter/manifest.json @@ -7,6 +7,6 @@ "dependencies": ["websocket_api"], "documentation": "https://www.home-assistant.io/integrations/matter", "iot_class": "local_push", - "requirements": ["python-matter-server==7.0.0"], + "requirements": ["python-matter-server==8.0.0"], "zeroconf": ["_matter._tcp.local.", "_matterc._udp.local."] } diff --git a/homeassistant/components/playstation_network/strings.json b/homeassistant/components/playstation_network/strings.json index aee4dc0d7370b4..d3a9c986e88e85 100644 --- a/homeassistant/components/playstation_network/strings.json +++ b/homeassistant/components/playstation_network/strings.json @@ -77,7 +77,7 @@ "unit_of_measurement": "[%key:component::playstation_network::entity::sensor::earned_trophies_platinum::unit_of_measurement%]" }, "online_id": { - "name": "Online-ID" + "name": "Online ID" }, "last_online": { "name": "Last online" diff --git a/homeassistant/components/private_ble_device/manifest.json b/homeassistant/components/private_ble_device/manifest.json index f1e1839b735fe6..439e44faad1864 100644 --- a/homeassistant/components/private_ble_device/manifest.json +++ b/homeassistant/components/private_ble_device/manifest.json @@ -6,5 +6,5 @@ "dependencies": ["bluetooth_adapters"], "documentation": "https://www.home-assistant.io/integrations/private_ble_device", "iot_class": "local_push", - "requirements": ["bluetooth-data-tools==1.28.1"] + "requirements": ["bluetooth-data-tools==1.28.2"] } diff --git a/homeassistant/components/thermopro/manifest.json b/homeassistant/components/thermopro/manifest.json index 29dadfd3d63919..6749a53b7b6c9c 100644 --- a/homeassistant/components/thermopro/manifest.json +++ b/homeassistant/components/thermopro/manifest.json @@ -24,5 +24,5 @@ "dependencies": ["bluetooth_adapters"], "documentation": "https://www.home-assistant.io/integrations/thermopro", "iot_class": "local_push", - "requirements": ["thermopro-ble==0.13.0"] + "requirements": ["thermopro-ble==0.13.1"] } diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 1feb0f1339f7c8..f1906df5bc16e5 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -24,7 +24,7 @@ bleak-retry-connector==3.9.0 bleak==0.22.3 bluetooth-adapters==0.21.4 bluetooth-auto-recovery==1.5.2 -bluetooth-data-tools==1.28.1 +bluetooth-data-tools==1.28.2 cached-ipaddress==0.10.0 certifi>=2021.5.30 ciso8601==2.3.2 diff --git a/requirements_all.txt b/requirements_all.txt index 3c57b28903070a..f88f29c628db02 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -185,7 +185,7 @@ aioairzone-cloud==0.6.12 aioairzone==1.0.0 # homeassistant.components.alexa_devices -aioamazondevices==3.1.22 +aioamazondevices==3.2.1 # homeassistant.components.ambient_network # homeassistant.components.ambient_station @@ -652,7 +652,7 @@ bluetooth-auto-recovery==1.5.2 # homeassistant.components.ld2410_ble # homeassistant.components.led_ble # homeassistant.components.private_ble_device -bluetooth-data-tools==1.28.1 +bluetooth-data-tools==1.28.2 # homeassistant.components.bond bond-async==0.2.1 @@ -2462,7 +2462,7 @@ python-linkplay==0.2.12 # python-lirc==1.2.3 # homeassistant.components.matter -python-matter-server==7.0.0 +python-matter-server==8.0.0 # homeassistant.components.melcloud python-melcloud==0.1.0 @@ -2925,7 +2925,7 @@ tessie-api==0.1.1 thermobeacon-ble==0.10.0 # homeassistant.components.thermopro -thermopro-ble==0.13.0 +thermopro-ble==0.13.1 # homeassistant.components.thingspeak thingspeak==1.0.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index a53fd0f868a759..7e4c494cb94383 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -173,7 +173,7 @@ aioairzone-cloud==0.6.12 aioairzone==1.0.0 # homeassistant.components.alexa_devices -aioamazondevices==3.1.22 +aioamazondevices==3.2.1 # homeassistant.components.ambient_network # homeassistant.components.ambient_station @@ -583,7 +583,7 @@ bluetooth-auto-recovery==1.5.2 # homeassistant.components.ld2410_ble # homeassistant.components.led_ble # homeassistant.components.private_ble_device -bluetooth-data-tools==1.28.1 +bluetooth-data-tools==1.28.2 # homeassistant.components.bond bond-async==0.2.1 @@ -2035,7 +2035,7 @@ python-linkplay==0.2.12 # python-lirc==1.2.3 # homeassistant.components.matter -python-matter-server==7.0.0 +python-matter-server==8.0.0 # homeassistant.components.melcloud python-melcloud==0.1.0 @@ -2411,7 +2411,7 @@ tessie-api==0.1.1 thermobeacon-ble==0.10.0 # homeassistant.components.thermopro -thermopro-ble==0.13.0 +thermopro-ble==0.13.1 # homeassistant.components.lg_thinq thinqconnect==1.0.7 diff --git a/tests/components/alexa_devices/test_config_flow.py b/tests/components/alexa_devices/test_config_flow.py index 57049617986087..def3a6ec547803 100644 --- a/tests/components/alexa_devices/test_config_flow.py +++ b/tests/components/alexa_devices/test_config_flow.py @@ -2,7 +2,7 @@ from unittest.mock import AsyncMock -from aioamazondevices.exceptions import CannotAuthenticate, CannotConnect +from aioamazondevices.exceptions import CannotAuthenticate, CannotConnect, WrongCountry import pytest from homeassistant.components.alexa_devices.const import CONF_LOGIN_DATA, DOMAIN @@ -57,6 +57,7 @@ async def test_full_flow( [ (CannotConnect, "cannot_connect"), (CannotAuthenticate, "invalid_auth"), + (WrongCountry, "wrong_country"), ], ) async def test_flow_errors( diff --git a/tests/components/eheimdigital/test_init.py b/tests/components/eheimdigital/test_init.py index c64997ee37270b..4b2823389549e3 100644 --- a/tests/components/eheimdigital/test_init.py +++ b/tests/components/eheimdigital/test_init.py @@ -2,8 +2,9 @@ from unittest.mock import MagicMock -from eheimdigital.types import EheimDeviceType +from eheimdigital.types import EheimDeviceType, EheimDigitalClientError +from homeassistant.config_entries import ConfigEntryState from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr from homeassistant.setup import async_setup_component @@ -54,3 +55,15 @@ async def test_remove_device( device_entry.id, mock_config_entry.entry_id ) assert response["success"] + + +async def test_entry_setup_error( + hass: HomeAssistant, + eheimdigital_hub_mock: MagicMock, + mock_config_entry: MockConfigEntry, +) -> None: + """Test errors on setting up the config entry.""" + + eheimdigital_hub_mock.return_value.connect.side_effect = EheimDigitalClientError() + await init_integration(hass, mock_config_entry) + assert mock_config_entry.state is ConfigEntryState.SETUP_RETRY diff --git a/tests/components/eheimdigital/test_light.py b/tests/components/eheimdigital/test_light.py index c6b2063ec0c524..a25fd7cd872f9d 100644 --- a/tests/components/eheimdigital/test_light.py +++ b/tests/components/eheimdigital/test_light.py @@ -5,7 +5,7 @@ from aiohttp import ClientError from eheimdigital.classic_led_ctrl import EheimDigitalClassicLEDControl -from eheimdigital.types import EheimDeviceType +from eheimdigital.types import EheimDeviceType, EheimDigitalClientError from freezegun.api import FrozenDateTimeFactory import pytest from syrupy.assertion import SnapshotAssertion @@ -24,6 +24,7 @@ Platform, ) from homeassistant.core import HomeAssistant +from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers import entity_registry as er from homeassistant.util.color import value_to_brightness @@ -114,20 +115,34 @@ async def test_dynamic_new_devices( await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id) -@pytest.mark.usefixtures("eheimdigital_hub_mock") async def test_turn_off( hass: HomeAssistant, mock_config_entry: MockConfigEntry, + eheimdigital_hub_mock: MagicMock, classic_led_ctrl_mock: EheimDigitalClassicLEDControl, ) -> None: """Test turning off the light.""" await init_integration(hass, mock_config_entry) - await mock_config_entry.runtime_data._async_device_found( + await eheimdigital_hub_mock.call_args.kwargs["device_found_callback"]( "00:00:00:00:00:01", EheimDeviceType.VERSION_EHEIM_CLASSIC_LED_CTRL_PLUS_E ) await hass.async_block_till_done() + classic_led_ctrl_mock.hub.send_packet.side_effect = EheimDigitalClientError + + with pytest.raises(HomeAssistantError) as exc_info: + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_OFF, + {ATTR_ENTITY_ID: "light.mock_classicledcontrol_e_channel_1"}, + blocking=True, + ) + + assert exc_info.value.translation_key == "communication_error" + + classic_led_ctrl_mock.hub.send_packet.side_effect = None + await hass.services.async_call( LIGHT_DOMAIN, SERVICE_TURN_OFF, @@ -140,9 +155,9 @@ async def test_turn_off( for call in classic_led_ctrl_mock.hub.mock_calls if call[0] == "send_packet" ] - assert len(calls) == 2 - assert calls[0][1][0].get("title") == "MAN_MODE" - assert calls[1][1][0]["currentValues"][1] == 0 + assert len(calls) == 3 + assert calls[1][1][0].get("title") == "MAN_MODE" + assert calls[2][1][0]["currentValues"][1] == 0 @pytest.mark.parametrize( @@ -169,6 +184,23 @@ async def test_turn_on_brightness( ) await hass.async_block_till_done() + classic_led_ctrl_mock.hub.send_packet.side_effect = EheimDigitalClientError + + with pytest.raises(HomeAssistantError) as exc_info: + await hass.services.async_call( + LIGHT_DOMAIN, + SERVICE_TURN_ON, + { + ATTR_ENTITY_ID: "light.mock_classicledcontrol_e_channel_1", + ATTR_BRIGHTNESS: dim_input, + }, + blocking=True, + ) + + assert exc_info.value.translation_key == "communication_error" + + classic_led_ctrl_mock.hub.send_packet.side_effect = None + await hass.services.async_call( LIGHT_DOMAIN, SERVICE_TURN_ON, @@ -184,9 +216,9 @@ async def test_turn_on_brightness( for call in classic_led_ctrl_mock.hub.mock_calls if call[0] == "send_packet" ] - assert len(calls) == 2 - assert calls[0][1][0].get("title") == "MAN_MODE" - assert calls[1][1][0]["currentValues"][1] == expected_dim_value + assert len(calls) == 3 + assert calls[1][1][0].get("title") == "MAN_MODE" + assert calls[2][1][0]["currentValues"][1] == expected_dim_value async def test_turn_on_effect( diff --git a/tests/components/google_generative_ai_conversation/test_config_flow.py b/tests/components/google_generative_ai_conversation/test_config_flow.py index b43c8a4227540a..a3fa487e1d3b61 100644 --- a/tests/components/google_generative_ai_conversation/test_config_flow.py +++ b/tests/components/google_generative_ai_conversation/test_config_flow.py @@ -43,25 +43,21 @@ def get_models_pager(): """Return a generator that yields the models.""" model_25_flash = Mock( - display_name="Gemini 2.5 Flash", supported_actions=["generateContent"], ) model_25_flash.name = "models/gemini-2.5-flash" model_20_flash = Mock( - display_name="Gemini 2.0 Flash", supported_actions=["generateContent"], ) model_20_flash.name = "models/gemini-2.0-flash" model_15_flash = Mock( - display_name="Gemini 1.5 Flash", supported_actions=["generateContent"], ) model_15_flash.name = "models/gemini-1.5-flash-latest" model_15_pro = Mock( - display_name="Gemini 1.5 Pro", supported_actions=["generateContent"], ) model_15_pro.name = "models/gemini-1.5-pro-latest" diff --git a/tests/components/playstation_network/snapshots/test_sensor.ambr b/tests/components/playstation_network/snapshots/test_sensor.ambr index 233791c05bd7d3..59cd979ed7690d 100644 --- a/tests/components/playstation_network/snapshots/test_sensor.ambr +++ b/tests/components/playstation_network/snapshots/test_sensor.ambr @@ -220,7 +220,7 @@ }), 'original_device_class': None, 'original_icon': None, - 'original_name': 'Online-ID', + 'original_name': 'Online ID', 'platform': 'playstation_network', 'previous_unique_id': None, 'suggested_object_id': None, @@ -234,7 +234,7 @@ StateSnapshot({ 'attributes': ReadOnlyDict({ 'entity_picture': 'http://static-resource.np.community.playstation.net/avatar_xl/WWS_A/UP90001312L24_DD96EB6A4FF5FE883C09_XL.png', - 'friendly_name': 'testuser Online-ID', + 'friendly_name': 'testuser Online ID', }), 'context': , 'entity_id': 'sensor.testuser_online_id',