diff --git a/homeassistant/components/calendar/__init__.py b/homeassistant/components/calendar/__init__.py index 6c34c8bf540..066235b9f50 100644 --- a/homeassistant/components/calendar/__init__.py +++ b/homeassistant/components/calendar/__init__.py @@ -506,6 +506,8 @@ def is_offset_reached( class CalendarEntityDescription(EntityDescription, frozen_or_thawed=True): """A class that describes calendar entities.""" + initial_color: str | None = None + class CalendarEntity(Entity): """Base class for calendar event entities.""" @@ -516,12 +518,16 @@ class CalendarEntity(Entity): _alarm_unsubs: list[CALLBACK_TYPE] | None = None - _attr_initial_color: str | None = None + _attr_initial_color: str | None @property def initial_color(self) -> str | None: """Return the initial color for the calendar entity.""" - return self._attr_initial_color + if hasattr(self, "_attr_initial_color"): + return self._attr_initial_color + if hasattr(self, "entity_description"): + return self.entity_description.initial_color + return None def get_initial_entity_options(self) -> er.EntityOptionsType | None: """Return initial entity options.""" diff --git a/homeassistant/components/google/calendar.py b/homeassistant/components/google/calendar.py index e9d5b41fef3..35b612cdc24 100644 --- a/homeassistant/components/google/calendar.py +++ b/homeassistant/components/google/calendar.py @@ -101,7 +101,6 @@ class GoogleCalendarEntityDescription(CalendarEntityDescription): search: str | None local_sync: bool device_id: str - initial_color: str | None = None event_type: EventTypeEnum | None = None @@ -361,7 +360,6 @@ class GoogleCalendarEntity( if entity_description.entity_id: self.entity_id = entity_description.entity_id self._attr_unique_id = unique_id - self._attr_initial_color = entity_description.initial_color if not entity_description.read_only: self._attr_supported_features = ( CalendarEntityFeature.CREATE_EVENT | CalendarEntityFeature.DELETE_EVENT diff --git a/tests/components/calendar/conftest.py b/tests/components/calendar/conftest.py index 2382f37783e..2b6dad0faca 100644 --- a/tests/components/calendar/conftest.py +++ b/tests/components/calendar/conftest.py @@ -8,7 +8,12 @@ from unittest.mock import AsyncMock import pytest -from homeassistant.components.calendar import DOMAIN, CalendarEntity, CalendarEvent +from homeassistant.components.calendar import ( + DOMAIN, + CalendarEntity, + CalendarEntityDescription, + CalendarEvent, +) from homeassistant.config_entries import ConfigEntry, ConfigFlow from homeassistant.const import Platform from homeassistant.core import HomeAssistant @@ -54,8 +59,11 @@ class MockCalendarEntity(CalendarEntity): """Initialize entity.""" self._attr_name = name.capitalize() self._events = events or [] - self._attr_initial_color = initial_color self._attr_unique_id = unique_id + self.entity_description = CalendarEntityDescription( + key=unique_id or name, + initial_color=initial_color, + ) @property def event(self) -> CalendarEvent | None: diff --git a/tests/components/calendar/test_init.py b/tests/components/calendar/test_init.py index 67eca34728e..3f13cffb809 100644 --- a/tests/components/calendar/test_init.py +++ b/tests/components/calendar/test_init.py @@ -13,10 +13,16 @@ import pytest from syrupy.assertion import SnapshotAssertion import voluptuous as vol -from homeassistant.components.calendar import DOMAIN, SERVICE_GET_EVENTS +from homeassistant.components.calendar import ( + DOMAIN, + SERVICE_GET_EVENTS, + CalendarEntity, + CalendarEntityDescription, +) from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError, ServiceNotSupported from homeassistant.helpers import entity_registry as er +from homeassistant.helpers.typing import UNDEFINED from homeassistant.setup import async_setup_component from homeassistant.util import dt as dt_util @@ -657,3 +663,56 @@ async def test_calendar_initial_color_none( # Entities 1 and 2 were created without an initial_color entity = test_entities[0] assert entity.get_initial_entity_options() is None + + +@pytest.mark.parametrize( + ("description_color", "attr_color", "expected_color"), + [ + # no description and no attr_initial_color + (UNDEFINED, UNDEFINED, None), + # no description and attr_initial_color "A" + (UNDEFINED, "#AAAAAA", "#AAAAAA"), + # no description and attr_initial_color None + (UNDEFINED, None, None), + # description setting the color "B", and no attr_initial_color + ("#BBBBBB", UNDEFINED, "#BBBBBB"), + # description setting the color "B", but overridden by attr_initial_color "A" + ("#BBBBBB", "#AAAAAA", "#AAAAAA"), + # description setting the color "B", but overridden by attr_initial_color None + ("#BBBBBB", None, None), + ], +) +async def test_calendar_initial_color_precedence( + description_color: str | None | object, + attr_color: str | None | object, + expected_color: str | None, +) -> None: + """Test that _attr_initial_color takes precedence over entity_description.""" + + class TestCalendarEntity(CalendarEntity): + """Test entity for initial_color precedence tests.""" + + _attr_has_entity_name = True + + def __init__( + self, + description_color: str | None | object, + attr_color: str | None | object, + ) -> None: + """Initialize entity.""" + self._attr_name = "Test" + self._attr_unique_id = "test_precedence" + + # Only set entity_description if description_color is not UNDEFINED + if description_color is not UNDEFINED: + self.entity_description = CalendarEntityDescription( + key="test", + initial_color=description_color, + ) + + # Only set _attr_initial_color if attr_color is not UNDEFINED + if attr_color is not UNDEFINED: + self._attr_initial_color = attr_color + + entity = TestCalendarEntity(description_color, attr_color) + assert entity.initial_color == expected_color