from __future__ import print_function
from datetime import date, timedelta
from icalendar import Calendar
import recurring_ical_events
import requests
import logging
from pydantic import Field
from todays_paper_web.widgets import DataSource, registerDataSource
from todays_paper_web.widgets.datasource import DataSourceParams
_LOGGER = logging.getLogger(__name__)
class ICalendarModel:
"""Wraps a parsed calendar. `.walk()` delegates to the underlying
icalendar.Calendar for existing templates; `.eventsOn()`/`.eventsBetween()`
additionally expand recurring (RRULE) events into concrete occurrences,
which a plain `.walk('vevent')` cannot do."""
def __init__(self, calendar: Calendar):
self.calendar = calendar
def walk(self, name=None):
return self.calendar.walk(name)
def eventsBetween(self, start: date, end: date):
occurrences = recurring_ical_events.of(self.calendar).between(start, end)
occurrences.sort(key=lambda event: event.get("dtstart").dt)
return occurrences
def eventsOn(self, day: date):
return self.eventsBetween(day, day + timedelta(days=1))
[docs]
class ICalendarParams(DataSourceParams):
url: str = Field(..., description="The .ics feed URL, fetched fresh on every `.fetch()` call.")
@registerDataSource("calendar.ical")
class ICalendarDataSource(DataSource):
Params = ICalendarParams
def fetch(self):
r = requests.get(self.params.url)
cal = Calendar.from_ical(r.text)
return ICalendarModel(cal)