diff --git a/nextcloud_mcp_server/client/calendar.py b/nextcloud_mcp_server/client/calendar.py index d462bf2..610fb7b 100644 --- a/nextcloud_mcp_server/client/calendar.py +++ b/nextcloud_mcp_server/client/calendar.py @@ -1,14 +1,15 @@ """CalDAV client for Nextcloud calendar and task operations using caldav library.""" import datetime as dt +import inspect import logging import uuid from typing import Any, Dict, List, Optional import anyio -from caldav.async_collection import AsyncCalendar, AsyncEvent -from caldav.async_davclient import AsyncDAVClient +from caldav.aio import AsyncCalendar, AsyncDAVClient, AsyncEvent from caldav.elements import cdav, dav +from caldav.lib import error as caldav_error from httpx import Auth from icalendar import Alarm, Calendar, vDDDTypes, vRecur from icalendar import Event as ICalEvent @@ -20,6 +21,18 @@ from ..config import get_nextcloud_ssl_verify logger = logging.getLogger(__name__) +async def _maybe_await(result: Any) -> Any: + """Await a result if it's a coroutine, otherwise return it directly. + + caldav v3 uses dual-mode methods that return coroutines for async clients + but plain objects when the result is already available (e.g. load() on + already-loaded objects). + """ + if inspect.isawaitable(result): + return await result + return result + + class CalendarClient: """Client for Nextcloud CalDAV calendar and task operations.""" @@ -50,9 +63,29 @@ class CalendarClient: """Get an AsyncCalendar object for the given calendar name.""" calendar_url = self._get_calendar_url(calendar_name) return AsyncCalendar( - client=self._dav_client, url=calendar_url, name=calendar_name + client=self._dav_client, # type: ignore[arg-type] # AsyncDAVClient is valid for async mode + url=calendar_url, + name=calendar_name, ) + async def _async_object_by_uid( + self, calendar: AsyncCalendar, uid: str, comp_filter: Any = None + ) -> Any: + """Async version of Calendar.get_object_by_uid. + + Upstream caldav v3's get_object_by_uid is not async-aware: it calls + search() which returns a coroutine for async clients, then tries to + iterate the coroutine synchronously. This method properly awaits the + search result. + """ + items_found = await calendar.search( # type: ignore[misc] # dual-mode: returns coroutine for async clients + uid=uid, xml=comp_filter, post_filter=True, _hacks="insist" + ) + items_found = [o for o in items_found if o.id == uid] + if not items_found: + raise caldav_error.NotFoundError(f"{uid} not found on server") + return items_found[0] + async def close(self): """Close the DAV client connection.""" await self._dav_client.close() @@ -117,7 +150,9 @@ class CalendarClient: """ response = await self._dav_client.propfind( - self._calendar_home_url, props=propfind_body, depth=1 + self._calendar_home_url, + props=propfind_body, # type: ignore[arg-type] # props accepts XML body string + depth=1, ) result = [] @@ -267,12 +302,12 @@ class CalendarClient: expanded = bool(start_datetime and end_datetime) else: # No date filter — fetch all events - events = await calendar.events() + events = await calendar.events() # type: ignore[misc] # dual-mode expanded = False result = [] for event in events: - await event.load(only_if_unloaded=True) + await _maybe_await(event.load(only_if_unloaded=True)) if event.data: if expanded: # Server-side expansion: each response resource may contain @@ -326,7 +361,7 @@ class CalendarClient: query.xmlelement(), encoding="utf-8", xml_declaration=True ) assert calendar.client is not None - response = await calendar.client.report(str(calendar.url), body, depth=1) + response = await calendar.client.report(str(calendar.url), body, depth=1) # type: ignore[misc] # dual-mode # Parse response (same pattern as AsyncCalendar.search) objects = [] @@ -336,7 +371,12 @@ class CalendarClient: continue cal_data = props.get(cdav.CalendarData.tag) if cal_data: - obj = AsyncEvent(client=calendar.client, data=cal_data, parent=calendar) + obj = AsyncEvent( + client=calendar.client, + url=calendar.url.join(href), # type: ignore[union-attr] # url is always set for calendars + data=cal_data, + parent=calendar, + ) objects.append(obj) return objects @@ -350,13 +390,7 @@ class CalendarClient: event_uid = str(uuid.uuid4()) ical_content = self._create_ical_event(event_data, event_uid) - # save_event returns (event, response) tuple - event, response = await calendar.save_event(ical=ical_content) - - if response.status not in [201, 204]: - raise RuntimeError( - f"Failed to create event {event_uid}: HTTP {response.status}" - ) + event = await calendar.save_event(ical=ical_content) # type: ignore[misc] # dual-mode logger.debug(f"Created event {event_uid}") @@ -378,14 +412,16 @@ class CalendarClient: calendar = self._get_calendar(calendar_name) # Find the event by UID using caldav library - event = await calendar.event_by_uid(event_uid) - await event.load(only_if_unloaded=True) + event = await self._async_object_by_uid( + calendar, event_uid, cdav.CompFilter("VEVENT") + ) + await _maybe_await(event.load(only_if_unloaded=True)) # Merge updates into existing iCal data updated_ical = self._merge_ical_properties(event.data, event_data, event_uid) # type: ignore[arg-type] event.data = updated_ical # type: ignore[misc] - await event.save() + await _maybe_await(event.save()) logger.debug(f"Updated event {event_uid}") return { @@ -400,8 +436,10 @@ class CalendarClient: calendar = self._get_calendar(calendar_name) try: - event = await calendar.event_by_uid(event_uid) - await event.delete() + event = await self._async_object_by_uid( + calendar, event_uid, cdav.CompFilter("VEVENT") + ) + await _maybe_await(event.delete()) logger.debug(f"Deleted event {event_uid}") return {"status_code": 204} except Exception as e: @@ -414,8 +452,10 @@ class CalendarClient: """Get detailed information about a specific event.""" calendar = self._get_calendar(calendar_name) - event = await calendar.event_by_uid(event_uid) - await event.load(only_if_unloaded=True) + event = await self._async_object_by_uid( + calendar, event_uid, cdav.CompFilter("VEVENT") + ) + await _maybe_await(event.load(only_if_unloaded=True)) event_data = self._parse_ical_event(event.data) if event.data else None # type: ignore[arg-type] if not event_data: @@ -476,14 +516,14 @@ class CalendarClient: """List todos/tasks in a calendar.""" calendar = self._get_calendar(calendar_name) - # Get all todos using caldav library (now with proper filter) - todos = await calendar.todos() + # Get all todos including completed ones (filtering is done client-side) + todos = await calendar.todos(include_completed=True) # type: ignore[misc] # dual-mode result = [] for todo in todos: # Only load if data not already present from REPORT response # This avoids 404 errors for virtual calendars (e.g., Deck boards) - await todo.load(only_if_unloaded=True) + await _maybe_await(todo.load(only_if_unloaded=True)) if todo.data: todo_dict = self._parse_ical_todo(todo.data) # type: ignore[arg-type] else: @@ -508,13 +548,7 @@ class CalendarClient: todo_uid = str(uuid.uuid4()) ical_content = self._create_ical_todo(todo_data, todo_uid) - # save_todo returns (todo, response) tuple - todo, response = await calendar.save_todo(ical=ical_content) - - if response.status not in [201, 204]: - raise RuntimeError( - f"Failed to create todo {todo_uid}: HTTP {response.status}" - ) + todo = await calendar.save_todo(ical=ical_content) # type: ignore[misc] # dual-mode logger.debug(f"Created todo {todo_uid}") @@ -537,8 +571,10 @@ class CalendarClient: try: # Find the todo by UID - todo = await calendar.todo_by_uid(todo_uid) - await todo.load(only_if_unloaded=True) + todo = await self._async_object_by_uid( + calendar, todo_uid, cdav.CompFilter("VTODO") + ) + await _maybe_await(todo.load(only_if_unloaded=True)) logger.debug( f"Loaded todo {todo_uid}, current data length: {len(todo.data)}" # type: ignore @@ -555,8 +591,7 @@ class CalendarClient: todo.data = updated_ical - save_result = await todo.save() - logger.debug(f"Save result: {save_result}") + await _maybe_await(todo.save()) logger.debug(f"Updated todo {todo_uid}") return { @@ -574,8 +609,10 @@ class CalendarClient: calendar = self._get_calendar(calendar_name) try: - todo = await calendar.todo_by_uid(todo_uid) - await todo.delete() + todo = await self._async_object_by_uid( + calendar, todo_uid, cdav.CompFilter("VTODO") + ) + await _maybe_await(todo.delete()) logger.debug(f"Deleted todo {todo_uid}") return {"status_code": 204} except Exception as e: diff --git a/pyproject.toml b/pyproject.toml index a74dd07..d0073ce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,7 @@ dependencies = [ "pythonvcard4>=0.2.0", "pydantic>=2.11.4", "click>=8.1.8", - "caldav", + "caldav>=3.0.1,<4.0", "pyjwt[crypto]>=2.8.0", "aiosqlite>=0.20.0", # Async SQLite for refresh token storage "alembic>=1.14.0", # Database migrations @@ -114,7 +114,6 @@ extend-select = ["I", "PLC0415"] "tests/**" = ["PLC0415"] [tool.uv.sources] -caldav = { git = "https://github.com/cbcoutinho/caldav", branch = "feature/httpx" } qdrant-client = { git = "https://github.com/cbcoutinho/qdrant-client", branch = "fix/fusion-score-threshold" } [build-system] diff --git a/tests/client/calendar/test_calendar_operations.py b/tests/client/calendar/test_calendar_operations.py index 9e780ae..0ebd033 100644 --- a/tests/client/calendar/test_calendar_operations.py +++ b/tests/client/calendar/test_calendar_operations.py @@ -639,11 +639,10 @@ async def test_calendar_operations_error_handling( # Test with non-existent calendar fake_calendar = f"nonexistent_calendar_{uuid.uuid4().hex}" - # caldav library returns empty list for non-existent calendars, doesn't raise - # Testing that it doesn't crash and returns empty results - events = await nc_client.calendar.get_calendar_events(fake_calendar) - assert isinstance(events, list) - # Empty list is expected for non-existent calendar - assert len(events) == 0 + # caldav v3 raises NotFoundError for non-existent calendars + from caldav.lib.error import NotFoundError + + with pytest.raises(NotFoundError): + await nc_client.calendar.get_calendar_events(fake_calendar) logger.info("Error handling tests completed successfully") diff --git a/tests/client/calendar/test_field_preservation.py b/tests/client/calendar/test_field_preservation.py index 0c2e0b1..4102208 100644 --- a/tests/client/calendar/test_field_preservation.py +++ b/tests/client/calendar/test_field_preservation.py @@ -10,6 +10,8 @@ from datetime import datetime, timedelta import pytest +from nextcloud_mcp_server.client.calendar import _maybe_await + logger = logging.getLogger(__name__) @@ -34,8 +36,8 @@ async def test_calendar_event_custom_fields_preservation(nc_client): try: # Get the calendar object from the caldav library calendar = nc_client.calendar._get_calendar(calendar_name) - event = await calendar.event_by_uid(event_uid) - await event.load() + event = await nc_client.calendar._async_object_by_uid(calendar, event_uid) + await _maybe_await(event.load()) # Now manually inject custom iCal properties into the raw data # This simulates what would happen if the event was created by another CalDAV client @@ -306,8 +308,8 @@ async def test_calendar_event_roundtrip_data_loss_demonstration(nc_client): try: # Get the calendar object and event calendar = nc_client.calendar._get_calendar(calendar_name) - event = await calendar.event_by_uid(event_uid) - await event.load() + event = await nc_client.calendar._async_object_by_uid(calendar, event_uid) + await _maybe_await(event.load()) # Inject additional iCal properties that are valid but not supported by our parser extended_ical = f"""BEGIN:VCALENDAR @@ -348,7 +350,6 @@ END:VCALENDAR""" # Confirm extended properties exist extended_properties = [ - "SEQUENCE:1", "X-MICROSOFT-CDO-ALLDAYEVENT:FALSE", "X-CUSTOM-MEETING-ID:12345-67890", "X-ZOOM-MEETING-URL:https://zoom.us/j/1234567890", @@ -371,9 +372,14 @@ END:VCALENDAR""" } for prop in extended_properties: - assert prop in original_ical, ( - f"Extended property {prop} not found in original iCal" - ) + if prop in flexible_patterns: + assert any(alt in original_ical for alt in flexible_patterns[prop]), ( + f"Extended property {prop} (or alternatives) not found in original iCal" + ) + else: + assert prop in original_ical, ( + f"Extended property {prop} not found in original iCal" + ) logger.info("✓ All extended properties confirmed in original iCal") diff --git a/tests/server/test_calendar_todos_mcp.py b/tests/server/test_calendar_todos_mcp.py index 8041990..1087fd2 100644 --- a/tests/server/test_calendar_todos_mcp.py +++ b/tests/server/test_calendar_todos_mcp.py @@ -2,6 +2,7 @@ import json import logging +import uuid from datetime import datetime, timedelta import pytest @@ -467,3 +468,80 @@ async def test_mcp_todo_categories( await nc_client.calendar.delete_todo(calendar_name, todo_uid) except Exception: pass + + +async def test_mcp_todo_href_mismatch( + nc_mcp_client: ClientSession, nc_client: NextcloudClient, temporary_calendar: str +): + """Test that todos with filename != UID are handled correctly (issue #629). + + When a CalDAV object is stored with a filename different from its VTODO UID, + the server returns an href based on the filename. list_todos must return the + correct server-assigned href, and delete_todo must actually remove the todo. + """ + calendar_name = temporary_calendar + todo_uid = str(uuid.uuid4()) + different_filename = str(uuid.uuid4()) + + # Build iCal content with a UID that differs from the filename + ical_content = ( + "BEGIN:VCALENDAR\r\n" + "VERSION:2.0\r\n" + "PRODID:-//Test//Test//EN\r\n" + "BEGIN:VTODO\r\n" + f"UID:{todo_uid}\r\n" + "SUMMARY:Href Mismatch Test\r\n" + "STATUS:NEEDS-ACTION\r\n" + "END:VTODO\r\n" + "END:VCALENDAR\r\n" + ) + + try: + # PUT the todo with a filename that differs from the UID + calendar = nc_client.calendar._get_calendar(calendar_name) + put_url = f"{calendar.url}{different_filename}.ics" + await calendar.client.put( + put_url, + ical_content, + {"Content-Type": "text/calendar; charset=utf-8"}, + ) + + # list_todos via MCP should return href containing the filename, not the UID + list_result = await nc_mcp_client.call_tool( + "nc_calendar_list_todos", + {"calendar_name": calendar_name}, + ) + assert list_result.isError is False + + list_data = json.loads(list_result.content[0].text) + our_todo = next((t for t in list_data["todos"] if t["uid"] == todo_uid), None) + assert our_todo is not None, f"Todo {todo_uid} not found in list_todos" + assert different_filename in our_todo["href"], ( + f"Expected href to contain filename '{different_filename}', " + f"got '{our_todo['href']}'" + ) + assert todo_uid not in our_todo["href"], ( + f"href should NOT contain the UID '{todo_uid}', got '{our_todo['href']}'" + ) + + # delete_todo via MCP should actually remove the todo + delete_result = await nc_mcp_client.call_tool( + "nc_calendar_delete_todo", + {"calendar_name": calendar_name, "todo_uid": todo_uid}, + ) + assert delete_result.isError is False + + # Verify it's really gone + todos = await nc_client.calendar.list_todos(calendar_name) + assert not any(t["uid"] == todo_uid for t in todos), ( + "Todo should have been deleted but still exists" + ) + + logger.info("Todo href mismatch test passed") + + finally: + # Cleanup in case of failure + try: + await nc_client.calendar.delete_todo(calendar_name, todo_uid) + except Exception: + pass diff --git a/uv.lock b/uv.lock index d61abba..7148aaf 100644 --- a/uv.lock +++ b/uv.lock @@ -290,14 +290,22 @@ wheels = [ [[package]] name = "caldav" -version = "2.0.2.dev47+g3e44cf827" -source = { git = "https://github.com/cbcoutinho/caldav?branch=feature%2Fhttpx#3e44cf827e392a0073a16a6b01e299ecef02404b" } +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "httpx", extra = ["http2"] }, + { name = "dnspython" }, { name = "icalendar" }, + { name = "icalendar-searcher" }, { name = "lxml" }, + { name = "niquests" }, + { name = "python-dateutil" }, + { name = "pyyaml" }, { name = "recurring-ical-events" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/56/07/1a0127ba11ad55c449293d8893339f717851b50e1424e9f2228cab9c599d/caldav-3.0.1.tar.gz", hash = "sha256:c1fe3777f958d0dacd47d8beb18b10d1362032a9a74a46d314082bbb980da664", size = 10280185, upload-time = "2026-03-08T17:36:23.836Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/3e/6f0ed0ae7bf86e02cca3db2062d3b17331293c2abc23f79f9428b3003305/caldav-3.0.1-py3-none-any.whl", hash = "sha256:607f93f9ac8ecb29974e705a1a1324328359677a457fd89223c04c9efcdce348", size = 224826, upload-time = "2026-03-08T17:36:16.495Z" }, +] [[package]] name = "certifi" @@ -734,6 +742,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" }, ] +[[package]] +name = "dnspython" +version = "2.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" }, +] + [[package]] name = "docstring-parser" version = "0.17.0" @@ -1178,6 +1195,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/62/ab/e0d44b1de0beb703bbc507ca064300b34046f9f9628f052d1a97ffa61b95/icalendar-7.0.2-py3-none-any.whl", hash = "sha256:ad31a5825b39522a30b073c6ced3ffcdf6c02cbb7dab69ba2e4de32ddbf77cc9", size = 437913, upload-time = "2026-02-24T16:13:40.631Z" }, ] +[[package]] +name = "icalendar-searcher" +version = "1.0.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "icalendar" }, + { name = "recurring-ical-events" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cb/c3/56e751b7ae4f6ca61bf807e207c98e67756fc29134d219196806beb8957d/icalendar_searcher-1.0.5.tar.gz", hash = "sha256:abd99bf1ac9c9d675d84151101db4883a97e9958755708804c55abd30df58f6c", size = 68064, upload-time = "2026-02-25T09:10:17.962Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/b6/7ab1dfb1c5ba3ba394ff5ea285cbeb5db9f71ec5b3b906d01efd235f00d1/icalendar_searcher-1.0.5-py3-none-any.whl", hash = "sha256:66f6f5ece50041ceda5ea91995cd2ed80fa0b065a42b3b3f420f89343614b2a3", size = 37294, upload-time = "2026-02-25T09:10:16.61Z" }, +] + [[package]] name = "idna" version = "3.11" @@ -1254,6 +1284,73 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" }, ] +[[package]] +name = "jh2" +version = "5.0.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/ed/466eb2a162d9cfaa8452e9a05d24b4fc11d4cf84cf27f5a71457dc590323/jh2-5.0.10.tar.gz", hash = "sha256:2c737a47bee50dc727f7a766185e110befdceba5efb1c4fa240b1e4399291487", size = 7301475, upload-time = "2025-10-05T06:18:59.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/88/91e402bd0e323f3c7895d8eb6e79efe7d94bf40e035f6abcd9da0a08325c/jh2-5.0.10-cp313-cp313t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:5a6885a315bdd24d822873d5e581eac90ab25589fb48d34f822352710139439a", size = 603894, upload-time = "2025-10-05T06:16:22.199Z" }, + { url = "https://files.pythonhosted.org/packages/3e/52/cdf454b01bdf7432848f7576b6054826fc65d77062324164995ff77a813d/jh2-5.0.10-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fa031e2aba9bd4cf6e1c0514764781b907557484cf163f02f1ad65a5932faf2", size = 378697, upload-time = "2025-10-05T06:16:24.128Z" }, + { url = "https://files.pythonhosted.org/packages/8e/dd/6e7106bc020e9fc13a70476c95cd4b40d2d301ef1c5ff7cd093adeec2143/jh2-5.0.10-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c816cfe85ae5d4fb26efc2713aedf9dfe1bb826544fe76cfd35ce7a60e099e8f", size = 390293, upload-time = "2025-10-05T06:16:25.723Z" }, + { url = "https://files.pythonhosted.org/packages/88/94/e64d83f8d2f5b7490e32d12f0ba3835b45b19d14af72ea592aacfb65592e/jh2-5.0.10-cp313-cp313t-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:b28c70b440f32bb8f14c3adaa11c094ea109fc1d2540434a8fc6e08cf4cf1aef", size = 524781, upload-time = "2025-10-05T06:16:27.382Z" }, + { url = "https://files.pythonhosted.org/packages/25/72/a2c72aff206bc27f3373982d318f305d31aca62dd5daa0c4e50c528208bb/jh2-5.0.10-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:df79bdf69d33ec0093c63abb633a6cbdb4b905a5ea3dda2514c4adf7e5713d20", size = 518173, upload-time = "2025-10-05T06:16:29.029Z" }, + { url = "https://files.pythonhosted.org/packages/26/27/e41b23fa62a0bbbf87cefdecbd938056a44b9c47a454a11edd760b92a9b3/jh2-5.0.10-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c0b7cda4b50692e2f259382fc2a374cd9118a96f8d369ef04fe088124f84fc", size = 409290, upload-time = "2025-10-05T06:16:30.628Z" }, + { url = "https://files.pythonhosted.org/packages/8d/ed/516bdea8ff60bb321b92bac7d3b99a8aee322495e8b4dccc5b42eeede0b7/jh2-5.0.10-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ffeb6a352ce6c89d77bd185972185f20e3c35b3be4d0253963b6d8b6444c4aa", size = 386155, upload-time = "2025-10-05T06:16:31.898Z" }, + { url = "https://files.pythonhosted.org/packages/12/18/057408a548a66eb069c2fa12bfd13c1e34eaae07603f40ce32743ce0faa6/jh2-5.0.10-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:271720035a1293031c807e24a27235a2426c51de8755db872eb1adad310213cd", size = 403861, upload-time = "2025-10-05T06:16:33.036Z" }, + { url = "https://files.pythonhosted.org/packages/3d/70/73d22e62af0e756cb3b86ee57b67b117efe75091d56ff286bf136adde863/jh2-5.0.10-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:7b28fc12106654573881f19b1a78e41cf37657ae76efa84e7da518faced56f0f", size = 559909, upload-time = "2025-10-05T06:16:34.262Z" }, + { url = "https://files.pythonhosted.org/packages/66/fa/5d5e4304ecfa27773bbe036454b782882fc2ab02f7521ae0d367514c7618/jh2-5.0.10-cp313-cp313t-musllinux_1_1_armv7l.whl", hash = "sha256:976134b61b7fdf290a7cc70e7676c2605af84dd83e2a1e78c170928a0119278b", size = 653300, upload-time = "2025-10-05T06:16:35.825Z" }, + { url = "https://files.pythonhosted.org/packages/dc/b4/31583a8bcbe58ee13b30bdf9d82ca52a3272a13c45384bf8e193a2e4541f/jh2-5.0.10-cp313-cp313t-musllinux_1_1_i686.whl", hash = "sha256:75581b5acbcc344e070f811938919165999bf7221406845306e0ab860605cdbf", size = 580061, upload-time = "2025-10-05T06:16:37.598Z" }, + { url = "https://files.pythonhosted.org/packages/66/3e/ffcc082b72c7f83512cc1dbda866afa5c0dbd76c423e6f0294496744af27/jh2-5.0.10-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:206e4a92c687f6928b3846d7666ebf2602c16556feb154f16f1d399219046f5d", size = 550849, upload-time = "2025-10-05T06:16:38.887Z" }, + { url = "https://files.pythonhosted.org/packages/19/da/01f0df3a779d0d2e8b7ce121da48b1a91346264fd494c0be16a74e5c1c4f/jh2-5.0.10-cp313-cp313t-win32.whl", hash = "sha256:fca31a36827205c76c959be94e8bad7aaa1be06ea8ed904b20b5d96a7829ce45", size = 234414, upload-time = "2025-10-05T06:16:40.509Z" }, + { url = "https://files.pythonhosted.org/packages/82/c1/42a68cbe4c6ee9453d3685bd4ebce8e3bccbda608b3c26f380cf30640825/jh2-5.0.10-cp313-cp313t-win_amd64.whl", hash = "sha256:4bbefb69efaa365f3193d0db096d34e9e0da5885b0bb1341ab7593852e811f69", size = 241768, upload-time = "2025-10-05T06:16:41.701Z" }, + { url = "https://files.pythonhosted.org/packages/10/14/4d89e958e2a98ee09895290a105caee5cd158fb456fc9aae913f15251184/jh2-5.0.10-cp313-cp313t-win_arm64.whl", hash = "sha256:9752ea045ab3da4544104201a800d3f7ce7c63b529db5a9715c587cbfedca9b7", size = 237090, upload-time = "2025-10-05T06:16:43.228Z" }, + { url = "https://files.pythonhosted.org/packages/62/2d/d1d5161adadacd04afb98016c86ca3c429e89ec5e46a93c1f9bd613d9e2e/jh2-5.0.10-cp314-cp314t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e340215fa14b914096aa2e0960798603939f6bc85e9467057121c3aae4eadda1", size = 603721, upload-time = "2025-10-05T06:16:44.48Z" }, + { url = "https://files.pythonhosted.org/packages/77/88/06dd26cfd8e47f8b573af4be09161d0b0b3a26357cb5224da4ceebbb9d11/jh2-5.0.10-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6124124ea77ba77b22cb1f66554eddd61b14a2ce0bb2bc2032d91c3a2b9cbfed", size = 379003, upload-time = "2025-10-05T06:16:46.185Z" }, + { url = "https://files.pythonhosted.org/packages/d6/37/e6abb173b034151eca851ad18908f97cb984bf657c744a4ee72bd4836862/jh2-5.0.10-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:db95f18b629f5dc914cf962725b7dfcb9673c4bb06e50d654426615c3d8d88d2", size = 389806, upload-time = "2025-10-05T06:16:47.759Z" }, + { url = "https://files.pythonhosted.org/packages/bd/aa/158f6ebafac187f80837d024b864e547ffe4a0ffa4df368c6b5d1dd20f49/jh2-5.0.10-cp314-cp314t-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:c16af652777ce4edc0627d037ac5195b921665b2e13e3547782116ce5a62cd5a", size = 528227, upload-time = "2025-10-05T06:16:48.98Z" }, + { url = "https://files.pythonhosted.org/packages/2e/26/4fe6ec57e9e6610443dea281a246b86438f9f6ea090adee4095ce3096f70/jh2-5.0.10-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e0190daf5b65fbf52641ba761d1b895b74abcdb671ca1fb6cd138dd49050cfa8", size = 521170, upload-time = "2025-10-05T06:16:50.274Z" }, + { url = "https://files.pythonhosted.org/packages/d8/87/bbbaf7f146788544c5584142a7a4f5997147d65588ceed4a1ac769b7ab2d/jh2-5.0.10-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:578394d8a9409d540b45138cbecb9d611830ccce6c7f81157c96f2d8d54abd5a", size = 409999, upload-time = "2025-10-05T06:16:51.691Z" }, + { url = "https://files.pythonhosted.org/packages/0d/6f/ff1df3a83daa557e30ce0df48cf789a7faa0521ac56014e38fdd68457e79/jh2-5.0.10-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:108143494bba0b1bf5f8cd205f9c659667235e788d3e3f0f454ad8e52f2c8056", size = 386010, upload-time = "2025-10-05T06:16:53.256Z" }, + { url = "https://files.pythonhosted.org/packages/7a/c7/e3ba47b2cc066b99084278fd77828a2689c59e443cdf8089bd3411deb2e7/jh2-5.0.10-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:85631d5b4d0e1eb9f9daacc43e6394efd8c65eb39c7a7e8458f0c3894108003c", size = 404137, upload-time = "2025-10-05T06:16:54.854Z" }, + { url = "https://files.pythonhosted.org/packages/3a/f8/b7ae14f5d3fc0e7c66b20c94d56fcf191cf588e33d0b653da022a31f32de/jh2-5.0.10-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a9aec4760a6545a654f503d709456c1d8afb63b0ee876a1e11090b75f2fd7488", size = 560449, upload-time = "2025-10-05T06:16:56.278Z" }, + { url = "https://files.pythonhosted.org/packages/5b/6b/abc648a4149582733618e117d42e6b64d5f0885c4311b8108e2c2e667afc/jh2-5.0.10-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:028227ec9e44fb62e073b71ca391cb1f932c5c7da3981ccafff852df81d2b7f9", size = 653077, upload-time = "2025-10-05T06:16:57.903Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ec/8ccf1a7dbdabba5cdc27220507dd839e9bc36bdd4c2bf990334642ad6b8b/jh2-5.0.10-cp314-cp314t-musllinux_1_1_i686.whl", hash = "sha256:2c2ed55a32735b91a0683c7b995433e39325fdf42c6ffc8e87d56606ac6235bb", size = 580386, upload-time = "2025-10-05T06:16:59.322Z" }, + { url = "https://files.pythonhosted.org/packages/0b/57/50eab697d39b2a4d790355e304c79b3c2ab22f7a4889396155a946b8956a/jh2-5.0.10-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:0075415d2a2dfdf3a8ddeaa51cf8d92fb3d7c90fa09cb9752c79ee54e960b9a8", size = 551533, upload-time = "2025-10-05T06:17:00.802Z" }, + { url = "https://files.pythonhosted.org/packages/56/f5/4f73015f4d65f1b3024043a2516062fd3f34846fe88433b3c3a0922ff5fd/jh2-5.0.10-cp314-cp314t-win32.whl", hash = "sha256:a8404e17a3d90c215e67be8a5ccb679eb9cf9bfeeec732521487b65ffaeac4a6", size = 234381, upload-time = "2025-10-05T06:17:02.558Z" }, + { url = "https://files.pythonhosted.org/packages/02/8d/61fcba06faeb9ab7d1ead7e2ef3db07264523f2d2fd463a4d2ec1780103a/jh2-5.0.10-cp314-cp314t-win_amd64.whl", hash = "sha256:5d664450ab1435f6a78c64e076c7ea22ffe779bafceb9c42600cce95ff20f927", size = 241614, upload-time = "2025-10-05T06:17:03.732Z" }, + { url = "https://files.pythonhosted.org/packages/02/67/6641130f5f4f3e9e9254121267b0e7c2423863e8c1a46ee097098e7ede8f/jh2-5.0.10-cp314-cp314t-win_arm64.whl", hash = "sha256:ad6d18301f2162996d679be6759c6a120325b58a196231220b7a809e034280ed", size = 237355, upload-time = "2025-10-05T06:17:04.931Z" }, + { url = "https://files.pythonhosted.org/packages/63/8f/fe337b9104ab3a444a7b20baffc3dd54f3227a44f3037aba2a30bf36fefd/jh2-5.0.10-cp37-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7c2918379cce3352b6d40717ed3d5b06da6e6c17253317302cab2f0dbff62a5d", size = 622842, upload-time = "2025-10-05T06:17:06.121Z" }, + { url = "https://files.pythonhosted.org/packages/63/37/f3c59f62e771755b31b6d1ce9124d4ab40bc3a2206116bfd879a33c1b02f/jh2-5.0.10-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd229bbe7dfdf499394fa8453c92e2ea19de47c80afc1efaec7f85704be97717", size = 385674, upload-time = "2025-10-05T06:17:07.369Z" }, + { url = "https://files.pythonhosted.org/packages/03/9d/719cfd3afab6bb9115f574687fa24ea5731267ee9701439e30e06a45f468/jh2-5.0.10-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:36e9b5fb9cd8872846d031fae442df1b5c83f4dd29ef1dd1c3f70afd86fe8fc3", size = 396276, upload-time = "2025-10-05T06:17:08.933Z" }, + { url = "https://files.pythonhosted.org/packages/22/63/1f36ff610684f2cb177218c700d3a3f4f87aad4d45a6e3f59feb360812c6/jh2-5.0.10-cp37-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:217af8256551627b9253737a866c05ce5f6c49f171c099260b76915239cfb13a", size = 532742, upload-time = "2025-10-05T06:17:10.396Z" }, + { url = "https://files.pythonhosted.org/packages/59/c5/063fe0b930c0b15e8c0376d9d6cc20dcc3179823e6f456c1a571db1d27c4/jh2-5.0.10-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e20e3d747c4022d890865fb25f2e8b3ff6cbacf7556f29155dcfbff592d96202", size = 525320, upload-time = "2025-10-05T06:17:12.187Z" }, + { url = "https://files.pythonhosted.org/packages/e8/7a/c1f4a961554f6b521bfc75320264c0bde50210c11a206719e0c98c17e617/jh2-5.0.10-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6ea77b8b6b7defb67cbec69340e653495b36881671e9f0ac395cdd6b27144000", size = 416184, upload-time = "2025-10-05T06:17:13.428Z" }, + { url = "https://files.pythonhosted.org/packages/37/c9/75fdfd2ef673accba9b1ace28ffa2aaced23fba3209ac73521e441ae2265/jh2-5.0.10-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fd6b5b2d4d38e089ac982ea341b36f2cb827c0765217e6b8f3e58a409290e6f", size = 394145, upload-time = "2025-10-05T06:17:14.673Z" }, + { url = "https://files.pythonhosted.org/packages/52/5e/38b1b14182afcebf89d542b7a2e4cd4d7deaf9e4cae0a45b0a85115f0da7/jh2-5.0.10-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4c3d38121a1ddc2ffc769f09aaaa4c7e67f89e25c578921326b515402176e7cf", size = 411333, upload-time = "2025-10-05T06:17:15.913Z" }, + { url = "https://files.pythonhosted.org/packages/a8/04/10383a467f24d2643013f784bca4ddb81dc9d0d81641a846b71bd0aa64e0/jh2-5.0.10-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:33e4ac058acf8f3f89ea1375deb33ac61713d60fb9e3333bd079f3602425739c", size = 565892, upload-time = "2025-10-05T06:17:17.517Z" }, + { url = "https://files.pythonhosted.org/packages/9d/1a/b416bd65176593b405320bfd763ddc9cae3941fe96c7055ec1c46e081ebd/jh2-5.0.10-cp37-abi3-musllinux_1_1_armv7l.whl", hash = "sha256:86571f18274d7a5a7e6406e156a9f27fa1a72203a176921ea234c4a11fe0e105", size = 659878, upload-time = "2025-10-05T06:17:18.972Z" }, + { url = "https://files.pythonhosted.org/packages/a9/2d/e4c3b90585e92676777e9bcb9218ce97552f0c9797cec142d549904ca67b/jh2-5.0.10-cp37-abi3-musllinux_1_1_i686.whl", hash = "sha256:62f0842b5f8da463b6a548a8c2a7e69fa709888d03c997486390097341e88e09", size = 587129, upload-time = "2025-10-05T06:17:20.669Z" }, + { url = "https://files.pythonhosted.org/packages/98/d5/3e89d65bb6bbcdaa14236e9ec8f643cf77a5809d7315ce1208f0ef53927c/jh2-5.0.10-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f3b6401f089a65b87f2e5beffe81666a1c2ab1d90e8406cd49c756d66881bedc", size = 556811, upload-time = "2025-10-05T06:17:22.37Z" }, + { url = "https://files.pythonhosted.org/packages/7d/8c/a05403065463ef759059d75e0862c94aa60d2019a7dcd41d716f6d8d6c32/jh2-5.0.10-cp37-abi3-win32.whl", hash = "sha256:7b79771bd366a11a36041f49cabc7876047cf1b99cee89df1333e6890f66d973", size = 239474, upload-time = "2025-10-05T06:17:23.637Z" }, + { url = "https://files.pythonhosted.org/packages/96/ac/92f97f07f748bdc9280c5d50e787773bef188c29c32f6804f2fc72cca725/jh2-5.0.10-cp37-abi3-win_amd64.whl", hash = "sha256:9c730e3f40f22bd4ff0ab63ee41d70ee22aa1cc54e5cb295ae0ac3b0a016af3e", size = 246320, upload-time = "2025-10-05T06:17:25.313Z" }, + { url = "https://files.pythonhosted.org/packages/f0/ad/e9f4035ddd847efe26914da64f9d54198bf5b0bdcfd0e8bbcf6a328e1f7c/jh2-5.0.10-cp37-abi3-win_arm64.whl", hash = "sha256:d18eccec757374afca8de31bf012a888fb82903d5803e84f2e6f0b707478ced6", size = 241790, upload-time = "2025-10-05T06:17:26.488Z" }, + { url = "https://files.pythonhosted.org/packages/bf/bf/846ee9a66e6ee6083c7d2f113b8528dd1adc721af1701dc08a11b4617444/jh2-5.0.10-pp311-pypy311_pp73-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7c7fa4c48eeb72d6fd0b4c52982454c6adbb5b9058b391f12597edc3dd9d612e", size = 612502, upload-time = "2025-10-05T06:17:44.827Z" }, + { url = "https://files.pythonhosted.org/packages/37/3c/b16ead7a7229dcdadf64534152d493c2f17124e588f786092898769842aa/jh2-5.0.10-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0f0bac7286af3ba0556c5865322cdbfbbf77f43aa313be721523618d6d82216", size = 379754, upload-time = "2025-10-05T06:17:46.087Z" }, + { url = "https://files.pythonhosted.org/packages/d1/54/c69f1548489be4e293b34b5e4f18cf626d8e42f242c1a58c5c7db8c12b2c/jh2-5.0.10-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9c409cc630faf7c06b8da5391043409a5f7758cdcd5de520999855d2df6d59d7", size = 390892, upload-time = "2025-10-05T06:17:47.766Z" }, + { url = "https://files.pythonhosted.org/packages/29/7a/60a3e9b904cb5c1ec6513fe5162514fe9540dfd50300b7a7a7e689c22fa6/jh2-5.0.10-pp311-pypy311_pp73-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:2e8d3803e2cb2caca82e68eafd16db9d239888cbed7fd79ffa209898cfa89eda", size = 525641, upload-time = "2025-10-05T06:17:49.035Z" }, + { url = "https://files.pythonhosted.org/packages/b0/a1/7008e3779b5b53f745737857a060180cbfde9a5355282407098db979fe39/jh2-5.0.10-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bba536afdab619299f30473de68144714bf8fc82dc452b77333cf66a7ab78c77", size = 519309, upload-time = "2025-10-05T06:17:50.322Z" }, + { url = "https://files.pythonhosted.org/packages/99/65/1fff90e37a7afb9ee98202ed80087b29769cffd82be89fbaebaf5b938847/jh2-5.0.10-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7807ade662d56dcf5d67d92940d97a4d277be90735e085ce4719f0242c1af82b", size = 410302, upload-time = "2025-10-05T06:17:51.689Z" }, + { url = "https://files.pythonhosted.org/packages/5a/8d/8ee75e1ebfcedcb6d6f356e46b20124230d8c47b910690156c6b5226b984/jh2-5.0.10-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d9bf0eb30d40f5a82c816c52c6007b0acd317d418ee8e1d8d32b7d2d5314519", size = 387944, upload-time = "2025-10-05T06:17:52.885Z" }, + { url = "https://files.pythonhosted.org/packages/44/00/ae089c81fb1080b09d6e33f104d99ea53f5b87e78674b85c7940ecfd41f4/jh2-5.0.10-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9bf61215aa09bda4ac20e726f6dce701991fa81f043de7355899efd363444534", size = 406065, upload-time = "2025-10-05T06:17:54.156Z" }, + { url = "https://files.pythonhosted.org/packages/03/0f/290f70104c0d3b39382f408750bf9730f693eb0329e7c395a0fffec3f047/jh2-5.0.10-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4b9d6c16b466f0dce3b9c9bcab743ca1c1e36443d0db450c353652210a89a946", size = 561006, upload-time = "2025-10-05T06:17:55.481Z" }, + { url = "https://files.pythonhosted.org/packages/11/83/94a9984aee39115e261c024e981ee4dc2e1a44c07404dec2c8b98157fbd1/jh2-5.0.10-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:d752f99644c2d34a27863bdb8ac79f39938f83331f2f31d5e9c19bbf58a84ca2", size = 654202, upload-time = "2025-10-05T06:17:56.831Z" }, + { url = "https://files.pythonhosted.org/packages/32/e3/ce45ca7f4a39cfc2a6dcaf154dc2e44b822bd8fcd2b8bbc032e95c5cd46e/jh2-5.0.10-pp311-pypy311_pp73-musllinux_1_1_i686.whl", hash = "sha256:be98c17f5a2a9c0b11393c7c208f47a599664311d18aac135841d1674b15c209", size = 582456, upload-time = "2025-10-05T06:17:58.343Z" }, + { url = "https://files.pythonhosted.org/packages/40/30/f3ed310f02c591b3463d2c11fd8d72b713eb7ef68d4e86c423f354517b9e/jh2-5.0.10-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f082f417c0219a355e209dbfde71a9a57d3c9a6e67bec91a1128cc0e25999e75", size = 552441, upload-time = "2025-10-05T06:18:00.097Z" }, + { url = "https://files.pythonhosted.org/packages/69/10/392bd070cbf08379b267db160d6f2e7609bb1dcd1c0aff5d3aa694fdcded/jh2-5.0.10-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:576037676654def515aab8926da7f2ca069d6356bb55fde1a8f2e6f4c4f291c6", size = 242510, upload-time = "2025-10-05T06:18:01.49Z" }, + { url = "https://files.pythonhosted.org/packages/93/57/d0fcb025736e24cb68c4e250cc4cf63a87b7e0bd7285e188c543018d05c1/jh2-5.0.10-py3-none-any.whl", hash = "sha256:1808c0e5d355c60485bb282b34c6aa3f15069b2634eb44779fb9f3bda0256ac0", size = 98099, upload-time = "2025-10-05T06:18:58.203Z" }, +] + [[package]] name = "jinja2" version = "3.1.6" @@ -2048,7 +2145,7 @@ requires-dist = [ { name = "anthropic", specifier = ">=0.42.0" }, { name = "authlib", specifier = ">=1.6.5" }, { name = "boto3", specifier = ">=1.35.0" }, - { name = "caldav", git = "https://github.com/cbcoutinho/caldav?branch=feature%2Fhttpx" }, + { name = "caldav", specifier = ">=3.0.1,<4.0" }, { name = "click", specifier = ">=8.1.8" }, { name = "fastembed", specifier = ">=0.7.3" }, { name = "httpx", specifier = ">=0.28.1,<0.29.0" }, @@ -2092,6 +2189,20 @@ dev = [ { name = "ty", specifier = ">=0.0.1a25" }, ] +[[package]] +name = "niquests" +version = "3.18.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "charset-normalizer" }, + { name = "urllib3-future" }, + { name = "wassima", marker = "sys_platform != 'emscripten'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e4/a1/5ff5fa24486f14e8b0960b21e6a58d5105c585beba152c7cac695ca48785/niquests-3.18.2.tar.gz", hash = "sha256:12256e7ecaccc498d9cccd9f4116b91abab812bace37966f3f439e92e26195b9", size = 1019871, upload-time = "2026-03-12T06:38:34.463Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/eb/bc4bbd57d76941046619d66453c1ae5910d408f233dc75c54f90630502e9/niquests-3.18.2-py3-none-any.whl", hash = "sha256:930b43cb8633029e7acb4e8ff41607eca3b01a8e30f1806eed6734c74266b42c", size = 207682, upload-time = "2026-03-12T06:38:32.481Z" }, +] + [[package]] name = "numpy" version = "2.3.5" @@ -3370,6 +3481,75 @@ dependencies = [ { name = "urllib3" }, ] +[[package]] +name = "qh3" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/39/1abb9e4b88e86178a2b99b997d737e02c7f50053b7b8fa78cffcb86288fd/qh3-1.6.0-cp313-cp313t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:dcf6b75e0bf05b9f5965c531787d36194bd29be7ee1d731272f6808625072cf8", size = 4488306, upload-time = "2026-03-01T10:06:00.151Z" }, + { url = "https://files.pythonhosted.org/packages/60/47/4e0a4c78b2eb551bf111e2e9fd685d817158260f32522d77ce1ee2c49b4e/qh3-1.6.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e684dc8615807124b52604d352b9a925a86f1a9554327064b488dab283396e76", size = 2219830, upload-time = "2026-03-01T10:06:02.364Z" }, + { url = "https://files.pythonhosted.org/packages/fd/c4/a92d8393ebebd20d824abf204c2991eaedafdb74dd7c7577dd9eff22a03e/qh3-1.6.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ccc2d1f4c53e4c32fa642e21fd1d450ec4b42b4c54cb7844d91532cc00792a5c", size = 1934547, upload-time = "2026-03-01T10:06:04.208Z" }, + { url = "https://files.pythonhosted.org/packages/7f/98/8d654846728454df02028e5e918d0daab2fecbac7964bf324a0929e8c8b2/qh3-1.6.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:acd54d85418f3ba7f55f5dd98715a5d6a7847ffeb6af149e99f48b33d399d409", size = 2059621, upload-time = "2026-03-01T10:06:05.851Z" }, + { url = "https://files.pythonhosted.org/packages/9d/ec/c9eee0b2b8cb35d991bac17ee98d5e56a2cc01499684d376d8ef4cbfd7f0/qh3-1.6.0-cp313-cp313t-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:0741b2b058a1084a2671814f9dbad1a30740f52b3640e1803b277e9a9f215f5f", size = 2049012, upload-time = "2026-03-01T10:06:07.796Z" }, + { url = "https://files.pythonhosted.org/packages/d8/2d/3102c419b2438b996e19c008b2e7ac46b016337ab03e50d9bdd1a530318a/qh3-1.6.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3d52148a1c2a892edbed1a500d3102fcf844b70f4c4ab79bbfbbe9989a22cca7", size = 2041837, upload-time = "2026-03-01T10:06:10.048Z" }, + { url = "https://files.pythonhosted.org/packages/54/41/098f678225d8e114375871c8164be8c8586e557e8f2b25128a8ebbd10c19/qh3-1.6.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7f8a0731c7dcb1ccf39a1e4148da274a75849d3e02bd7f07fa4527af451dd1a6", size = 2116775, upload-time = "2026-03-01T10:06:12.091Z" }, + { url = "https://files.pythonhosted.org/packages/d3/83/494ea4337ae2bd3d66779afe7800ba0a1d8fdc860a6f934624d82793be16/qh3-1.6.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c98deec2fe5ff1247c762bc880fd7c2a146d448a193bb54b3798d8ccc59713f", size = 2405415, upload-time = "2026-03-01T10:06:13.975Z" }, + { url = "https://files.pythonhosted.org/packages/e3/07/2d655c08ff1d8c79e43c14e9cc3dd58c43762edfd3d3a4fa40014a9917d6/qh3-1.6.0-cp313-cp313t-manylinux_2_39_riscv64.whl", hash = "sha256:684c636c8bbd18ca51937b7ec0fcf2ef6a4001b70bfcfece5d0a0451f8e92327", size = 2059786, upload-time = "2026-03-01T10:06:15.905Z" }, + { url = "https://files.pythonhosted.org/packages/4a/eb/b55e700e4a85d8acfd3c3dda061692a03e1d5c32bfb0e2acb757b4a675b5/qh3-1.6.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:8d5875e9e5b4e70eb021038b03ae90dc6c120e1f50641c53d97af84d7cc9d020", size = 2409796, upload-time = "2026-03-01T10:06:17.825Z" }, + { url = "https://files.pythonhosted.org/packages/0f/d8/3323c6a0d5646ebae36de1b0e377961c3fd4769b2516aae5e92fc37bce4c/qh3-1.6.0-cp313-cp313t-musllinux_1_1_armv7l.whl", hash = "sha256:b99e0315f8e056a81775fcc13855a6b7fbe13e5d6cfb8f03b203fbcbab6b8a18", size = 2201368, upload-time = "2026-03-01T10:06:19.475Z" }, + { url = "https://files.pythonhosted.org/packages/a7/2e/8f2e9436546a9bdec218de676ea9033b5400a80f93dd910df0195ec9ae95/qh3-1.6.0-cp313-cp313t-musllinux_1_1_i686.whl", hash = "sha256:4642658d1f206ffe00fbff2eed37c52bcf42e060bb3b236bee68ac6ade60fd35", size = 2254702, upload-time = "2026-03-01T10:06:20.992Z" }, + { url = "https://files.pythonhosted.org/packages/95/45/b64e2c7d6b60c929e48930b531abf372e5d22cc79535c4e3861c0709687c/qh3-1.6.0-cp313-cp313t-musllinux_1_1_riscv64.whl", hash = "sha256:f143a5eefec02bd6fd90a584919b44c3743fe0c0348ac502b842f75ac9c9d4b6", size = 2167507, upload-time = "2026-03-01T10:06:22.951Z" }, + { url = "https://files.pythonhosted.org/packages/0a/54/086ffd9cf5e36a8e4fda4411637b839e99a0017f17b3a4f40adbbb053864/qh3-1.6.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:316326f7996e7c3e1b15f621740680cf99595e24cab08edacb64c28985559148", size = 2629222, upload-time = "2026-03-01T10:06:24.391Z" }, + { url = "https://files.pythonhosted.org/packages/4e/4d/cfec8cdcf553240276ec1edff77e69b68f3b623c7ab2bfae78bee821f9e7/qh3-1.6.0-cp313-cp313t-win32.whl", hash = "sha256:ac510b65274e4dfcf45dc9ec8d46eef666b3a65c9305ac58a0714e6f7b8bcc15", size = 1784819, upload-time = "2026-03-01T10:06:26.361Z" }, + { url = "https://files.pythonhosted.org/packages/f3/e1/96185f638d57aa3a878d0fb6d385f0d350bab88a3bb2424a4e4c8668f5f4/qh3-1.6.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3cfb4cde2d2d9873f0f2f4d04d810b1b436616a4fc4aa1808a8724b2013fbf0d", size = 2040346, upload-time = "2026-03-01T10:06:28.934Z" }, + { url = "https://files.pythonhosted.org/packages/ff/67/d4f7b7afa1976b3a2f4d54e1cc0833ee2f1b3e523e1f6e446f0aad40c70b/qh3-1.6.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9ffd94a8480a5e5d75ca8e373bf6756aa5c4be709685c269edec0b4dc62a5de2", size = 1876487, upload-time = "2026-03-01T10:25:27.853Z" }, + { url = "https://files.pythonhosted.org/packages/01/0a/111697864dc553b70cbd7938abe6cbc8466806699a226cc0029f09f1c8c1/qh3-1.6.0-cp314-cp314t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e2dba2d9a868ce3f7aa50d0c18cbb8f184173acf26bdfecac58903315d6fcf96", size = 4489384, upload-time = "2026-03-01T10:25:30.029Z" }, + { url = "https://files.pythonhosted.org/packages/8d/a6/598ac6704208bbead89ae2d4b79d3cc68981c1ee460fdca066dc43a27bcb/qh3-1.6.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a95810ec18b8cd726c149e3077d94b75d3a184ea61d42da34c183bf89976430", size = 2219974, upload-time = "2026-03-01T10:25:31.418Z" }, + { url = "https://files.pythonhosted.org/packages/6f/64/58b6752ff7fc68ea193d24bc698721c4ae55a62db812c66aee30b602b58f/qh3-1.6.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9f7482b45895cc825b53b1e0fddbee3ac0992f654eab5bc7067c55f6d721af4b", size = 1934782, upload-time = "2026-03-01T10:25:32.874Z" }, + { url = "https://files.pythonhosted.org/packages/4a/1f/4b331cae166eeb88205ce87d129effb4bf867c1630896dbcd318bc1c6513/qh3-1.6.0-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0cb51255b3fe9992c6b15dc4cafbabd49f3487342095acbc6427123a60887ab9", size = 2059995, upload-time = "2026-03-01T10:25:34.511Z" }, + { url = "https://files.pythonhosted.org/packages/9e/d6/010b89b6bfce5b17b6e9c865359518e2be8d6e8c3d343a65a24a97b43f44/qh3-1.6.0-cp314-cp314t-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:fa44697965215f431d1be32cb7e62813d1a2eb1999c16170aee77d0933c9c8ec", size = 2050319, upload-time = "2026-03-01T10:25:39.586Z" }, + { url = "https://files.pythonhosted.org/packages/85/1b/5a2b1d4459c05d99ba7dddce79a2ac06305ceea80936a15191c04b51753a/qh3-1.6.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1dfd2b805f60a337f74a9d4a82d267707c38a483978ce1ba9b9740b8c98318d", size = 2042786, upload-time = "2026-03-01T10:25:37.524Z" }, + { url = "https://files.pythonhosted.org/packages/f2/c6/6fd0fc3f55a3b3011b2693951b72b7fdbe8500851bdc4a6ac8702f77034e/qh3-1.6.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ccae9741133f0ebfc94dd11ddc84406ba7e5df5f7c1b72cfa002fe7a37b2a00", size = 2117011, upload-time = "2026-03-01T10:25:41.442Z" }, + { url = "https://files.pythonhosted.org/packages/60/b2/0a8a9c426d0afdc49c09591a660e287850d4ea31385de46df8080c2b590b/qh3-1.6.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72bdee28ff3d7ede992cfef02dd44a6b01e10bc7743cd2a37721fdae81da709e", size = 2406410, upload-time = "2026-03-01T10:25:43.299Z" }, + { url = "https://files.pythonhosted.org/packages/94/32/102140aceb087877e2a1f46fa10440954d7ab9c772eb700e04712cb9d6a7/qh3-1.6.0-cp314-cp314t-manylinux_2_39_riscv64.whl", hash = "sha256:a45b9e19983bf5834e9b4cf1b337153964c84fdf328b7314282ab5eee5676f99", size = 2060820, upload-time = "2026-03-01T10:25:44.762Z" }, + { url = "https://files.pythonhosted.org/packages/10/da/c47afb4c81a2cd6054b0ce8e3647d3b268044585ce9d1ba8c9ecc452c180/qh3-1.6.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:1f03d466ddf9c0fa1ed5b3f3f908441ab27091153c4ad1471131efa3ca2265ef", size = 2410155, upload-time = "2026-03-01T10:25:46.666Z" }, + { url = "https://files.pythonhosted.org/packages/20/8e/7e5446dc323e9678ea252b017736ab8b1fd884860975a9964d14eef8df23/qh3-1.6.0-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:218687f27b0560335159238b67f639437011d47316b33422366760e8208ab2dd", size = 2201684, upload-time = "2026-03-01T10:25:48.639Z" }, + { url = "https://files.pythonhosted.org/packages/cb/96/1ebfcdc4f3592512054e835488616c1f3fcfc88a85340b0450c5ee6673a7/qh3-1.6.0-cp314-cp314t-musllinux_1_1_i686.whl", hash = "sha256:b23b657a23cc4114d19e4fd06ca02615a327dc2ad986d173e73f5c95ab877ead", size = 2255480, upload-time = "2026-03-01T10:25:50.45Z" }, + { url = "https://files.pythonhosted.org/packages/22/bf/a4399cffb32bc8039945fc0b094f8aa301db6e9c9b2354f14cc7010d3770/qh3-1.6.0-cp314-cp314t-musllinux_1_1_riscv64.whl", hash = "sha256:fbaa8a5801079af724671eaf380bb6d3c4ce17af4f261b6200271c6d4169b149", size = 2167738, upload-time = "2026-03-01T10:25:52.227Z" }, + { url = "https://files.pythonhosted.org/packages/3d/78/47169e2550d423dc6be0815c8af9adb09b7951373f0822a00b33ba32f209/qh3-1.6.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:e6b9f1544830aeca311211b4ce07bd57f87533672dfe1f7ed326d23ee9564a93", size = 2630006, upload-time = "2026-03-01T10:25:53.757Z" }, + { url = "https://files.pythonhosted.org/packages/d1/49/ec489b75ec15d865a599870e875dea4cd85c6c9140deba26bf0e15c64fad/qh3-1.6.0-cp314-cp314t-win32.whl", hash = "sha256:49c0a4e98e2609734999b09a342e9c5620e70ed35bf08e4ffe3941c0d36221ab", size = 1784809, upload-time = "2026-03-01T10:25:55.792Z" }, + { url = "https://files.pythonhosted.org/packages/69/1e/0e8e224d9e7252f054536d6b98197e70d024450bb7dbc4e4e3c09b4d31fc/qh3-1.6.0-cp314-cp314t-win_amd64.whl", hash = "sha256:3bde20472c13a3490e05c56dc76826e097f516bdef4b394171e5f04159965385", size = 2040524, upload-time = "2026-03-01T10:25:57.431Z" }, + { url = "https://files.pythonhosted.org/packages/ee/30/6c9689534eb6b47f1d56c67381f062c090e2fa6a38785b5c3e96e1d95be6/qh3-1.6.0-cp37-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:e3f50196af52f72b648eeee1835d5f8204e69a5992e3b8b894e351c5eddc7bc2", size = 4505677, upload-time = "2026-03-01T10:25:59.472Z" }, + { url = "https://files.pythonhosted.org/packages/c8/d2/25007f01434ce128e833af337ae6c649aa592b0450b4aad5c5fecf6f868d/qh3-1.6.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00c7098ba551043c6037fbb65c0ea6298e8961eb6dace74806ac521388521a83", size = 2227542, upload-time = "2026-03-01T10:26:02.042Z" }, + { url = "https://files.pythonhosted.org/packages/b6/41/77bcaa7198f86bce0f0beda24a4dfa79a98b5376725a98ab8c2592e30ab0/qh3-1.6.0-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d5bf978e4b9a43a1d88170fed969f416b34e54a76e8fee37248ff14d8b39a355", size = 1937610, upload-time = "2026-03-01T10:26:03.5Z" }, + { url = "https://files.pythonhosted.org/packages/46/04/e4aaed0362bef48a15e64870f62e230ce49e39595f1cafc1f8506494bd89/qh3-1.6.0-cp37-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6bf9c089f8a19077b360ba8c2910af140ec05a92b0941e95f1469a8750735842", size = 2065183, upload-time = "2026-03-01T10:26:05.337Z" }, + { url = "https://files.pythonhosted.org/packages/c8/9e/def2840f89cc95274b526e1bc357325377563b1b7d972a2504e643f675fd/qh3-1.6.0-cp37-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:f54347d8711da00af472be98462eb17e923591db5c6f3e1cf498ac9974eccc97", size = 2057158, upload-time = "2026-03-01T10:26:08.48Z" }, + { url = "https://files.pythonhosted.org/packages/9e/7d/8200bdb8276f6adb98eac846b5a7e0b509e25b5ac125d8bd5eaafe15f94b/qh3-1.6.0-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0918a1a8cc9fc9ef9138dfedc56884c904bf623a411da45f49ebd010ef2257d1", size = 2046926, upload-time = "2026-03-01T10:26:06.972Z" }, + { url = "https://files.pythonhosted.org/packages/26/d5/7e251217c523388e9e70a3816c664dcaa81cc8d789be0dce15cb99028e6c/qh3-1.6.0-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f3644c25e125d3dedbfadc9f2f5ac5f09b947091777fa7ec14e1e42455db0c84", size = 2121111, upload-time = "2026-03-01T10:26:10.047Z" }, + { url = "https://files.pythonhosted.org/packages/85/e9/364d72f7b5c33ed7fbd002aadc3d3da14dc32b0262d7069f197dabf942dc/qh3-1.6.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c86f7b66c2effc48b9b5061115562cb4061bf1dcdc86cbf03856b24ac555accd", size = 2412779, upload-time = "2026-03-01T10:26:12.341Z" }, + { url = "https://files.pythonhosted.org/packages/ce/c9/3e58a3d875540b1fe01762aafbcb0ea0e6afd530e27c459ae29a69e7c363/qh3-1.6.0-cp37-abi3-manylinux_2_39_riscv64.whl", hash = "sha256:15a2bd2fe6253978084615645177c8b5b0f92f8f8c2ea0147cc477f9ddd920e2", size = 2066987, upload-time = "2026-03-01T10:26:14.34Z" }, + { url = "https://files.pythonhosted.org/packages/21/d1/28ed9b985cf7b01ca0148c58c21b54d4c140ed5684357f842441e0f0b749/qh3-1.6.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:9ed8bc4e967a016e41e41d2b421fbd9f9466c7fa8c051e857a3e4634c2d5caf0", size = 2413762, upload-time = "2026-03-01T10:26:16.269Z" }, + { url = "https://files.pythonhosted.org/packages/20/79/34559bc78845d9dad60c08074124bf76a2f94df954441b137f6924554cd5/qh3-1.6.0-cp37-abi3-musllinux_1_1_armv7l.whl", hash = "sha256:74040b3b08b695e991e0d2083c1abd0721ab93fea0ab963bfb0b999f8b663d50", size = 2206061, upload-time = "2026-03-01T10:26:17.933Z" }, + { url = "https://files.pythonhosted.org/packages/f8/86/9b9e0dc87045676bc849b7139f4f7c732cbc6b2007833991a06599c25145/qh3-1.6.0-cp37-abi3-musllinux_1_1_i686.whl", hash = "sha256:747a401a5e53c0374121dbf5ccaaab95865534ef25620ed77afb6899f07cd3fa", size = 2259193, upload-time = "2026-03-01T10:26:19.436Z" }, + { url = "https://files.pythonhosted.org/packages/e2/44/4b0dcdfd23de0c35629c09f9500e61b58e2947afae6e214fb71095d20ee8/qh3-1.6.0-cp37-abi3-musllinux_1_1_riscv64.whl", hash = "sha256:d9dc249ef6a08d7b1ef836dca9323916bffde8fad982345a71933264a2797482", size = 2171788, upload-time = "2026-03-01T10:26:21.21Z" }, + { url = "https://files.pythonhosted.org/packages/7d/d4/ad800a588a34e32aecd3f510569f450135f63c77acb7d80877df3e3cbdd1/qh3-1.6.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:2b593bf3728a8aa271540bc6bbff8b2dde406743433e27d418873ea040cf5da7", size = 2634037, upload-time = "2026-03-01T10:26:23.03Z" }, + { url = "https://files.pythonhosted.org/packages/73/9f/d3793aaf6a51b2509c93ca69b9ca9f8532c3856c65f140c3aaf7a63e64f1/qh3-1.6.0-cp37-abi3-win32.whl", hash = "sha256:a18ae99a1346963aa3cf4172c05eb6873395995edcc7ba53bda5aeaa2d4f7023", size = 1791065, upload-time = "2026-03-01T10:26:25.483Z" }, + { url = "https://files.pythonhosted.org/packages/ba/32/9b2acecfacd214f9255fea86806964dd2b24ac9b661c735056106dea2b60/qh3-1.6.0-cp37-abi3-win_amd64.whl", hash = "sha256:b97f9261bd5563af1597d242a1fbbb78e1b442d40b6db363da596fe15f66f572", size = 2049375, upload-time = "2026-03-01T10:26:27.432Z" }, + { url = "https://files.pythonhosted.org/packages/9f/d8/ab1ac4c38d9666a68a57c7aba82a734895327d8c7c7ca702753893748e6f/qh3-1.6.0-pp311-pypy311_pp73-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:cf3d92dd1015d62e208354bf3741486396a0c9f65d46c1486bf4aecaa6f94141", size = 4493730, upload-time = "2026-03-01T10:26:54.65Z" }, + { url = "https://files.pythonhosted.org/packages/4a/dd/f4a8a53c35245abd64e5405ef3f1655defca39be78ad3f82090f10b619b9/qh3-1.6.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:444f9aa989f5f90cb93580b342ee92d9dda186d2df05b3d20caa0c31ba48106c", size = 2220387, upload-time = "2026-03-01T10:26:56.321Z" }, + { url = "https://files.pythonhosted.org/packages/d6/a3/d552b1e32e38ad5473eba8716a6cbf4fd68316170e857a605d6f523b3368/qh3-1.6.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1366500e617e2e6347116e83b503ff15b4d8cc14ec97d0fbbbe1126e89555b98", size = 1933613, upload-time = "2026-03-01T10:26:58.265Z" }, + { url = "https://files.pythonhosted.org/packages/d8/8b/7e06fae17b70dcf0e72f65b3bc94795d1cb93c0764b6d933bae8885a75c0/qh3-1.6.0-pp311-pypy311_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4962f3f3ef9384204e49c5f005f86a58be55e81362287f370264aa31807e9b5a", size = 2061383, upload-time = "2026-03-01T10:27:00.191Z" }, + { url = "https://files.pythonhosted.org/packages/52/74/ed66caf844846d2ff7cf1ce4ce3d796fcd68e6517c236a9b1c5f6402b012/qh3-1.6.0-pp311-pypy311_pp73-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:e6e519f088dbf19451af1565d078c86ea9fc985b08201b6f4d51067e595e6ba9", size = 2052213, upload-time = "2026-03-01T10:27:03.654Z" }, + { url = "https://files.pythonhosted.org/packages/7d/2d/5dc57779bcd3696a53204e9803372c9a760e524f1eda2db3c2a7645b202c/qh3-1.6.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34ceba137415b5be1741976c2b6ea26e84f967f910212ea82d973c1bf920ccbf", size = 2044099, upload-time = "2026-03-01T10:27:01.764Z" }, + { url = "https://files.pythonhosted.org/packages/20/e4/1aba7b37d25f22b721ff45a7a8a3a33c2b910e2efb40dcbd0e6f0b58be18/qh3-1.6.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c9abc8c5bcab0a59a9824b3ccd63ceceff393b9334bdfef624d74781069d3bf0", size = 2115024, upload-time = "2026-03-01T10:27:05.194Z" }, + { url = "https://files.pythonhosted.org/packages/ed/9b/415ae5a96a095ab2264858247a8d29f5bbac79b652594ce1a42d5c5611c1/qh3-1.6.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:375d4892ae86ba8e7beb1ef7e53eb30a94257eabe1fcf8e73388e74035a97f67", size = 2406742, upload-time = "2026-03-01T10:27:07.484Z" }, + { url = "https://files.pythonhosted.org/packages/5e/3c/8d271e08a1850fbd6cac10f397c09a77b8758bedbe751e70f5dd64be5ff4/qh3-1.6.0-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:35084e465cca660e1253a0fd003dd8917d9283dbffad8c9e191e27d86efd1871", size = 2410069, upload-time = "2026-03-01T10:27:09.3Z" }, + { url = "https://files.pythonhosted.org/packages/fa/d8/ae7ed5488cb53aa9924e1b519e4356d2ce54dbc8f94e76e6d886f9ec682c/qh3-1.6.0-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:b4ea681f15dd348b8ad313362fcf6de9ae930367ac1ff416f493e4c997938b8a", size = 2201086, upload-time = "2026-03-01T10:27:10.974Z" }, + { url = "https://files.pythonhosted.org/packages/44/3e/7fd14cf239722242fed7ded1e239f839ec8146d66442541e226d8b091a97/qh3-1.6.0-pp311-pypy311_pp73-musllinux_1_1_i686.whl", hash = "sha256:8297d7e5b582aff82e4d1b1a86e1ab4169014e63ea497447f65d83740651cba9", size = 2255689, upload-time = "2026-03-01T10:27:12.881Z" }, + { url = "https://files.pythonhosted.org/packages/42/54/c68ccd87e37d24e8f888b6ce62f8533c4f6460a856a0319fa7e95a6db985/qh3-1.6.0-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:2c167c45e949fdc13fe8bfcddc2a8ce61d7a979c06663a306c7eeeb1a8cbf024", size = 2629965, upload-time = "2026-03-01T10:27:14.541Z" }, + { url = "https://files.pythonhosted.org/packages/e8/27/60fd31c50b96e637933a6693ec4804e5c5845c0629d83267c3c1378c86b1/qh3-1.6.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:4caff02237e4961ca689d143e49b69a20ce999d1364d4b2f8b33441b8fc01edd", size = 2042968, upload-time = "2026-03-01T10:27:16.596Z" }, +] + [[package]] name = "questionary" version = "2.1.1" @@ -3971,6 +4151,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/56/1a/9ffe814d317c5224166b23e7c47f606d6e473712a2fad0f704ea9b99f246/urllib3-2.6.0-py3-none-any.whl", hash = "sha256:c90f7a39f716c572c4e3e58509581ebd83f9b59cced005b7db7ad2d22b0db99f", size = 131083, upload-time = "2025-12-05T15:08:45.983Z" }, ] +[[package]] +name = "urllib3-future" +version = "2.17.901" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "h11" }, + { name = "jh2" }, + { name = "qh3", marker = "(python_full_version < '3.12' and platform_machine == 'AMD64' and platform_python_implementation == 'PyPy' and sys_platform == 'darwin') or (python_full_version < '3.12' and platform_machine == 'ARM64' and platform_python_implementation == 'PyPy' and sys_platform == 'darwin') or (python_full_version < '3.12' and platform_machine == 'aarch64' and platform_python_implementation == 'PyPy' and sys_platform == 'darwin') or (python_full_version < '3.12' and platform_machine == 'arm64' and platform_python_implementation == 'PyPy' and sys_platform == 'darwin') or (python_full_version < '3.12' and platform_machine == 'armv7l' and platform_python_implementation == 'PyPy' and sys_platform == 'darwin') or (python_full_version < '3.12' and platform_machine == 'i686' and platform_python_implementation == 'PyPy' and sys_platform == 'darwin') or (python_full_version < '3.12' and platform_machine == 'ppc64' and platform_python_implementation == 'PyPy' and sys_platform == 'darwin') or (python_full_version < '3.12' and platform_machine == 'ppc64le' and platform_python_implementation == 'PyPy' and sys_platform == 'darwin') or (python_full_version < '3.12' and platform_machine == 'riscv64' and platform_python_implementation == 'PyPy' and sys_platform == 'darwin') or (python_full_version < '3.12' and platform_machine == 'riscv64gc' and platform_python_implementation == 'PyPy' and sys_platform == 'darwin') or (python_full_version < '3.12' and platform_machine == 's390x' and platform_python_implementation == 'PyPy' and sys_platform == 'darwin') or (python_full_version < '3.12' and platform_machine == 'x86' and platform_python_implementation == 'PyPy' and sys_platform == 'darwin') or (python_full_version < '3.12' and platform_machine == 'x86_64' and platform_python_implementation == 'PyPy' and sys_platform == 'darwin') or (python_full_version < '3.12' and platform_machine == 'AMD64' and platform_python_implementation == 'PyPy' and sys_platform == 'linux') or (python_full_version < '3.12' and platform_machine == 'ARM64' and platform_python_implementation == 'PyPy' and sys_platform == 'linux') or (python_full_version < '3.12' and platform_machine == 'aarch64' and platform_python_implementation == 'PyPy' and sys_platform == 'linux') or (python_full_version < '3.12' and platform_machine == 'arm64' and platform_python_implementation == 'PyPy' and sys_platform == 'linux') or (python_full_version < '3.12' and platform_machine == 'armv7l' and platform_python_implementation == 'PyPy' and sys_platform == 'linux') or (python_full_version < '3.12' and platform_machine == 'i686' and platform_python_implementation == 'PyPy' and sys_platform == 'linux') or (python_full_version < '3.12' and platform_machine == 'ppc64' and platform_python_implementation == 'PyPy' and sys_platform == 'linux') or (python_full_version < '3.12' and platform_machine == 'ppc64le' and platform_python_implementation == 'PyPy' and sys_platform == 'linux') or (python_full_version < '3.12' and platform_machine == 'riscv64' and platform_python_implementation == 'PyPy' and sys_platform == 'linux') or (python_full_version < '3.12' and platform_machine == 'riscv64gc' and platform_python_implementation == 'PyPy' and sys_platform == 'linux') or (python_full_version < '3.12' and platform_machine == 's390x' and platform_python_implementation == 'PyPy' and sys_platform == 'linux') or (python_full_version < '3.12' and platform_machine == 'x86' and platform_python_implementation == 'PyPy' and sys_platform == 'linux') or (python_full_version < '3.12' and platform_machine == 'x86_64' and platform_python_implementation == 'PyPy' and sys_platform == 'linux') or (python_full_version < '3.12' and platform_machine == 'AMD64' and platform_python_implementation == 'PyPy' and sys_platform == 'win32') or (python_full_version < '3.12' and platform_machine == 'ARM64' and platform_python_implementation == 'PyPy' and sys_platform == 'win32') or (python_full_version < '3.12' and platform_machine == 'aarch64' and platform_python_implementation == 'PyPy' and sys_platform == 'win32') or (python_full_version < '3.12' and platform_machine == 'arm64' and platform_python_implementation == 'PyPy' and sys_platform == 'win32') or (python_full_version < '3.12' and platform_machine == 'armv7l' and platform_python_implementation == 'PyPy' and sys_platform == 'win32') or (python_full_version < '3.12' and platform_machine == 'i686' and platform_python_implementation == 'PyPy' and sys_platform == 'win32') or (python_full_version < '3.12' and platform_machine == 'ppc64' and platform_python_implementation == 'PyPy' and sys_platform == 'win32') or (python_full_version < '3.12' and platform_machine == 'ppc64le' and platform_python_implementation == 'PyPy' and sys_platform == 'win32') or (python_full_version < '3.12' and platform_machine == 'riscv64' and platform_python_implementation == 'PyPy' and sys_platform == 'win32') or (python_full_version < '3.12' and platform_machine == 'riscv64gc' and platform_python_implementation == 'PyPy' and sys_platform == 'win32') or (python_full_version < '3.12' and platform_machine == 's390x' and platform_python_implementation == 'PyPy' and sys_platform == 'win32') or (python_full_version < '3.12' and platform_machine == 'x86' and platform_python_implementation == 'PyPy' and sys_platform == 'win32') or (python_full_version < '3.12' and platform_machine == 'x86_64' and platform_python_implementation == 'PyPy' and sys_platform == 'win32') or (platform_machine == 'AMD64' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'ARM64' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'arm64' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'armv7l' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'i686' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'ppc64' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'ppc64le' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'riscv64' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'riscv64gc' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 's390x' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'x86' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'AMD64' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'ARM64' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'aarch64' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'arm64' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'armv7l' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'i686' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'ppc64' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'ppc64le' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'riscv64' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'riscv64gc' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 's390x' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'x86' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'x86_64' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'AMD64' and platform_python_implementation == 'CPython' and sys_platform == 'win32') or (platform_machine == 'ARM64' and platform_python_implementation == 'CPython' and sys_platform == 'win32') or (platform_machine == 'aarch64' and platform_python_implementation == 'CPython' and sys_platform == 'win32') or (platform_machine == 'arm64' and platform_python_implementation == 'CPython' and sys_platform == 'win32') or (platform_machine == 'armv7l' and platform_python_implementation == 'CPython' and sys_platform == 'win32') or (platform_machine == 'i686' and platform_python_implementation == 'CPython' and sys_platform == 'win32') or (platform_machine == 'ppc64' and platform_python_implementation == 'CPython' and sys_platform == 'win32') or (platform_machine == 'ppc64le' and platform_python_implementation == 'CPython' and sys_platform == 'win32') or (platform_machine == 'riscv64' and platform_python_implementation == 'CPython' and sys_platform == 'win32') or (platform_machine == 'riscv64gc' and platform_python_implementation == 'CPython' and sys_platform == 'win32') or (platform_machine == 's390x' and platform_python_implementation == 'CPython' and sys_platform == 'win32') or (platform_machine == 'x86' and platform_python_implementation == 'CPython' and sys_platform == 'win32') or (platform_machine == 'x86_64' and platform_python_implementation == 'CPython' and sys_platform == 'win32')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b5/ae/08e5a46f96b80da73605b9df7ae37724f45fb03847e9de394de04fdf1a1d/urllib3_future-2.17.901.tar.gz", hash = "sha256:763dd2459c4c9f274ae9ba0cae3166204ccc1cad38fc08dc22a125e15d85f72f", size = 1138515, upload-time = "2026-03-11T05:56:34.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/5d/f164a7de2790f048d74c42bc3561e4cfa09b41e4ae7d64e419f30cd5aa68/urllib3_future-2.17.901-py3-none-any.whl", hash = "sha256:4e31ee8a68ac553732de0b9cfeda36ef8c1f2207f00fef13534b1ba5413ff59b", size = 707251, upload-time = "2026-03-11T05:56:31.705Z" }, +] + [[package]] name = "uuid-utils" version = "0.12.0" @@ -4013,6 +4207,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ee/d9/d88e73ca598f4f6ff671fb5fde8a32925c2e08a637303a1d12883c7305fa/uvicorn-0.38.0-py3-none-any.whl", hash = "sha256:48c0afd214ceb59340075b4a052ea1ee91c16fbc2a9b1469cca0e54566977b02", size = 68109, upload-time = "2025-10-18T13:46:42.958Z" }, ] +[[package]] +name = "wassima" +version = "2.0.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/e6/4f9413cd115fe724fcc0ea83db1d43fdeb8dff59ea5d55e7788a946b0afd/wassima-2.0.5.tar.gz", hash = "sha256:91a0da50799d9b4ef7a85f23a37c9aabe629f75c2dd9616ee4abc1f4c17d10a7", size = 143472, upload-time = "2026-02-07T16:52:34.484Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e3/d9/e81c8de18b3edd22e1884ed6b8cfc2ce260addb110fd519781ea54274e38/wassima-2.0.5-py3-none-any.whl", hash = "sha256:e60b567b26b87c83ff310a191d9c584113f13c0bcea0564f92e7630b17da319b", size = 138778, upload-time = "2026-02-07T16:52:32.844Z" }, +] + [[package]] name = "wcwidth" version = "0.2.14"