Skip to content

Commit 1b947f0

Browse files
committed
documentation changes
1 parent 6bdc140 commit 1b947f0

4 files changed

Lines changed: 107 additions & 46 deletions

File tree

docs/source/about.rst

Lines changed: 82 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -160,68 +160,110 @@ For convenience, the classes above are also available as
160160
Compatibility
161161
=============
162162

163-
(This will probably never be completely up-to-date. CalDAV-servers
164-
tend to be a moving target, and I rarely recheck if things works in
165-
newer versions of the software after I find an incompatibility)
163+
CalDAV server implementations vary widely in which optional RFC features they
164+
support, and how gracefully they handle things they do not support. The caldav
165+
library contains a compatibility layer that works around known issues
166+
automatically when the server is identified.
167+
168+
Compatibility hints system
169+
--------------------------
170+
..todo:: the sections about the compatibility hints should be moved somewhere else, maybe to a new document.
171+
172+
Server quirks and workarounds are encoded in ``caldav/compatibility_hints.py``.
173+
Each feature has a *support level*:
174+
175+
* ``full`` — works (as expected or better than expected)
176+
* ``quirk`` — supported, but needs special client-side handling
177+
* ``fragile`` — sometimes works, sometimes not
178+
* ``broken`` — server does something unexpected
179+
* ``ungraceful`` — server raises an HTTP error instead of handling gracefully
180+
* ``unsupported`` — feature is absent; attempts are silently skipped or adapted
181+
* ``unknown`` — not yet tested
182+
183+
The library calls ``is_supported(feature)`` internally before issuing requests,
184+
and applies workarounds where possible (for example, injecting an explicit time
185+
range when ``search.unlimited-time-range`` is ``broken``).
186+
187+
Configuring compatibility hints
188+
--------------------------------
189+
190+
The ``features`` parameter of :func:`caldav.get_davclient` (or
191+
:class:`caldav.DAVClient`) selects a named server profile from
192+
``compatibility_hints.py``, or accepts a dict of feature overrides:
166193

167-
The test suite is regularly run against several calendar servers, see https://github.com/python-caldav/caldav/issues/45 for the latest updates. See ``compatibility_hints.py`` for the most up-to-date list of compatibility issues. In early versions of this library test breakages was often an indication that the library did not conform well enough to the standards, but as of today it mostly indicates that the servers does not support the standard well enough. It may be an option to add tweaks to the library code to cover some of the missing functionality.
194+
.. code-block:: python
168195
169-
Here are some known issues:
196+
# Use a named profile — workarounds are applied automatically
197+
client = get_davclient(url="https://caldav.icloud.com/", features="icloud", ...)
170198
171-
* iCloud, Google and Zimbra are notoriously bad on their CalDAV-support.
199+
# Override individual features
200+
client = get_davclient(url="https://...", features={"search.text": {"support": "unsupported"}}, ...)
172201
173-
* You may want to avoid non-ASCII characters in the calendar name, or
174-
some servers (at least Zimbra) may behave a bit unexpectedly.
202+
(Best practice is to keep the configuration including passwords in a
203+
configuration file rather than hard-coding it in the python code)
175204

176-
* It's non-trivial to fix proper support for recurring events and
177-
tasks on the server side. DAViCal and Baikal are the only one I
178-
know of that does it right, all other calendar implementations that
179-
I've tested fails (but in different ways) on the tests covering
180-
recurrent events and tasks. Xandikos developer claims that it
181-
should work, I should probably revisit it again.
205+
For well-known providers (iCloud, ecloud, etc.) the ``features`` string also
206+
encodes the well-known CalDAV URL, so only the credentials are required. See
207+
:doc:`configfile` for how to specify ``features`` in the config file.
182208

183-
* Baikal does not support date search for todo tasks. DAViCal has
184-
slightly broken support for such date search.
209+
The test suite is regularly run against several calendar servers, see
210+
https://github.com/python-caldav/caldav/issues/45 for the latest updates.
211+
See ``compatibility_hints.py`` for the authoritative and up-to-date list of
212+
known quirks. Earlier versions of the library often had test failures that
213+
indicated the library itself was wrong; nowadays failures more often indicate
214+
that the server deviates from the standard.
185215

186-
* There are some special hacks both in the code and the tests to work
187-
around compatibility issues in Zimbra (this should be solved differently)
216+
Server-specific highlights
217+
--------------------------
188218

189-
* Not all servers supports task lists, not all servers supports
190-
freebusy, and not all servers supports journals. Xandikos and
191-
Baikal seems to support them all.
219+
* **iCloud, Google, Zimbra** are notoriously incomplete in their CalDAV
220+
support — see the server profile names ``icloud``, ``google``, ``zimbra``
221+
in ``compatibility_hints.py`` for the current list of known issues.
192222

193-
* Calendar creation is actually not a mandatory feature according to
194-
the RFC, but the tests depends on it. The google calendar does
195-
support creating calendars, but not through their CalDAV adapter.
223+
iCloud has not been tested for a while. As the maintainer has no account there, YOUR help is needed to ensure iCloud-compatibility.
196224

197-
* iCloud may be a bit tricky, this is tracked in issue
198-
https://github.com/python-caldav/caldav/issues/3 - the list of incompatibilities found includes:
225+
Notable iCloud limitations (tracked in https://github.com/python-caldav/caldav/issues/3):
199226

200-
* No support for freebusy-requests, tasks or journals (only support for basic events).
227+
* No support for freebusy, tasks, or journals.
228+
* Broken or absent support for recurring events.
229+
* Objects deleted from one client may reappear after recreating a
230+
calendar with the same name.
231+
* ``get_object_by_uid()`` does not work despite following the RFC example.
201232

202-
* Broken (or no) support for recurring events
233+
Google's CalDAV adapter does not support creating calendars; use the Google
234+
API directly for that. As with iCloud, Google support hasn't been tested for quite a while.
203235

204-
* We've observed information reappearing even if it has been deleted (i.e. recreating a calendar with the same name as a deleted calendar, and finding that the old events are still there)
236+
* **Radicale** will auto-create a calendar when accessing a URL that does not
237+
exist, and listing calendars owned by the user may fail.
205238

206-
* Seems impossible to have the same event on two calendars
239+
* **Baikal** does not support date-range searches for todo tasks.
207240

208-
* Some problems observed with the propfind method
241+
* **DAViCal** has slightly broken support for date-range searches on todos.
209242

210-
* get_object_by_uid does not work (and my get_object_by_uid follows the example in the RFC)
243+
* **OX App Suite** applies a "sliding window" to all calendar REPORT queries:
244+
objects whose date lies too far in the past (or future) are invisible.
245+
There is no CalDAV mechanism to enumerate those objects — they are invisible
246+
to ``calendar.search()``, ``calendar.events()``,
247+
``calendar.get_objects_by_sync_token()``, and ``calendar.get_object_by_uid()``;
248+
the only way to access them is a direct GET if the URL is already known.
249+
The library works around this by injecting an explicit 1970–2126 time range
250+
(``search.unlimited-time-range: broken``), which makes recurring events with
251+
future occurrences visible, but truly old non-recurring objects remain
252+
inaccessible. OX also rejects VTODOs containing RRULE with HTTP 400, and
253+
VTODOs must be stored in a calendar explicitly created for the ``VTODO``
254+
component type.
211255

212-
* Google seems to be the new Microsoft, according to the issue
213-
tracker it seems like their CalDAV-support is rather lacking. At least they have a list ... https://developers.google.com/calendar/caldav/v2/guide
256+
* **Calendar creation** is not mandatory under RFC 4791. Most self-hosted
257+
servers support it; Google's CalDAV adapter does not.
214258

215-
* radicale will auto-create a calendar if one tries to access a calendar that does not exist. The normal method of accessing a list of the calendars owned by the user seems to fail.
259+
* **Recurring events and tasks** are non-trivial to implement correctly on
260+
the server side. DAViCal and Baikal are the only servers known to handle
261+
them correctly in the test suite.
216262

217263
Some notes on CalDAV URLs
218264
=========================
219265

220-
.. todo::
221-
This section should be moved into separate HOWTOs for each calendar server/provider.
222-
Check if comment "to be released" can be removed
223-
224-
From v2.1, well-known URLs were hard-coded into the compatibility_hints. As of v2.2 (to be released 2025-12) auto-detection based on RFC6764 is supported. This protocol is widely used. For servers supporting it, it's sufficient to add something like "demo2.nextcloud.com" in the URL. For well-known calendar providers, it's not needed to enter anything in the URL, it suffices to put i.e. `features="ecloud"` into the connection parameters.
266+
From v2.1, well-known URLs were hard-coded into the compatibility_hints. As of v2.2, auto-detection based on RFC6764 is supported. This protocol is widely used. For servers supporting it, it's sufficient to add something like "demo2.nextcloud.com" in the URL. For well-known calendar providers, it's not needed to enter anything in the URL, it suffices to put i.e. `features="ecloud"` into the connection parameters.
225267

226268
CalDAV URLs can be quite confusing, some software requires the URL to the calendar, other requires the URL to the principal. The Python CalDAV library does support accessing calendars and principals using such URLs, but the recommended practice is to configure up the CalDAV root URL and tell the library to find the principal and calendars from that. Typical examples of CalDAV URLs:
227269

docs/source/howtos.rst

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,27 @@ For simple read access, use the ``component`` property:
5959
summary = event.component["SUMMARY"]
6060
start = event.component.start
6161
62-
.. todo::
62+
Backing Up a Calendar
63+
---------------------
64+
65+
Use :func:`caldav.get_calendar` (available since v2.0) to fetch all objects
66+
from a specific calendar and write them to disk:
67+
68+
.. code-block:: python
69+
70+
import pathlib
71+
from caldav import get_calendar
72+
73+
backup_dir = pathlib.Path("backup")
74+
backup_dir.mkdir(exist_ok=True)
75+
76+
with get_calendar(calendar_name="Work") as cal:
77+
for obj in cal.search():
78+
uid = obj.icalendar_instance.subcomponents[0]["UID"]
79+
(backup_dir / f"{uid}.ics").write_text(obj.data)
6380
64-
* Make a how-to on how to create a local backup and syncing it. (procrastinated until the ``get_calendar`` function is completed)
65-
* Make how-tos on each known calendar server and/or service provider - including known incompatibilities. Some information in the `about.rst`, should be moved here
66-
* Particularly Google.
81+
To restore, iterate over the saved ``.ics`` files and call ``cal.add_event()``
82+
(or ``add_todo()``/``add_journal()`` as appropriate).
6783

68-
See also https://github.com/python-caldav/caldav/issues/513
84+
For more on server-specific connection details and known incompatibilities,
85+
see :ref:`about:Compatibility` and :ref:`about:Some notes on CalDAV URLs`.

docs/source/index.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,16 @@ NOTE: version 3 introduces quite some new API. The documentation has been AI-ma
99
* The quality of the doc may be varying. I will get back to it and do proper QA on the documentation when I have my hands free.
1010
* This is the v3-documentation. If you're stuck on v2, then quite some of the instructions in this documentation will not work for you.
1111

12+
Upgrading from v2? See :doc:`v3-migration`.
13+
1214
Contents
1315
========
1416

1517
.. toctree::
1618
:maxdepth: 1
1719

1820
about
21+
v3-migration
1922
tutorial
2023
async
2124
jmap

pyproject.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,6 @@ ignore = [
136136
"UP008", # super() style (existing code uses explicit form)
137137
"UP031", # %-format (existing code uses it extensively)
138138
"UP036", # Outdated version blocks (will clean up when dropping old Python)
139-
"UP038", # isinstance tuple vs | (used in try/except for backwards compat)
140139
"UP045", # X | None vs Optional (both are fine)
141140
]
142141

0 commit comments

Comments
 (0)