Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
161 commits
Select commit Hold shift + click to select a range
afffdc7
Add deptry for dependency verification
tobixen Dec 22, 2025
f96ae4f
actually, this is second version (get_principals was renamed search_p…
tobixen Dec 9, 2025
d4b55fc
Research: API inconsistencies and URL parameter semantics
tobixen Dec 9, 2025
3dd6f23
Analysis: get_davclient() as primary entry point
tobixen Dec 9, 2025
c10f5b7
Analysis: Refactoring _query() to eliminate dependency on method wrap…
tobixen Dec 9, 2025
f950628
Add connection probe analysis
tobixen Dec 9, 2025
a4e4d1c
Analysis: Method generation vs manual implementation
tobixen Dec 9, 2025
3b23d49
Add comprehensive async refactoring plan and fix redundancy
tobixen Dec 9, 2025
8574091
Refine async refactoring plan based on maintainer feedback
tobixen Dec 9, 2025
be2d37a
Add Ruff configuration proposal for partial codebase
tobixen Dec 9, 2025
c76c3ff
Organize async refactoring design documents
tobixen Dec 9, 2025
9c099ca
underscores should only be used when needed
tobixen Dec 9, 2025
73f0e7c
links between the markdown files
tobixen Dec 13, 2025
0f67df7
Implement Phase 1: Core Async Client
tobixen Dec 13, 2025
48279a0
Add comprehensive tests for Phase 1 async implementation
tobixen Dec 13, 2025
5d9a2f9
Add demonstration sync wrapper validating async-first architecture
tobixen Dec 14, 2025
dfef0c5
Fix authentication issues in async wrapper
tobixen Dec 14, 2025
e967bfe
Fix feature derivation when subfeatures have mixed statuses
tobixen Dec 14, 2025
eff7d7b
Fix feature derivation to skip independent subfeatures
tobixen Dec 14, 2025
5468467
Add unit tests for independent subfeature derivation
tobixen Dec 14, 2025
195ca54
Fix DAVClient.close() to not reference removed _async_client
tobixen Dec 14, 2025
d9d0480
Add Ruff linting for new async files (post-v2.2.2)
tobixen Dec 14, 2025
255844d
Fix all remaining Ruff issues in async files
tobixen Dec 14, 2025
320aec1
Update Ruff documentation to reflect all issues resolved
tobixen Dec 14, 2025
0ba67d9
Use AsyncHTTPDigestAuth for async sessions in sync-wrapper
tobixen Dec 14, 2025
e3ddfd1
Fix http.multiplexing being incorrectly set during auth retry
tobixen Dec 14, 2025
e8e81b0
Add missing password decode retry and AuthorizationError raising
tobixen Dec 14, 2025
952d02c
Fix infinite recursion by converting DAVClient.request() to async wra…
tobixen Dec 14, 2025
c30bf9e
Add unit test compatibility for mocked DAVClient
tobixen Dec 14, 2025
bee290a
Make test server containers truly ephemeral
tobixen Dec 15, 2025
6198cf4
Minor test improvements
tobixen Dec 15, 2025
07fe463
Fix Baikal start script to work with tmpfs ephemeral storage
tobixen Dec 15, 2025
bf3fd87
Improve exception handling in DAVClient.__enter__
tobixen Dec 15, 2025
3e05f61
Remove problematic mode=1777 from tmpfs mounts
tobixen Dec 16, 2025
49e44c3
I'm still not smart on this teardown problem
tobixen Dec 16, 2025
1ac8f27
Document NextCloud repeated compatibility test issue
tobixen Dec 16, 2025
52dca3e
Implement Phase 4: Sync wrappers for async-first architecture
tobixen Dec 16, 2025
7af737b
Fix UID generation and data serialization in async CalendarObjectReso…
tobixen Dec 16, 2025
bb61f1c
Fix sync wrapper implementation for save() method
tobixen Dec 16, 2025
bbb2f98
Fix infinite redirect loop and path matching issues
tobixen Dec 17, 2025
37b49e9
Fix sync-to-async HTTPDigestAuth conversion
tobixen Dec 17, 2025
7d833e5
Fix load() to handle unit tests without client
tobixen Dec 17, 2025
dd211fc
Document MockedDAVClient limitation with async delegation
tobixen Dec 17, 2025
1add178
Fix mocked client detection and add sync fallback for unit tests
tobixen Dec 17, 2025
c7b66ef
Update TODO.md with latest fixes
tobixen Dec 17, 2025
006d0ce
minor bugfix
tobixen Dec 17, 2025
2dba483
Implement persistent event loop for HTTP connection reuse
tobixen Dec 17, 2025
3da9482
Add lychee link checker: GitHub workflow and pre-commit hook
tobixen Dec 18, 2025
3aca035
Optimize Docker test server setup: start once, skip cleanup
tobixen Dec 18, 2025
3c62292
Fix Nextcloud test failures and cleanup regime configuration
tobixen Dec 19, 2025
dda903e
Fix broken links in documentation
tobixen Dec 22, 2025
a1d8475
Fix remaining broken links and add lychee ignore file
tobixen Dec 22, 2025
032338b
Fix pre-commit style issues: import ordering, black formatting, EOF n…
tobixen Dec 23, 2025
c46b674
Implement AsyncCalendarSet with sync wrapper delegation
tobixen Dec 23, 2025
9a38eae
Implement AsyncPrincipal with sync wrapper delegation
tobixen Dec 23, 2025
b57b630
Implement AsyncCalendar core methods
tobixen Dec 23, 2025
c1233ab
Update design README with Phase 3 implementation status
tobixen Dec 23, 2025
62eb1e2
Fix file descriptor leak in async delegation methods
tobixen Dec 23, 2025
c0eabb1
Fix file descriptor leak in async event loop management
tobixen Dec 24, 2025
6c01028
Make testCreateDeleteCalendar more robust against interrupted runs
tobixen Dec 24, 2025
5c0987d
Implement AsyncCalendar search methods (Phase 3 Search)
tobixen Dec 24, 2025
1414a59
Update design docs: Phase 3 Search methods complete
tobixen Dec 24, 2025
e949d36
Phase 4: DAVResponse directly accepts AsyncDAVResponse
tobixen Dec 25, 2025
81204fd
Update design docs: Phase 4 complete
tobixen Dec 25, 2025
6d3e99a
Phase 5: Add async API documentation and examples
tobixen Dec 25, 2025
758dbf3
Add has_component() method to AsyncCalendarObjectResource
tobixen Dec 30, 2025
52e0f04
Add code review for async API implementation
tobixen Dec 30, 2025
e467d7c
Fix unused imports in async_davobject.py
tobixen Dec 30, 2025
ecb3650
Implement async delegation for sync Calendar.search()
tobixen Dec 31, 2025
86ff439
Add sync vs async implementation overview documentation
tobixen Dec 31, 2025
fd57fa8
Unify sync and async search logic via CalDAVSearcher
tobixen Dec 31, 2025
56942d1
Unify config discovery for sync and async get_davclient()
tobixen Jan 1, 2026
49dcd4d
Add test server framework package
tobixen Jan 1, 2026
6a5d4b3
Fix async integration tests for Radicale and Xandikos
tobixen Jan 1, 2026
84ba8c2
Add deprecation warnings to tests/conf.py
tobixen Jan 1, 2026
e187678
Fix linting issues in async tests and embedded servers
tobixen Jan 1, 2026
7a2d530
Refactor: Extract BaseDAVResponse to eliminate ~250 lines of duplication
tobixen Jan 1, 2026
fb8524a
Remove duplicate _get_async_client() method in DAVClient
tobixen Jan 1, 2026
8430fee
Implement missing AsyncCalendar methods
tobixen Jan 1, 2026
508e139
Add complete() and uncomplete() methods to AsyncTodo
tobixen Jan 1, 2026
b965bed
Fix test to match new unified config error message
tobixen Jan 1, 2026
86e13a1
Add property accessor methods to AsyncEvent and AsyncTodo
tobixen Jan 1, 2026
524bf7b
Add DAViCal docker container to test framework
tobixen Jan 2, 2026
55bba40
Fix FeatureSet copying and config parsing issues
tobixen Jan 2, 2026
1e41c52
Fix search to handle async classes and mark fragile features
tobixen Jan 3, 2026
b908c00
Fix pending todos path condition to not trigger on include_completed=…
tobixen Jan 3, 2026
63d7d03
Fix port conflict when running multiple xandikos test modules
tobixen Jan 3, 2026
dd86563
Add design analysis of sync/async library patterns
tobixen Jan 5, 2026
9385856
Update design docs README with SYNC_ASYNC_PATTERNS.md
tobixen Jan 5, 2026
635e51c
Add playground branch analysis comparing to industry patterns
tobixen Jan 5, 2026
43166a9
Add Sans-I/O architecture design plan
tobixen Jan 5, 2026
11d2313
Expand Sans-I/O design with API stability analysis and hybrid approach
tobixen Jan 5, 2026
59f1670
claude thoughts
tobixen Jan 5, 2026
46294e3
Add detailed Sans-I/O implementation plan and update docs
tobixen Jan 5, 2026
838661b
Add Sans-I/O protocol layer foundation (Phases 1-3)
tobixen Jan 7, 2026
a357c55
Add CalDAVProtocol operations class, I/O layer, and tests (Phases 4-5)
tobixen Jan 7, 2026
2be889e
Add protocol-based client classes with tests (Phase 6)
tobixen Jan 7, 2026
26952d9
Add protocol layer usage guide and update design docs
tobixen Jan 7, 2026
873821b
Add integration tests for Sans-I/O protocol clients
tobixen Jan 7, 2026
8cdec70
Update design docs to reflect completed Sans-I/O implementation
tobixen Jan 7, 2026
55f3a88
Document decision to keep DAVClient and protocol layer separate
tobixen Jan 7, 2026
834612c
Phase 1: Enhance protocol layer parsers for complex properties
tobixen Jan 7, 2026
e67e33a
Refactor AsyncDAVClient to use protocol layer (Phase 2)
tobixen Jan 7, 2026
b2b2f40
Migrate AsyncCalendar.get_supported_components() to protocol layer (P…
tobixen Jan 7, 2026
0bf5e7c
Add protocol-layer parsed results to DAVResponse (Phase 4)
tobixen Jan 7, 2026
6d6b201
Migrate sync Calendar.get_supported_components() to async delegation …
tobixen Jan 7, 2026
23b7872
Migrate async get_properties() to use response.results
tobixen Jan 7, 2026
c78137b
Document response.results interface in PROTOCOL_LAYER_USAGE.md
tobixen Jan 7, 2026
af41271
Update design docs README with Phase 8 completion status
tobixen Jan 7, 2026
648318a
Use factory methods in documentation examples
tobixen Jan 7, 2026
f56c2ad
Refactor DAVClient to use sync path directly with protocol layer
tobixen Jan 7, 2026
3ec3c14
Remove async delegation from sync API (Option A)
tobixen Jan 7, 2026
db677bd
Add search-cache delay handling to async integration tests
tobixen Jan 8, 2026
3065a4f
Fix async integration tests for Baikal and other servers
tobixen Jan 8, 2026
547d07f
Exclude localhost URLs from link checker
tobixen Jan 8, 2026
f9a9d1d
Fix SOGo test server password configuration
tobixen Jan 8, 2026
75ae937
Fix missing Content-Type header in async MKCALENDAR/MKCOL/PROPPATCH
tobixen Jan 8, 2026
d99ed74
Fix Cyrus and Bedework Docker test server credentials
tobixen Jan 8, 2026
ee147d8
Add auth negotiation to sync DAVClient request method
tobixen Jan 9, 2026
deb86a9
Fix auth handling in sync DAVClient
tobixen Jan 9, 2026
7d0111b
Remove orphaned Sans-I/O files that were never integrated
tobixen Jan 14, 2026
f1de468
Fix Nextcloud Docker test server tmpfs permissions
tobixen Jan 14, 2026
bef240b
Fix auth negotiation to check for None credentials properly
tobixen Jan 15, 2026
edffbd9
Update Sans-I/O design documentation
tobixen Jan 15, 2026
b13e3a1
Extract shared auth utilities to reduce client duplication
tobixen Jan 15, 2026
ef74b22
Consolidate response handling in BaseDAVResponse
tobixen Jan 15, 2026
aefc6d9
Update implementation plan: Phase 2-3 complete
tobixen Jan 15, 2026
f08acf0
Add testing_allowed flag for test server configuration
tobixen Jan 15, 2026
c5ccb3e
Fix test server config to support both config file and built-in servers
tobixen Jan 15, 2026
f762e0f
Add operations layer foundation (Sans-I/O Phase 1)
tobixen Jan 15, 2026
0cad090
Add DAVObject operations (Sans-I/O Phase 2)
tobixen Jan 15, 2026
f6116a3
Add CalendarObjectResource operations (Sans-I/O Phase 3)
tobixen Jan 15, 2026
0097635
Add Principal operations (Sans-I/O Phase 4)
tobixen Jan 15, 2026
b0f1126
Add CalendarSet operations (Sans-I/O Phase 5)
tobixen Jan 15, 2026
f586a07
Add Calendar operations (Sans-I/O Phase 6)
tobixen Jan 15, 2026
804cdfa
Replace niquests with httpx in async_davclient
tobixen Jan 16, 2026
3d03d4c
Apply pre-commit formatting fixes
tobixen Jan 16, 2026
f883943
Support both httpx (preferred) and niquests for async HTTP
tobixen Jan 16, 2026
016a229
next step of the sans-io implementation plan
tobixen Jan 16, 2026
8b5a6f3
Refactor CalDAVSearcher to use operations layer (Sans-I/O Phase 7)
tobixen Jan 16, 2026
be407ad
Add high-level methods to DAVClient and AsyncDAVClient (Sans-I/O Phas…
tobixen Jan 16, 2026
2e39177
Add dual-mode domain objects and delete async files (Sans-I/O Phase 9)
tobixen Jan 16, 2026
206211d
Fix Nextcloud container permission race condition
tobixen Jan 16, 2026
e2c024b
Add comprehensive async support to domain objects
tobixen Jan 16, 2026
64846ba
Consolidate shared client logic into BaseDAVClient
tobixen Jan 16, 2026
06a74bc
Simplify get_davclient wrappers with thin delegation
tobixen Jan 16, 2026
61ba080
Fix async race condition in events() and todos() methods
tobixen Jan 17, 2026
af58622
Add shared test fixture helpers for async/sync consistency
tobixen Jan 17, 2026
4503320
Fix multiple issues in sync/async clients and Nextcloud setup
tobixen Jan 17, 2026
203c5d9
Move _make_absolute_url helper to BaseDAVClient
tobixen Jan 17, 2026
4827b84
AI policy brushup
tobixen Jan 17, 2026
f918bb0
Fix Nextcloud container config directory permissions on tmpfs
tobixen Jan 17, 2026
8105f8a
Fix Nextcloud password in legacy test conf.py
tobixen Jan 17, 2026
64de680
Fix search method patch leaking from async to sync tests
tobixen Jan 17, 2026
aa639fa
Add pytest-asyncio to test dependencies
tobixen Jan 17, 2026
1cd8ab4
Reduce test warnings by fixing internal deprecation and adding filters
tobixen Jan 17, 2026
6bc13fa
Fix Python 3.9 compatibility in search.py
tobixen Jan 17, 2026
e16952c
Fix code formatting (pre-commit auto-fixes)
tobixen Jan 17, 2026
2b934bc
Fix HTTP/2 when h2 package is not installed
tobixen Jan 18, 2026
9fbfc59
Fix Nextcloud password in GitHub workflow
tobixen Jan 18, 2026
a546381
Don't send Depth header for calendar-multiget REPORT
tobixen Jan 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .github/workflows/linkcheck.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: Link check

on: [push, pull_request]

jobs:
linkcheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check links with Lychee
uses: lycheeverse/lychee-action@v2
with:
fail: true
args: >-
--timeout 10
--max-retries 2
'**/*.md'
'**/*.rst'
38 changes: 37 additions & 1 deletion .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ jobs:
docker exec ${{ job.services.nextcloud.id }} php occ app:disable password_policy || true

# Create test user
docker exec -e OC_PASS="TestPassword123!" ${{ job.services.nextcloud.id }} php occ user:add --password-from-env --display-name="Test User" testuser || echo "User may already exist"
docker exec -e OC_PASS="testpass" ${{ job.services.nextcloud.id }} php occ user:add --password-from-env --display-name="Test User" testuser || echo "User may already exist"

# Enable calendar and contacts apps
docker exec ${{ job.services.nextcloud.id }} php occ app:enable calendar || true
Expand Down Expand Up @@ -313,3 +313,39 @@ jobs:
key: pre-commit|${{ hashFiles('.pre-commit-config.yaml') }}
- run: pip install tox
- run: tox -e style
deptry:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.13"
- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: pip|${{ hashFiles('setup.py') }}|${{ hashFiles('tox.ini') }}
- run: pip install tox
- run: tox -e deptry
async-niquests:
# Test that async code works with niquests when httpx is not installed
name: async (niquests fallback)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install dependencies without httpx
run: |
pip install --editable .[test]
pip uninstall -y httpx
- name: Verify niquests is used
run: |
python -c "
from caldav.async_davclient import _USE_HTTPX, _USE_NIQUESTS
assert not _USE_HTTPX, 'httpx should not be available'
assert _USE_NIQUESTS, 'niquests should be used'
print('✓ Using niquests for async HTTP')
"
- name: Run async tests with niquests
run: pytest tests/test_async_davclient.py -v
20 changes: 20 additions & 0 deletions .lycheeignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Example domains that don't resolve
https?://your\.server\.example\.com/.*
https?://.*\.example\.com/.*

# Localhost URLs for test servers (not accessible in CI)
http://localhost:\d+/.*

# CalDAV endpoints that require authentication (401/403 expected)
https://caldav\.fastmail\.com/.*
https://caldav\.gmx\.net/.*
https://caldav\.icloud\.com/.*
https://p\d+-caldav\.icloud\.com/.*
https://posteo\.de:\d+/.*
https://purelymail\.com/.*
https://webmail\.all-inkl\.com/.*
https://www\.google\.com/calendar/dav/.*
https://caldav-jp\.larksuite\.com/.*

# Apple namespace URL (returns 404 but is a valid XML namespace reference)
http://apple\.com/ns/ical/
6 changes: 6 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,9 @@ repos:
- id: check-byte-order-marker
- id: trailing-whitespace
- id: end-of-file-fixer
- repo: https://github.com/lycheeverse/lychee
rev: lychee-v0.22.0
hooks:
- id: lychee-docker
args: ["--no-progress", "--timeout", "10"]
types: [markdown, rst]
9 changes: 4 additions & 5 deletions AI_POLICY.md → AI-POLICY.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,10 @@ experiences is that the AI performs best when being "supervised" and
<noreply@anthropic.com>` when it's doing commits, that's also OK.

* **YOU** should be ready to follow up and respond to feedback and
questions on the contribution. If all you do is to relay it to the
AI and relaying the AI output back to the pull request, then
you're not adding value to the project and you're not transparent
and honest. You should at least do a quick QA on the AI-answer and
acknowledge that it was generated by the AI.
questions on the contribution. If you're letting the AI do this for
you, then you're neither honest nor adding value to the project.
You should at least do a quick QA on the AI-answer and acknowledge
that it was generated by the AI.

* The Contributors Guidelines aren't strongly enforced on this project
as of 2025-12, and I can hardly see cases where the AI would break
Expand Down
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ Changelogs prior to v1.2 is pruned, but available in the v1.2 release

This project should adhere to [Semantic Versioning](https://semver.org/spec/v2.0.0.html), though some earlier releases may be incompatible with the SemVer standard.

## [Unreleased]

### Added

* Added deptry for dependency verification in CI
* Added python-dateutil and PyYAML as explicit dependencies (were transitive)

## [2.2.3] - [2025-12-06]

### Fixed
Expand Down Expand Up @@ -440,7 +447,7 @@ Since the roadmap was made, the maintainer has spent 39 hours working on the Cal
* Search method has some logic handling non-conformant servers (loading data from the server if the search response didn't include the icalendar data, ignoring trash from the Google server when it returns data without a VTODO/VEVENT/VJOURNAL component), but it was inside an if-statement and applied only if Expanded-flag was set to True. Moved the logic out of the if, so it always applies.
* Revisited a problem that Google sometimes delivers junk when doing searches - credits to github user @zhwei in https://github.com/python-caldav/caldav/pull/366
* There were some compatibility-logic loading objects if the server does not deliver icalendar data (as it's suppsoed to do according to the RFC), but only if passing the `expand`-flag to the `search`-method. Fixed that it loads regardless of weather `expand` is set or not. Also in https://github.com/python-caldav/caldav/pull/366
* Tests - lots of work getting as much test code as possible to pass on different servers, and now testing also for Python 3.12 - ref https://github.com/python-caldav/caldav/pull/368 https://github.com/python-caldav/caldav/issues/360 https://github.com/python-caldav/caldav/pull/447 https://github.com/python-caldav/caldav/pull/369 https://github.com/python-caldav/caldav/pull/370 https://github.com/python-caldav/caldav/pull/441 https://github.com/python-caldav/caldav/pull/443a
* Tests - lots of work getting as much test code as possible to pass on different servers, and now testing also for Python 3.12 - ref https://github.com/python-caldav/caldav/pull/368 https://github.com/python-caldav/caldav/issues/360 https://github.com/python-caldav/caldav/pull/447 https://github.com/python-caldav/caldav/pull/369 https://github.com/python-caldav/caldav/pull/370 https://github.com/python-caldav/caldav/pull/441 https://github.com/python-caldav/caldav/pull/443
* The vcal fixup method was converting implicit dates into timestamps in the COMPLETED property, as it should be a timestamp according to the RFC - however, the regexp failed on explicit dates. Now it will take explicit dates too. https://github.com/python-caldav/caldav/pull/387
* Code cleanups and modernizing the code - https://github.com/python-caldav/caldav/pull/404 https://github.com/python-caldav/caldav/pull/405 https://github.com/python-caldav/caldav/pull/406 https://github.com/python-caldav/caldav/pull/407 https://github.com/python-caldav/caldav/pull/408 https://github.com/python-caldav/caldav/pull/409 https://github.com/python-caldav/caldav/pull/412 https://github.com/python-caldav/caldav/pull/414 https://github.com/python-caldav/caldav/pull/415 https://github.com/python-caldav/caldav/pull/418 https://github.com/python-caldav/caldav/pull/419 https://github.com/python-caldav/caldav/pull/417 https://github.com/python-caldav/caldav/pull/421 https://github.com/python-caldav/caldav/pull/423 https://github.com/python-caldav/caldav/pull/430 https://github.com/python-caldav/caldav/pull/431 https://github.com/python-caldav/caldav/pull/440 https://github.com/python-caldav/caldav/pull/365
* Doc - improved examples, https://github.com/python-caldav/caldav/pull/427
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Contributions are mostly welcome. If the length of this text scares you, then I

## Usage of AI and other tools

A separate [AI POLICY](AI_POLICY.md) has been made. The gist of it, be transparent and inform if your contribution was a result of clever tool usage and/or AI-usage, don't submit code if you don't understand the code yourself, and you are supposed to contribute value to the project. If you're too lazy to read the AI Policy, then at least have a chat with the AI to work out if your contribution is within the policy or not.
A separate [AI POLICY](AI-POLICY.md) has been made. The gist of it, be transparent and inform if your contribution was a result of clever tool usage and/or AI-usage, don't submit code if you don't understand the code yourself, and you are supposed to contribute value to the project. If you're too lazy to read the AI Policy, then at least have a chat with the AI to work out if your contribution is within the policy or not.

## GitHub

Expand Down
33 changes: 32 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,40 @@ Features:
* create, modify calendar
* create, update and delete event
* search events by dates
* async support via `caldav.aio` module
* etc.

The documentation was freshed up a bit as of version 2.0, and is available at https://caldav.readthedocs.io/
## Quick Start

```python
from caldav import get_davclient

with get_davclient() as client:
principal = client.principal()
calendars = principal.calendars()
for cal in calendars:
print(f"Calendar: {cal.name}")
```

## Async API

For async/await support, use the `caldav.aio` module:

```python
import asyncio
from caldav import aio

async def main():
async with aio.get_async_davclient() as client:
principal = await client.principal()
calendars = await principal.calendars()
for cal in calendars:
print(f"Calendar: {cal.name}")

asyncio.run(main())
```

The documentation was updated as of version 2.0, and is available at https://caldav.readthedocs.io/

The package is published at [Pypi](https://pypi.org/project/caldav)

Expand Down
4 changes: 2 additions & 2 deletions caldav/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
warnings.warn(
"You need to install the `build` package and do a `python -m build` to get caldav.__version__ set correctly"
)
from .davclient import DAVClient
from .davclient import DAVClient, get_davclient
from .search import CalDAVSearcher

## TODO: this should go away in some future version of the library.
Expand All @@ -29,4 +29,4 @@ def emit(self, record) -> None:

log.addHandler(NullHandler())

__all__ = ["__version__", "DAVClient"]
__all__ = ["__version__", "DAVClient", "get_davclient"]
95 changes: 95 additions & 0 deletions caldav/aio.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#!/usr/bin/env python
"""
Async-first CalDAV API.

This module provides async versions of the CalDAV client and objects.
Use this for new async code:

from caldav import aio

async with aio.AsyncDAVClient(url=..., username=..., password=...) as client:
principal = await client.get_principal()
calendars = await principal.calendars()
for cal in calendars:
events = await cal.events()

For backward-compatible sync code, continue using:

from caldav import DAVClient

Note: As of the Sans-I/O refactoring (Phase 9), the domain objects (Calendar,
Principal, Event, etc.) are now dual-mode - they work with both sync and async
clients. When used with AsyncDAVClient, methods like calendars(), events(), etc.
return coroutines that must be awaited.

The Async* aliases are kept for backward compatibility but now point to the
unified dual-mode classes.
"""
# Import the async client (this is truly async)
from caldav.async_davclient import AsyncDAVClient
from caldav.async_davclient import AsyncDAVResponse
from caldav.async_davclient import get_davclient as get_async_davclient
from caldav.calendarobjectresource import CalendarObjectResource
from caldav.calendarobjectresource import Event
from caldav.calendarobjectresource import FreeBusy
from caldav.calendarobjectresource import Journal
from caldav.calendarobjectresource import Todo
from caldav.collection import Calendar
from caldav.collection import CalendarSet
from caldav.collection import Principal
from caldav.collection import ScheduleInbox
from caldav.collection import ScheduleMailbox
from caldav.collection import ScheduleOutbox
from caldav.davobject import DAVObject

# Import unified dual-mode domain classes

# Create aliases for backward compatibility with code using Async* names
AsyncDAVObject = DAVObject
AsyncCalendarObjectResource = CalendarObjectResource
AsyncEvent = Event
AsyncTodo = Todo
AsyncJournal = Journal
AsyncFreeBusy = FreeBusy
AsyncCalendar = Calendar
AsyncCalendarSet = CalendarSet
AsyncPrincipal = Principal
AsyncScheduleMailbox = ScheduleMailbox
AsyncScheduleInbox = ScheduleInbox
AsyncScheduleOutbox = ScheduleOutbox

__all__ = [
# Client
"AsyncDAVClient",
"AsyncDAVResponse",
"get_async_davclient",
# Base objects (unified dual-mode)
"DAVObject",
"CalendarObjectResource",
# Calendar object types (unified dual-mode)
"Event",
"Todo",
"Journal",
"FreeBusy",
# Collections (unified dual-mode)
"Calendar",
"CalendarSet",
"Principal",
# Scheduling (RFC6638)
"ScheduleMailbox",
"ScheduleInbox",
"ScheduleOutbox",
# Legacy aliases for backward compatibility
"AsyncDAVObject",
"AsyncCalendarObjectResource",
"AsyncEvent",
"AsyncTodo",
"AsyncJournal",
"AsyncFreeBusy",
"AsyncCalendar",
"AsyncCalendarSet",
"AsyncPrincipal",
"AsyncScheduleMailbox",
"AsyncScheduleInbox",
"AsyncScheduleOutbox",
]
Loading
Loading