def test_events_all_day_recurring(self): ical = "test/test_data/recurring.ics" start = date(2018, 10, 30) end = date(2018, 10, 31) evs = icalevents.events(file=ical, start=start, end=end) event_set = icalevents.events(url=None, file=ical, start=start, end=end) ev = event_set[0] self.assertEqual(len(event_set), 1) self.assertEqual(ev.summary, "Recurring All-day Event") self.assertEqual(ev.description, "All-day event recurring on tuesday each week") self.assertTrue(ev.all_day, "Recurring All-day Event's first instance is an all-day event") start_2nd_instance = date(2018, 11, 6) end_2nd_instance = date(2018, 11, 7) event_set2 = icalevents.events(url=None, file=ical, start=start_2nd_instance, end=end_2nd_instance) ev_2 = event_set2[0] self.assertEqual(len(event_set2), 1) self.assertEqual(ev_2.summary, "Recurring All-day Event") self.assertEqual(ev_2.description, "All-day event recurring on tuesday each week") self.assertTrue(ev_2.all_day, "Recurring All-day Event's second instance is an all-day event")
def get_current_events(feed_url_or_path, files): """Retrieves data from iCal iCal feed and returns an ics.Calendar object containing the parsed data. Returns the parsed Calendar object or None if an error occurs. """ events_end = datetime.now() if config.get('ICAL_DAYS_TO_SYNC', 0) == 0: # default to 1 year ahead events_end += DEFAULT_TIMEDELTA else: # add on a number of days events_end += timedelta(days=config['ICAL_DAYS_TO_SYNC']) try: if files: cal = events(file=feed_url_or_path, end=events_end) else: # directly configure http connection object to set ssl and authentication parameters http_conn = Http(disable_ssl_certificate_validation=not config.get('ICAL_FEED_VERIFY_SSL_CERT', True)) if config.get('ICAL_FEED_USER') and config.get('ICAL_FEED_PASS'): # credentials used for every connection http_conn.add_credentials(name=config.get('ICAL_FEED_USER'), password=config.get('ICAL_FEED_PASS')) cal = events(feed_url_or_path, start=datetime.now()-timedelta(days=config.get('PAST_DAYS_TO_SYNC', 0)), end=events_end, http=http_conn) except Exception as e: logger.error('> Error retrieving iCal data ({})'.format(e)) return None return cal
def validateLink(self, link: str) -> bool: """ Check if the given link could be a valid RaPla link @param link: The link to be checked @return: If the link could be valid """ try: events(link) # TODO: Rewrite this with a regex if 'https://rapla.dhbw-karlsruhe.de/rapla' in link: return True else: return False except: return False
def get_events(days_to_check=14): in_two_weeks = datetime.combine(datetime.today(), time.max) + timedelta(days=days_to_check) es = events(calendar_url, start=datetime.now(), end=in_two_weeks) message = "" for event in (event for event in sorted(es) if not ("Lunch Break Make" in event.summary or "Making Hours" in event.summary)): event.start = event.start.astimezone() event.end = event.end.astimezone() if not "Special Events" in message: message = f"{message}\n*Special Events:*" translator = { "[": r"\[", "]": r"]" } #only escape the opening [ because otherwise telegram will show \] in the message message = f"{message}\n*{event.start.strftime('%A')}, {event.start.day:02}.{event.start.month:02}.{event.start.year:04}*\n {event.start.hour:02}:{event.start.minute:02} - {event.end.hour:02}:{event.end.minute:02}\n {event.summary.translate(str.maketrans(translator))}" for event in (event for event in sorted(es) if ("Lunch Break Make" in event.summary or "Making Hours" in event.summary)): event.start = event.start.astimezone() event.end = event.end.astimezone() if not "Opening Hours" in message: message = "{}\n*Opening Hours*:".format(message) name = event.summary[event.summary.find("("):] message = f"{message}\n{event.start.strftime('%A')}, {event.start.day:02}.{event.start.month:02}.{event.start.year:04}\n {event.start.hour:02}:{event.start.minute:02} - {event.end.hour:02}:{event.end.minute:02} {name}" return message
def get_upcoming_events(self, very_soon=False): """ returns a list of upcoming events """ events = icalevents.events(url=self._calurl, file=self._calfile, fix_apple=True) ## XXX filter all day events here as icalparser compares offset-naive ## and offset-aware datetimes otherwise events = filter(lambda e: not e.all_day, events) def keep(event): """ removes all_day, ended, and far events """ if very_soon: return ( not event.ended() and event.very_soon() and event.uid not in self._ignore ) return ( not event.ended() and event.soon() and event.uid not in self._ignore ) events = list(filter(keep, events)) ## sort by start events.sort() return list(events)
def getCalendarData(self): logging.info("Updating calendar info...") url = self.calendarUrl # result = requests.get(url) # print(result.text) # cal = result.text self.calendar = events(url, fix_apple=True)
def test_event_str(self): ical = "test/test_data/duration.ics" start = date(2018, 1, 1) end = date(2018, 2, 1) n = datetime.now(UTC) m = relativedelta(hour=0, minute=0, second=0, microsecond=0) evs = icalevents.events(file=ical, start=start, end=end) e1 = evs[0] self.assertIsNotNone( search(r"ended", str(e1.copy_to(n - relativedelta(days=5) + m))), "stringify past event") self.assertIsNotNone( search(r"today", str(e1.copy_to(n - relativedelta(days=1) + m))), "stringify ongoing event") self.assertIsNotNone( search(r"days left", str(e1.copy_to(n + relativedelta(days=3) + m))), "stringify future event") e2 = evs[1] self.assertIsNotNone( search(r"ended", str(e2.copy_to(n - relativedelta(hours=5)))), "stringify past event") self.assertIsNotNone( search(r"now", str(e2.copy_to(n - relativedelta(hours=1)))), "stringify ongoing event") self.assertIsNotNone( search(r"hours left", str(e2.copy_to(n + relativedelta(hours=3)))), "stringify future event") self.assertIsNotNone( search(r"days left", str(e2.copy_to(n + relativedelta(days=3)))), "stringify future event")
def check_for_changes(seen_uids: Optional[set] = None): if seen_uids is None: seen_uids = {} logging.info("checking for changes, %d event uids known" % len(seen_uids)) try: now = datetime.now(tz=UTC) events = sorted([ event for url in URLS for event in icalevents.events(url, start=now - timedelta(days=365), end=now + timedelta(days=3 * 365)) ]) messages = get_messages(events, now, seen_uids if len(seen_uids) > 0 else None) for message in messages: post_message(message) seen_uids.clear() seen_uids.update({e.uid for e in events}) logging.info("checking for changes done, %d event uids known" % len(seen_uids)) except Exception as e: logging.error(str(e)) try: post_error_message( get_message("Sorry, there was an error 🤯.\n%s" % str(e), [])) except Exception as e: logging.error("WTF: " + str(e))
def event_list(self, start_year, start_month, num_months): start = datetime(start_year, start_month, 1, tzinfo=chi_time) end_year = start_year + (num_months // 12) end_month = start_month + (num_months % 12) if end_month > 12: end_month -= 12 end_year += 1 end = datetime(end_year, end_month, 1, tzinfo=chi_time) tour_dict = {} for event in icalevents.events(file=self.ics_file, start=start, end=end): if event.all_day: continue id = (event.uid.split('@')[0], event.start) if id not in tour_dict: tour_dict[id] = event continue if tour_dict[id].recurring == event.recurring: raise RuntimeError("This should never happen!") if not event.recurring: tour_dict[id] = event result = [DetourEvent(event) for event in tour_dict.values()] result.sort(key=lambda e: (e.guidename, e.start)) return result
def get_events(): start = datetime.datetime.utcnow() - datetime.timedelta(hours=10) end = datetime.datetime.utcnow() + datetime.timedelta(days=100) events = icalevents.events( 'https://kalender.eigenbaukombinat.de/public/all.ics', start=BERLIN.localize(start), end=BERLIN.localize(end)) next_events = [] for event in events: startdt = event.start.astimezone(BERLIN) enddt = event.end.astimezone(BERLIN) eventdata = dict(summary=event.summary, sortdate=startdt.strftime('%Y%m%d%H%M'), startdate=startdt.strftime('%d.%m.%Y'), starttime=startdt.strftime('%H:%M'), enddate=enddt.strftime('%d.%m.%Y'), endtime=enddt.strftime('%H:%M'), all_day=event.all_day) if event.description and event.description.startswith('http'): eventurl = event.description else: eventurl = None eventdata['url'] = eventurl next_events.append(eventdata) next_events = sorted(next_events, key=lambda ev: ev['sortdate']) return next_events
def test_events_start(self): ical = "test/test_data/basic.ics" start = date(2017, 5, 16) evs = icalevents.events(url=None, file=ical, start=start) self.assertEqual(len(evs), 3, "three events are found")
def update(self): # Transform include/exclude to lower-case. # We'll later transform the other "end" to lower case, too. include = [inc.lower() for inc in self.include or []] exclude = [exc.lower() for exc in self.exclude or []] def _should_add(evt_name): # Include overrides exclude. if include and evt_name.lower() in include: return True if not exclude or evt_name.lower() not in exclude: return not include return False if os.path.isfile(self.url): kwargs = {'file': self.url} else: kwargs = {'url': self.url} from icalevents.icalevents import events # Get ical events from now + x (future) days. evts = events(start=datetime.now(), end=datetime.now() + timedelta(days=self.future), fix_apple=True, **kwargs) # Group events by summary. grpd = defaultdict(list) for e in evts: grpd[e.summary].append(e) # Only grab the next event for each group/summary. next_events = { k: sorted(v, key=lambda x: x.start)[0] for k, v in grpd.items() if _should_add(k) } self.data = next_events
def events_from_urlfile(filename): 'Read a list of urls from a file' event_list = [] with open(filename) as urlfile: for url in urlfile: event_list += events(url.strip()) return event_list
def test_recurence_id_ms(self): ical = "test/test_data/recurrenceid_ms.ics" start = date(2021, 1, 1) end = date(2021, 12, 31) evs = icalevents.events(file=ical, start=start, end=end) self.assertEqual(len(evs), 41, "41 events in total - one was moved")
def test_events(self): ical = "test/test_data/basic.ics" start = date(2017, 5, 18) end = date(2017, 5, 19) evs = icalevents.events(url=None, file=ical, start=start, end=end) self.assertEqual(len(evs), 2, "two events are found")
def refresh(self, day): if not self.refreshed or self.refreshed + timedelta(days=1) < day: try: es = events(self.url) self.spaces = [(ev.start, ev.end) for ev in es] except Exception as e: print("ERROR while refreshing iCal") print(e)
def test_cest(self): ical = "test/test_data/cest.ics" start = date(2021, 1, 1) end = date(2021, 12, 31) evs = icalevents.events(file=ical, start=start, end=end) self.assertEqual(len(evs), 115, "4 events in total")
def get_event_by_uid(self, uid): """ returns the event for the given uid or None """ events = icalevents.events(url=self._calurl, file=self._calfile, fix_apple=True) for event in events: if event.uid == uid: return event return None
def get_events(self, start, end): if start is None: start = datetime.now() - timedelta(days=1) return sorted(events(string_content=self.__ical_data, start=start, end=end), key=attrgetter('start'))
def test_events_start(self): ical = "test/test_data/basic.ics" start = date(2017, 5, 16) evs = icalevents.events(url=None, file=ical, start=start) self.assertEqual(len(evs), 3, "three events are found") self.assertEqual(evs[0].modified_at, datetime(2017, 5, 21, 12, 56, 19, tzinfo=UTC))
def test_recurence_id_google(self): ical = "test/test_data/recurrenceid_google.ics" start = date(2021, 1, 1) end = date(2021, 12, 31) evs = icalevents.events(file=ical, start=start, end=end) self.assertEqual(len(evs), 4, "4 events in total")
def test_events_url(self): url = "https://raw.githubusercontent.com/jazzband/icalevents/master/test/test_data/basic.ics" start = date(2017, 5, 18) end = date(2017, 5, 19) evs = icalevents.events(url=url, file=None, start=start, end=end) self.assertEqual(len(evs), 2, "two events are found")
def get_tasks_and_calendar_events_string(): s = "Tasks / Events:" tz = pytz.timezone("US/Eastern") today = datetime.today().astimezone(tz) tasks = [] events = [] with open(ICAL_URLS_TXT) as f: calendar_urls = [line.strip() for line in f.readlines()] for calendar_url in calendar_urls: try: events += list(icalevents.events(calendar_url, fix_apple=True)) except: print(f"Failed to get iCal events from URL: {calendar_url}") for e in events: e.start = e.start.astimezone(tz) e.end = e.end.astimezone(tz) events = sorted(events, key=lambda e: e.start) events = [e for e in events if e.start.date() == today.date()] filtered_events = [] event_count_dict = collections.defaultdict(int) for e in events: start = e.start.strftime("%H:%M") end = e.end.strftime("%H:%M") event_id_str = str(start) + str(end) + str(e.summary) if event_count_dict[event_id_str] == 0: if ((e.start.day == today.day) and (e.end.day == (today + timedelta(days=1)).day) and (e.start.hour == 0) and (e.end.hour == 0) and (e.start.minute == 0) and (e.end.minute == 0)): tasks.append(e.summary) else: filtered_events.append(e) event_count_dict[event_id_str] += 1 events = filtered_events if len(events) > 0: for e in events: start = e.start.strftime("%H:%M") end = e.end.strftime("%H:%M") s += f"\n- {start}-{end} {today.tzname()}: {e.summary}" if tasks: for task in tasks: s += "\n- " + task if (len(events) == 0) and (not tasks): s += "\n<empty>" return s
def test_transparent(self): ical = "test/test_data/transparent.ics" start = date(2021, 1, 1) end = date(2021, 12, 31) [e1, e2] = icalevents.events(file=ical, start=start, end=end) self.assertEqual(e1.transparent, True, "respect transparency") self.assertEqual(e2.transparent, False, "respect opaqueness")
def getRecomendedWorkout(): from datetime import timedelta from icalevents.icalevents import events cal = events( 'https://api.band.us/ical?token=aAAxADYxZDhkNzk0ZmFiOWFkMTA1Njk1MzZkMTczN2MwNzU2YzY2YWE1Nzg', end=timedelta(days=0)) for event in cal: if event.summary != "Core" and event.summary != "Lift": return event
def test_event_recurring_attribute(self): ical = "test/test_data/basic.ics" start = date(2017, 7, 12) end = date(2017, 7, 13) ev = icalevents.events(url=None, file=ical, start=start, end=end)[0] self.assertEqual(ev.recurring, False, "check recurring=False for non recurring event") ical = "test/test_data/recurring.ics" start = date(2018, 10, 15) end = date(2018, 11, 15) evs = icalevents.events(file=ical, start=start, end=end) e1 = evs[1] e2 = evs[2] self.assertEqual(e1.recurring, True, "check recurring=True for recurring event (1)") self.assertEqual(e2.recurring, True, "check recurring=True for recurring event (2)")
def update(self): self.events = [] try: # NOTE: default_span= is not currently exposed by events() interface, # or we could shorten this to just providing the timedelta(minutes=1) start_time = datetime.utcnow() end_time = start_time + timedelta(minutes=1) # FUTURE: # - use events_async() to do the update asynchronously to not block the # Home Assistant event loop # - use X-HA-REFRESH-INTERVAL to set the default refresh interval (in seconds) # - use X-HA-MIN-REFRESH-INTERVAL to set the minimum refresh interval (in seconds) # - use X-HA-SENSOR-NAME as the sensor's name, if supplied # - use X-HA-DEFAULT-VALUE as the sensor's default value, if supplied # - use X-HA-ATTRIBUTES to define additional attributes for the calendar # event, such as "color=green", that apply to a specific event _LOGGER.error('TEST!! %s', source) if self._file: source = self._file es = events(file=self._file, start=start_time, end=end_time, fix_apple=self._fix_apple_format) elif self._url: source = self._url es = events(url=self._url, start=start_time, end=end_time, fix_apple=self._fix_apple_format) if es is None: _LOGGER.error('Unable to fetch iCal data from %s', source) self.events = [] return False _LOGGER.info("Fetched iCal data from %s", source) self.events = es except requests.exceptions.RequestException: _LOGGER.error("Error fetching data from %s", source) self.events = []
def get_events(self): """ Retrieve events of the day. """ now = utc.localize(datetime.utcnow()) events = icalevents.events(url=self.url, end=now + timedelta(days=1)) data = [] for event in events: data.append((event.start.strftime('%H:%M'), event.end.strftime('%H:%M'), event.summary)) return sorted(set(data), key=lambda x: x[0])
def test_events_no_description(self): ical = "test/test_data/no_description.ics" start = date(2018, 10, 15) end = date(2018, 11, 15) e1 = icalevents.events(file=ical, start=start, end=end)[0] self.assertEqual(e1.description, None) self.assertEqual(e1.summary, None) self.assertEqual(e1.location, None)
def test_events_exdates(self): ical = "test/test_data/recurring.ics" start = date(2018, 6, 1) end = date(2018, 6, 30) evs = icalevents.events(file=ical, start=start, end=end) self.assertEqual(evs[0].start.day, 1, "check first recurrence.") self.assertEqual(evs[1].start.day, 15, "check first exdate.") self.assertEqual(evs[2].start.day, 29, "check second exdate.")
def parse_ics(ics): es = events(file=ics, start=TODAY, end=TODAY) return es