Skip to content
Merged
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
1 change: 1 addition & 0 deletions caldav/async_davclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ class AsyncDAVClient(BaseDAVClient):
principal = await client.get_principal()
"""

is_async = True
proxy: str | None = None
url: URL = None
huge_tree: bool = False
Expand Down
2 changes: 2 additions & 0 deletions caldav/base_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ class BaseDAVClient(ABC):
- Common properties (username, password, auth_type, etc.)
"""

is_async = False

# Property lists for PROPFIND requests - shared between sync and async
CALENDAR_HOME_SET_PROPS = ["{urn:ietf:params:xml:ns:caldav}calendar-home-set"]
CALENDAR_LIST_PROPS = [
Expand Down
5 changes: 2 additions & 3 deletions caldav/davobject.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,8 @@ def is_async_client(self) -> bool:
"""
if self.client is None:
return False
from caldav.async_davclient import AsyncDAVClient

return isinstance(self.client, AsyncDAVClient)
# `is True` is deliberate: a Mock attribute must count as False.
return getattr(self.client, "is_async", False) is True

def children(
self, type: str | None = None
Expand Down
1 change: 1 addition & 0 deletions changes/+sync-without-async-library.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The sync client raised `ImportError` on calendar and object operations when no async HTTP library was installed (e.g. a `requests`-only install). https://github.com/python-caldav/caldav/pull/827
32 changes: 32 additions & 0 deletions tests/test_http_libraries.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,3 +313,35 @@ def test_response_resolves(self) -> None:
from caldav.lib.http_sync import Response as SharedResponse

assert Response is SharedResponse


_SYNC_WITHOUT_ASYNC = textwrap.dedent(
"""
import sys

class Blocker:
def find_spec(self, fullname, path=None, target=None):
if fullname.split(".")[0] in {names!r}:
raise ImportError("blocked by the test: " + fullname)
return None

sys.meta_path.insert(0, Blocker())
from caldav import DAVClient
from caldav.collection import Calendar

client = DAVClient(url="http://cal.example.com/")
calendar = Calendar(client=client, url="http://cal.example.com/cal/")
assert calendar.is_async_client is False
"""
)


@pytest.mark.skipif(not importlib.util.find_spec("requests"), reason="requests not installed")
def test_sync_client_works_without_an_async_library() -> None:
"""A requests-only install must not trip over the async client's import."""
result = subprocess.run(
[sys.executable, "-c", _SYNC_WITHOUT_ASYNC.format(names=set(ASYNC_CANDIDATES))],
capture_output=True,
text=True,
)
assert result.returncode == 0, result.stderr or result.stdout
Loading