Skip to content

Commit 358512d

Browse files
tobixenclaude
andcommitted
feat: add save-load.property.related-to and search.time-range.todo.{duration,open-start} feature flags
Adds three new feature flags replacing old_flags: - save-load.property.related-to: tracks whether servers preserve RELATED-TO properties (replaces no_relships old flag) - search.time-range.todo.duration: tracks VTODO DTSTART+DURATION time-range search correctness - search.time-range.todo.open-start: tracks open-start time-range search correctness for VTODOs Updates server compatibility hints for xandikos, bedework, zimbra, robur, ox, and davical accordingly. Replaces skip_on_compatibility_flag("no_relships") with skip_unless_support("save-load.property.related-to") in tests. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 6322464 commit 358512d

File tree

2 files changed

+25
-35
lines changed

2 files changed

+25
-35
lines changed

caldav/compatibility_hints.py

Lines changed: 23 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,11 @@ class FeatureSet:
163163
"save-load.event.timezone": {
164164
"description": "The server accepts events with non-UTC timezone information. When unsupported or broken, the server may reject events with timezone data (e.g., return 403 Forbidden). Related to GitHub issue https://github.com/python-caldav/caldav/issues/372."
165165
},
166+
"save-load.icalendar": {"description": "Is it possible to save icalendar data to the calendar? (Most likely yes - but we need a parent to collect all icalendar compatibility problems that aren't specific to one kind of object resource types"},
167+
"save-load.icalendar.related-to": {
168+
"description": "The server preserves RELATED-TO properties (RFC5545 section 3.8.4.5) when saving and loading calendar objects. When 'unsupported', the server may typically silently strip all RELATED-TO lines",
169+
"default": {"support": "full"},
170+
},
166171
"search": {
167172
"description": "calendar MUST support searching for objects using the REPORT method, as specified in RFC4791, section 7"
168173
},
@@ -183,6 +188,14 @@ class FeatureSet:
183188
},
184189
"search.time-range.todo": {"description": "basic time range searches for tasks works", "default": {"support": "full"}},
185190
"search.time-range.todo.old-dates": {"description": "time range searches for tasks with old dates (e.g. year 2000) work - some servers enforce a min-date-time restriction"},
191+
"search.time-range.todo.duration": {
192+
"description": "Time-range searches correctly handle VTODOs that specify their interval via DTSTART+DURATION (without a DUE property). RFC4791 section 9.9 specifies that such tasks overlap a time range if DTSTART+DURATION falls within the range. When 'unsupported', the server ignores DURATION and fails to find such tasks.",
193+
"default": {"support": "full"},
194+
},
195+
"search.time-range.todo.open-start": {
196+
"description": "Time-range searches with only an end bound (no start) correctly exclude tasks whose DTSTART is after the end bound. RFC4791 section 9.9: a VTODO with both DTSTART and DUE should not overlap if its DTSTART > search_end. When 'broken', the server incorrectly returns future tasks.",
197+
"default": {"support": "full"},
198+
},
186199
"search.time-range.event": {"description": "basic time range searches for event works", "default": {"support": "full"}},
187200
"search.time-range.event.old-dates": {"description": "time range searches for events with old dates (e.g. year 2000) work - some servers enforce a min-date-time restriction"},
188201
"search.time-range.journal": {"description": "basic time range searches for journal works"},
@@ -754,9 +767,6 @@ def dotted_feature_set_list(self, compact=False):
754767
"""date searches for todo-items will (only) find tasks that has either """
755768
"""a dtstart or due set""",
756769

757-
'vtodo_datesearch_nostart_future_tasks_delivered':
758-
"""Future tasks are yielded when doing a date search with some end timestamp and without start timestamp and the task contains both dtstart and due, but not duration (xandikos 0.2.12)""",
759-
760770
'vtodo_no_due_infinite_duration':
761771
"""date search will find todo-items without due if dtstart is """
762772
"""before the date search interval. This is in breach of rfc4791"""
@@ -778,18 +788,12 @@ def dotted_feature_set_list(self, compact=False):
778788
'dav_not_supported':
779789
"""when asked, the server may claim it doesn't support the DAV protocol. Observed by one baikal server, should be investigated more (TODO) and robur""",
780790

781-
'date_todo_search_ignores_duration':
782-
"""Same as above, but specifically for tasks""",
783-
784791
'fastmail_buggy_noexpand_date_search':
785792
"""The 'blissful anniversary' recurrent example event is returned when asked for a no-expand date search for some timestamps covering a completely different date""",
786793

787794
'non_existing_raises_other':
788795
"""Robur raises AuthorizationError when trying to access a non-existing resource (while 404 is expected). Probably so one shouldn't probe a public name space?""",
789796

790-
'no_relships':
791-
"""The calendar server does not support child/parent relationships between calendar components""",
792-
793797
'robur_rrule_freq_yearly_expands_monthly':
794798
"""Robur expands a yearly event into a monthly event. I believe I've reported this one upstream at some point, but can't find back to it""",
795799

@@ -813,19 +817,9 @@ def dotted_feature_set_list(self, compact=False):
813817
'principal-search': {'support': 'unsupported'},
814818
'freebusy-query.rfc4791': {'support': 'ungraceful', 'behaviour': '500 internal server error'},
815819
"scheduling": {"support": "unsupported"},
816-
"old_flags": [
817820
## https://github.com/jelmer/xandikos/issues/8
818-
'date_todo_search_ignores_duration',
819-
'vtodo_datesearch_nostart_future_tasks_delivered',
820-
821-
## The test with an rrule and an overridden event passes as
822-
## long as it's with timestamps. With dates, xandikos gets
823-
## into troubles. I've chosen to edit the test to use timestamp
824-
## rather than date, just to have the test exercised ... but we
825-
## should report this upstream
826-
#'broken_expand_on_exceptions',
827-
828-
]
821+
'search.time-range.todo.duration': {'support': 'unsupported'},
822+
'search.time-range.todo.open-start': {'support': 'broken', 'behaviour': 'future tasks are returned when only an end bound is given'},
829823
}
830824

831825
xandikos = {
@@ -846,11 +840,9 @@ def dotted_feature_set_list(self, compact=False):
846840
"auto-connect.url": {"domain": "localhost", "scheme": "http", "basepath": "/"},
847841

848842
"scheduling": {"support": "unsupported"},
849-
"old_flags": [
850843
## https://github.com/jelmer/xandikos/issues/8
851-
'date_todo_search_ignores_duration',
852-
'vtodo_datesearch_nostart_future_tasks_delivered',
853-
]
844+
'search.time-range.todo.duration': {'support': 'unsupported'},
845+
'search.time-range.todo.open-start': {'support': 'broken', 'behaviour': 'future tasks are returned when only an end bound is given'},
854846
}
855847

856848
## This seems to work as of version 3.5.4 of Radicale.
@@ -953,6 +945,7 @@ def dotted_feature_set_list(self, compact=False):
953945
## auto-processed into the attendee's calendar; no iTIP notification appears in the inbox.
954946
"scheduling.mailbox": True,
955947
"scheduling.mailbox.inbox-delivery": {"support": "unsupported"},
948+
'save-load.icalendar.related-to': {'support': 'unsupported'},
956949

957950
"old_flags": [
958951
## setting display name in zimbra does not work (display name,
@@ -963,7 +956,6 @@ def dotted_feature_set_list(self, compact=False):
963956
## anymore)
964957
## 'event_by_url_is_broken' removed - works in zimbra/zcs-foss:latest
965958
'vtodo_datesearch_notime_task_is_skipped',
966-
'no_relships',
967959

968960
## TODO: I just discovered that when searching for a date some
969961
## years after a recurring daily event was made, the event does
@@ -1008,10 +1000,10 @@ def dotted_feature_set_list(self, compact=False):
10081000
"scheduling.mailbox": {"support": "unknown"},
10091001

10101002
## TODO: play with this and see if it's needed
1003+
'save-load.icalendar.related-to': {'support': 'broken', 'behaviour': 'first RELATED-TO line is preserved but subsequent RELATED-TO lines are stripped'},
10111004
'old_flags': [
10121005
'propfind_allprop_failure',
10131006
'duplicates_not_allowed',
1014-
'no_relships' ## relships seems to work as long as it's one RELATED-TO-line, but as soon as there are multiple lines the implementation seems broken
10151007
],
10161008

10171009
}
@@ -1118,11 +1110,11 @@ def dotted_feature_set_list(self, compact=False):
11181110
#'nofreebusy', ## for old versions
11191111
## 'fragile_sync_tokens' removed - covered by 'sync-token': {'support': 'fragile'}
11201112
'vtodo_datesearch_nodtstart_task_is_skipped', ## no issue raised yet
1121-
'date_todo_search_ignores_duration',
11221113
'calendar_color',
11231114
'calendar_order',
11241115
'vtodo_datesearch_notime_task_is_skipped',
1125-
]
1116+
],
1117+
'search.time-range.todo.duration': {'support': 'unsupported'},
11261118
}
11271119

11281120
sogo = {
@@ -1226,8 +1218,8 @@ def dotted_feature_set_list(self, compact=False):
12261218
"scheduling": {"support": "unsupported"},
12271219
'old_flags': [
12281220
'non_existing_raises_other', ## AuthorizationError instead of NotFoundError
1229-
'no_relships',
12301221
],
1222+
'save-load.icalendar.related-to': {'support': 'unsupported'},
12311223
'test-calendar': {'cleanup-regime': 'wipe-calendar'},
12321224
"sync-token": {"support": "ungraceful"},
12331225
"get-supported-components": {"support": "unsupported"},
@@ -1497,9 +1489,7 @@ def dotted_feature_set_list(self, compact=False):
14971489
'principal-search.list-all': {'support': 'unsupported'},
14981490
## Cross-calendar duplicate UID test fails (AuthorizationError creating second calendar)
14991491
'save.duplicate-uid.cross-calendar': {'support': 'ungraceful'},
1500-
'old_flags': [
1501-
'no_relships',
1502-
],
1492+
'save-load.icalendar.related-to': {'support': 'unsupported'},
15031493
## OX App Suite has complex user provisioning; cross-user scheduling tests not yet set up.
15041494
"scheduling.mailbox.inbox-delivery": {"support": "unknown"},
15051495
}

tests/test_caldav.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2440,7 +2440,7 @@ def testWrongPassword(self):
24402440

24412441
def testCreateChildParent(self):
24422442
self.skip_unless_support("save-load.event")
2443-
self.skip_on_compatibility_flag("no_relships")
2443+
self.skip_unless_support("save-load.icalendar.related-to")
24442444
c = self._fixCalendar(supported_calendar_component_set=["VEVENT"])
24452445
parent = c.add_event(
24462446
dtstart=datetime(2022, 12, 26, 19, 15),
@@ -2602,7 +2602,7 @@ def testSetDue(self):
26022602

26032603
some_todo.save()
26042604

2605-
self.skip_on_compatibility_flag("no_relships")
2605+
self.skip_unless_support("save-load.icalendar.related-to")
26062606

26072607
parent = c.add_todo(
26082608
dtstart=datetime(2022, 12, 26, 19, 00, tzinfo=utc),

0 commit comments

Comments
 (0)