Skip to content

Commit

Permalink
Merge pull request #54 from Plonq/keep-recurrence-attributes-option
Browse files Browse the repository at this point in the history
Add ability to keep recurrence attributes on event copies
  • Loading branch information
niccokunzmann authored May 24, 2021
2 parents 7d46524 + 17452e2 commit 3cf3270
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 12 deletions.
4 changes: 3 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,9 @@ However, these attributes may differ from the source event:

* DTSTART which is the start of the event instance.
* DTEND which is the end of the event instance.
* RDATE, EXDATE, RRULE are the rules to create event repetitions. They are **not** included in repeated events, see `Issue 23 <https://github.com/niccokunzmann/python-recurring-ical-events/issues/23>`_.
* RDATE, EXDATE, RRULE are the rules to create event repetitions.
They are **not** included in repeated events, see `Issue 23 <https://github.com/niccokunzmann/python-recurring-ical-events/issues/23>`_.
To change this, use ``of(calendar, keep_recurrence_attributes=True)``.

Development
-----------
Expand Down
27 changes: 16 additions & 11 deletions recurring_ical_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,18 +109,20 @@ class Repetition:
"RRULE", "RDATE", "EXDATE"
]

def __init__(self, source, start, stop):
def __init__(self, source, start, stop, keep_recurrence_attributes=False):
self.source = source
self.start = start
self.stop = stop
self.keep_recurrence_attributes = keep_recurrence_attributes

def as_vevent(self):
revent = self.source.copy()
revent["DTSTART"] = vDDDTypes(self.start)
revent["DTEND"] = vDDDTypes(self.stop)
for attribute in self.ATTRIBUTES_TO_DELETE_ON_COPY:
if attribute in revent:
del revent[attribute]
if not self.keep_recurrence_attributes:
for attribute in self.ATTRIBUTES_TO_DELETE_ON_COPY:
if attribute in revent:
del revent[attribute]
for subcomponent in self.source.subcomponents:
revent.add_component(subcomponent)
return revent
Expand All @@ -131,10 +133,11 @@ def is_in_span(self, span_start, span_stop):
def __repr__(self):
return "{}({{'UID':{}...}}, {}, {})".format(self.__class__.__name__, self.source.get("UID"), self.start, self.stop)

def __init__(self, event):
def __init__(self, event, keep_recurrence_attributes=False):
self.event = event
self.start = self.original_start = event["DTSTART"].dt
self.end = self.original_end = self._get_event_end()
self.keep_recurrence_attributes = keep_recurrence_attributes
self.exdates = []
self.exdates_utc = set()
exdates = event.get("EXDATE", [])
Expand Down Expand Up @@ -242,8 +245,10 @@ def within_days(self, span_start, span_stop):
yield self.Repetition(
self.event,
self.convert_to_original_type(start),
self.convert_to_original_type(stop))

self.convert_to_original_type(stop),
self.keep_recurrence_attributes,
)

def convert_to_original_type(self, date):
if not isinstance(self.original_start, datetime.datetime) and \
not isinstance(self.original_end, datetime.datetime):
Expand All @@ -260,14 +265,14 @@ def _get_event_end(self):
return self.event["DTSTART"].dt


def __init__(self, calendar):
def __init__(self, calendar, keep_recurrence_attributes=False):
"""Create an unfoldable calendar from a given calendar."""
assert calendar.get("CALSCALE", "GREGORIAN") == "GREGORIAN", "Only Gregorian calendars are supported." # https://www.kanzaki.com/docs/ical/calscale.html
self.repetitions = []
for event in calendar.walk():
if not is_event(event):
continue
self.repetitions.append(self.RepeatedEvent(event))
self.repetitions.append(self.RepeatedEvent(event, keep_recurrence_attributes))


@staticmethod
Expand Down Expand Up @@ -369,7 +374,7 @@ def add_event(event):
add_event(repetition.as_vevent())
return events

def of(a_calendar):
def of(a_calendar, keep_recurrence_attributes=False):
"""Unfold recurring events of a_calendar"""
return UnfoldableCalendar(a_calendar)
return UnfoldableCalendar(a_calendar, keep_recurrence_attributes)

55 changes: 55 additions & 0 deletions test/test_keep_recurrence_attributes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"""This file tests the `keep_recurrence_attributes` argument of `of` works as expected."""
import os

from datetime import datetime
from recurring_ical_events import of
from icalendar import Calendar

HERE = os.path.dirname(__name__) or "test"
CALENDARS_FOLDER = os.path.join(HERE, "calendars")
calendar_path = os.path.join(CALENDARS_FOLDER, "rdate.ics")


def test_keep_recurrence_attributes_default(calendars):
with open(calendar_path, "rb") as file:
content = file.read()

calendar = Calendar.from_ical(content)
today = datetime.today()
one_year_ahead = today.replace(year=today.year + 1)

events = of(calendar).between(today, one_year_ahead)
for event in events:
assert event.get("RRULE", False) is False
assert event.get("RDATE", False) is False
assert event.get("EXDATE", False) is False


def test_keep_recurrence_attributes_false(calendars):
with open(calendar_path, "rb") as file:
content = file.read()

calendar = Calendar.from_ical(content)
today = datetime.today()
one_year_ahead = today.replace(year=today.year + 1)

events = of(calendar, keep_recurrence_attributes=False).between(today, one_year_ahead)
for event in events:
assert event.get("RRULE", False) is False
assert event.get("RDATE", False) is False
assert event.get("EXDATE", False) is False


def test_keep_recurrence_attributes_true(calendars):
with open(calendar_path, "rb") as file:
content = file.read()

calendar = Calendar.from_ical(content)
today = datetime.today()
one_year_ahead = today.replace(year=today.year + 1)

events = of(calendar, keep_recurrence_attributes=True).between(today, one_year_ahead)
for event in events:
assert event.get("RRULE", False) is not False
assert event.get("RDATE", False) is not False
assert event.get("EXDATE", False) is not False

0 comments on commit 3cf3270

Please sign in to comment.