Open
Conversation
4f2a2e3 to
9d110c8
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
>=2.2.6,<3→>=3,<4Release Notes
python-caldav/caldav (caldav)
v3.0.0Compare Source
Version 3.0 should be fully backward-compatible with version 2.x - but there are massive code changes in version 3.0, so if you're using the Python CalDAV client library in some sharp production environment, I would recommend to wait for two months before upgrading.
Highlights
AsyncDAVClientand async domain objects using a Sans-I/O architecture. The sameCalendar,Event,Todo, etc. objects work with both sync and async clients.caldav.jmappackage withJMAPClientandAsyncJMAPClientfor servers implementing RFC 8620 (JMAP Core) and RFC 8984 (JMAP Calendars). Note that this is experimental, and the public API may be changed in upcoming minor-releases.Test runs before release
The tests broke with lots of AuthorizationErrors with GMX. The tests were running successfully towards GMX before releasing the last alpha-release. It's probably a transient issue. I don't want to delay the release by doing more research into it.
Breaking Changes
Be aware that some of the 2.x minor-versions also tagged some "Potentially Breaking Changes" - so if you're upgrading i.e. from 2.1, you may want to browse through the "Potentially Breaking Changes" for the intermediate minor releases too.
tests/conf.pyhas been removed andconf_private.pywill be ignored. See the Test Framework section below.caldav/objects.pyremoved -- the backward-compatibility re-export shim has been deleted. Any code doingfrom caldav.objects import <something>must be updated; all public symbols remain available directly viacaldavor from their respective submodules.caldav.config.read_config()now raisesValueErroron YAML/JSON parse errors instead of logging and returning an empty dict. This ensures config errors are detected early.Deprecated
The following have been deprecated and emit
DeprecationWarning:calendar.date_search()- usecalendar.search()insteadclient.principals()- useclient.search_principals()insteadobj.split_expanded- may be removed in a future versionobj.expand_rrule- may be removed in a future version.instanceproperty on calendar objects - use.vobject_instanceor.icalendar_instanceresponse.find_objects_and_props()- useresponse.resultsinsteadThe
save_*-methods are deprecated but do not yet emit warnings (see #71):calendar.save_event()- usecalendar.add_event()insteadcalendar.save_todo()- usecalendar.add_todo()insteadcalendar.save_journal()- usecalendar.add_journal()insteadcalendar.save_object()- usecalendar.add_object()insteadMethods that fetch data from the server should use the
get_prefix (see #92). The following are deprecated but do not yet emit warnings:calendar.event_by_uid()- usecalendar.get_event_by_uid()insteadcalendar.todo_by_uid()- usecalendar.get_todo_by_uid()insteadcalendar.journal_by_uid()- usecalendar.get_journal_by_uid()insteadcalendar.object_by_uid()- usecalendar.get_object_by_uid()insteadprincipal.calendars()- useprincipal.get_calendars()insteadcalendar.events()- usecalendar.get_events()insteadcalendar.todos()- usecalendar.get_todos()insteadcalendar.journals()- usecalendar.get_journals()insteadcalendar.objects_by_sync_token()- usecalendar.get_objects_by_sync_token()insteadThe following
check_*_support()methods are deprecated but do not yet emit warnings:client.check_dav_support()- useclient.supports_dav()insteadclient.check_cdav_support()- useclient.supports_caldav()insteadclient.check_scheduling_support()- useclient.supports_scheduling()instead(Those methods actively probe the server;
is_supported()is a configuration lookup.)Additionally, direct
DAVClient()instantiation should migrate toget_davclient()factory method (seedocs/design/API_NAMING_CONVENTIONS.md)Added
Experimental JMAP calendar client — new
caldav.jmappackage providing a JMAP clientfor servers implementing RFC 8620 (JMAP Core) and RFC 8984 (JMAP Calendars).
Features:
JMAPClientand asynchronousAsyncJMAPClientwith mirrored APIscreate_event,get_event,update_event,delete_event,search_events)get_sync_token/get_objects_by_sync_tokencreate_task,get_task,update_task,delete_taskget_jmap_client()factory reads from the same config sources asget_davclient()(env vars, config file)Full async API - New
AsyncDAVClientand async-compatible domain objects:Retry-After / rate-limit handling (RFC 6585 / RFC 9110) --
DAVClientandAsyncDAVClientnow exposerate_limit_handle,rate_limit_default_sleep, andrate_limit_max_sleepparameters (this may be specified in the configuration file as well). Whenrate_limit_handle=Truethe client automatically sleeps and retries on 429 Too Many Requests and 503 Service Unavailable responses that include aRetry-Afterheader. Whenrate_limit_handle=False(default) aRateLimitErroris raised immediately so callers can implement their own back-off strategy. Newcaldav.lib.error.RateLimitErrorhasretry_after(raw header string) andretry_after_seconds(parsed float) attributes. #627search.is-not-defined.categoryandsearch.is-not-defined.dtend-- new client-side workaround sub-features for servers that do not support theCALDAV:is-not-definedfilter natively for these properties.Base+override feature profiles -- YAML config now supports inheriting from a base profile:
Compatibility fixes
save-load.event.recurrences.exceptionwhich is supported if the server stores master+exception VEVENTs as a single calendar object as per the RFC. Stalwart splits them into separate objects. Stalwart recombines the data when doing an expanded search, soexpand=Truesearches now automatically fall back to server-sideCALDAV:expand. (Arguably,unsupportedhere could also mean the exception data was simply discarded. If needed, I'll refine this in a future version)save-load.journal.mixed-calendar- some calendar servers offers a separate journal list.save-load.reuse-deleted-uid- server allows immediate reuse of an uid if the old object has been deletedsearch.time-range.*.old-dates- test data mostly have historic dates. Calendars are primarily made for future happenings. Some calendar servers does not support searching for things that happened 20 years ago, even for a very small calendar.search.is-not-defined.categoryandsearch.is-not-defined.dtend- actually, those are artifacts. The bug was on the client side, not server side. I may delete them in a future release.calendar-home-setproperty is not available (e.g. GMX).CalendarObjectResource.load()now falls back to UID-based lookup when servers change object URLs after a save.Added python-dateutil and PyYAML as explicit dependencies (were transitive)
Quite some methods have been renamed for consistency and to follow best current practices. See the Deprecated section.
Calendarclass now accepts anameparameter in its constructor, addressing a long-standing API inconsistency (#128)CalendarObjectResource.id property - Returns the UID of calendar objects (#515)
calendar.searcher() API - Factory method for advanced search queries (#590):
Improved API for accessing the
CalendarObjectResourceproperties (#613 ):get_data(),get_icalendar_instance,get_vobject_instance,get_icalendar_component:edit_*(but noedit_data- the data is an immutable string, should use simplyobject.data = foofor editing it)with obj.get_foo, the client may edit foo, and thenobj.save()to send it to the server.Fixed
is-not-definedfilter for CATEGORIES did not work, and for DTEND it did not work for full day events. (this was fixes in theicalendar-searcher, version 1.0.5).Changed
CalendarObjectResourceproperties (#613 )import caldavis now significantly faster. Heavy dependencies (lxml, niquests, icalendar) are deferred until first use. #621_search_implyields(SearchAction, data)tuples consumed by sync or async wrappersget_connection_params()provides unified config discovery with clear priority (explicit params > test server config > env vars > config file)${VAR}and${VAR:-default}environment variable expansion in config valuestests/conf.pyto newtests/test_servers/frameworkSecurity
Test Framework
tests/test_servers/module. It provides YAML-based server configuration: seetests/test_servers/__init__.pyfor usageconvert_conf_private.pymigration tool for legacy config formattest_lazy_import.py; expandedtest_async_davclient.py,test_async_integration.py,test_compatibility_hints.py,test_search.py,test_caldav_unit.pyCheckRecurrenceSearchnow also verifies implicit recurrence support for all-day (VALUE=DATE) recurring events, marking the feature asfragile(with behaviour description) when only datetime recurring events work.GitHub Pull Requests Merged
calendar.search-- Tobias Brox (@tobixen)get_display_name()-- Tobias Brox (@tobixen)GitHub Pull Requests Closed (not merged)
GitHub Issues Closed
get_davclientto be importable from caldav -- Tobias Brox (@tobixen)Credits
The following people contributed to this release through issue reports, pull requests, and/or commits:
Time Spent
Since the 2.2.1-release and excluding the JMAP-work done by Sashank,
Tobias has spent around 132 hours on this project.
In the 3.0-release, AI-tools have been used for improving quality and
speed. My first impression was very good. It seemed like the AI
understood the project, and it could fix things faster and better than
what I could do myself - I really didn't expect it to create any good
code at all. Well, sometimes it does, other times not. Soon enough I
also learned that the AI is good at creating crap code, breaking
things and Claude is particularly good at duplicating code and code
paths. In the end, despite using Claude I've spent more time on this
release than what I had estimated. However, I believe I've done a
quite through work on preserving backward-compatibility while also
developing a better API.
From my roadmap, those are the estimates:
In addition, lots of time spent on things that aren't covered by the roadmap:
[2.2.6] - [2026-02-01]
Fixed
loggingmodule, which was masking actual errors when handling malformed iCalendar data. #614Changed
get_davclient()factory function instead ofDAVClient()directlyTest Framework
GitHub Pull Requests Merged
GitHub Issues Closed
(2.2.4 is without niquests in the dependencies. 2.2.5 is with niquests. 2.2.6 is with niquests and a tiny CHANGELOG-fix)
Added
get_davclientis now exported from thecaldavpackage, allowingfrom caldav import get_davclient. #612[2.2.3] - [2025-12-06]
Fixed
vcal.fix-scrubber has been updated to make up a DTSTAMP if it's missing. Fixes #504[2.2.2] - [2025-12-04]
2.2.1 is released with requests support (mispelled riquests in 2.2.0), 2.2.2 with niquests support
[2.2.1] - [2025-12-04]
Highlights:
featuresconfiguration flag.Potentially Breaking Changes
(More information on the changes in the Changed section)
icalendar-searcher. so this may also break if you manage the dependencies manually. As this package was made by the maintainer of the CalDAV package, the security impact of adding this dependency should be low.Changed
caldav.CalDAVSearcherobject, add filters and do asearcher.search(cal)instead of doingcal.search(...).features/compatibility_hintssystem. This may be a breaking change for some use cases, as backward-bug-compatibility is not preserved - searches may return different results if the previous behavior was relying on server quirks.Fixed
Added
DAVClient(username='user@example.com')) and the library will automatically discover the CalDAV service endpoint. The discovery process follows RFC 6764 specification. This involves a new required dependency:dnspythonfor DNS queries. DNS-based discovery can be disabled in the davclient connection settings, but I've opted against implementing a fallback if the dns library is not installed.features: posteoinstead ofurl: https://posteo.de:8443/in the connection configuration.features: nextcloudandurl: my.nextcloud.provider.euinstead ofurl: https://my.nextcloud.provider.eu/remote.php/davfeatures: nextcloudandusername: tobixen@example.comrequire_tlsparameter (default:True) prevents DNS-based downgrade attacksfeaturesmay now simply be a string label referencing a well-known server or cloud solution - likefeatures: posteo. #561urlis no longer needed when referencing a well-known cloud solution. #561urlmay contain just the domain name (without any slashes). It may then either look up the URL path in the known caldav server database, or through RFC6764mysearcher = caldav.CalDAVSearcher(...) ; mysearcher.add_property_filter(...) ; mysearcher.search(calendar). It's a bit harder to use, but opens up the possibility to do more complicated searches.CalDAVSearcher.add_property_filter()method now acceptscase_sensitiveandcollationparameters. Supported collations include:i;octet(case-sensitive, binary comparison) - defaulti;ascii-casemap(case-insensitive for ASCII characters, RFC 4790)i;unicode-casemap(Unicode case-insensitive, RFC 5051 - server support may vary)CalDAVSearcher.filter()provides comprehensive client-side filtering, expansion, and sorting of calendar objects with full timezone preservation support.examples/collation_usage.pydemonstrates case-sensitive and case-insensitive calendar searches.Security
There is a major security flaw with the RFC6764 discovery. If the DNS is not trusted (public hotspot, for instance), someone can highjack the connection by spoofing the service records. The protocol also allows to downgrade from https to http. Utilizing this it may be possible to steal the credentials. Mitigations:
Also, the RFC6764 discovery may not always be robust, causing fallbacks and hence a non-deterministic behaviour.
Deprecated
Event.expand_rrulewill be removed in some future release, unless someone protests.Event.split_expandedtoo. Both of them were used internally, now it's not. It's dead code, most likely nobody and nothing is using them.GitHub Issues Closed
calendar.search-method with timestamp filters yielding too much (created 2023, closed 2025-12-02) - #351 the new search interface may do client-side filteringGitHub Pull Requests Merged
Test Framework
pytest -k Radicaleorpytest -k Xandikos- or run the tests in an environment not having access to docker if you want a quicker test run - or set up a localconf_private.pywhere you specify what servers to test. It may also be a good idea to runstart.shandstop.shintests/docker-test-servers/*manually so the container can stay up for the whole duration of the testing rather than being taken up and down for every test./var/lib/docker/volumesfrom filling up with leftover test data. This applies to Cyrus, Nextcloud, and Baikal test servers.caldav/compatibility_hints.py. Use the package caldav-server-checker to check the feature-set of your CalDAV server (though, as for now the last work done is on a separate branch. A relase will be made soon).testCheckCompatibilitywill be run if and only if the caldav-server-checker package is installed and available. If the package is installed, the version of it has to correspond exactly to the caldav version - and even then, it may break for various reasons (the caldav server tester is still under development, no stable release exists yet). The corresponding version of the package has not been released yet (it's even not merged to the main branch). I hope to improve on this somehow before the next release. It can be a very useful test - if the compatibility configuration is wrong, tests may break or be skipped for the wrong reasons.Time Spent
(The "Time Spent"-section was missing from the 2.1-release, so this includes everything since 2.0)
The maintainer has spent around 230 hours since version 2.0.0, plus paid some money for AI-assistance from Claude. This time includes work on the two sub-projects icalendar-searcher and caldav-server-tester (not released yet).
The estimation given at the road map was 28h for "Server checker and server compatibility hints project", 8h for "Maintain and expand the test server list", and 12h for "Outstanding issues slated for v3.0". Including the Claude efforts, consider this to be 5x as much time as estimated.
Some few reasons of the overrun:
Credits
The following contributors (by GitHub username) have assisted by reporting issues, submitting pull requests and provided feedback:
@ArtemIsmagilov, @cbcoutinho, @cdce8p, @dieterbahr, @dozed, @Ducking2180, @edel-macias-cubix, @erahhal, @greve, @jannistpl, @julien4215, @Kreijstal, @lbt, @lothar-mar, @mauritium, @moi90, @niccokunzmann, @oxivanisher, @paramazo, @pessimo, @Savvasg35, @seanmills1020, @siderai, @slyon, @smurfix, @soundstorm, @thogitnet, @thomasloven, @thyssentishman, @ugniusslev, @whoamiafterall, @yuwash, @zealseeker, @Zhx-Chenailuoding, @Zocker1999NET, @Sashank, @Claude and @tobixen
Test runs before release
Local docker containers and python server instances:
External servers tested:
Servers and platforms not tested this time:
I should probably look more into the breakages with PurelyMail and GMX.
Those servers ought to be tested, but I'm missing accounts/capacity to do it at the moment:
[2.1.2] - [2025-11-08]
Version 2.1.0 comes without niquests in the dependency file. Version 2.1.2 come with niquests in the dependency file. Also fixed up some minor mistakes in the CHANGELOG.
[2.1.1] - [2025-11-08] [YANKED]
Version 2.1.0 comes without niquests in the dependency file. Version 2.1.1 should come with niquests in the dependency file, but I made a mistake.
[2.1.0] - [2025-11-08]
I'm working on a caldav compatibility checker side project. While doing so, I'm working on redefining the "compatibility matrix". This should only affect the test code. If you maintain a file
tests/conf_private.py, chances are that the latest changesets will break Since "running tests towards private CalDAV servers" is not considered to be part of the public API, I deem this to be allowed without bumping the major version number. If you are affected and can't figure out of it, reach out by email, GitHub issue or GitHub discussions. (Frankly, I'm interessted if anyone except me uses this, so feel free to reach out also if you can figure out of it).As always, the new release comes with quite some bugfixes, compatibility fixes and workarounds improving the support for various calendar servers observed in the wild.
Potentially Breaking Changes
tests/conf_private.py, chances are that your test runs will break. Does anyone except me maintain atests/conf_private.py-file? Please reach out by email, GitHub issues or GitHub discussions.Changed
search-method will automatically deliver a union of a search of the three different comp-types if a comp-type is not set in the parameters and it's declared that the compatibility matrix does not work. In parallel I'm developing a stand-alone tool caldav-server-tester to check the compatibility of a caldav server. #532 / #537try: import niquests as requests except: import requests, making it easier to flap between requests and niquests.Fixes
objects.pywas broken up in smaller files. Which again highlights that I probably have some dead, moot code in the project. #554davclient.principals-method, allowing it to work on more servers - #559Added
CalendarObjectResourcefrom an icalendarEvent,Todoetc, and not onlyCalendar. Arguably a bugfix as it would be silently accepted and throw some arbitrary error, very confusing for end users. #546Other
[2.0.1] - [2025-06-24]
Due to feedback we've fallen back from niquests to requests again.
Changes
Configuration
📅 Schedule: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR was generated by Mend Renovate. View the repository job log.