mirror of
https://github.com/home-assistant/core.git
synced 2026-09-26 17:31:15 -04:00
Service exceptions for collection_image (#182442)
This commit is contained in:
@@ -80,6 +80,11 @@ class CollectionImageImageEntity(ImageEntity):
|
||||
self._attr_image_url = UNDEFINED
|
||||
self._cached_image = None
|
||||
self.async_write_ha_state()
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="no_images",
|
||||
translation_placeholders={"entity": self.entity_id},
|
||||
)
|
||||
|
||||
async def get_valid_images(self) -> list[BrowseMedia]:
|
||||
"""Given the configured media directory for the entity, get a list of all child images."""
|
||||
@@ -107,15 +112,15 @@ class CollectionImageImageEntity(ImageEntity):
|
||||
media_content_id,
|
||||
)
|
||||
|
||||
if not images:
|
||||
self.set_unavailable()
|
||||
|
||||
return images
|
||||
|
||||
async def get_random_image(self) -> None:
|
||||
"""Update the image entity with a random image from the source media."""
|
||||
|
||||
filtered = await self.get_valid_images()
|
||||
if not filtered:
|
||||
self.set_unavailable()
|
||||
return
|
||||
|
||||
# Don't allow random shuffle to return the same image we are currently viewing.
|
||||
if self._current_image_id:
|
||||
@@ -151,9 +156,6 @@ class CollectionImageImageEntity(ImageEntity):
|
||||
"""Get the first or last image."""
|
||||
|
||||
filtered = await self.get_valid_images()
|
||||
if not filtered:
|
||||
self.set_unavailable()
|
||||
return
|
||||
|
||||
child = filtered[position]
|
||||
self._attr_available = True
|
||||
@@ -165,9 +167,6 @@ class CollectionImageImageEntity(ImageEntity):
|
||||
"""Get the next or previous image."""
|
||||
|
||||
filtered = await self.get_valid_images()
|
||||
if not filtered:
|
||||
self.set_unavailable()
|
||||
return
|
||||
|
||||
current_index = next(
|
||||
(
|
||||
@@ -197,13 +196,19 @@ class CollectionImageImageEntity(ImageEntity):
|
||||
try:
|
||||
resolved = await async_resolve_media(self.hass, image_id, self.entity_id)
|
||||
except Unresolvable as err:
|
||||
_LOGGER.warning("%s: %s", self.entity_id, str(err))
|
||||
self._attr_image_last_updated = None
|
||||
self.path = None
|
||||
self._attr_image_url = UNDEFINED
|
||||
self._attr_content_type = DEFAULT_CONTENT_TYPE
|
||||
self.async_write_ha_state()
|
||||
return
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="unresolvable",
|
||||
translation_placeholders={
|
||||
"entity": self.entity_id,
|
||||
"id": image_id,
|
||||
},
|
||||
) from err
|
||||
finally:
|
||||
self._current_image_id = image_id
|
||||
|
||||
@@ -223,7 +228,12 @@ class CollectionImageImageEntity(ImageEntity):
|
||||
"""Initialize the first image after entity has been created."""
|
||||
|
||||
async def get_random_image_on_start(_hass: HomeAssistant) -> None:
|
||||
await self.get_random_image()
|
||||
try:
|
||||
await self.get_random_image()
|
||||
except HomeAssistantError:
|
||||
_LOGGER.exception(
|
||||
"Unable to get an initial image",
|
||||
)
|
||||
|
||||
self.async_on_remove(async_at_started(self.hass, get_random_image_on_start))
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ rules:
|
||||
comment: Integration does not connect to any physical object or service.
|
||||
|
||||
# Silver
|
||||
action-exceptions: todo
|
||||
action-exceptions: done
|
||||
config-entry-unloading: done
|
||||
docs-configuration-parameters: done
|
||||
docs-installation-parameters: done
|
||||
|
||||
@@ -30,6 +30,12 @@
|
||||
"exceptions": {
|
||||
"image_read_error": {
|
||||
"message": "Error reading image from {path}: {error}"
|
||||
},
|
||||
"no_images": {
|
||||
"message": "No image files were found in the configured media. {entity} will now be unavailable. Reload the config entry after correcting the media source."
|
||||
},
|
||||
"unresolvable": {
|
||||
"message": "Selected media id {id} failed to resolve for {entity}."
|
||||
}
|
||||
},
|
||||
"services": {
|
||||
|
||||
@@ -270,6 +270,8 @@ async def test_media_error(
|
||||
for err in error_messages:
|
||||
assert err in caplog.text
|
||||
|
||||
assert "No image files were found in the configured media" in caplog.text
|
||||
|
||||
client = await hass_client()
|
||||
resp = await client.get(f"/api/image_proxy/{DEFAULT_ENTITY_ID}")
|
||||
assert resp.status == HTTPStatus.INTERNAL_SERVER_ERROR
|
||||
@@ -301,7 +303,15 @@ async def test_unresolvable(
|
||||
|
||||
await hass.async_block_till_done(wait_background_tasks=True)
|
||||
|
||||
assert "image.random_image: Mock image failed to resolve" in caplog.text
|
||||
assert "Mock image failed to resolve" in caplog.text
|
||||
|
||||
with pytest.raises(HomeAssistantError, match="failed to resolve"):
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
"shuffle",
|
||||
{ATTR_ENTITY_ID: DEFAULT_ENTITY_ID},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
# Test we can recover by calling shuffle again when the image is resolvable
|
||||
del media_source_state.resolve_exceptions[MOCK_MEDIA_IMAGE_URI_1]
|
||||
@@ -316,8 +326,8 @@ async def test_unresolvable(
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert mock_media_source.image_browse.call_count == 2
|
||||
assert mock_media_source.resolve.call_count == 2
|
||||
assert mock_media_source.image_browse.call_count == 3
|
||||
assert mock_media_source.resolve.call_count == 3
|
||||
|
||||
state = hass.states.get(DEFAULT_ENTITY_ID)
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from homeassistant.components.collection_image.const import DOMAIN
|
||||
from homeassistant.components.collection_image.image import CollectionImageImageEntity
|
||||
from homeassistant.components.collection_image.services import (
|
||||
@@ -11,6 +13,7 @@ from homeassistant.components.collection_image.services import (
|
||||
from homeassistant.components.media_source import PlayMedia
|
||||
from homeassistant.const import ATTR_ENTITY_ID, STATE_UNAVAILABLE
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
|
||||
from .conftest import MediaSourceMocks, MediaSourceState
|
||||
from .const import DEFAULT_ENTITY_ID, MOCK_MEDIA_DIR_URI_1
|
||||
@@ -176,12 +179,13 @@ async def test_navigation(
|
||||
|
||||
# Now there are no images, go to unavailable
|
||||
media_source_state.browse_results = {MOCK_MEDIA_DIR_URI_1: directory("My pictures")}
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
CollectionImageService.SELECT_NEXT,
|
||||
data,
|
||||
blocking=True,
|
||||
)
|
||||
with pytest.raises(HomeAssistantError, match="No image files were found"):
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
CollectionImageService.SELECT_NEXT,
|
||||
data,
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
state = hass.states.get(DEFAULT_ENTITY_ID)
|
||||
assert state and state.state == STATE_UNAVAILABLE
|
||||
@@ -214,11 +218,12 @@ async def test_first_unavailable(
|
||||
assert state and state.state != STATE_UNAVAILABLE
|
||||
|
||||
media_source_state.browse_results = {MOCK_MEDIA_DIR_URI_1: directory("My pictures")}
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
CollectionImageService.SELECT_FIRST,
|
||||
{ATTR_ENTITY_ID: DEFAULT_ENTITY_ID},
|
||||
blocking=True,
|
||||
)
|
||||
with pytest.raises(HomeAssistantError, match="No image files were found"):
|
||||
await hass.services.async_call(
|
||||
DOMAIN,
|
||||
CollectionImageService.SELECT_FIRST,
|
||||
{ATTR_ENTITY_ID: DEFAULT_ENTITY_ID},
|
||||
blocking=True,
|
||||
)
|
||||
state = hass.states.get(DEFAULT_ENTITY_ID)
|
||||
assert state and state.state == STATE_UNAVAILABLE
|
||||
|
||||
Reference in New Issue
Block a user