Skip to content

Commit b555dca

Browse files
authored
Documentation project - tutorial with doctests
... and quite some changes and improvements to the doc. #503
1 parent 6a6590b commit b555dca

15 files changed

Lines changed: 635 additions & 445 deletions

CODE_OF_CONDUCT

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,25 @@
1-
I hope and believe we'll never need to refer to the Code of Conduct for the Python CalDAV client library, but if the need should arise: The "Contributor Covenant" applies to this project, currently version 2.1 at https://www.contributor-covenant.org/version/2/1/code_of_conduct/ . This applies to activities on the GitHub platform (issues and pull requests), documentation, code, comments in the code, and other project-related communication.
1+
I hope and believe we'll never need to refer to the Code of Conduct
2+
for the Python CalDAV client library, but if the need should arise:
3+
The "Contributor Covenant" applies to this project, currently version
4+
2.1 at https://www.contributor-covenant.org/version/2/1/code_of_conduct/ .
5+
This applies to activities on the GitHub platform (issues and pull
6+
requests), documentation, code, comments in the code, and other
7+
project-related communication.
28

3-
I would point out the importantance of avoiding toxic negativity. Some of us contributes to open source projects for the fun of it and not for profit - negativity can ruin the fun. Kenneth Reiz has a good essay about this at https://kennethreitz.org/essays/2013/be_cordial_or_be_on_your_way . That said, personally I'm all ears for suggestions on how to improve the CalDAV library - even if that includes blunt criticism of the work I've done.
9+
I would point out the importantance of avoiding toxic negativity.
10+
Some of us contributes to open source projects for the fun of it and
11+
not for profit - negativity can ruin the fun. Kenneth Reiz has a good
12+
essay about this at https://kennethreitz.org/essays/2013/be_cordial_or_be_on_your_way .
13+
That said, personally I'm all ears for suggestions on how to improve
14+
the CalDAV library - even if that includes blunt criticism of the work
15+
I've done.
416

5-
Unacceptable behavior may be reported to Tobias Brox, the current maintainer of the project. The email address coc-abuse@plann.no may be used. If complaining to Tobias doesn't help, you may try reaching out to the original maintainer and owner of the project, Cyril Robert. If Tobias is the subject of the complaint, you may want to put Cyril on the Cc-list in your complaint. His email address can be found through http://scr.im/22q7
17+
Unacceptable behavior may be reported to Tobias Brox, the current
18+
maintainer of the project. The email address coc-abuse@plann.no may
19+
be used. If complaining to Tobias doesn't help, you may try reaching
20+
out to the original maintainer and owner of the project, Cyril Robert.
21+
If Tobias is the subject of the complaint, you may want to put Cyril
22+
on the Cc-list in your complaint. His email address can be found
23+
through http://scr.im/22q7
624

725
Tobias Brox, 2025-05-21

caldav/collection.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,10 @@ def calendar(
153153
"No calendar with name %s found under %s" % (name, self.url)
154154
)
155155
if not cal_id and not name:
156-
return self.calendars()[0]
156+
cals = self.calendars()
157+
if not cals:
158+
raise error.NotFoundError("no calendars found")
159+
return cals[0]
157160

158161
if self.client is None:
159162
raise ValueError("Unexpected value None for self.client")

caldav/davclient.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -880,7 +880,7 @@ def auto_calendar(*largs, **kwargs) -> Iterable["Calendar"]:
880880
return next(auto_calendars(*largs, **kwargs), None)
881881

882882

883-
def auto_conn(*largs, **kwargs):
883+
def auto_conn(*largs, config_data: dict = None, **kwargs):
884884
"""A quite stubbed verison of get_davclient was included in the
885885
v1.5-release as auto_conn, but renamed a few days later. Probably
886886
nobody except my caldav tester project uses auto_conn, but as a
@@ -894,6 +894,8 @@ def auto_conn(*largs, **kwargs):
894894
DeprecationWarning,
895895
stacklevel=2,
896896
)
897+
if config_data:
898+
kwargs.update(config_data)
897899
return get_davclient(*largs, **kwargs)
898900

899901

@@ -902,22 +904,18 @@ def get_davclient(
902904
config_section="default",
903905
testconfig=False,
904906
environment: bool = True,
905-
config_data: dict = None,
906907
name: str = None,
908+
**config_data,
907909
) -> "DAVClient":
908910
"""
909-
Normally you would like to look into auto_calendars or
910-
auto_calendar instead. However, in some cases it's needed
911-
with a DAVClient object rather than a Calendar object.
912-
913911
This function will yield a DAVClient object. It will not try to
914912
connect (see auto_calendars for that). It will read configuration
915913
from various sources, dependent on the parameters given, in this
916914
order:
917915
918-
* Data from the given dict
919-
* Environment variables prepended with "CALDAV_"
920-
* Environment variables PYTHON_CALDAV_USE_TEST_SERVER and CALDAV_CONFIG_FILE will be honored if environment is set
916+
* Data from the parameters given
917+
* Environment variables prepended with `CALDAV_`, like `CALDAV_URL`, `CALDAV_USERNAME`, `CALDAV_PASSWORD`.
918+
* Environment variables `PYTHON_CALDAV_USE_TEST_SERVER` and `CALDAV_CONFIG_FILE` will be honored if environment is set
921919
* Data from `./tests/conf.py` or `./conf.py` (this includes the possibility to spin up a test server)
922920
* Configuration file. Documented in the plann project as for now. (TODO - move it)
923921
"""

docs/source/about.rst

Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
=================================
2+
Objective, RFCs, compatibility and misc
3+
=================================
4+
5+
6+
Project home
7+
============
8+
9+
The project currently lives on github,
10+
https://github.com/python-caldav/caldav - if you have problems using
11+
the library (including problems understanding the documentation),
12+
please feel free to report it on the issue tracker there or send email
13+
to caldav@plann.no.
14+
15+
Objective and scope
16+
===================
17+
18+
The python caldav library should make interactions with calendar servers
19+
simple and easy. Simple operations (like find a list of all calendars
20+
owned, inserting a new event into a calendar, do a simple date
21+
search, etc) should be trivial to accomplish even if the end-user of
22+
the library has no or very little knowledge of the caldav, webdav or
23+
icalendar standards. The library should be agile enough to allow
24+
"power users" to do more advanced stuff.
25+
26+
The library aims to take a pragmatic approach towards compatibility -
27+
it should work as well as possible for as many as possible. This also
28+
means the library will modify icalendar data to get around known
29+
compatibility issues - so no guarantee is given on the immutability of
30+
icalendar data.
31+
32+
Backward compatibility support
33+
==============================
34+
35+
The 1.x version series is intended to be maintained at least until
36+
2026-01.
37+
38+
The 2.x version series (not released as of 2025-06-01) is supposed to
39+
be fully backwards-compatible with version 1.x, and is intended to be
40+
maintained at least until 2027.
41+
42+
2.0 sheds compatibility with python 3.7 and python 3.8, and one
43+
obscure deprecated method has been ripped out.
44+
45+
API that is marked as deprecated 2.x will most likely be removed in version 3.0
46+
If you have any suggestions on API-changes, please
47+
comment on https://github.com/python-caldav/caldav/issues/92
48+
49+
Warnings will be issued when using legacy interface.
50+
51+
52+
Python compatibility notice
53+
===========================
54+
55+
Most of the code is regularly tested towards different versions of
56+
Python, the oldest being Python 3.9.
57+
58+
Support for Python2 was officially not supported starting from caldav
59+
version 1.0.
60+
61+
62+
RFC 4791, 2518, 5545, 6638 et al
63+
--------------------------------
64+
65+
RFC 4791 (CalDAV) outlines the standard way of communicating with a
66+
calendar server. RFC 4791 is an extension of RFC 4918 (WebDAV). The
67+
scope of this library is basically to cover RFC 4791/4918, the actual
68+
communication with the caldav server. (The WebDAV standard also has
69+
quite some extensions, this library supports some of the relevant
70+
extensions as well).
71+
72+
There exists another library webdavclient3 for handling RFC 4918
73+
(WebDAV), ideally we should be depending on it rather than overlap it.
74+
75+
RFC 6638/RFC 6047 is extending the CalDAV and iCalendar protocols for
76+
scheduling purposes, work is in progress to support RFC 6638. Support
77+
for RFC 6047 is considered mostly outside the scope of this library,
78+
though for convenience this library may contain methods like accept()
79+
on a calendar invite (which involves fetching the invite from the
80+
server, editing the calendar data and putting it to the server).
81+
82+
This library should make it trivial to fetch an event, modify the data
83+
and save it back to the server - but to do that it's also needed to
84+
support RFC 5545 (icalendar). It's outside the scope of this library
85+
to implement logic for parsing and modifying RFC 5545, instead we
86+
depend on another library for that.
87+
88+
RFC 5545 describes the icalendar format. Constructing or parsing
89+
icalendar data was considered out of the scope of this library, but we
90+
do make exceptions - like, there is a method to complete a task - it
91+
involves editing the icalendar data, and now the ``save_event``,
92+
``save_todo`` and ``save_journal`` methods are able to construct icalendar
93+
data if needed.
94+
95+
There exists two libraries supporting RFC 5545, vobject and icalendar.
96+
vobject was unmaintained for several years, but seems to be actively
97+
maintained now. The caldav library originally came with vobject
98+
support, but as many people requested the vobject dependency to be
99+
replaced with icalendar, both are now supported, and the icalendar
100+
library is now consistently used internally
101+
102+
Misbehaving server implementations
103+
----------------------------------
104+
105+
Some server implementations may have some "caldav"-support that either
106+
doesn't implement all of RFC 4791, breaks the standard a bit, or has
107+
extra features. As long as it doesn't add too much complexity to the
108+
code, hacks and workarounds for "badly behaving caldav servers" are
109+
considered to be within the scope. Ideally, users of the caldav
110+
library should be able to download all the data from one calendar
111+
server or cloud provider, upload it to another server type or cloud
112+
provider, and continue using the library without noticing any
113+
differences. To get there, it may be needed to add tweaks in the
114+
library covering the things the servers are doing wrong.
115+
116+
There exists an extension to the standard covering calendar color and
117+
calendar order, allegedly with an xml namespace
118+
``http://apple.com/ns/ical/``. That URL gives (301 https and
119+
then) 404. I've so far found no documentation at all
120+
on this extension - however, it seems to be supported by several
121+
caldav libraries, clients and servers. As of 0.7, calendar colors and
122+
order is available for "power users".
123+
124+
125+
Notable classes and workflow
126+
============================
127+
128+
* You'd always start by initiating a :class:`caldav.davclient.DAVClient`
129+
object, this object holds the authentication details for the
130+
server. In 2.0 there is a function :class:`caldav.davclient.get_davclient` that can be used.
131+
132+
* From the client object one can get hold of a
133+
:class:`caldav.collection.Principal` object representing the logged-in
134+
principal.
135+
136+
* From the principal object one can fetch / generate
137+
:class:`caldav.collection.Calendar` objects.
138+
139+
* From the calendar object one can fetch / generate
140+
:class:`caldav.calendarobjectresource.Event` objects and
141+
:class:`caldav.calendarobjectresource.Todo` objects (as well as :class:`caldav.calendarobjectresource.Journal` objects - does anyone use Journal objects?). Eventually the library may also spew out objects of the base class (:class:`caldav.calendarobjectresource.CalendarObjectResource`) if the object type is unknown when the object is instantiated.
142+
143+
* If one happens to know the URLs, objects like calendars, principals
144+
and events can be instantiated without going through the
145+
Principal-object of the logged-in user. A path, relative URL or
146+
full URL should work, but the URL should be without authentication
147+
details.
148+
149+
For convenience, the classes above are also available as
150+
:class:`caldav.DAVClient`, :class:`caldav.Principal`,
151+
:class:`caldav.Calendar`, :class:`caldav.Event`,
152+
:class:`caldav.Todo` etc.
153+
154+
Compatibility
155+
=============
156+
157+
(This will probably never be completely up-to-date. CalDAV-servers
158+
tend to be a moving target, and I rarely recheck if things works in
159+
newer versions of the software after I find an incompatibility)
160+
161+
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.
162+
163+
Here are some known issues:
164+
165+
* iCloud, Google and Zimbra are notoriously bad on their CalDAV-support.
166+
167+
* You may want to avoid non-ASCII characters in the calendar name, or
168+
some servers (at least Zimbra) may behave a bit unexpectedly.
169+
170+
* It's non-trivial to fix proper support for recurring events and
171+
tasks on the server side. DAViCal and Baikal are the only one I
172+
know of that does it right, all other calendar implementations that
173+
I've tested fails (but in different ways) on the tests covering
174+
recurrent events and tasks. Xandikos developer claims that it
175+
should work, I should probably revisit it again.
176+
177+
* Baikal does not support date search for todo tasks. DAViCal has
178+
slightly broken support for such date search.
179+
180+
* There are some special hacks both in the code and the tests to work
181+
around compatibility issues in Zimbra (this should be solved differently)
182+
183+
* Not all servers supports task lists, not all servers supports
184+
freebusy, and not all servers supports journals. Xandikos and
185+
Baikal seems to support them all.
186+
187+
* Calendar creation is actually not a mandatory feature according to
188+
the RFC, but the tests depends on it. The google calendar does
189+
support creating calendars, but not through their CalDAV adapter.
190+
191+
* iCloud may be a bit tricky, this is tracked in issue
192+
https://github.com/python-caldav/caldav/issues/3 - the list of incompatibilities found includes:
193+
194+
* No support for freebusy-requests, tasks or journals (only support for basic events).
195+
196+
* Broken (or no) support for recurring events
197+
198+
* 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)
199+
200+
* Seems impossible to have the same event on two calendars
201+
202+
* Some problems observed with the propfind method
203+
204+
* object_by_uid does not work (and my object_by_uid follows the example in the RFC)
205+
206+
* Google seems to be the new Microsoft, according to the issue
207+
tracker it seems like their CalDAV-support is rather lacking. At least they have a list ... https://developers.google.com/calendar/caldav/v2/guide
208+
209+
* 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.
210+
211+
Some notes on CalDAV URLs
212+
=========================
213+
214+
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:
215+
216+
* iCloud: ``https://caldav.icloud.com/``. Note that there is no
217+
template for finding the calendar URL and principal URL for iCloud -
218+
such URLs contains some ID numbers, by simply sticking to the
219+
recommended practice the caldav library will find those URLs. A
220+
typical icloud calendar URL looks like
221+
``https://p12-caldav.icloud.com/12345/calendars/CALNAME``.
222+
If you encounter troubles with iCloud, try toggling
223+
between IPv4 and IPv6 (see [issue 393](https://github.com/python-caldav/caldav/issues/393))
224+
225+
* Google - legacy: ``https://www.google.com/calendar/dav/``,
226+
The calendar URL for the primary personal calendar seems to be of the
227+
format ``https://www.google.com/calendar/dav/donald%40gmail.com/events``. When
228+
creating new calendars, they seem to end up under a global
229+
namespace.
230+
231+
* Google - new api: see https://developers.google.com/calendar/caldav/v2/guide.
232+
Please comment in https://github.com/python-caldav/caldav/issues/119 if you manage to connect to Google calendar.
233+
234+
* DAViCal: The caldav URL typically seems to be on the format ``https://your.server.example.com/caldav.php/``, though it depends on how the web server is configured. The primary calendars have URLs like ``https://your.server.example.com/caldav.php/donald/calendar`` and other calendars have names like ``https://your.server.example.com/caldav.php/donald/golfing_calendar``.
235+
236+
* Zimbra: The caldav URL is typically on the format ``https://mail.example.com/dav/``, calendar URLs can be on the format ``https://mail.example.com/dav/donald@example.com/My%20Golfing%20Calendar``. Display name always matches the last part of the URL.
237+
238+
* Fastmail: ``https://caldav.fastmail.com/dav/`` - note that the trailing dash is significant (ref https://github.com/home-assistant/core/issues/66599)
239+
240+
* GMX: `f"https://caldav.gmx.net/begenda/dav/{userid}@gmx.net/calendar`"`
241+
242+
* Purelymail: `https://purelymail.com/webdav/`
243+
244+
* Posteo: `https://posteo.de:8443/`
245+
246+
* all-inkl: `https://webmail.all-inkl.com/calendars/`
247+
248+
* Lark: `https://caldav-jp.larksuite.com` - note that Lark offers a very limited read-only access through the CalDAV protocol.
249+
250+
Unit testing
251+
============
252+
253+
To start the tests code, install everything from the setup.tests_requires list and run:
254+
255+
.. code-block:: bash
256+
257+
$ python setup.py test
258+
259+
tox should also work:
260+
261+
.. code-block:: bash
262+
263+
$ tox -e py
264+
265+
It will run some unit tests and some functional tests. You may want to add your own
266+
private servers into tests/conf_private.py, see tests/conf_private.py.EXAMPLE
267+
268+
Documentation
269+
=============
270+
271+
To build the documentation, install sphinx and run:
272+
273+
.. code-block:: bash
274+
275+
$ python setup.py build_sphinx
276+
277+
Code of Conduct
278+
===============
279+
280+
While I hope we never will need to refer to it, the `Contributor Covenant <https://www.contributor-covenant.org/version/2/1/code_of_conduct/>`_ applies to this project, see also `CODE_OF_CONDUCT <https://github.com/python-caldav/caldav/blob/master/CODE_OF_CONDUCT>`_. Avoid toxic negativity in general, but Tobias Brox can probably handle some blunt criticism if it may help getting the project on a better track.
281+
282+
License
283+
=======
284+
285+
Caldav is dual-licensed under the GNU GENERAL PUBLIC LICENSE Version 3 and the Apache License 2.0.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
:mod:`calendarobjectresource` -- Calendar Object Resources (Todo, Event, Journal, FreeBusy)
2+
===========================================================================================
3+
4+
.. automodule:: caldav.calendarobjectresource
5+
:synopsis: Calendar Object Resources (Events etc)
6+
:members:

docs/source/caldav/collection.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
:mod:`collection` -- Calendars, calendar sets, mailboxes and principal
2+
======================================================================
3+
4+
.. automodule:: caldav.collection
5+
:synopsis: Collection classes and principal
6+
:members:

docs/source/caldav/davobject.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
:mod:`davobject` -- Base object definition
2+
==========================================
3+
4+
.. automodule:: caldav.davobject
5+
:synopsis: Base DAVObject class
6+
:members:

0 commit comments

Comments
 (0)