From 379ed8bf07de2c2d8d5b1bb34c63db12538c2f95 Mon Sep 17 00:00:00 2001 From: Tobias Brox Date: Tue, 15 Jul 2025 13:31:48 +0200 Subject: [PATCH 1/3] test code --- tests/test_caldav.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/test_caldav.py b/tests/test_caldav.py index 81937c77..1d46bf32 100644 --- a/tests/test_caldav.py +++ b/tests/test_caldav.py @@ -2477,6 +2477,21 @@ def testTodoDatesearch(self): # TODO: prod the caldav server implementers about the RFC # breakages. + def testSearchWithoutCompType(self): + """ + Test for https://github.com/python-caldav/caldav/issues/539 + """ + self.skip_on_compatibility_flag("search_needs_comptype") + self.skip_on_compatibility_flag("search_always_needs_comptype") + self.skip_on_compatibility_flag("no_todo") + self.skip_on_compatibility_flag("no_events_and_tasks_on_same_calendar") + cal = self._fixCalendar() + cal.save_todo(todo) + cal.save_event(ev1) + objects = cal.search() + assert len(objects) == 2 + assert set([str(type(x)) for x in objects]) == {"Todo", "Event"} + def testTodoCompletion(self): """ Will check that todo-items can be completed and deleted From 7d43173d7d94e4f93448282fba09902551dce152 Mon Sep 17 00:00:00 2001 From: Tobias Brox Date: Tue, 15 Jul 2025 13:50:59 +0200 Subject: [PATCH 2/3] Bugfix - search could give objects of wrong classes --- CHANGELOG.md | 9 ++++++++- caldav/collection.py | 9 ++++----- tests/test_caldav.py | 2 +- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 437293dc..9b43bf49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,14 @@ This project should adhere to [Semantic Versioning](https://semver.org/spec/v2.0 ## [Unreleased] -The niquests dependency has proven controversial. See https://github.com/python-caldav/caldav/issues/457 https://github.com/python-caldav/caldav/issues/530 https://github.com/jawah/niquests/issues/267 for details. While continuing work on the 2.x-series I've decided to always release two versions of caldav, one based on requests and the next one based on niquests - giving package maintainers and other parties the option to choose between niquests (which resolves some of the issues reported to the caldav library) and requests (which is mature and firmly established in the python community, although fading to irrelevance unless 3.0 is shipped soon). Master branch will use niquests, as it's more forward-leaning. I will make a new decision on this before starting work on 3.0. +### Fixes + +* A search without filtering on comp-type on a calendar containing a mix of events, journals and tasks should return a mix of such. (All the examples in the RFC includes the comp-type filter, so many servers does not support this). There were a bug in the auto-detection of comp-type, so tasks would typically be wrapped as events or vice-versa. https://github.com/python-caldav/caldav/pull/540 + +### Other + +* Example code: Basic usage examples have been brushed up, thanks to David Greaves - https://github.com/python-caldav/caldav/pull/534 +* PEP 639 conforming license expression in the pyproject.toml, thanks to Marc Mueller - https://github.com/python-caldav/caldav/pull/538 ## [2.0.1] - [2025-06-24] diff --git a/caldav/collection.py b/caldav/collection.py index eab30690..abbd6e5a 100644 --- a/caldav/collection.py +++ b/caldav/collection.py @@ -730,13 +730,12 @@ def _request_report_build_resultlist( pdata = results[r] if cdav.CalendarData.tag in pdata: cdata = pdata.pop(cdav.CalendarData.tag) - if comp_class is None: - comp_class = self._calendar_comp_class_by_data(cdata) + comp_class_ = self._calendar_comp_class_by_data(cdata) if comp_class is None else comp_class else: cdata = None - if comp_class is None: + if comp_class_ is None: ## no CalendarData fetched - which is normal i.e. when doing a sync-token report and only asking for the URLs - comp_class = CalendarObjectResource + comp_class_ = CalendarObjectResource url = URL(r) if url.hostname is None: # Quote when result is not a full URL @@ -745,7 +744,7 @@ def _request_report_build_resultlist( if self.url.join(url) == self.url: continue matches.append( - comp_class( + comp_class_( self.client, url=self.url.join(url), data=cdata, diff --git a/tests/test_caldav.py b/tests/test_caldav.py index 1d46bf32..478d4821 100644 --- a/tests/test_caldav.py +++ b/tests/test_caldav.py @@ -2490,7 +2490,7 @@ def testSearchWithoutCompType(self): cal.save_event(ev1) objects = cal.search() assert len(objects) == 2 - assert set([str(type(x)) for x in objects]) == {"Todo", "Event"} + assert set([type(x).__name__ for x in objects]) == {"Todo", "Event"} def testTodoCompletion(self): """ From cc979a0ffde51ac88c1f476caa87b6dac811932f Mon Sep 17 00:00:00 2001 From: Tobias Brox Date: Tue, 15 Jul 2025 13:53:53 +0200 Subject: [PATCH 3/3] =?UTF-8?q?style,=20style,=20style=20...=20=20style:?= =?UTF-8?q?=20commands[0]>=20pre-commit=20run=20--all-files=20--show-diff-?= =?UTF-8?q?on-failure=20Reorder=20python=20imports........................?= =?UTF-8?q?...........................=1B[42mPassed=1B[m=20black..........?= =?UTF-8?q?..........................................................=1B[4?= =?UTF-8?q?2mPassed=1B[m=20check=20BOM=20-=20deprecated:=20use=20fix-byte-?= =?UTF-8?q?order-marker........................=1B[42mPassed=1B[m=20trim?= =?UTF-8?q?=20trailing=20whitespace.......................................?= =?UTF-8?q?..........=1B[42mPassed=1B[m=20fix=20end=20of=20files..........?= =?UTF-8?q?...............................................=1B[42mPassed=1B?= =?UTF-8?q?[m=20=20=20style:=20OK=20(1.41=3Dsetup[0.11]+cmd[1.30]=20second?= =?UTF-8?q?s)=20=20=20congratulations=20:)=20(1.54=20seconds)=20to=20the?= =?UTF-8?q?=20rescue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- caldav/collection.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/caldav/collection.py b/caldav/collection.py index abbd6e5a..ccd1a366 100644 --- a/caldav/collection.py +++ b/caldav/collection.py @@ -730,7 +730,11 @@ def _request_report_build_resultlist( pdata = results[r] if cdav.CalendarData.tag in pdata: cdata = pdata.pop(cdav.CalendarData.tag) - comp_class_ = self._calendar_comp_class_by_data(cdata) if comp_class is None else comp_class + comp_class_ = ( + self._calendar_comp_class_by_data(cdata) + if comp_class is None + else comp_class + ) else: cdata = None if comp_class_ is None: