Skip to content

Commit 7eca837

Browse files
committed
misc changes done while working on a server checker script
1 parent 867d0a9 commit 7eca837

10 files changed

Lines changed: 233 additions & 139 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,18 @@ This project should adhere to [Semantic Versioning](https://semver.org/spec/v2.0
1010

1111
In version 2.0, the requests library will be replaced with niquests or httpx. See https://github.com/python-caldav/caldav/issues/457. Master branch is currently running niquests.
1212

13-
(Also, in version 2.0, support for python 3.7 will be dropped, possibly also python 3.8. Master branch supports both as for now).
13+
In version 2.0, support for python 3.7 will be dropped, possibly also python 3.8. Master branch supports both as for now.
1414

1515
## [1.5.0] - [Unreleased]
1616

17-
### Fixed
18-
19-
* Readthedocs integration has been repaired (https://github.com/python-caldav/caldav/pull/453 - but eventually the fix was introduced directly in the master branch)
20-
2117
### Deprecated
2218

2319
Python 3.7 is no longer tested - but it should work. Please file a bug report if it doesn't work. (Note that the caldav library pulls in many dependencies, and not all of them supports dead snakes).
2420

2521
### Changed
2622

23+
* Some exotic servers may return object URLs on search, but it does not work out to fetch the calendar data. Now it will log an error instead of raising an error in such cases.
24+
2725
#### Refactoring
2826

2927
* Minor code cleanups by github user @ArtemIsmagilov in https://github.com/python-caldav/caldav/pull/456
@@ -38,15 +36,19 @@ Python 3.7 is no longer tested - but it should work. Please file a bug report i
3836
* Creating a local xandikos or radicale server in the `tests.client`-method, which is also used in the `examples`-section.
3937
* Allows offline testing of my upcoming `check_server_compatibility`-script
4038
* Also added the possibility to tag test servers with a name
39+
* Many changes done to the compatibility flag list (due to work on the server-checker project)
4140

4241
### Added
4342

44-
* By now `calendar.search(..., sort_keys=("DTSTART")` will work. Sort keys expects a list or a tuple, but it's easy to send an attribute by mistake. https://github.com/python-caldav/caldav/pull/449
43+
* By now `calendar.search(..., sort_keys=("DTSTART")` will work. Sort keys expects a list or a tuple, but it's easy to send an attribute by mistake. https://github.com/python-caldav/caldav/issues/448 https://github.com/python-caldav/caldav/pull/449
4544
* Compatibility workaround: If `event.load()` fails, it will retry the load by doing a multiget - https://github.com/python-caldav/caldav/pull/475 - https://github.com/python-caldav/caldav/issues/459
45+
* The `class_`-parameter now works when sending data to `save_event()` etc.
4646

4747
### Fixed
4848

4949
* Bugfix for saving component failing on multi-component recurrence objects - https://github.com/python-caldav/caldav/pull/467
50+
* Readthedocs integration has been repaired (https://github.com/python-caldav/caldav/pull/453 - but eventually the fix was introduced directly in the master branch)
51+
5052

5153
## [1.4.0] - 2024-11-05
5254

caldav/davclient.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ def _parse_response(self, response) -> Tuple[str, List[_Element], Optional[Any]]
207207
status = None
208208
href: Optional[str] = None
209209
propstats: List[_Element] = []
210+
check_404 = False ## special for purelymail
210211
error.assert_(response.tag == dav.Response.tag)
211212
for elem in response:
212213
if elem.tag == dav.Status.tag:
@@ -223,13 +224,29 @@ def _parse_response(self, response) -> Tuple[str, List[_Element], Optional[Any]]
223224
href = unquote(elem.text)
224225
elif elem.tag == dav.PropStat.tag:
225226
propstats.append(elem)
227+
elif elem.tag == "{DAV:}error":
228+
## This happens with purelymail on a 404.
229+
## This code is mostly moot, but in debug
230+
## mode I want to be sure we do not toss away any data
231+
children = elem.getchildren()
232+
error.assert_(len(children) == 1)
233+
error.assert_(
234+
children[0].tag == "{https://purelymail.com}does-not-exist"
235+
)
236+
check_404 = True
226237
else:
227-
error.assert_(False)
238+
## i.e. purelymail may contain one more tag, <error>...</error>
239+
## This is probably not a breach of the standard. It may
240+
## probably be ignored. But it's something we may want to
241+
## know.
242+
error.weirdness("unexpected element found in response", elem)
228243
error.assert_(href)
244+
if check_404:
245+
error.assert_("404" in status)
229246
## TODO: is this safe/sane?
230247
## Ref https://github.com/python-caldav/caldav/issues/435 the paths returned may be absolute URLs,
231248
## but the caller expects them to be paths. Could we have issues when a server has same path
232-
## but different URLs for different elements?
249+
## but different URLs for different elements? Perhaps href should always be made into an URL-object?
233250
if ":" in href:
234251
href = unquote(URL(href).path)
235252
return (cast(str, href), propstats, status)

caldav/lib/debug.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33

44
def xmlstring(root):
5+
if isinstance(root, str):
6+
return root
57
if hasattr(root, "xmlelement"):
68
root = root.xmlelement()
79
return etree.tostring(root, pretty_print=True).decode("utf-8")

caldav/lib/error.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
## one of DEBUG_PDB, DEBUG, DEVELOPMENT, PRODUCTION
1515
debugmode = os.environ["PYTHON_CALDAV_DEBUGMODE"]
1616
except:
17-
if "dev" in __version__:
17+
if "dev" in __version__ or __version__ == "(unknown)":
1818
debugmode = "DEVELOPMENT"
1919
else:
2020
debugmode = "PRODUCTION"
@@ -26,6 +26,18 @@
2626
log.setLevel(logging.WARNING)
2727

2828

29+
def weirdness(*reasons):
30+
from caldav.lib.debug import xmlstring
31+
32+
reason = " : ".join([xmlstring(x) for x in reasons])
33+
log.warning(f"Deviation from expectations found: {reason}")
34+
if debugmode == "DEBUG_PDB":
35+
log.error(f"Dropping into debugger due to {reason}")
36+
import pdb
37+
38+
pdb.set_trace()
39+
40+
2941
def assert_(condition: object) -> None:
3042
try:
3143
assert condition

caldav/lib/vcal.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ def create_ical(ical_fragment=None, objtype=None, language="en_DK", **props):
154154
I somehow feel this fits more into the icalendar library than here
155155
"""
156156
ical_fragment = to_normal_str(ical_fragment)
157+
if "class_" in props:
158+
props["class"] = props.pop("class_")
157159
if not ical_fragment or not re.search("^BEGIN:V", ical_fragment, re.MULTILINE):
158160
my_instance = icalendar.Calendar()
159161
if objtype is None:

caldav/objects.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -794,7 +794,7 @@ def _create(
794794
if name:
795795
try:
796796
self.set_properties([display_name])
797-
except:
797+
except Exception as e:
798798
## TODO: investigate. Those asserts break.
799799
error.assert_(False)
800800
try:
@@ -1232,9 +1232,19 @@ def search(
12321232
)
12331233
raise
12341234

1235+
obj2 = []
12351236
for o in objects:
12361237
## This would not be needed if the servers would follow the standard ...
1237-
o.load(only_if_unloaded=True)
1238+
try:
1239+
o.load(only_if_unloaded=True)
1240+
obj2.append(o)
1241+
except:
1242+
logging.error(
1243+
"Server does not want to reveal details about the calendar object",
1244+
exc_info=True,
1245+
)
1246+
pass
1247+
objects = obj2
12381248

12391249
## Google sometimes returns empty objects
12401250
objects = [o for o in objects if o.has_component()]

tests/compatibility_issues.py

Lines changed: 79 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
'rate_limited':
1616
"""It may be needed to pause a bit between each request when doing tests""",
1717

18+
'search_delay':
19+
"""Server populates indexes through some background job, so it takes some time from an event is added/edited until it's possible to search for it""",
20+
1821
'cleanup_calendar':
1922
"""Remove everything on the calendar for every test""",
2023

@@ -30,6 +33,9 @@
3033
'broken_expand_on_exceptions':
3134
"""The testRecurringDateWithExceptionSearch test breaks as the icalendar_component is missing a RECURRENCE-ID field. TODO: should be investigated more""",
3235

36+
'inaccurate_datesearch':
37+
"""A date search may yield results outside the search interval""",
38+
3339
'no_current-user-principal':
3440
"""Current user principal not supported by the server (flag is ignored by the tests as for now - pass the principal URL as the testing URL and it will work, albeit with one warning""",
3541

@@ -92,6 +98,9 @@
9298
'event_by_url_is_broken':
9399
"""A GET towards a valid calendar object resource URL will yield 404 (wtf?)""",
94100

101+
'no_delete_event':
102+
"""Zimbra does not support deleting an event, probably because event_by_url is broken""",
103+
95104
'no_sync_token':
96105
"""RFC6578 is not supported, things will break if we try to do a sync-token report""",
97106

@@ -121,6 +130,9 @@
121130
'no_todo':
122131
"""Support for VTODO (tasks) apparently missing""",
123132

133+
'no_todo_on_standard_calendar':
134+
"""Tasklists can be created, but a normal calendar does not support tasks""",
135+
124136
'no_todo_datesearch':
125137
"""Date search on todo items fails""",
126138

@@ -134,15 +146,27 @@
134146
"""date searches for todo-items will (only) find tasks that has either """
135147
"""a dtstart or due set""",
136148

149+
'vtodo_datesearch_nostart_future_tasks_delivered':
150+
"""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)""",
151+
137152
'vtodo_no_due_infinite_duration':
138153
"""date search will find todo-items without due if dtstart is """
139-
"""before the date search interval. I didn't find anything explicit """
140-
"""in The RFC on this (), but an event should be considered to have 0 """
141-
"""duration if no dtend is set, and most server implementations seems to """
142-
"""treat VTODOs the same""",
154+
"""before the date search interval. This is in breach of rfc4791"""
155+
"""section 9.9""",
143156

144-
'no_todo_on_standard_calendar':
145-
"""Tasklists can be created, but a normal calendar does not support tasks""",
157+
'vtodo_no_dtstart_infinite_duration':
158+
"""date search will find todo-items without dtstart if due is """
159+
"""after the date search interval. This is in breach of rfc4791"""
160+
"""section 9.9""",
161+
162+
'vtodo_no_dtstart_search_weirdness':
163+
"""Zimbra is weird""",
164+
165+
'vtodo_no_duration_search_weirdness':
166+
"""Zimbra is weird""",
167+
168+
'vtodo_with_due_weirdness':
169+
"""Zimbra is weird""",
146170

147171
'unique_calendar_ids':
148172
"""For every test, generate a new and unique calendar id""",
@@ -181,8 +205,11 @@
181205
'text_search_not_working':
182206
"""Text search is generally broken""",
183207

184-
'radicale_breaks_on_category_search':
185-
"""See https://github.com/Kozea/Radicale/issues/1125""",
208+
'date_search_ignores_duration':
209+
"""Date search with search interval overlapping event interval works on events with dtstart and dtend, but not on events with dtstart and due""",
210+
211+
'date_todo_search_ignores_duration':
212+
"""Same as above, but specifically for tasks""",
186213

187214
'fastmail_buggy_noexpand_date_search':
188215
"""The 'blissful anniversary' recurrent example event is returned when asked for a no-expand date search for some timestamps covering a completely different date""",
@@ -226,35 +253,54 @@
226253
## https://github.com/jelmer/xandikos/issues/8
227254
"no_recurring",
228255

256+
'date_todo_search_ignores_duration',
229257
'text_search_is_exact_match_only',
230-
231-
## This one is fixed - but still breaks our test code for python 3.7
232-
## TODO: remove this when shredding support for python 3.7
233-
## https://github.com/jelmer/xandikos/pull/194
234-
'category_search_yields_nothing',
258+
"search_needs_comptype",
259+
'vtodo_datesearch_nostart_future_tasks_delivered',
235260

236261
## scheduling is not supported
237262
"no_scheduling",
263+
264+
## The test in the tests itself passes, but the test in the
265+
## check_server_compatibility triggers a 500-error
266+
"no_freebusy_rfc4791",
267+
268+
## The test with an rrule and an overridden event passes as
269+
## long as it's with timestamps. With dates, xandikos gets
270+
## into troubles. I've chosen to edit the test to use timestamp
271+
## rather than date, just to have the test exercised ... but we
272+
## should report this upstream
273+
#'broken_expand_on_exceptions',
238274
]
239275

276+
## This can soon be removed (relevant for running tests under python 3.7 and python 3.8)
277+
## https://github.com/jelmer/xandikos/pull/194
278+
'category_search_yields_nothing',
279+
try:
280+
from xandikos import __version__ as xver
281+
goodver = (0,2,12)
282+
for i in range(0,3):
283+
if xver[i]<goodver[i]:
284+
xandikos.append('category_search_yields_nothing')
285+
break
286+
except Exception:
287+
pass
288+
240289
radicale = [
241290
## calendar listings and calendar creation works a bit
242291
## "weird" on radicale
243292
"broken_expand",
244293
"no_default_calendar",
245294

246295
## freebusy is not supported yet, but on the long-term road map
247-
"no_freebusy_rfc4791",
248-
249-
## TODO: raise an issue on this one
250-
"radicale_breaks_on_category_search",
296+
#"no_freebusy_rfc4791",
251297

252298
'no_scheduling',
253-
'no_todo_datesearch',
299+
"no_todo_datesearch",
254300

255301
'text_search_is_case_insensitive',
256-
'text_search_is_exact_match_sometimes',
257-
'combined_search_not_working',
302+
#'text_search_is_exact_match_sometimes',
303+
"search_needs_comptype",
258304

259305
## extra features not specified in RFC5545
260306
"calendar_order",
@@ -276,10 +322,9 @@
276322
## earlier versions of Zimbra display-name could be changed, but
277323
## then the calendar would not be available on the old URL
278324
## anymore)
279-
'no_displayname',
280325
'duplicate_in_other_calendar_with_same_uid_is_lost',
281326
'event_by_url_is_broken',
282-
'no_todo_on_standard_calendar',
327+
'no_delete_event',
283328
'no_sync_token',
284329
'vtodo_datesearch_notime_task_is_skipped',
285330
'category_search_yields_nothing',
@@ -341,7 +386,11 @@
341386
#'nofreebusy', ## for old versions
342387
'fragile_sync_tokens', ## no issue raised yet
343388
'vtodo_datesearch_nodtstart_task_is_skipped', ## no issue raised yet
344-
'broken_expand_on_exceptions',
389+
'broken_expand_on_exceptions', ## no issue raised yet
390+
'date_todo_search_ignores_duration'
391+
'calendar_color',
392+
'calendar_order',
393+
'vtodo_datesearch_notime_task_is_skipped'
345394
]
346395

347396
google = [
@@ -366,10 +415,16 @@
366415
]
367416

368417
nextcloud = [
418+
'date_search_ignores_duration',
369419
'sync_breaks_on_delete',
370420
'no_recurring_todo',
371421
'combined_search_not_working',
372422
'text_search_is_exact_match_sometimes',
423+
'search_needs_comptype',
424+
'calendar_color',
425+
'calendar_order',
426+
'date_todo_search_ignores_duration',
427+
'broken_expand_on_exceptions'
373428
]
374429

375430
fastmail = [
@@ -440,11 +495,7 @@
440495

441496
## Purelymail claims that the search indexes are "lazily" populated,
442497
## so search works some minutes after the event was created/edited.
443-
## I tried adding arbitrary delays in commit 5d052b1 but still didn't
444-
## manage to get search to work. Should eventually do more research
445-
## into this. (personal email communication with contact@purelymail.com)
446-
'no_search',
447-
'object_by_uid_is_broken',
498+
'search_delay'
448499
]
449500

450501
# fmt: on

0 commit comments

Comments
 (0)