From 27198ab8ba5434cd9078a69744ff9533f9796c52 Mon Sep 17 00:00:00 2001 From: Matthew Bafford Date: Wed, 30 Mar 2022 09:49:31 -0400 Subject: [PATCH] Handle multiple EXDATE entries on same line --- icalevents/icalparser.py | 9 ++-- test/test_data/multi_exdate_same_line_ms.ics | 47 ++++++++++++++++++++ test/test_icalevents.py | 21 ++++++++- 3 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 test/test_data/multi_exdate_same_line_ms.ics diff --git a/icalevents/icalparser.py b/icalevents/icalparser.py index a35469e..7c0f4bb 100644 --- a/icalevents/icalparser.py +++ b/icalevents/icalparser.py @@ -344,9 +344,10 @@ def parse_events(content, start=None, end=None, default_span=timedelta(days=7)): found = [] recurrence_ids = [] - # Skip dates that are stored as exceptions. - exceptions = {} for component in calendar.walk(): + # Skip dates that are stored as exceptions. + exceptions = {} + if component.name == "VEVENT": e = create_event(component, cal_tz) @@ -359,7 +360,9 @@ def parse_events(content, start=None, end=None, default_span=timedelta(days=7)): # Deal with the fact that sometimes it's a list and # sometimes it's a singleton exlist = [] - if isinstance(component["EXDATE"], list): + if isinstance(component["EXDATE"], vDDDLists): + exlist = component["EXDATE"].dts + elif isinstance(component["EXDATE"], list): exlist = component["EXDATE"] else: exlist.append(component["EXDATE"]) diff --git a/test/test_data/multi_exdate_same_line_ms.ics b/test/test_data/multi_exdate_same_line_ms.ics new file mode 100644 index 0000000..f3808e6 --- /dev/null +++ b/test/test_data/multi_exdate_same_line_ms.ics @@ -0,0 +1,47 @@ +BEGIN:VCALENDAR +METHOD:PUBLISH +PRODID:Microsoft Exchange Server 2010 +VERSION:2.0 +X-WR-CALNAME:Calendar +BEGIN:VTIMEZONE +TZID:Eastern Standard Time +BEGIN:STANDARD +DTSTART:16010101T020000 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=1SU;BYMONTH=11 +END:STANDARD +BEGIN:DAYLIGHT +DTSTART:16010101T020000 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=2SU;BYMONTH=3 +END:DAYLIGHT +END:VTIMEZONE +BEGIN:VEVENT +DESCRIPTION:Test event that has an RRULE with multiple EXDATE +RRULE:FREQ=WEEKLY;UNTIL=20220429T150000Z;INTERVAL=1;BYDAY=FR;WKST=MO +EXDATE;TZID=Eastern Standard Time:20220318T110000,20220401T110000,20220408T + 110000 +UID:040000008200R00074P5O7101N82R00800000000R0Q793689428Q801000000000000000 + 010000000QOPN4SS024R0264S9P0Q7OOQQ16PN399 +SUMMARY:Recurring With Exclusions +DTSTART;TZID=Eastern Standard Time:20220311T110000 +DTEND;TZID=Eastern Standard Time:20220311T113000 +CLASS:PUBLIC +PRIORITY:5 +DTSTAMP:20220330T125447Z +TRANSP:OPAQUE +STATUS:CONFIRMED +SEQUENCE:0 +LOCATION:Microsoft Teams Meeting +X-MICROSOFT-CDO-APPT-SEQUENCE:0 +X-MICROSOFT-CDO-BUSYSTATUS:BUSY +X-MICROSOFT-CDO-INTENDEDSTATUS:BUSY +X-MICROSOFT-CDO-ALLDAYEVENT:FALSE +X-MICROSOFT-CDO-IMPORTANCE:1 +X-MICROSOFT-CDO-INSTTYPE:1 +X-MICROSOFT-DONOTFORWARDMEETING:FALSE +X-MICROSOFT-DISALLOW-COUNTER:FALSE +END:VEVENT +END:VCALENDAR diff --git a/test/test_icalevents.py b/test/test_icalevents.py index d54f8b2..19c1139 100644 --- a/test/test_icalevents.py +++ b/test/test_icalevents.py @@ -425,7 +425,7 @@ def test_cest(self): evs = icalevents.events(file=ical, start=start, end=end) - self.assertEqual(len(evs), 115, "4 events in total") + self.assertEqual(len(evs), 116, "4 events in total") def test_transparent(self): ical = "test/test_data/transparent.ics" @@ -450,3 +450,22 @@ def test_status_and_url(self): self.assertEqual(ev3.status, "CANCELLED") self.assertEqual(ev4.status, "CANCELLED") self.assertEqual(ev5.status, None) + + def test_multi_exdate_same_line(self): + ical = "test/test_data/multi_exdate_same_line_ms.ics" + tz = gettz("America/New_York") + start = date(2022, 3, 1) + end = date(2022, 5, 1) + + evs = icalevents.events(file=ical, start=start, end=end) + + # parsing starts at 2022-03-01 + self.assertEqual(evs[0].start, datetime(2022, 3, 11, 11, 0, 0, tzinfo=tz)) + # 2022-03-18 is excluded by EXDATE rule + self.assertEqual(evs[1].start, datetime(2022, 3, 25, 11, 0, 0, tzinfo=tz)) + # 2022-04-01 is excluded by EXDATE rule + # 2022-04-08 is excluded by EXDATE rule + self.assertEqual(evs[2].start, datetime(2022, 4, 15, 11, 0, 0, tzinfo=tz)) + self.assertEqual(evs[3].start, datetime(2022, 4, 22, 11, 0, 0, tzinfo=tz)) + self.assertEqual(evs[4].start, datetime(2022, 4, 29, 11, 0, 0, tzinfo=tz)) + # parsing stops at 2022-05-01