Skip to content

Commit

Permalink
Fix tests for RDATE as PERIOD
Browse files Browse the repository at this point in the history
- fix spelling
- fix versions of dependencies
- create changelog entry
  • Loading branch information
niccokunzmann committed Sep 20, 2023
1 parent 002d69a commit 54e87d0
Show file tree
Hide file tree
Showing 7 changed files with 43 additions and 26 deletions.
8 changes: 7 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ To release new versions,
1. edit the Changelog Section
2. edit setup.py, the ``__version__`` variable
3. create a commit and push it
4. Wait for `GitHub Actions <https://github.com/niccokunzmann/python-recurring-ical-events/actions>`_ to finish the build.
4. wait for `GitHub Actions <https://github.com/niccokunzmann/python-recurring-ical-events/actions>`_ to finish the build
5. run

.. code-block:: shell
Expand All @@ -278,6 +278,12 @@ To release new versions,
Changelog
---------

- v2.1.0

- Added support for PERIOD values in RDATE. See `Issue 113 <https://github.com/niccokunzmann/python-recurring-ical-events/issues/113>`_.
- Fixed ``icalendar>=5.0.9`` to support ``RDATE`` of type ``PERIOD`` with a time zone.
- Fixed ``pytz>=2023.3`` to assure compatibility.

- v2.0.2

- Fixed omitting last event of ``RRULE`` with ``UNTIL`` when using ``pytz``, the event starting in winter time and ending in summer time. See `Issue 107 <https://github.com/niccokunzmann/python-recurring-ical-events/issues/107>`_.
Expand Down
15 changes: 11 additions & 4 deletions recurring_ical_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ def __init__(self, component, keep_recurrence_attributes=False):
self.keep_recurrence_attributes = keep_recurrence_attributes
self.exdates = []
self.exdates_utc = set()
self.replace_ends = {} # DTSTART -> DTEND # for periods
exdates = component.get("EXDATE", [])
for exdates in ((exdates,) if not isinstance(exdates, list) else exdates):
for exdate in exdates.dts:
Expand All @@ -178,7 +179,13 @@ def __init__(self, component, keep_recurrence_attributes=False):
rdates = component.get("RDATE", [])
for rdates in ((rdates,) if not isinstance(rdates, list) else rdates):
for rdate in rdates.dts:
self.rdates.append(rdate.dt)
if isinstance(rdate.dt, tuple):
# we have a period as rdate
self.rdates.append(rdate.dt[0])
self.replace_ends[timestamp(rdate.dt[0])] = rdate.dt[1]
else:
# we have a date/datetime
self.rdates.append(rdate.dt)

self.make_all_dates_comparable()

Expand Down Expand Up @@ -242,7 +249,7 @@ def rrulestr(self, rule_string):
rule.until = until = self._get_rrule_until(rule)
if is_pytz(self.start.tzinfo) and rule.until:
# when starting in a time zone that is one hour off to the end,
# we might miss the last occurence
# we might miss the last occurrence
# see issue 107 and test/test_issue_107_omitting_last_event.py
rule = rule.replace(until=rule.until + datetime.timedelta(hours=1))
rule.until = until
Expand All @@ -266,7 +273,7 @@ def make_all_dates_comparable(self):
Dates may be mixed and we have many of them.
- date
- datetime without timezome
- datetime without timezone
- datetime with timezone
These three are not comparable but can be converted.
"""
Expand Down Expand Up @@ -311,7 +318,7 @@ def within_days(self, span_start, span_stop):
continue
if self._unify_exdate(start) in self.exdates_utc:
continue
stop = start + self.duration
stop = self.replace_ends.get(timestamp(start), start + self.duration)
yield Repetition(
self.component,
self.convert_to_original_type(start),
Expand Down
5 changes: 3 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
icalendar
pytz
icalendar>=5.0.9
icalendar<6.0.0
pytz>=2023.3
python-dateutil>=2.8.1
x-wr-timezone < 1.0.0
x-wr-timezone >= 0.0.5
3 changes: 1 addition & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
HERE = os.path.abspath(os.path.dirname(__file__))
sys.path.insert(0, HERE) # for package import

__version__ = "2.0.2"
__version__ = "2.0.3"
__author__ = 'Nicco Kunzmann'


Expand Down Expand Up @@ -124,7 +124,6 @@ def run(self):
'License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)',
'Topic :: Software Development :: Libraries :: Python Modules',
'Topic :: Utilities',
'Intended Audience :: Developers',
'Natural Language :: English',
'Operating System :: OS Independent',
'Programming Language :: Python :: 3',
Expand Down
25 changes: 21 additions & 4 deletions test/test_issue_113_period_in_rdate.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
"""This tests that RDATE can be a PERIOD.
See https://github.com/niccokunzmann/python-recurring-ical-events/issues/113
Value Type: The default value type for this property is DATE-TIME.
The value type can be set to DATE or PERIOD.
If the "RDATE" property is
specified as a PERIOD value the duration of the recurrence
instance will be the one specified by the "RDATE" property, and
not the duration of the recurrence instance defined by the
"DTSTART" property.
"""
from datetime import datetime
import pytz

def test_rdate_is_period(calendars):
"""The recurring event has a period rdate."""
event = calendars.test_issue_113_period_in_rdate.at("20231213")
assert event["DTSTART"] == pytz.timezone("America/Vancouver").localize(datetime.datetime(2023, 12, 13, 12, 0))
def test_start_of_rdate(calendars):
"""The event starts on that time."""
event = calendars.issue_113_period_in_rdate.at("20231213")[0]
expected_start = pytz.timezone("America/Vancouver").localize(datetime(2023, 12, 13, 12, 0))
start = event["DTSTART"].dt
assert start == expected_start

def test_end_of_rdate(calendars):
"""The event starts on that time."""
event = calendars.issue_113_period_in_rdate.at("20231213")[0]
assert event["DTEND"].dt == pytz.timezone("America/Vancouver").localize(datetime(2023, 12, 13, 15, 0))
13 changes: 0 additions & 13 deletions test/test_rdate.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,19 +70,6 @@ def test_rdate_and_rrule_can_be_excluded_by_exdate(calendars):
events = calendars.rdate.at("20150705")
assert len(events) == 0

def test_period_as_rdate(todo):
"""Test the PERIOD type.
Value Type: The default value type for this property is DATE-TIME.
The value type can be set to DATE or PERIOD.
If the "RDATE" property is
specified as a PERIOD value the duration of the recurrence
instance will be the one specified by the "RDATE" property, and
not the duration of the recurrence instance defined by the
"DTSTART" property.
"""

def test_rdate_occurs_multiple_times(calendars):
"""An event can not only have an RDATE once but also many of them."""
events = calendars.rdate_hackerpublicradio.all()
Expand Down

0 comments on commit 54e87d0

Please sign in to comment.