From 8e12fbff88da5e783da88e8579f4fc645a64232b Mon Sep 17 00:00:00 2001 From: Manu <4445816+tr4nt0r@users.noreply.github.com> Date: Fri, 29 Nov 2024 03:31:38 +0100 Subject: [PATCH] Refactor calendars in Habitica (#131020) * Refactor calendars * changes --- homeassistant/components/habitica/calendar.py | 159 +++++++----------- 1 file changed, 63 insertions(+), 96 deletions(-) diff --git a/homeassistant/components/habitica/calendar.py b/homeassistant/components/habitica/calendar.py index 6de22a0314a..ff483b71fd8 100644 --- a/homeassistant/components/habitica/calendar.py +++ b/homeassistant/components/habitica/calendar.py @@ -2,6 +2,7 @@ from __future__ import annotations +from abc import abstractmethod from datetime import date, datetime, timedelta from enum import StrEnum @@ -60,6 +61,43 @@ class HabiticaCalendarEntity(HabiticaBase, CalendarEntity): """Initialize calendar entity.""" super().__init__(coordinator, self.entity_description) + @abstractmethod + def get_events( + self, start_date: datetime, end_date: datetime | None = None + ) -> list[CalendarEvent]: + """Return events.""" + + @property + def event(self) -> CalendarEvent | None: + """Return the current or next upcoming event.""" + + return next(iter(self.get_events(dt_util.now())), None) + + async def async_get_events( + self, hass: HomeAssistant, start_date: datetime, end_date: datetime + ) -> list[CalendarEvent]: + """Return calendar events within a datetime range.""" + + return self.get_events(start_date, end_date) + + @property + def start_of_today(self) -> datetime: + """Habitica daystart.""" + return dt_util.start_of_local_day( + datetime.fromisoformat(self.coordinator.data.user["lastCron"]) + ) + + def get_recurrence_dates( + self, recurrences: rrule, start_date: datetime, end_date: datetime | None = None + ) -> list[datetime]: + """Calculate recurrence dates based on start_date and end_date.""" + if end_date: + return recurrences.between( + start_date, end_date - timedelta(days=1), inc=True + ) + # if no end_date is given, return only the next recurrence + return [recurrences.after(start_date, inc=True)] + class HabiticaTodosCalendarEntity(HabiticaCalendarEntity): """Habitica todos calendar entity.""" @@ -69,7 +107,7 @@ class HabiticaTodosCalendarEntity(HabiticaCalendarEntity): translation_key=HabiticaCalendar.TODOS, ) - def dated_todos( + def get_events( self, start_date: datetime, end_date: datetime | None = None ) -> list[CalendarEvent]: """Get all dated todos.""" @@ -112,18 +150,6 @@ class HabiticaTodosCalendarEntity(HabiticaCalendarEntity): ), ) - @property - def event(self) -> CalendarEvent | None: - """Return the current or next upcoming event.""" - - return next(iter(self.dated_todos(dt_util.now())), None) - - async def async_get_events( - self, hass: HomeAssistant, start_date: datetime, end_date: datetime - ) -> list[CalendarEvent]: - """Return calendar events within a datetime range.""" - return self.dated_todos(start_date, end_date) - class HabiticaDailiesCalendarEntity(HabiticaCalendarEntity): """Habitica dailies calendar entity.""" @@ -133,13 +159,6 @@ class HabiticaDailiesCalendarEntity(HabiticaCalendarEntity): translation_key=HabiticaCalendar.DAILIES, ) - @property - def today(self) -> datetime: - """Habitica daystart.""" - return dt_util.start_of_local_day( - datetime.fromisoformat(self.coordinator.data.user["lastCron"]) - ) - def end_date(self, recurrence: datetime, end: datetime | None = None) -> date: """Calculate the end date for a yesterdaily. @@ -152,29 +171,20 @@ class HabiticaDailiesCalendarEntity(HabiticaCalendarEntity): if end: return recurrence.date() + timedelta(days=1) return ( - dt_util.start_of_local_day() if recurrence == self.today else recurrence + dt_util.start_of_local_day() + if recurrence == self.start_of_today + else recurrence ).date() + timedelta(days=1) - def get_recurrence_dates( - self, recurrences: rrule, start_date: datetime, end_date: datetime | None = None - ) -> list[datetime]: - """Calculate recurrence dates based on start_date and end_date.""" - if end_date: - return recurrences.between( - start_date, end_date - timedelta(days=1), inc=True - ) - # if no end_date is given, return only the next recurrence - return [recurrences.after(self.today, inc=True)] - - def due_dailies( + def get_events( self, start_date: datetime, end_date: datetime | None = None ) -> list[CalendarEvent]: """Get dailies and recurrences for a given period or the next upcoming.""" # we only have dailies for today and future recurrences - if end_date and end_date < self.today: + if end_date and end_date < self.start_of_today: return [] - start_date = max(start_date, self.today) + start_date = max(start_date, self.start_of_today) events = [] for task in self.coordinator.data.tasks: @@ -187,10 +197,12 @@ class HabiticaDailiesCalendarEntity(HabiticaCalendarEntity): recurrences, start_date, end_date ) for recurrence in recurrence_dates: - is_future_event = recurrence > self.today - is_current_event = recurrence <= self.today and not task["completed"] + is_future_event = recurrence > self.start_of_today + is_current_event = ( + recurrence <= self.start_of_today and not task["completed"] + ) - if not (is_future_event or is_current_event): + if not is_future_event and not is_current_event: continue events.append( @@ -214,20 +226,15 @@ class HabiticaDailiesCalendarEntity(HabiticaCalendarEntity): @property def event(self) -> CalendarEvent | None: """Return the next upcoming event.""" - return next(iter(self.due_dailies(self.today)), None) - - async def async_get_events( - self, hass: HomeAssistant, start_date: datetime, end_date: datetime - ) -> list[CalendarEvent]: - """Return calendar events within a datetime range.""" - - return self.due_dailies(start_date, end_date) + return next(iter(self.get_events(self.start_of_today)), None) @property def extra_state_attributes(self) -> dict[str, bool | None] | None: """Return entity specific state attributes.""" return { - "yesterdaily": self.event.start < self.today.date() if self.event else None + "yesterdaily": self.event.start < self.start_of_today.date() + if self.event + else None } @@ -239,7 +246,7 @@ class HabiticaTodoRemindersCalendarEntity(HabiticaCalendarEntity): translation_key=HabiticaCalendar.TODO_REMINDERS, ) - def reminders( + def get_events( self, start_date: datetime, end_date: datetime | None = None ) -> list[CalendarEvent]: """Reminders for todos.""" @@ -282,18 +289,6 @@ class HabiticaTodoRemindersCalendarEntity(HabiticaCalendarEntity): key=lambda event: event.start, ) - @property - def event(self) -> CalendarEvent | None: - """Return the next upcoming event.""" - return next(iter(self.reminders(dt_util.now())), None) - - async def async_get_events( - self, hass: HomeAssistant, start_date: datetime, end_date: datetime - ) -> list[CalendarEvent]: - """Return calendar events within a datetime range.""" - - return self.reminders(start_date, end_date) - class HabiticaDailyRemindersCalendarEntity(HabiticaCalendarEntity): """Habitica daily reminders calendar entity.""" @@ -321,47 +316,31 @@ class HabiticaDailyRemindersCalendarEntity(HabiticaCalendarEntity): tzinfo=dt_util.DEFAULT_TIME_ZONE, ) - @property - def today(self) -> datetime: - """Habitica daystart.""" - return dt_util.start_of_local_day( - datetime.fromisoformat(self.coordinator.data.user["lastCron"]) - ) - - def get_recurrence_dates( - self, recurrences: rrule, start_date: datetime, end_date: datetime | None = None - ) -> list[datetime]: - """Calculate recurrence dates based on start_date and end_date.""" - if end_date: - return recurrences.between( - start_date, end_date - timedelta(days=1), inc=True - ) - # if no end_date is given, return only the next recurrence - return [recurrences.after(self.today, inc=True)] - - def reminders( + def get_events( self, start_date: datetime, end_date: datetime | None = None ) -> list[CalendarEvent]: """Reminders for dailies.""" events = [] - if end_date and end_date < self.today: + if end_date and end_date < self.start_of_today: return [] - start_date = max(start_date, self.today) + start_date = max(start_date, self.start_of_today) for task in self.coordinator.data.tasks: if not (task["type"] == HabiticaTaskType.DAILY and task["everyX"]): continue recurrences = build_rrule(task) - recurrences_start = self.today + recurrences_start = self.start_of_today recurrence_dates = self.get_recurrence_dates( recurrences, recurrences_start, end_date ) for recurrence in recurrence_dates: - is_future_event = recurrence > self.today - is_current_event = recurrence <= self.today and not task["completed"] + is_future_event = recurrence > self.start_of_today + is_current_event = ( + recurrence <= self.start_of_today and not task["completed"] + ) if not is_future_event and not is_current_event: continue @@ -388,15 +367,3 @@ class HabiticaDailyRemindersCalendarEntity(HabiticaCalendarEntity): events, key=lambda event: event.start, ) - - @property - def event(self) -> CalendarEvent | None: - """Return the next upcoming event.""" - return next(iter(self.reminders(dt_util.now())), None) - - async def async_get_events( - self, hass: HomeAssistant, start_date: datetime, end_date: datetime - ) -> list[CalendarEvent]: - """Return calendar events within a datetime range.""" - - return self.reminders(start_date, end_date)