Skip to content

Commit 20555f3

Browse files
authored
Test code for #397 (#521)
* some more documentation, trying to make it more visible that a CalendarObjectResource (event) should contain one calendar component except for recurrences where it may contain overridden instances * test code for #397 - reporter did report some weird behaviour and came with the code for reproducing it. I'm not able to reproduce it, but I will leave it in the tests anyway. #521
1 parent 4e73c64 commit 20555f3

2 files changed

Lines changed: 57 additions & 4 deletions

File tree

caldav/calendarobjectresource.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,17 @@
7979

8080

8181
class CalendarObjectResource(DAVObject):
82-
"""
83-
Ref RFC 4791, section 4.1, a "Calendar Object Resource" can be an
82+
"""Ref RFC 4791, section 4.1, a "Calendar Object Resource" can be an
8483
event, a todo-item, a journal entry, or a free/busy entry
84+
85+
As per the RFC, a CalendarObjectResource can at most contain one
86+
calendar component, with the exception of recurrence components.
87+
Meaning that event.data typically contains one VCALENDAR with one
88+
VEVENT and possibly one VTIMEZONE.
89+
90+
In the case of expanded calendar date searches, each recurrence
91+
will (by default) wrapped in a distinct CalendarObjectResource
92+
object. This is a deviation from the definition given in the RFC.
8593
"""
8694

8795
## There is also STARTTOFINISH, STARTTOSTART and FINISHTOFINISH in RFC9253,
@@ -473,7 +481,7 @@ def _set_icalendar_component(self, value) -> None:
473481
icalendar_component = property(
474482
_get_icalendar_component,
475483
_set_icalendar_component,
476-
doc="icalendar component - should not be used with recurrence sets",
484+
doc="icalendar component - this is the simplest way to access the event/task - it will give you the first component that isn't a timezone component. For recurrence sets, the master component will be returned. For any non-recurring event/task/journal, there should be only one calendar component in the object. For results from an expanded search, there should be only one calendar component in the object",
477485
)
478486

479487
component = icalendar_component

tests/test_caldav.py

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -843,6 +843,51 @@ def testSchedulingMailboxes(self):
843843
inbox = self.principal.schedule_inbox()
844844
outbox = self.principal.schedule_outbox()
845845

846+
def testIssue397(self):
847+
cal = self._fixCalendar()
848+
cal.save_event(
849+
"""BEGIN:VCALENDAR
850+
VERSION:2.0
851+
PRODID:-//PeterB//caldav//en_DK
852+
BEGIN:VEVENT
853+
SUMMARY:recurrence with attendee one single item
854+
DTSTART;TZID=Europe/Zurich:20240101T090000
855+
DTEND;TZID=Europe/Zurich:20240101T180000
856+
UID:test1
857+
DESCRIPTION:this is the recurrent series
858+
TRANSP:OPAQUE
859+
RRULE:FREQ=WEEKLY;BYDAY=TU,WE,TH
860+
END:VEVENT
861+
BEGIN:VEVENT
862+
SUMMARY:single item
863+
DTSTART;TZID=Europe/Zurich:20240605T090000
864+
DTEND;TZID=Europe/Zurich:20240605T170000
865+
UID:test1
866+
DESCRIPTION:this is the single item assigning a attendee to just one event
867+
ATTENDEE:foo.bar@corge.baz
868+
RECURRENCE-ID:20240605T070000Z
869+
END:VEVENT
870+
END:VCALENDAR
871+
"""
872+
)
873+
874+
object_by_id = cal.object_by_uid("test1", comp_class=Event)
875+
instance = object_by_id.icalendar_instance
876+
events = [
877+
event
878+
for event in instance.subcomponents
879+
if isinstance(event, icalendar.Event)
880+
]
881+
assert len(events) == 2
882+
object_by_id = cal.object_by_uid("test1", comp_class=None)
883+
instance = object_by_id.icalendar_instance
884+
events = [
885+
event
886+
for event in instance.subcomponents
887+
if isinstance(event, icalendar.Event)
888+
]
889+
assert len(events) == 2
890+
846891
def testPropfind(self):
847892
"""
848893
Test of the propfind methods. (This is sort of redundant, since
@@ -3001,7 +3046,7 @@ def search(month):
30013046
event=True,
30023047
start=datetime(2015, month, 1),
30033048
end=datetime(2015, month, 2),
3004-
expand="client", ## client will be default from 2.0
3049+
expand=True,
30053050
)
30063051
assert len(recurrence) == 1
30073052
return recurrence[0]

0 commit comments

Comments
 (0)