Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .readthedocs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@ python:
- method: pip
path: .
extra_requirements:
- doc
- jmap
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,25 @@ Changelogs prior to v3.0 are pruned, but are available in the v3.1 release

This project should adhere to [Semantic Versioning](https://semver.org/spec/v2.0.0.html), though for pre-releases PEP 440 takes precedence.

## [Unreleased]

### Breaking changes

The JMAP support was declared experimental in 3.0, hence the changes below are deemed allowable in a minor release:

* **Breaking:** `caldav.jmap` no longer works on a plain `pip install caldav`. The implementation moved to the standalone [calendaring-jmap](https://pypi.org/project/calendaring-jmap/) package, which is an optional dependency - install `caldav[jmap]` (or `calendaring-jmap`). Importing `caldav.jmap` without it raises an `ImportError` saying so.
* **Breaking:** `caldav[jmap]` brings dependencies caldav itself does not have. calendaring-jmap 1.1.0 requires `icalendar>=7.3.0` (caldav asks only for `icalendar>6.0.0`, so the extra raises the floor), and it requires both `niquests` and `requests` outright - so `requests` is installed even in the environments that deliberately avoid it, see [HTTP Library Configuration](https://caldav.readthedocs.io/stable/http-libraries.html).
* **Breaking:** the JMAP code is licensed differently from the rest of caldav. caldav is `GPL-3.0-or-later OR Apache-2.0`; calendaring-jmap is `AGPL-3.0-or-later`. The import path is unchanged, so this is easy to miss: if you relied on the Apache-2.0 option, note that the JMAP code you get through `caldav[jmap]` carries the AGPL network-copyleft obligation. Nothing changes for users of caldav without the `jmap` extra.

### Changed

* `caldav.lib.http_sync` no longer exports `AsyncSession` or `require_async_session()`. They existed only for the async JMAP client, which has moved out of this library; `caldav.lib.http_libraries.required_library_error()` is kept, but has no caller in caldav today.
* `caldav.jmap` no longer carries its own JMAP client implementation. It's now a thin re-export of calendaring-jmap.
* Old imports still work, including the submodule paths the 3.3 documentation used: `from caldav.jmap import JMAPClient`, `from caldav.jmap.error import JMAPAuthError`, `caldav.jmap.convert.jscal_to_ical` and so on all resolve to calendaring-jmap's own modules.
* Importing `caldav.jmap` now emits a `DeprecationWarning`. Use `from calendaring_jmap import JMAPClient` going forward; the wrapper will be removed in a future release.
* `get_jmap_client()`/`get_async_jmap_client()` still resolve configuration the same way `get_davclient()` does - that is the one thing the wrapper adds over importing calendaring-jmap directly.
* JMAP errors remain catchable as `DAVError`.

## [3.3.1] - 2026-09-16

The two main things in this release:
Expand Down
84 changes: 75 additions & 9 deletions caldav/jmap/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
"""
JMAP calendar support for python-caldav.

.. deprecated::
Thin re-export of the standalone `calendaring-jmap
<https://pypi.org/project/calendaring-jmap/>`_ package. Import from
``calendaring_jmap`` directly instead.

Provides synchronous and asynchronous JMAP clients with the same public API as
the CalDAV client, so user code works regardless of server protocol.

Expand All @@ -27,16 +32,77 @@
calendars = await client.get_calendars()
"""

from caldav.jmap.async_client import AsyncJMAPClient
from caldav.jmap.client import JMAPClient
from caldav.jmap.error import (
JMAPAuthError,
JMAPCapabilityError,
JMAPError,
JMAPMethodError,
import importlib
import sys
import warnings

_SUBMODULES = (
"async_client",
"client",
"constants",
"convert",
"convert.ical_to_jscal",
"convert.jscal_to_ical",
"error",
"objects",
"objects.calendar",
"objects.calendar_object",
"session",
)

try:
from calendaring_jmap import (
AsyncJMAPClient,
JMAPAuthError,
JMAPCalendar,
JMAPCalendarObject,
JMAPCapabilityError,
JMAPClient,
JMAPError,
JMAPMethodError,
)

## calendaring-jmap mirrors the submodule layout caldav.jmap used to have,
## so alias each public submodule into place. Without this, the import
## line the v3.3 documentation spelled out - `from caldav.jmap.error import
## JMAPAuthError` - dies with ModuleNotFoundError instead of going through
## the DeprecationWarning below. sys.modules is what `from X.Y import Z`
## consults; globals() is what makes `caldav.jmap.error` work as an
## attribute, which the import machinery would otherwise have set itself.
for _name in _SUBMODULES:
_module = importlib.import_module(f"calendaring_jmap.{_name}")
sys.modules[f"{__name__}.{_name}"] = _module
if "." not in _name:
globals()[_name] = _module
del _name, _module
except ImportError as e:
## Python removes a half-imported caldav.jmap from sys.modules, but not the
## aliases the loop above may already have registered. Left behind, a
## later `from caldav.jmap.error import ...` would resolve against a
## package that never finished importing. (calendaring-jmap 1.1.0 imports
## all of these eagerly, so the loop cannot currently be the thing that
## fails - this is here for the version that makes one of them lazy.)
for _name in _SUBMODULES:
sys.modules.pop(f"{__name__}.{_name}", None)
## Only the top-level package being absent means "not installed". Anything
## raised from inside calendaring-jmap is a broken install or a version
## mismatch, and saying "install it" sends the reader after something they
## already have.
if e.name != "calendaring_jmap":
raise
raise ImportError(
"caldav.jmap requires the standalone calendaring-jmap package "
"(>=1.1.0), which is not installed. Install it with "
"`pip install caldav[jmap]` or `pip install 'calendaring-jmap>=1.1.0'`."
) from e

warnings.warn(
"caldav.jmap is deprecated; import from the standalone calendaring-jmap "
"package instead (pip install calendaring-jmap). caldav.jmap now just "
"re-exports it and will be removed in a future release.",
DeprecationWarning,
stacklevel=2,
)
from caldav.jmap.objects.calendar import JMAPCalendar
from caldav.jmap.objects.calendar_object import JMAPCalendarObject

_JMAP_KEYS = {"url", "username", "password", "auth", "auth_type", "timeout"}

Expand Down
12 changes: 0 additions & 12 deletions caldav/jmap/_methods/__init__.py

This file was deleted.

68 changes: 0 additions & 68 deletions caldav/jmap/_methods/calendar.py

This file was deleted.

Loading
Loading