From 7811c8b7d19b49f2bcdd2d0915c39dd2683dd256 Mon Sep 17 00:00:00 2001 From: Francis Secada Date: Wed, 2 Feb 2022 11:43:00 -0500 Subject: [PATCH 1/8] Update setup.py Allow for h11 V. 013. Facilitates installation alongside latest version of Uvicorn. --- setup.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 9bfc613b..b11f129e 100644 --- a/setup.py +++ b/setup.py @@ -54,7 +54,7 @@ def get_packages(package): include_package_data=True, zip_safe=False, install_requires=[ - "h11>=0.11,<0.13", + "h11>=0.11,<=0.13", "sniffio==1.*", "anyio==3.*", "certifi", @@ -73,7 +73,6 @@ def get_packages(package): "Framework :: AsyncIO", "Framework :: Trio", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", From 6664449ff0c919979f436200555eeb3c989d6985 Mon Sep 17 00:00:00 2001 From: Michael Adkins Date: Fri, 25 Mar 2022 10:43:00 -0500 Subject: [PATCH 2/8] Bump h11 pin to 0.14 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index b11f129e..4ec6f8de 100644 --- a/setup.py +++ b/setup.py @@ -54,7 +54,7 @@ def get_packages(package): include_package_data=True, zip_safe=False, install_requires=[ - "h11>=0.11,<=0.13", + "h11>=0.11,<0.14", "sniffio==1.*", "anyio==3.*", "certifi", From 4207b8bd4f4f045830a6dd621454e45ef032ab53 Mon Sep 17 00:00:00 2001 From: Michael Adkins Date: Fri, 25 Mar 2022 10:43:04 -0500 Subject: [PATCH 3/8] Remove reassignment of `event` to prevent type failure --- httpcore/_async/http11.py | 3 +-- httpcore/_sync/http11.py | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/httpcore/_async/http11.py b/httpcore/_async/http11.py index a4880f3c..49096cd4 100644 --- a/httpcore/_async/http11.py +++ b/httpcore/_async/http11.py @@ -127,8 +127,7 @@ async def _send_request_body(self, request: Request) -> None: event = h11.Data(data=chunk) await self._send_event(event, timeout=timeout) - event = h11.EndOfMessage() - await self._send_event(event, timeout=timeout) + await self._send_event(h11.EndOfMessage(), timeout=timeout) async def _send_event( self, event: H11Event, timeout: Optional[float] = None diff --git a/httpcore/_sync/http11.py b/httpcore/_sync/http11.py index d7ea2755..550468e9 100644 --- a/httpcore/_sync/http11.py +++ b/httpcore/_sync/http11.py @@ -127,8 +127,7 @@ def _send_request_body(self, request: Request) -> None: event = h11.Data(data=chunk) self._send_event(event, timeout=timeout) - event = h11.EndOfMessage() - self._send_event(event, timeout=timeout) + self._send_event(h11.EndOfMessage(), timeout=timeout) def _send_event( self, event: H11Event, timeout: Optional[float] = None From 3c46a892259411dbf85548aad1beeb99b39fee8d Mon Sep 17 00:00:00 2001 From: Michael Adkins Date: Fri, 25 Mar 2022 10:49:26 -0500 Subject: [PATCH 4/8] Add an explicit check for `None` in `_send_event` This also reverted commit f9a984756c2e1d8affb1d87f8d1af32f67c52461 which was dropped during rebase with the `master` branch. We probably do not want to suggest that passing `None` to the `write` function is proper. The short circuit there (return on empty buffer) should be targeted to an empty byte array. --- httpcore/_async/http11.py | 3 ++- httpcore/_sync/http11.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/httpcore/_async/http11.py b/httpcore/_async/http11.py index 49096cd4..df1b034c 100644 --- a/httpcore/_async/http11.py +++ b/httpcore/_async/http11.py @@ -133,7 +133,8 @@ async def _send_event( self, event: H11Event, timeout: Optional[float] = None ) -> None: bytes_to_send = self._h11_state.send(event) - await self._network_stream.write(bytes_to_send, timeout=timeout) + if bytes_to_send is not None: + await self._network_stream.write(bytes_to_send, timeout=timeout) # Receiving the response... diff --git a/httpcore/_sync/http11.py b/httpcore/_sync/http11.py index 550468e9..f12c0d6a 100644 --- a/httpcore/_sync/http11.py +++ b/httpcore/_sync/http11.py @@ -133,7 +133,8 @@ def _send_event( self, event: H11Event, timeout: Optional[float] = None ) -> None: bytes_to_send = self._h11_state.send(event) - self._network_stream.write(bytes_to_send, timeout=timeout) + if bytes_to_send is not None: + self._network_stream.write(bytes_to_send, timeout=timeout) # Receiving the response... From ca728c21bdcd3e78420b5f96a20453d2df3da6bf Mon Sep 17 00:00:00 2001 From: Michael Adkins Date: Fri, 25 Mar 2022 11:08:09 -0500 Subject: [PATCH 5/8] Replace h11 event with new base class type; add stubs for PAUSED handling --- httpcore/_async/http11.py | 33 ++++++++++++++++++++------------- httpcore/_sync/http11.py | 34 +++++++++++++--------------------- 2 files changed, 33 insertions(+), 34 deletions(-) diff --git a/httpcore/_async/http11.py b/httpcore/_async/http11.py index df1b034c..ad123be6 100644 --- a/httpcore/_async/http11.py +++ b/httpcore/_async/http11.py @@ -1,7 +1,16 @@ import enum import time from types import TracebackType -from typing import AsyncIterable, AsyncIterator, List, Optional, Tuple, Type, Union +from typing import ( + AsyncIterable, + AsyncIterator, + List, + Optional, + Tuple, + Type, + cast, + Union, +) import h11 @@ -17,15 +26,6 @@ from ..backends.base import AsyncNetworkStream from .interfaces import AsyncConnectionInterface -H11Event = Union[ - h11.Request, - h11.Response, - h11.InformationalResponse, - h11.Data, - h11.EndOfMessage, - h11.ConnectionClosed, -] - class HTTPConnectionState(enum.IntEnum): NEW = 0 @@ -130,7 +130,7 @@ async def _send_request_body(self, request: Request) -> None: await self._send_event(h11.EndOfMessage(), timeout=timeout) async def _send_event( - self, event: H11Event, timeout: Optional[float] = None + self, event: h11.Event, timeout: Optional[float] = None ) -> None: bytes_to_send = self._h11_state.send(event) if bytes_to_send is not None: @@ -168,10 +168,14 @@ async def _receive_response_body(self, request: Request) -> AsyncIterator[bytes] elif isinstance(event, (h11.EndOfMessage, h11.PAUSED)): break - async def _receive_event(self, timeout: Optional[float] = None) -> H11Event: + async def _receive_event(self, timeout: Optional[float] = None) -> h11.Event: while True: with map_exceptions({h11.RemoteProtocolError: RemoteProtocolError}): - event = self._h11_state.next_event() + # The h11 type signature uses a private return type + event = cast( + Union[h11.Event, h11.NEED_DATA, h11.PAUSED], + self._h11_state.next_event(), + ) if event is h11.NEED_DATA: data = await self._network_stream.read( @@ -191,6 +195,9 @@ async def _receive_event(self, timeout: Optional[float] = None) -> H11Event: raise RemoteProtocolError(msg) self._h11_state.receive_data(data) + elif event is h11.PAUSED: + # TODO: Implement handling for paused + ... else: return event diff --git a/httpcore/_sync/http11.py b/httpcore/_sync/http11.py index f12c0d6a..7f31f5c5 100644 --- a/httpcore/_sync/http11.py +++ b/httpcore/_sync/http11.py @@ -1,7 +1,7 @@ import enum import time from types import TracebackType -from typing import Iterable, Iterator, List, Optional, Tuple, Type, Union +from typing import Iterable, Iterator, List, Optional, Tuple, Type, Union, cast import h11 @@ -17,15 +17,6 @@ from ..backends.base import NetworkStream from .interfaces import ConnectionInterface -H11Event = Union[ - h11.Request, - h11.Response, - h11.InformationalResponse, - h11.Data, - h11.EndOfMessage, - h11.ConnectionClosed, -] - class HTTPConnectionState(enum.IntEnum): NEW = 0 @@ -73,9 +64,7 @@ def handle_request(self, request: Request) -> Response: self._send_request_headers(**kwargs) with Trace("http11.send_request_body", request, kwargs) as trace: self._send_request_body(**kwargs) - with Trace( - "http11.receive_response_headers", request, kwargs - ) as trace: + with Trace("http11.receive_response_headers", request, kwargs) as trace: ( http_version, status, @@ -129,9 +118,7 @@ def _send_request_body(self, request: Request) -> None: self._send_event(h11.EndOfMessage(), timeout=timeout) - def _send_event( - self, event: H11Event, timeout: Optional[float] = None - ) -> None: + def _send_event(self, event: h11.Event, timeout: Optional[float] = None) -> None: bytes_to_send = self._h11_state.send(event) if bytes_to_send is not None: self._network_stream.write(bytes_to_send, timeout=timeout) @@ -168,15 +155,17 @@ def _receive_response_body(self, request: Request) -> Iterator[bytes]: elif isinstance(event, (h11.EndOfMessage, h11.PAUSED)): break - def _receive_event(self, timeout: Optional[float] = None) -> H11Event: + def _receive_event(self, timeout: Optional[float] = None) -> h11.Event: while True: with map_exceptions({h11.RemoteProtocolError: RemoteProtocolError}): - event = self._h11_state.next_event() + # The h11 type signature uses a private return type + event = cast( + Union[h11.Event, h11.NEED_DATA, h11.PAUSED], + self._h11_state.next_event(), + ) if event is h11.NEED_DATA: - data = self._network_stream.read( - self.READ_NUM_BYTES, timeout=timeout - ) + data = self._network_stream.read(self.READ_NUM_BYTES, timeout=timeout) # If we feed this case through h11 we'll raise an exception like: # @@ -191,6 +180,9 @@ def _receive_event(self, timeout: Optional[float] = None) -> H11Event: raise RemoteProtocolError(msg) self._h11_state.receive_data(data) + elif event is h11.PAUSED: + # TODO: Implement handling for paused + ... else: return event From 4de236cf52be1548a429fbc96a1cb571d2f33ec1 Mon Sep 17 00:00:00 2001 From: Michael Adkins Date: Fri, 25 Mar 2022 11:11:35 -0500 Subject: [PATCH 6/8] Lint; add cast for return type --- httpcore/_async/http11.py | 4 ++-- httpcore/_sync/http11.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/httpcore/_async/http11.py b/httpcore/_async/http11.py index ad123be6..3d81ebf6 100644 --- a/httpcore/_async/http11.py +++ b/httpcore/_async/http11.py @@ -8,8 +8,8 @@ Optional, Tuple, Type, - cast, Union, + cast, ) import h11 @@ -199,7 +199,7 @@ async def _receive_event(self, timeout: Optional[float] = None) -> h11.Event: # TODO: Implement handling for paused ... else: - return event + return cast(h11.Event, event) async def _response_closed(self) -> None: async with self._state_lock: diff --git a/httpcore/_sync/http11.py b/httpcore/_sync/http11.py index 7f31f5c5..7543c936 100644 --- a/httpcore/_sync/http11.py +++ b/httpcore/_sync/http11.py @@ -184,7 +184,7 @@ def _receive_event(self, timeout: Optional[float] = None) -> h11.Event: # TODO: Implement handling for paused ... else: - return event + return cast(h11.Event, event) def _response_closed(self) -> None: with self._state_lock: From 668dce8b2f50eb206aa9d302726ced3884abc898 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Sun, 19 Jun 2022 17:53:30 +0100 Subject: [PATCH 7/8] apply unasync --- httpcore/_sync/http11.py | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/httpcore/_sync/http11.py b/httpcore/_sync/http11.py index 7543c936..eb029af7 100644 --- a/httpcore/_sync/http11.py +++ b/httpcore/_sync/http11.py @@ -1,7 +1,16 @@ import enum import time from types import TracebackType -from typing import Iterable, Iterator, List, Optional, Tuple, Type, Union, cast +from typing import ( + Iterable, + Iterator, + List, + Optional, + Tuple, + Type, + Union, + cast, +) import h11 @@ -64,7 +73,9 @@ def handle_request(self, request: Request) -> Response: self._send_request_headers(**kwargs) with Trace("http11.send_request_body", request, kwargs) as trace: self._send_request_body(**kwargs) - with Trace("http11.receive_response_headers", request, kwargs) as trace: + with Trace( + "http11.receive_response_headers", request, kwargs + ) as trace: ( http_version, status, @@ -118,7 +129,9 @@ def _send_request_body(self, request: Request) -> None: self._send_event(h11.EndOfMessage(), timeout=timeout) - def _send_event(self, event: h11.Event, timeout: Optional[float] = None) -> None: + def _send_event( + self, event: h11.Event, timeout: Optional[float] = None + ) -> None: bytes_to_send = self._h11_state.send(event) if bytes_to_send is not None: self._network_stream.write(bytes_to_send, timeout=timeout) @@ -165,7 +178,9 @@ def _receive_event(self, timeout: Optional[float] = None) -> h11.Event: ) if event is h11.NEED_DATA: - data = self._network_stream.read(self.READ_NUM_BYTES, timeout=timeout) + data = self._network_stream.read( + self.READ_NUM_BYTES, timeout=timeout + ) # If we feed this case through h11 we'll raise an exception like: # From f42eab9c90162379f5c3ae02be0f644816cef39e Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Sun, 19 Jun 2022 18:08:21 +0100 Subject: [PATCH 8/8] do not attempt to handle paused in _receive_event --- httpcore/_async/http11.py | 11 +++++------ httpcore/_sync/http11.py | 11 +++++------ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/httpcore/_async/http11.py b/httpcore/_async/http11.py index 3d81ebf6..8902789a 100644 --- a/httpcore/_async/http11.py +++ b/httpcore/_async/http11.py @@ -168,7 +168,9 @@ async def _receive_response_body(self, request: Request) -> AsyncIterator[bytes] elif isinstance(event, (h11.EndOfMessage, h11.PAUSED)): break - async def _receive_event(self, timeout: Optional[float] = None) -> h11.Event: + async def _receive_event( + self, timeout: Optional[float] = None + ) -> Union[h11.Event, h11.PAUSED]: while True: with map_exceptions({h11.RemoteProtocolError: RemoteProtocolError}): # The h11 type signature uses a private return type @@ -177,7 +179,7 @@ async def _receive_event(self, timeout: Optional[float] = None) -> h11.Event: self._h11_state.next_event(), ) - if event is h11.NEED_DATA: + if isinstance(event, h11.NEED_DATA): data = await self._network_stream.read( self.READ_NUM_BYTES, timeout=timeout ) @@ -195,11 +197,8 @@ async def _receive_event(self, timeout: Optional[float] = None) -> h11.Event: raise RemoteProtocolError(msg) self._h11_state.receive_data(data) - elif event is h11.PAUSED: - # TODO: Implement handling for paused - ... else: - return cast(h11.Event, event) + return event async def _response_closed(self) -> None: async with self._state_lock: diff --git a/httpcore/_sync/http11.py b/httpcore/_sync/http11.py index eb029af7..f4fa9c29 100644 --- a/httpcore/_sync/http11.py +++ b/httpcore/_sync/http11.py @@ -168,7 +168,9 @@ def _receive_response_body(self, request: Request) -> Iterator[bytes]: elif isinstance(event, (h11.EndOfMessage, h11.PAUSED)): break - def _receive_event(self, timeout: Optional[float] = None) -> h11.Event: + def _receive_event( + self, timeout: Optional[float] = None + ) -> Union[h11.Event, h11.PAUSED]: while True: with map_exceptions({h11.RemoteProtocolError: RemoteProtocolError}): # The h11 type signature uses a private return type @@ -177,7 +179,7 @@ def _receive_event(self, timeout: Optional[float] = None) -> h11.Event: self._h11_state.next_event(), ) - if event is h11.NEED_DATA: + if isinstance(event, h11.NEED_DATA): data = self._network_stream.read( self.READ_NUM_BYTES, timeout=timeout ) @@ -195,11 +197,8 @@ def _receive_event(self, timeout: Optional[float] = None) -> h11.Event: raise RemoteProtocolError(msg) self._h11_state.receive_data(data) - elif event is h11.PAUSED: - # TODO: Implement handling for paused - ... else: - return cast(h11.Event, event) + return event def _response_closed(self) -> None: with self._state_lock: