From 3e0e886050d11d464a9bf8a5aba32ba98f2a8433 Mon Sep 17 00:00:00 2001 From: Anuraag Agrawal Date: Fri, 17 Apr 2026 11:58:43 +0900 Subject: [PATCH 1/4] Reraise non-connect exceptions in ASGI Signed-off-by: Anuraag Agrawal --- src/connectrpc/_server_async.py | 7 ++- test/test_errors.py | 95 ++++++++++++++++++++++++++++++++- 2 files changed, 100 insertions(+), 2 deletions(-) diff --git a/src/connectrpc/_server_async.py b/src/connectrpc/_server_async.py index e9a8b62..c9f2002 100644 --- a/src/connectrpc/_server_async.py +++ b/src/connectrpc/_server_async.py @@ -232,7 +232,10 @@ async def __call__( ctx, ) except Exception as e: - return await self._handle_error(e, ctx, send) + await self._handle_error(e, ctx, send) + if not isinstance(e, ConnectError): + raise + return None # Streams have their own error handling so move out of the try block. return await self._handle_stream( @@ -486,6 +489,8 @@ async def _watch_for_disconnect() -> None: "more_trailers": False, } ) + if error and not isinstance(error, ConnectError): + raise error async def _handle_error( self, exc: Exception, ctx: RequestContext | None, send: ASGISendCallable diff --git a/test/test_errors.py b/test/test_errors.py index cfcc226..70a7ed7 100644 --- a/test/test_errors.py +++ b/test/test_errors.py @@ -3,7 +3,7 @@ import asyncio import threading from http import HTTPStatus -from typing import NoReturn +from typing import TYPE_CHECKING, NoReturn import pytest from pyqwest import ( @@ -32,6 +32,11 @@ ) from .haberdasher_pb2 import Hat, Size +if TYPE_CHECKING: + from collections.abc import AsyncIterator + + from connectrpc.request import RequestContext + _errors = [ (Code.CANCELED, "Operation was cancelled", 499), (Code.UNKNOWN, "An unknown error occurred", 500), @@ -424,3 +429,91 @@ async def make_hat(self, request, ctx) -> NoReturn: assert exc_info.value.code == Code.DEADLINE_EXCEEDED assert exc_info.value.message == "Request timed out" assert recorded_timeout_header == "200" + + +@pytest.mark.asyncio +async def test_async_unhandled_exception_reraised() -> None: + class RaisingHaberdasher(Haberdasher): + async def make_hat(self, request, ctx) -> NoReturn: + raise TypeError("Something went wrong") + + app = HaberdasherASGIApplication(RaisingHaberdasher()) + transport = ASGITransport(app) + http_client = Client(transport) + + async with HaberdasherClient( + "http://localhost", timeout_ms=200, http_client=http_client + ) as client: + with pytest.raises(ConnectError, match="Something went wrong"): + await client.make_hat(request=Size(inches=10)) + + assert isinstance(transport.app_exception, TypeError) + assert str(transport.app_exception) == "Something went wrong" + + +@pytest.mark.asyncio +async def test_async_unhandled_exception_reraised_stream() -> None: + class RaisingHaberdasher(Haberdasher): + def make_similar_hats( + self, request: Size, ctx: RequestContext + ) -> AsyncIterator[Hat]: + raise TypeError("Something went wrong") + + app = HaberdasherASGIApplication(RaisingHaberdasher()) + transport = ASGITransport(app) + http_client = Client(transport) + + async with HaberdasherClient( + "http://localhost", timeout_ms=200, http_client=http_client + ) as client: + with pytest.raises(ConnectError, match="Something went wrong"): + async for _ in client.make_similar_hats(request=Size(inches=10)): + pass + + assert isinstance(transport.app_exception, TypeError) + assert str(transport.app_exception) == "Something went wrong" + + +@pytest.mark.asyncio +async def test_async_connect_exception_not_reraised() -> None: + class RaisingHaberdasher(Haberdasher): + async def make_hat(self, request, ctx) -> NoReturn: + raise ConnectError(Code.INTERNAL, "We're broken") + + app = HaberdasherASGIApplication(RaisingHaberdasher()) + transport = ASGITransport(app) + http_client = Client(transport) + + async with HaberdasherClient( + "http://localhost", timeout_ms=200, http_client=http_client + ) as client: + with pytest.raises(ConnectError, match="We're broken"): + await client.make_hat(request=Size(inches=10)) + + # Workaround https://github.com/curioswitch/pyqwest/pull/148 + # TODO: Remove after fix is released + assert getattr(transport, "_app_exception", None) is None + + +@pytest.mark.asyncio +async def test_async_connect_exception_not_reraised_stream() -> None: + class RaisingHaberdasher(Haberdasher): + def make_similar_hats( + self, request: Size, ctx: RequestContext + ) -> AsyncIterator[Hat]: + raise ConnectError(Code.INTERNAL, "We're broken") + + app = HaberdasherASGIApplication(RaisingHaberdasher()) + transport = ASGITransport(app) + http_client = Client(transport) + + async with HaberdasherClient( + "http://localhost", timeout_ms=200, http_client=http_client + ) as client: + with pytest.raises(ConnectError, match="We're broken"): + async for _ in client.make_similar_hats(request=Size(inches=10)): + pass + + # Workaround https://github.com/curioswitch/pyqwest/pull/148 + # TODO: Remove after fix is released + assert getattr(transport, "_app_exception", None) is None From 485b5d97dbbccc4e16b30232e105fca2451f656a Mon Sep 17 00:00:00 2001 From: Anuraag Agrawal Date: Fri, 17 Apr 2026 12:02:04 +0900 Subject: [PATCH 2/4] Don't reraise for HTTP exception Signed-off-by: Anuraag Agrawal --- src/connectrpc/_server_async.py | 2 +- test/test_errors.py | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/connectrpc/_server_async.py b/src/connectrpc/_server_async.py index c9f2002..46162c9 100644 --- a/src/connectrpc/_server_async.py +++ b/src/connectrpc/_server_async.py @@ -233,7 +233,7 @@ async def __call__( ) except Exception as e: await self._handle_error(e, ctx, send) - if not isinstance(e, ConnectError): + if not isinstance(e, (ConnectError, HTTPException)): raise return None diff --git a/test/test_errors.py b/test/test_errors.py index 70a7ed7..204e4a8 100644 --- a/test/test_errors.py +++ b/test/test_errors.py @@ -19,6 +19,7 @@ ) from pyqwest.testing import ASGITransport, WSGITransport +from connectrpc._protocol import HTTPException from connectrpc.code import Code from connectrpc.errors import ConnectError @@ -517,3 +518,24 @@ def make_similar_hats( # Workaround https://github.com/curioswitch/pyqwest/pull/148 # TODO: Remove after fix is released assert getattr(transport, "_app_exception", None) is None + + +@pytest.mark.asyncio +async def test_async_http_exception_not_reraised() -> None: + class RaisingHaberdasher(Haberdasher): + async def make_hat(self, request, ctx) -> NoReturn: + raise HTTPException(status=HTTPStatus.INTERNAL_SERVER_ERROR, headers=[]) + + app = HaberdasherASGIApplication(RaisingHaberdasher()) + transport = ASGITransport(app) + http_client = Client(transport) + + async with HaberdasherClient( + "http://localhost", timeout_ms=200, http_client=http_client + ) as client: + with pytest.raises(ConnectError, match="Internal Server Error"): + await client.make_hat(request=Size(inches=10)) + + # Workaround https://github.com/curioswitch/pyqwest/pull/148 + # TODO: Remove after fix is released + assert getattr(transport, "_app_exception", None) is None From 373f9f117a6456fcb5591b77b4e6e5addf25e71f Mon Sep 17 00:00:00 2001 From: Anuraag Agrawal Date: Fri, 17 Apr 2026 13:00:38 +0900 Subject: [PATCH 3/4] WSGI Signed-off-by: Anuraag Agrawal --- pyproject.toml | 2 +- src/connectrpc/_server_sync.py | 16 +++++- test/test_errors.py | 58 ++++++++++++++++---- uv.lock | 98 +++++++++++++++------------------- 4 files changed, 107 insertions(+), 67 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 274b671..fc48330 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,7 +28,7 @@ classifiers = [ "Topic :: Software Development :: Libraries :: Python Modules", "Typing :: Typed", ] -dependencies = ["protobuf>=5.28", "pyqwest>=0.4.1"] +dependencies = ["protobuf>=5.28", "pyqwest>=0.5.1"] [project.urls] Documentation = "https://connectrpc.com/docs/python/getting-started/" diff --git a/src/connectrpc/_server_sync.py b/src/connectrpc/_server_sync.py index 83b3896..d3650e2 100644 --- a/src/connectrpc/_server_sync.py +++ b/src/connectrpc/_server_sync.py @@ -2,6 +2,7 @@ import base64 import functools +import traceback from abc import ABC, abstractmethod from dataclasses import replace from http import HTTPStatus @@ -46,9 +47,9 @@ from .compression import Compression if sys.version_info >= (3, 11): - from wsgiref.types import StartResponse, WSGIEnvironment + from wsgiref.types import ErrorStream, StartResponse, WSGIEnvironment else: - from _typeshed.wsgi import StartResponse, WSGIEnvironment + from _typeshed.wsgi import ErrorStream, StartResponse, WSGIEnvironment else: StartResponse = "wsgiref.types.StartResponse" WSGIEnvironment = "wsgiref.types.WSGIEnvironment" @@ -251,6 +252,7 @@ def __call__( except Exception as e: _drain_request_body(environ) + _maybe_log_exception(environ, e) return self._handle_error(e, ctx, start_response) def _handle_unary( @@ -502,6 +504,7 @@ def _handle_stream( # response message will be handled by _response_stream, so here we have a # full error-only response. _drain_request_body(environ) + _maybe_log_exception(environ, e) _send_stream_response_headers( start_response, protocol, codec, resp_compression.name(), ctx ) @@ -668,3 +671,12 @@ def _drain_request_body(environ: WSGIEnvironment) -> None: # server that doesn't do so, so we go ahead and do it ourselves. for _ in _read_body(environ): pass + + +def _maybe_log_exception(environ: WSGIEnvironment, exc: Exception) -> None: + if isinstance(exc, (ConnectError, HTTPException)): + return + errors: ErrorStream = environ["wsgi.errors"] + errors.write( + f"Exception in WSGI application\n{''.join(traceback.format_exception(type(exc), exc, exc.__traceback__))}" + ) diff --git a/test/test_errors.py b/test/test_errors.py index 204e4a8..fb80138 100644 --- a/test/test_errors.py +++ b/test/test_errors.py @@ -491,9 +491,7 @@ async def make_hat(self, request, ctx) -> NoReturn: with pytest.raises(ConnectError, match="We're broken"): await client.make_hat(request=Size(inches=10)) - # Workaround https://github.com/curioswitch/pyqwest/pull/148 - # TODO: Remove after fix is released - assert getattr(transport, "_app_exception", None) is None + assert transport.app_exception is None @pytest.mark.asyncio @@ -515,9 +513,7 @@ def make_similar_hats( async for _ in client.make_similar_hats(request=Size(inches=10)): pass - # Workaround https://github.com/curioswitch/pyqwest/pull/148 - # TODO: Remove after fix is released - assert getattr(transport, "_app_exception", None) is None + assert transport.app_exception is None @pytest.mark.asyncio @@ -536,6 +532,50 @@ async def make_hat(self, request, ctx) -> NoReturn: with pytest.raises(ConnectError, match="Internal Server Error"): await client.make_hat(request=Size(inches=10)) - # Workaround https://github.com/curioswitch/pyqwest/pull/148 - # TODO: Remove after fix is released - assert getattr(transport, "_app_exception", None) is None + assert transport.app_exception is None + + +def test_sync_unhandled_exception_logged() -> None: + class RaisingHaberdasher(HaberdasherSync): + def make_hat(self, request, ctx) -> NoReturn: + raise TypeError("Something went wrong") + + app = HaberdasherWSGIApplication(RaisingHaberdasher()) + transport = WSGITransport(app) + http_client = SyncClient(transport) + + with ( + HaberdasherClientSync( + "http://localhost", timeout_ms=200, http_client=http_client + ) as client, + pytest.raises(ConnectError, match="Something went wrong"), + ): + client.make_hat(request=Size(inches=10)) + + logged_error = transport.error_stream.getvalue() + assert "Exception in WSGI application" in logged_error + assert "TypeError: Something went wrong" in logged_error + assert "Traceback" in logged_error + + +def test_sync_unhandled_exception_logged_stream() -> None: + class RaisingHaberdasher(HaberdasherSync): + def make_similar_hats(self, request, ctx) -> NoReturn: + raise TypeError("Something went wrong") + + app = HaberdasherWSGIApplication(RaisingHaberdasher()) + transport = WSGITransport(app) + http_client = SyncClient(transport) + + with ( + HaberdasherClientSync( + "http://localhost", timeout_ms=200, http_client=http_client + ) as client, + pytest.raises(ConnectError, match="Something went wrong"), + ): + next(client.make_similar_hats(request=Size(inches=10))) + + logged_error = transport.error_stream.getvalue() + assert "Exception in WSGI application" in logged_error + assert "TypeError: Something went wrong" in logged_error + assert "Traceback" in logged_error diff --git a/uv.lock b/uv.lock index c5f627d..03490d5 100644 --- a/uv.lock +++ b/uv.lock @@ -406,7 +406,7 @@ docs = [ [package.metadata] requires-dist = [ { name = "protobuf", specifier = ">=5.28" }, - { name = "pyqwest", specifier = ">=0.4.1" }, + { name = "pyqwest", specifier = ">=0.5.1" }, ] [package.metadata.requires-dev] @@ -683,7 +683,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -1621,61 +1621,49 @@ wheels = [ [[package]] name = "pyqwest" -version = "0.4.1" +version = "0.5.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6e/e3/cf7e1eaa975fff450f3886d6297a3041e37eb424c9a9f6531bab7c9d29b3/pyqwest-0.4.1.tar.gz", hash = "sha256:08ff72951861d2bbdd9e9e98e3ed710c81c47ec66652a5622645c68c71d9f609", size = 440370, upload-time = "2026-03-06T02:32:43.207Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d6/5d/9322e9ae2d7053dd420339c38973176406c1f528cbdbb99a26008e7ea596/pyqwest-0.4.1-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:cf8014048ca9a7c5a2bc6501352e3bdc6883450c1dd5965ae3a488f721c199d4", size = 5059099, upload-time = "2026-04-11T04:20:41.838Z" }, - { url = "https://files.pythonhosted.org/packages/65/59/509526fca743a4cfcb96374e08716aa0edbb97dabd65bfc4b02c54e60fea/pyqwest-0.4.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de88bfe87f4b0b9841999bb804bfc485caee4e4eea2540dd1e4126967addb4e6", size = 5447975, upload-time = "2026-04-11T04:20:43.586Z" }, - { url = "https://files.pythonhosted.org/packages/4a/3e/78dd63075455b2874f40666ea3f065ce437f27b7f90b3368f6849a585049/pyqwest-0.4.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9b0027adb5c8f539cb1141fdf48969f9de34429362b8e52568ff546e982e17d", size = 5492016, upload-time = "2026-04-11T04:20:45.512Z" }, - { url = "https://files.pythonhosted.org/packages/35/03/1ea620b8bc9abdc4f793d0a7b306e76fd2786f072f546494bb9b0108fbd1/pyqwest-0.4.1-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0ebda89631c47c0a46946e809f0a501b4a9ec457401fd4fa11541fa4be4602b5", size = 5610148, upload-time = "2026-04-11T04:20:47.19Z" }, - { url = "https://files.pythonhosted.org/packages/bf/98/56a3085fd5b9f8efe3259c7c463223dbbca9609d49475ecf2094ad5c6d64/pyqwest-0.4.1-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1f6c7349c40748c10d6ec670b577358b9a6438b75106b90a2d3a13591453e627", size = 5790336, upload-time = "2026-04-11T04:20:48.754Z" }, - { url = "https://files.pythonhosted.org/packages/2f/8c/452f80066ca1595f29761b2fbfd4ebcc7782d247fdf07dc970f4b42b8d02/pyqwest-0.4.1-cp310-abi3-win_amd64.whl", hash = "sha256:a8ad6b3b4ed422f71472d37087f000fdb45f5fd2d81c65c8376b1f4aa8eef0b1", size = 4638128, upload-time = "2026-04-11T04:20:51.08Z" }, - { url = "https://files.pythonhosted.org/packages/19/86/cc92251f81a2dbe2b7b5762c351cdff0a445847162fe1d3d4133e2f162cb/pyqwest-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0d99b54779fcfa7bb1486153e848d409f3b3b817a433abe2d8014f25b0a93b64", size = 5008561, upload-time = "2026-03-06T02:31:31.187Z" }, - { url = "https://files.pythonhosted.org/packages/4d/e8/f8ee78c88b99ad48deb442d606a8d26234263ed079dea9b53000fb3c0dfd/pyqwest-0.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18d8db4906b3451b714e8e305e994ac19a0a07f990e8d437d767f9b792b03bbe", size = 5388147, upload-time = "2026-03-06T02:31:33.513Z" }, - { url = "https://files.pythonhosted.org/packages/7d/ac/5dca8b00ef3e5670fc19610fff2fe6aa95168a43540850ca40f6a30f2e52/pyqwest-0.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58f33d7f9a0af5e7e51162ab3fd2a9770cdb8839541601c06230ac792f60c2d4", size = 5432282, upload-time = "2026-03-06T02:31:35.271Z" }, - { url = "https://files.pythonhosted.org/packages/74/68/61cc7a2670e90a809fe15bc31fce952e54750862563ab3bb6f975d97c1ba/pyqwest-0.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:1f8f0a9ec0daf75c45133de1fd9d3117b7b233d984621d7147109be9fd6730b6", size = 5552064, upload-time = "2026-03-06T02:31:36.82Z" }, - { url = "https://files.pythonhosted.org/packages/ca/a0/0ae2f4d539d8603195ef08e46ae451eb25fb70380854069ba53dfb2d8193/pyqwest-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0804091b284dce73ae12984de1845ddd5c95490f24658c62fc86fe35390456f7", size = 5732612, upload-time = "2026-03-06T02:31:38.646Z" }, - { url = "https://files.pythonhosted.org/packages/8e/35/247cab7f4aa75a3b3cf75040ffd4a94d221131f9acf2b36a5a74f8fbeef2/pyqwest-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:f253b6007b879a0aedbd8e5a5d342d6a304185caea9e187f6c16eade28999cba", size = 4608165, upload-time = "2026-03-06T02:31:40.417Z" }, - { url = "https://files.pythonhosted.org/packages/bd/fb/2badaaac4776181675dc624542e7f2c718f14f4f88ca9a07ee9282b4d59d/pyqwest-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7822bfb74a1c899cb1675792efb703fc8296f9aa45bf599bf6c8e01c6988192f", size = 5006840, upload-time = "2026-03-06T02:31:42.232Z" }, - { url = "https://files.pythonhosted.org/packages/69/35/e0f89a0a394fa265be98377ca82bc51c2931cb217d01c9354d5d13e57be5/pyqwest-0.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f09b7850e4851b284bae2bf619bbf80863fe1731814f68a36dbdc94a3424d28", size = 5387337, upload-time = "2026-03-06T02:31:43.757Z" }, - { url = "https://files.pythonhosted.org/packages/c7/f2/915308fd03b4eb3872ffdd53cb99ab5e4a741de26c93191a612fed5ca198/pyqwest-0.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6787809a5511b26e7409ef7f3000b88cf3dabd4541faa18144451fc915182d90", size = 5433037, upload-time = "2026-03-06T02:31:45.612Z" }, - { url = "https://files.pythonhosted.org/packages/57/0c/9e06d49c6857d43124627bd70ff36afb34583d874a341f7f19006458a390/pyqwest-0.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f0d954b8db81f8bd7f441edfa9856a5c8bbc8be9a9ffffef40ece6f8ded11063", size = 5552306, upload-time = "2026-03-06T02:31:47.33Z" }, - { url = "https://files.pythonhosted.org/packages/bd/83/7af431646b54f35311c5e48cbeec3333e65543698bde9ce7fe257f47b8a1/pyqwest-0.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:830eecc1740e3838817a2c425745b31fb9feb7dcf6e9205d960dab1fcf82c3e3", size = 5732490, upload-time = "2026-03-06T02:31:48.955Z" }, - { url = "https://files.pythonhosted.org/packages/4c/02/7d254fbd8b93c2be7653a4a1089efcba2b2f8ffaa839bb1df910dd62d862/pyqwest-0.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:6ebb9542019211e12873d03221b76a3d9d34814e16fee8458dfb4f7fe117f2aa", size = 4607600, upload-time = "2026-03-06T02:31:50.458Z" }, - { url = "https://files.pythonhosted.org/packages/f2/25/70832796e6cce303acdca41de51dee68f9b25a965a42ed1efc8688f498fc/pyqwest-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d5877a9c16277040074eedee2faf2580be5c5bc86879760a38eac81a61ee8313", size = 5009802, upload-time = "2026-03-06T02:31:52.452Z" }, - { url = "https://files.pythonhosted.org/packages/8d/ed/88777c23957b4ca24556843454c4ba8f98b562609f02040a9110b02b9a0c/pyqwest-0.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fec9e91983237478abb88affcaaf0a813232288038b4b4bd68b5a7aa86cf88ea", size = 5374251, upload-time = "2026-03-06T02:31:53.893Z" }, - { url = "https://files.pythonhosted.org/packages/ac/08/c3d67388e974f8bbdaf924f5fbb3130c713a124e061361f84b77fd35cada/pyqwest-0.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43f160c4cc19dd3b5232c06c5009f2d2bb3afbe0d3053497f088ed1e3d901285", size = 5418540, upload-time = "2026-03-06T02:31:55.692Z" }, - { url = "https://files.pythonhosted.org/packages/72/71/624c67abc80cbf19a2a68d7e29768551f47f4f1e4f727fda82b6a8d402eb/pyqwest-0.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bc60f22ffe6f172e47f528ca039a726c7eb08ac2694bcd890202928e8ca37618", size = 5541498, upload-time = "2026-03-06T02:31:57.164Z" }, - { url = "https://files.pythonhosted.org/packages/e2/5a/9fd9f304c9ca7d76a1bfa06423ad4fd950d1b9d728bf314237ddaa1fa300/pyqwest-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:5ced7c18abad3c86602cc5d372a5135174581b0db28493cc3f6285e89bef7932", size = 5719839, upload-time = "2026-03-06T02:31:58.712Z" }, - { url = "https://files.pythonhosted.org/packages/a2/86/abe83391c4ece34eafe0489e2502eb027ef18cdf992cd3e76d8be9347f43/pyqwest-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:a282e4aef7024fed593d4cbc3587f3b6970f70cbc0e4e55d0c7252c1b61c60da", size = 4597026, upload-time = "2026-03-06T02:32:00.315Z" }, - { url = "https://files.pythonhosted.org/packages/17/bd/40b9d924b1eacaf29c5091920adddcb399953224884d47ba32ae2c14424b/pyqwest-0.4.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eef280656e939d4615286aec938814a0de8f6a32d19a0b01e401b41c7d2ffb5b", size = 5009765, upload-time = "2026-03-06T02:32:01.995Z" }, - { url = "https://files.pythonhosted.org/packages/ff/e1/4a6646fbd84f633bcf5baa0b12acf84f53c84aabea363cc8c00911d60da7/pyqwest-0.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:079695544599375395aed985e8c398154ecf5939366d10d7475565cb501d440b", size = 5373955, upload-time = "2026-03-06T02:32:03.567Z" }, - { url = "https://files.pythonhosted.org/packages/66/69/21573dc1edab5bd76b1d77d83a628f22bd6a201f21ec4892af2e0d714e44/pyqwest-0.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c4197a0798fa8233263ace3ddcb7967d4e4ebed60dd4162aced948fad94a7b2", size = 5417908, upload-time = "2026-03-06T02:32:05.348Z" }, - { url = "https://files.pythonhosted.org/packages/03/22/8617b9f1e4a4d26f08b1d6aedfc0698dacd26f0c3f29bea100753f3df534/pyqwest-0.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:300145aa204b546ed952a8fa396ca5c96043fe7662d6d8fea9ed666cb787b378", size = 5541316, upload-time = "2026-03-06T02:32:06.929Z" }, - { url = "https://files.pythonhosted.org/packages/b4/23/a09b2e2b7679835b4f1a8cf15feaab84b875bada67e9fce8772701442dc5/pyqwest-0.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:de49b3193dfb684e4ca07a325b856889fb43a5b9ac52808a2c1549c0ad3b1d30", size = 5719921, upload-time = "2026-03-06T02:32:08.396Z" }, - { url = "https://files.pythonhosted.org/packages/6f/ee/a58a2e71dfa418c7c3d2426daa57357cb93cf2c9d8f9a0d8dceb20098470/pyqwest-0.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:da8996db7ef18a2394de12b465cf20cf1daa9fab7b9d3de731445166b6fd1a6b", size = 4596906, upload-time = "2026-03-06T02:32:10.134Z" }, - { url = "https://files.pythonhosted.org/packages/4a/6f/ed9be2ee96d209ba81467abf4c15f20973c676992597019399998adb5da0/pyqwest-0.4.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:d1ae7a901f58c0d1456ce7012ccb60c4ef85cbc3d6daa9b17a43415b362a3f74", size = 5005846, upload-time = "2026-03-06T02:32:11.677Z" }, - { url = "https://files.pythonhosted.org/packages/ec/29/cb412b9e5b0a1f72cf63b5b551df18aa580aafa020f907fe27c794482362/pyqwest-0.4.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:588f95168779902a734db2a39af353768888a87aa1d91c93002a3132111e72b0", size = 5377385, upload-time = "2026-03-06T02:32:13.821Z" }, - { url = "https://files.pythonhosted.org/packages/84/9e/be8c0192c2fb177834870de10ece2751cd38ca1d357908112a8da6a26106/pyqwest-0.4.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b97a3adfa54188029e93361bacb248ca81272d9085cb6189e4a2a2586c4346e", size = 5422653, upload-time = "2026-03-06T02:32:15.518Z" }, - { url = "https://files.pythonhosted.org/packages/18/74/98afc627c0b91bb3e0214daf3dfbbd348d504574d4c6843a890a0dcc6f33/pyqwest-0.4.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2351d5b142e26df482c274d405185dc56f060559038a8e5e0e5feb8241bb4bb3", size = 5543025, upload-time = "2026-03-06T02:32:17.254Z" }, - { url = "https://files.pythonhosted.org/packages/17/1d/c79c78103aa90a1eff56b5841c1f24bd4ca950957116387de1f1e3291066/pyqwest-0.4.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1fae17504ea83166e495fe93d9f2bfc22dc331dd68bca354a18597e3d1020984", size = 5723286, upload-time = "2026-03-06T02:32:18.8Z" }, - { url = "https://files.pythonhosted.org/packages/24/5b/975b4275ee49cff860f5680dd4ed7f9d74c4c2294cc7c829012e69077e71/pyqwest-0.4.1-cp314-cp314-win_amd64.whl", hash = "sha256:05320841aaa40af070ceb55bfd557f623b5f8aeca1831f97da79b5965775a549", size = 4596486, upload-time = "2026-03-06T02:32:20.813Z" }, - { url = "https://files.pythonhosted.org/packages/ae/ed/08ba859cf528451a9325e5a71c13db8b9aeb7cda794d1e6b7f4d3b3d581d/pyqwest-0.4.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:84e396c6ba396daa974dba2d7090264af26dcfce074d7812c2d7125602969da3", size = 5001684, upload-time = "2026-03-06T02:32:22.332Z" }, - { url = "https://files.pythonhosted.org/packages/e4/ed/b75026973f77cba73c2c6785107cd30407ca8285a7159a0a443801fdd30d/pyqwest-0.4.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f98b11081b3e0d117fda4e03fee6925d870c334fa35085362e980a44e118ab9", size = 5375558, upload-time = "2026-03-06T02:32:24.148Z" }, - { url = "https://files.pythonhosted.org/packages/36/21/2b22d1117c440b020269dbd292f47890579ae5a78d14022a294eb558710b/pyqwest-0.4.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:952842d7f4935ff42d55fdfbf7f0538997b48c62e4aa9a20e4b42bce97ed82a4", size = 5424612, upload-time = "2026-03-06T02:32:25.663Z" }, - { url = "https://files.pythonhosted.org/packages/74/9a/0b3d77903e0bfbfb6a836050aa08ff3d6efae332ce429980146dcd15b151/pyqwest-0.4.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:32e313d2357624a54e60f14976bdf22e41267871b913d51ec7b41be492a0c442", size = 5542133, upload-time = "2026-03-06T02:32:27.191Z" }, - { url = "https://files.pythonhosted.org/packages/2e/3b/fcbfa0f1e8a64ebca0b28ec8f638defddbba47461d755b33658347f8ed84/pyqwest-0.4.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:284e2c99cbebb257ff84c14f14aa87f658ebe57ddfc833aa1d2fd6a3c4687a37", size = 5724980, upload-time = "2026-03-06T02:32:29.102Z" }, - { url = "https://files.pythonhosted.org/packages/2d/d8/d6710bbb38f6a715135f7c8a8e5c6227d69299a2b7e989c81315a08054e7/pyqwest-0.4.1-cp314-cp314t-win_amd64.whl", hash = "sha256:a7b8d8ae51ccf6375a9e82e5b38d2129ee3121acf4933a37e541f4fe04a5f758", size = 4577924, upload-time = "2026-03-06T02:32:31.013Z" }, - { url = "https://files.pythonhosted.org/packages/00/d2/a242fab2782ac122f13cedfa15aa264dc747d43f04856299d6682853d569/pyqwest-0.4.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:1ccb9fcd26bfa2f6b9f03b16a139cf788f0814b81981b0c6cfa90a052720a019", size = 5004305, upload-time = "2026-03-06T02:32:32.67Z" }, - { url = "https://files.pythonhosted.org/packages/75/19/bff53b4fe6c921eda71cd5904c1dc6aafc0e3a7128a0a81297e24ed82bf2/pyqwest-0.4.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22583185b614588c0926921a7c78c9fff8a01a31bf8c8c386c4b3c0d20439a8c", size = 5384524, upload-time = "2026-03-06T02:32:34.658Z" }, - { url = "https://files.pythonhosted.org/packages/0b/d1/3c0ee295c34919b45ebd68be8a9d085a20b90bcc3490814a52cc79519c1c/pyqwest-0.4.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:070c5b6e209293167d79904adfba80507b635e5e49ee2e69c79ad49a344363bf", size = 5432540, upload-time = "2026-03-06T02:32:36.152Z" }, - { url = "https://files.pythonhosted.org/packages/c2/e6/358bebf6d51c1df8ba7c8d145fd1c376d75d384d16a8f2c32a3c87e629d5/pyqwest-0.4.1-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:a562f4d7ce0b4fbd2b4344b458abdcbfe610ec9e39aee9f5affa4819a8696730", size = 5549984, upload-time = "2026-03-06T02:32:37.695Z" }, - { url = "https://files.pythonhosted.org/packages/f6/fb/e8636de8929a01cac87fb5592121c31deb968bd583a4cadc1e0ae2a057bf/pyqwest-0.4.1-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:61b8f2279a446aaddc9d5142332ada0470734bb374b3f7c6564628f1796c5aef", size = 5733441, upload-time = "2026-03-06T02:32:39.437Z" }, - { url = "https://files.pythonhosted.org/packages/7e/0e/1028292c372662b1c2e5f90eb38d52d27d55a2dda63fb0069da4fa2fc55a/pyqwest-0.4.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:b53b242af4869493f46c9556f291a37bf406e0d32147e5a9a7a9f8227c4ae7bb", size = 4596891, upload-time = "2026-03-06T02:32:41.575Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/fc/42/9328a1a057bc191e02514fbd8c9aa899e38ec29420491017f057ac6b5313/pyqwest-0.5.1.tar.gz", hash = "sha256:49535565a55a23830d376c6c0b8ca1276f19bb871e39330e1fbb3df69d9f02df", size = 448653, upload-time = "2026-04-17T03:56:00.279Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d3/48/a869484add1102bbedaf76b1e3840a3f34bb611bf9228ec89a03d51328b1/pyqwest-0.5.1-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:047078c4c3f7c93d8a1df07138c471cfdb234577f60563afe090b160ada1a132", size = 5058870, upload-time = "2026-04-17T03:54:36.807Z" }, + { url = "https://files.pythonhosted.org/packages/4f/b7/f06e56398ea41a183a0494b6557d1e28ed122ac8a20315a7f24ec316b7c1/pyqwest-0.5.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f732aed3498abf5742f0c952f24fc21625d62fe0a701ec8e472257709540d61", size = 5438347, upload-time = "2026-04-17T03:54:39.108Z" }, + { url = "https://files.pythonhosted.org/packages/39/df/6160cab1d48ad2d1a2038ac8a1ff94d72f267cb6a3e3a7181c1ae41d98c9/pyqwest-0.5.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77565ad8e551a101eddbf08328b0e3d54a179efec97a3da195ce831f0474ef92", size = 5457281, upload-time = "2026-04-17T03:54:41.347Z" }, + { url = "https://files.pythonhosted.org/packages/8d/56/343516d26e153a60c19f2dbbe83460238feddd18a27c42ae11f843e79bf1/pyqwest-0.5.1-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:57ea14094f841d735fcf401a6428e94a39aabf22d15762a979cf8d6096fea90b", size = 5600773, upload-time = "2026-04-17T03:54:43.615Z" }, + { url = "https://files.pythonhosted.org/packages/32/f3/56c2cca5b7fcf708d41628cd3bd8a8be48d364a33a469fc056a5e92d5de3/pyqwest-0.5.1-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e6716309fc179b0714978d1f8c32a70724b3b9f43acc9aea3cf9507872e631d6", size = 5763641, upload-time = "2026-04-17T03:54:45.804Z" }, + { url = "https://files.pythonhosted.org/packages/92/c1/ac5dceb438ec71f5a3aaf1d9481ddc3535cf875fa8c8ff3622758d49fe50/pyqwest-0.5.1-cp310-abi3-win_amd64.whl", hash = "sha256:736b560fd2256a41264f554243edf3ff872ead4da347392531576203cf97a4ce", size = 4638049, upload-time = "2026-04-17T03:54:48.108Z" }, + { url = "https://files.pythonhosted.org/packages/c3/e6/42b24a7daba2b900287ee0b89ba24e864c1976b4b371ec5aba3ddcd52f0a/pyqwest-0.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c30bb16da6580d085d86a46e28c3b59813c634c5dd7363faa980c6e53d42ea21", size = 5055607, upload-time = "2026-04-17T03:54:50.139Z" }, + { url = "https://files.pythonhosted.org/packages/7e/51/05ad3a8eba6a14cede32f0446199505782e43734ac1d0ebeb43286e94a64/pyqwest-0.5.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4540be138c7e4ee498c084fa9f19f34dd135f263653619ec91ccebecefd32a3a", size = 5433373, upload-time = "2026-04-17T03:54:52.275Z" }, + { url = "https://files.pythonhosted.org/packages/ba/02/eeb8bb3cb80dc4449303294e94d7e7b11e2bfd0ca319a93bfa4ce604d50c/pyqwest-0.5.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae56109419b37be3e90a134f827fda26c6338c432bae5ecef561e93c3df275ab", size = 5457842, upload-time = "2026-04-17T03:54:54.865Z" }, + { url = "https://files.pythonhosted.org/packages/22/32/929fe6f208e18d1ab2b4b188be9830a8d6f22641aa77434d08674f6b0a4f/pyqwest-0.5.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:82fbf17cf45b5a67c95734934f584045f114a1aa59d179fb79d80e56e653e052", size = 5600494, upload-time = "2026-04-17T03:54:57.485Z" }, + { url = "https://files.pythonhosted.org/packages/9a/b6/3da1250e26e435262a7113e8d8bc5628eba0518d06b5b07e74bbad3efd7f/pyqwest-0.5.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:717b65ee898bc3e4f29a74e068bb753bbb8a338456f1fb65edc2edabc3f3eaa5", size = 5762097, upload-time = "2026-04-17T03:54:59.536Z" }, + { url = "https://files.pythonhosted.org/packages/eb/b1/159538a856bee250431d4976a3b7731c1402932af94c00d832bf71a7ceda/pyqwest-0.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:26498ead2aaf491430980c06cbee3bd72a26a8f33a025e9a19ddcd7e781a069a", size = 4632471, upload-time = "2026-04-17T03:55:02.369Z" }, + { url = "https://files.pythonhosted.org/packages/28/f6/5f5eaf7357ade38a5e8697935a156ac47ff3bef0bb9cc32ef2f5b4cf0190/pyqwest-0.5.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:81bf0feb6d07fc25ffbe96be09ef64ff732d444e26c80db1b1de999d74a7a7ed", size = 5054876, upload-time = "2026-04-17T03:55:04.992Z" }, + { url = "https://files.pythonhosted.org/packages/fb/e8/3b17156c13745a17ce39c7bfe9ed9fdec8ba19a5a47ddd762c89f00fb642/pyqwest-0.5.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a7d2c4a162e72b57dfd175f53882558702c3ddd5704f536599f463e46081bd9", size = 5433361, upload-time = "2026-04-17T03:55:07.182Z" }, + { url = "https://files.pythonhosted.org/packages/35/fc/a50cde1003e1c39c2087b1ae50cd074a41ab89f5a1ad2998cc3f481cf10c/pyqwest-0.5.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b33bcba509e07ee79e61f9311880a22e8c11a562382648166f624f0b480266c1", size = 5457142, upload-time = "2026-04-17T03:55:09.358Z" }, + { url = "https://files.pythonhosted.org/packages/a9/65/f8c50d2ebe3e6d41f04a9924baef9f106feec2eb87acdd60fcb1c3ce2e84/pyqwest-0.5.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3a7a7b56e0f9099b50dae2e5907f05fc5e61252cd48cc1561f156765b233dd7b", size = 5601185, upload-time = "2026-04-17T03:55:11.626Z" }, + { url = "https://files.pythonhosted.org/packages/7e/1f/13f250e31d5503d326da8d9874891bedbfd7eeaa86711ab15acce157e59f/pyqwest-0.5.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a3cd54af62f01fd0daf694218074325ccbbea6527f27738a85fc1e38880119f0", size = 5761677, upload-time = "2026-04-17T03:55:13.915Z" }, + { url = "https://files.pythonhosted.org/packages/b3/ab/11a1bf107af0f21fa8f1d9516e59c8b742c19c32f82cae49f6340ffa7336/pyqwest-0.5.1-cp313-cp313-win_amd64.whl", hash = "sha256:938ac244f96730a8c1addb260cbec93e44ef63d73358285bafb00f18526c106b", size = 4631790, upload-time = "2026-04-17T03:55:16.002Z" }, + { url = "https://files.pythonhosted.org/packages/2b/17/f227c99b53890157b737aed6c0840ebedda8eaafb513d1db3092a85c12a3/pyqwest-0.5.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7755dd658c612016c38f0e26938b80dafd37d80ee074c5cc4301f54f385b1e52", size = 5058021, upload-time = "2026-04-17T03:55:18.237Z" }, + { url = "https://files.pythonhosted.org/packages/26/14/c3924ee479fce346124ef07550262e4f91b1d0d6d14f3024d2c2efe38055/pyqwest-0.5.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29015b12242f2feeb24cbad7d1025a78b3239872efcbfa975ce23527e8c05ec7", size = 5420148, upload-time = "2026-04-17T03:55:20.446Z" }, + { url = "https://files.pythonhosted.org/packages/3b/7d/a8f45ea52cb97b410fad96597eccbf6be9417eb0a2bf7c0d6be9a936c897/pyqwest-0.5.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1271fb28a78484e93d09b7c78df5213900538af8cf5a53ce377ed2cbb82e72b2", size = 5443389, upload-time = "2026-04-17T03:55:22.914Z" }, + { url = "https://files.pythonhosted.org/packages/aa/47/9870f5e24f49f5c77fbc9d21f2a6ace3a065cc3c8411ae6d25001605ba5a/pyqwest-0.5.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:eaf970412356f9d6482045a8e7b7c9d36c07b6a7352c96c90a811e730eba906f", size = 5584772, upload-time = "2026-04-17T03:55:25.197Z" }, + { url = "https://files.pythonhosted.org/packages/44/a5/d5b81d67902f0526fb69ff0b71aa5fcadc052133fa4692aa35c7dbfd6c8e/pyqwest-0.5.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:986b787138893459e02485e89a7d4a383ec2864194a5ab7e0650dce9635f5215", size = 5746464, upload-time = "2026-04-17T03:55:27.649Z" }, + { url = "https://files.pythonhosted.org/packages/81/d7/49197597a26186c4a1e3cf0d915b04f0a15a52eaeb82ee8b1659ca131bab/pyqwest-0.5.1-cp314-cp314-win_amd64.whl", hash = "sha256:4d9fb2bcbea6adc365ea3c69727b34dd21dee29edb1551b64531b25babb68f91", size = 4647610, upload-time = "2026-04-17T03:55:29.75Z" }, + { url = "https://files.pythonhosted.org/packages/1a/a3/be43b05f7821e8fba21af2eaee3a8418979da40cf895042e1705aa63e394/pyqwest-0.5.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:dc7a7c65e839057bcc3a5d4f48c6c2202f89fc13ddb12bd8e2f20d95378a95d8", size = 5054843, upload-time = "2026-04-17T03:55:32.655Z" }, + { url = "https://files.pythonhosted.org/packages/5d/e1/0e76b0bb3c71c87e63eebfcc1d5dfbee6ca69332336fea975defc30d8747/pyqwest-0.5.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e30c2268e9f7ec5509874047ebf83ecde1cab29d0bd7dc352fa2a782da2b2abf", size = 5432984, upload-time = "2026-04-17T03:55:34.925Z" }, + { url = "https://files.pythonhosted.org/packages/9d/98/f32513e74f30009eef6979632590df32287a19f85215dd5654a9676da184/pyqwest-0.5.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f632070abff4d0bfd0f6deada3beaaaa42a042809e50c7f2e2b25014687e070", size = 5452771, upload-time = "2026-04-17T03:55:37.44Z" }, + { url = "https://files.pythonhosted.org/packages/ba/40/334e2184dbc4641743f47cbaa0079c32239bdcb972aee659f37196b920fe/pyqwest-0.5.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:78f8b6b41c0206e9605d75b9fc3f20db97c266829f5a0bee8eff7d524de2bf20", size = 5598688, upload-time = "2026-04-17T03:55:39.808Z" }, + { url = "https://files.pythonhosted.org/packages/16/cb/d1a80c6d3cc89207d02bf4abca856420efaecc4e9482fb1c3906f27228ba/pyqwest-0.5.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a1d95a8a7e4246ba37dc3115b10b72c5dcdf4b226447d1a7a51973d686460fa4", size = 5759621, upload-time = "2026-04-17T03:55:41.956Z" }, + { url = "https://files.pythonhosted.org/packages/1e/57/eb4bc81fea27b0f0515e97168bb67145b9d7c81cd2f2f94f9deb0febd639/pyqwest-0.5.1-cp314-cp314t-win_amd64.whl", hash = "sha256:fbd3232cca327bc591d47b0368ba712d929f66658d4822ac5129f5ede1a581df", size = 4623418, upload-time = "2026-04-17T03:55:44.129Z" }, + { url = "https://files.pythonhosted.org/packages/68/05/6340fcb599734691832b60829236c53f813220f0a642af90e05c5df5d6a9/pyqwest-0.5.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:45f9d448fedd6d85c4c9a5cb8e743b83fdd798c335936588f5d90628c6163f73", size = 5059333, upload-time = "2026-04-17T03:55:46.264Z" }, + { url = "https://files.pythonhosted.org/packages/52/65/9d98c421a5ec3283bb77337f51920504c4d770bbd09b36a6164eaa21c4e8/pyqwest-0.5.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:144c22aa18de37f5b6f877939c50fb2aafb94a6433ac47ddab3850793402e46b", size = 5438850, upload-time = "2026-04-17T03:55:48.542Z" }, + { url = "https://files.pythonhosted.org/packages/1f/6e/b5862ef8e6a61c1baf48740e9f9ea256ef63d26c10df8c340a3fbefc35e2/pyqwest-0.5.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:850c58da7df5c0a4c6351ffe66f99768cb5d92e882b55daf9984a96a5c46e11e", size = 5455438, upload-time = "2026-04-17T03:55:51.106Z" }, + { url = "https://files.pythonhosted.org/packages/8b/b5/765fadb80caea4d62e6895a5404264a78746662044a2c64e73a8dceee588/pyqwest-0.5.1-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:03e57c1d58d7f236a08dfe5b27493ee56ae2d5e4b40e5c4bd9e6309000b4b86f", size = 5605021, upload-time = "2026-04-17T03:55:53.508Z" }, + { url = "https://files.pythonhosted.org/packages/98/eb/9d52f55f724edd40a2c2317074e283d8bb4bab564f7354a36e4f4f89e80e/pyqwest-0.5.1-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:958540d4861b9e7a228a775ea8b937c019bdc769d52b6e2e872b5bdc1ebf6870", size = 5761909, upload-time = "2026-04-17T03:55:56.063Z" }, + { url = "https://files.pythonhosted.org/packages/92/8c/7287ef3e34c5045fe1583385cf03a5a5681b7fae62676391444cfa44a4d1/pyqwest-0.5.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:469dfd7baaac6fd6565d396c8d05f19cb5ba279856af38b5f69ff8278e991c49", size = 4630018, upload-time = "2026-04-17T03:55:58.249Z" }, ] [[package]] @@ -1956,8 +1944,8 @@ name = "taskgroup" version = "0.2.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "exceptiongroup" }, - { name = "typing-extensions" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f0/8d/e218e0160cc1b692e6e0e5ba34e8865dbb171efeb5fc9a704544b3020605/taskgroup-0.2.2.tar.gz", hash = "sha256:078483ac3e78f2e3f973e2edbf6941374fbea81b9c5d0a96f51d297717f4752d", size = 11504, upload-time = "2025-01-03T09:24:13.761Z" } wheels = [ From b064b2aa47e040b0a8c6b306f060cb02b1ccb624 Mon Sep 17 00:00:00 2001 From: Anuraag Agrawal Date: Sat, 18 Apr 2026 00:07:19 +0900 Subject: [PATCH 4/4] Types --- test/test_errors.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/test/test_errors.py b/test/test_errors.py index fb80138..c95df00 100644 --- a/test/test_errors.py +++ b/test/test_errors.py @@ -34,8 +34,6 @@ from .haberdasher_pb2 import Hat, Size if TYPE_CHECKING: - from collections.abc import AsyncIterator - from connectrpc.request import RequestContext _errors = [ @@ -455,9 +453,7 @@ async def make_hat(self, request, ctx) -> NoReturn: @pytest.mark.asyncio async def test_async_unhandled_exception_reraised_stream() -> None: class RaisingHaberdasher(Haberdasher): - def make_similar_hats( - self, request: Size, ctx: RequestContext - ) -> AsyncIterator[Hat]: + def make_similar_hats(self, request: Size, ctx: RequestContext) -> NoReturn: raise TypeError("Something went wrong") app = HaberdasherASGIApplication(RaisingHaberdasher()) @@ -497,9 +493,7 @@ async def make_hat(self, request, ctx) -> NoReturn: @pytest.mark.asyncio async def test_async_connect_exception_not_reraised_stream() -> None: class RaisingHaberdasher(Haberdasher): - def make_similar_hats( - self, request: Size, ctx: RequestContext - ) -> AsyncIterator[Hat]: + def make_similar_hats(self, request: Size, ctx: RequestContext) -> NoReturn: raise ConnectError(Code.INTERNAL, "We're broken") app = HaberdasherASGIApplication(RaisingHaberdasher())