feat(jmap): add caldav/jmap — JMAP calendar and task client#625
Open
SashankBhamidi wants to merge 32 commits intomasterfrom
Open
feat(jmap): add caldav/jmap — JMAP calendar and task client#625SashankBhamidi wants to merge 32 commits intomasterfrom
SashankBhamidi wants to merge 32 commits intomasterfrom
Conversation
Introduces caldav/jmap/ as a purely additive package providing JMAP calendar support alongside the existing CalDAV client. No existing files are modified.
…nd parse_event_set to 6-tuple
tobixen
reviewed
Feb 20, 2026
caldav/jmap/convert/jscal_to_ical.py
Outdated
|
|
||
| if time_zone: | ||
| try: | ||
| import pytz # type: ignore[import] |
Collaborator
Author
There was a problem hiding this comment.
Yeah, I was thinking to replace it to use zoneinfo instead
Collaborator
Author
There was a problem hiding this comment.
The semantics are identical
SashankBhamidi
commented
Feb 20, 2026
SashankBhamidi
commented
Feb 20, 2026
SashankBhamidi
commented
Feb 20, 2026
Apply suggestions from code review
Apply suggestions from code review
Collaborator
Author
|
@tobixen Is this better now? I’ll pull it tomorrow and work on CI errors. I committed the changes as suggestions for now. |
SashankBhamidi
commented
Feb 20, 2026
SashankBhamidi
commented
Feb 20, 2026
docs(jmap): JMAP usage documentation and autodoc stubs
…tion label; fix async docs wording
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.
Adds
caldav/jmap/, a new module providing JMAP calendar and task support alongside the existing CalDAV client. Zero modifications to any existing file.The module follows the same layered sans-I/O design as the CalDAV side: pure method builders/parsers in
methods/, dataclasses inobjects/, bidirectional iCalendar ↔ JSCalendar conversion inconvert/, HTTP + session logic inclient.pyandasync_client.py.Usage documentation in
docs/source/jmap.rstcovers auth, event CRUD, search, incremental sync, tasks, async API, and error handling.Session bootstrap (
session.py): GET/.well-known/jmap, resolve relativeapiUrlviaurljoin(Cyrus returns a relative path), select account viaprimaryAccounts[CALENDAR_CAPABILITY]with a fallback scan of all accounts. RaisesJMAPCapabilityErrorif no calendar-capable account is found.Auth (
client.py): Basic whenusernameis supplied, Bearer when onlypasswordis given, or a pre-built auth object via theauthkwarg. No 401-challenge-retry — a 401/403 from session or API endpoint raisesJMAPAuthErrorimmediately.JMAPErrorextendsDAVErrorso existing CalDAV exception handlers catch JMAP errors too.Calendar operations on both
JMAPClientandAsyncJMAPClient:get_calendars,create_event,get_event,update_event,delete_event,search_events,get_sync_token,get_objects_by_sync_token.search_eventsuses a single batched request —CalendarEvent/query+ a result reference intoCalendarEvent/get— one HTTP round-trip regardless of result size.get_objects_by_sync_tokenraisesJMAPMethodError(error_type="serverPartialFail")when the server truncates the change list (hasMoreChanges: true).Task operations (RFC 9553):
get_task_lists,create_task,get_task,update_task,delete_task. Task methods send_TASK_USING = [CORE_CAPABILITY, TASK_CAPABILITY]; servers withouturn:ietf:params:jmap:tasksreturn an error methodResponse which_requestconverts toJMAPMethodError. Cyrus does not implement RFC 9553, so task integration tests are deferred.AsyncJMAPClient(async_client.py) mirrors every method as a coroutine. Each request opens its ownniquests.AsyncSession— no long-lived connection is held.iCalendar ↔ JSCalendar conversion (
convert/): full bidirectional mapping covering DTSTART (all-day, floating, UTC, IANA-tz, non-IANA TZID passthrough), DTEND/DURATION, RRULE, EXRULE, EXDATE, RECURRENCE-ID overrides, ORGANIZER/ATTENDEE with roles and participation status, VALARM (relative and absolute triggers), CATEGORIES, LOCATION, CLASS, TRANSP, SEQUENCE, PRIORITY, COLOR. Shared duration/datetime primitives (_timedelta_to_duration,_duration_to_timedelta,_format_local_dt) live only inconvert/_utils.py.Entry points (
__init__.py):get_jmap_client(**kwargs)andget_async_jmap_client(**kwargs)read from the same sources asget_davclient— explicit kwargs, env vars, config file — and returnNonewhen no configuration is found.254 unit tests (zero network, all mocked). 17 integration tests against live Cyrus Docker (6 sync + 6 async event CRUD/search/sync, 5 session/calendar checks); auto-skipped if server unreachable.