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
57 changes: 53 additions & 4 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -335,28 +335,77 @@ jobs:
- run: pip install tox
- run: tox -e deptry
async-niquests:
# Test that async code works with niquests when httpx is not installed
# Test that async code works with niquests when httpx/httpxyz are 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
- name: Install dependencies without httpx/httpxyz
run: |
pip install --editable .[test]
pip uninstall -y httpx
pip uninstall -y httpx httpxyz
- 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 not _USE_HTTPX, 'httpx/httpxyz 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
async-httpxyz:
# Test that async code works with httpxyz when niquests is not installed
name: async (httpxyz fallback)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install dependencies with httpxyz, without niquests
run: |
pip install --editable .[test]
pip uninstall -y niquests
pip install httpxyz
- name: Verify httpxyz is used
run: |
python -c "
from caldav.async_davclient import _USE_HTTPX, _USE_HTTPXYZ, _USE_NIQUESTS
assert not _USE_NIQUESTS, 'niquests should not be available'
assert _USE_HTTPXYZ, 'httpxyz should be used'
assert _USE_HTTPX, '_USE_HTTPX should be set when httpxyz is used'
print('✓ Using httpxyz for async HTTP')
"
- name: Run async tests with httpxyz
run: pytest tests/test_async_davclient.py -v
async-httpx:
# Test that async code works with plain httpx when niquests and httpxyz are not installed
name: async (httpx fallback)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install dependencies with httpx only
run: |
pip install --editable .[test]
pip uninstall -y niquests httpxyz
- name: Verify httpx is used
run: |
python -c "
from caldav.async_davclient import _USE_HTTPX, _USE_HTTPXYZ, _USE_NIQUESTS
assert not _USE_NIQUESTS, 'niquests should not be available'
assert not _USE_HTTPXYZ, 'httpxyz should not be available'
assert _USE_HTTPX, 'httpx should be used'
print('✓ Using httpx for async HTTP')
"
- name: Run async tests with httpx
run: pytest tests/test_async_davclient.py -v
sync-requests:
# Test that sync code works with requests when niquests is not installed
name: sync (requests fallback)
Expand Down
38 changes: 32 additions & 6 deletions caldav/async_davclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@
from caldav.calendarobjectresource import CalendarObjectResource
from caldav.collection import Calendar, Principal

# Try niquests first (preferred), fall back to httpx
# Try niquests first (preferred), then httpxyz, then httpx
_USE_HTTPX = False
_USE_HTTPXYZ = False
_USE_NIQUESTS = False
_H2_AVAILABLE = False

Expand All @@ -34,10 +35,10 @@

if not _USE_NIQUESTS:
try:
import httpx
import httpxyz as httpx

_USE_HTTPXYZ = True
_USE_HTTPX = True
# Check if h2 is available for HTTP/2 support
try:
import h2 # noqa: F401

Expand All @@ -46,6 +47,31 @@
pass

class _HttpxBearerAuth(httpx.Auth):
"""httpx/httpxyz-compatible bearer token auth."""

def __init__(self, password: str) -> None:
self.password = password

def auth_flow(self, request):
request.headers["Authorization"] = f"Bearer {self.password}"
yield request

except ImportError:
pass

if not _USE_NIQUESTS and not _USE_HTTPXYZ:
try:
import httpx

_USE_HTTPX = True
try:
import h2 # noqa: F401

_H2_AVAILABLE = True
except ImportError:
pass

class _HttpxBearerAuth(httpx.Auth): # type: ignore[no-redef]
"""httpx-compatible bearer token auth."""

def __init__(self, password: str) -> None:
Expand All @@ -60,8 +86,8 @@ def auth_flow(self, request):

if not _USE_HTTPX and not _USE_NIQUESTS:
raise ImportError(
"Either httpx or niquests library is required for async_davclient. "
"Install with: pip install httpx (or: pip install niquests)"
"An async HTTP library is required for async_davclient. "
"Install with: pip install niquests (or: pip install httpxyz or: pip install httpx)"
)


Expand Down Expand Up @@ -105,7 +131,7 @@ def __init__(
proxy: str | None = None,
username: str | None = None,
password: str | None = None,
auth: Any | None = None, # httpx.Auth or niquests.auth.AuthBase
auth: Any | None = None, # httpx.Auth, httpxyz.Auth, or niquests.auth.AuthBase
auth_type: str | None = None,
timeout: int | None = None,
ssl_verify_cert: bool | str = True,
Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ test = [
"radicale",
"pyfakefs",
"httpx",
"httpxyz",
#"caldav_server_tester"
"deptry>=0.24.0; python_version >= '3.10'",
]
Expand All @@ -101,7 +102,7 @@ namespaces = false
ignore = ["DEP002"] # Test dependencies (pytest, coverage, etc.) are not imported in main code

[tool.deptry.per_rule_ignores]
DEP001 = ["conf", "h2"] # conf: Local test config, h2: Optional HTTP/2 support
DEP001 = ["conf", "h2", "httpxyz"] # conf: Local test config, h2: Optional HTTP/2 support, httpxyz: Optional async HTTP client
DEP003 = ["aiohttp"] # aiohttp: optional dep used only in caldav/testing.py (XandikosServer)

[tool.ruff]
Expand Down
Loading