Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-httpx-ws for openSUSE:Factory checked in at 2024-11-14 16:08:56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-httpx-ws (Old) and /work/SRC/openSUSE:Factory/.python-httpx-ws.new.2017 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-httpx-ws" Thu Nov 14 16:08:56 2024 rev:2 rq:1223990 version:0.6.2 Changes: -------- --- /work/SRC/openSUSE:Factory/python-httpx-ws/python-httpx-ws.changes 2024-09-05 15:47:09.884014619 +0200 +++ /work/SRC/openSUSE:Factory/.python-httpx-ws.new.2017/python-httpx-ws.changes 2024-11-14 16:09:55.077856788 +0100 @@ -1,0 +2,10 @@ +Wed Nov 13 15:14:59 UTC 2024 - Dirk Müller <dmuel...@suse.com> + +- update to 0.6.2: + * Improve efficiency of WebSocketSession by reusing a single + thread pool when waiting for messages + * Fix (#73) anyio misusages + * Fix (#74) unclosed anyio streams + * Fix (#76) memory leak with non-async WebSocketSession + +------------------------------------------------------------------- Old: ---- httpx_ws-0.6.0.tar.gz New: ---- httpx_ws-0.6.2.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-httpx-ws.spec ++++++ --- /var/tmp/diff_new_pack.hFRY0w/_old 2024-11-14 16:09:58.157985419 +0100 +++ /var/tmp/diff_new_pack.hFRY0w/_new 2024-11-14 16:09:58.157985419 +0100 @@ -17,7 +17,7 @@ Name: python-httpx-ws -Version: 0.6.0 +Version: 0.6.2 Release: 0 Summary: WebSockets support for HTTPX License: MIT ++++++ httpx_ws-0.6.0.tar.gz -> httpx_ws-0.6.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/httpx_ws-0.6.0/.all-contributorsrc new/httpx_ws-0.6.2/.all-contributorsrc --- old/httpx_ws-0.6.0/.all-contributorsrc 2020-02-02 01:00:00.000000000 +0100 +++ new/httpx_ws-0.6.2/.all-contributorsrc 2020-02-02 01:00:00.000000000 +0100 @@ -31,7 +31,8 @@ "avatar_url": "https://avatars.githubusercontent.com/u/4711805?v=4", "profile": "https://github.com/davidbrochart", "contributions": [ - "platform" + "platform", + "code" ] }, { @@ -109,6 +110,26 @@ "contributions": [ "code" ] + }, + { + "login": "agronholm", + "name": "Alex Grönholm", + "avatar_url": "https://avatars.githubusercontent.com/u/130003?v=4", + "profile": "https://github.com/agronholm", + "contributions": [ + "bug", + "code" + ] + }, + { + "login": "ro-oliveira95", + "name": "Rodrigo de Oliveira Neto", + "avatar_url": "https://avatars.githubusercontent.com/u/27009864?v=4", + "profile": "https://github.com/ro-oliveira95", + "contributions": [ + "bug", + "code" + ] } ], "contributorsPerLine": 7, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/httpx_ws-0.6.0/PKG-INFO new/httpx_ws-0.6.2/PKG-INFO --- old/httpx_ws-0.6.0/PKG-INFO 2020-02-02 01:00:00.000000000 +0100 +++ new/httpx_ws-0.6.2/PKG-INFO 2020-02-02 01:00:00.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.3 Name: httpx-ws -Version: 0.6.0 +Version: 0.6.2 Summary: WebSockets support for HTTPX Project-URL: Documentation, https://frankie567.github.io/httpx-ws/ Project-URL: Source, https://github.com/frankie567/httpx-ws @@ -81,7 +81,7 @@ <tr> <td align="center" valign="top" width="14.28%"><a href="http://francoisvoron.com"><img src="https://avatars.githubusercontent.com/u/1144727?v=4?s=100" width="100px;" alt="François Voron"/><br /><sub><b>François Voron</b></sub></a><br /><a href="#maintenance-frankie567" title="Maintenance">ð§</a> <a href="https://github.com/frankie567/httpx-ws/commits?author=frankie567" title="Code">ð»</a></td> <td align="center" valign="top" width="14.28%"><a href="http://kousikmitra.github.io"><img src="https://avatars.githubusercontent.com/u/15109533?v=4?s=100" width="100px;" alt="Kousik Mitra"/><br /><sub><b>Kousik Mitra</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/commits?author=kousikmitra" title="Code">ð»</a></td> - <td align="center" valign="top" width="14.28%"><a href="https://github.com/davidbrochart"><img src="https://avatars.githubusercontent.com/u/4711805?v=4?s=100" width="100px;" alt="David Brochart"/><br /><sub><b>David Brochart</b></sub></a><br /><a href="#platform-davidbrochart" title="Packaging/porting to new platform">ð¦</a></td> + <td align="center" valign="top" width="14.28%"><a href="https://github.com/davidbrochart"><img src="https://avatars.githubusercontent.com/u/4711805?v=4?s=100" width="100px;" alt="David Brochart"/><br /><sub><b>David Brochart</b></sub></a><br /><a href="#platform-davidbrochart" title="Packaging/porting to new platform">ð¦</a> <a href="https://github.com/frankie567/httpx-ws/commits?author=davidbrochart" title="Code">ð»</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/ysmu"><img src="https://avatars.githubusercontent.com/u/17018576?v=4?s=100" width="100px;" alt="ysmu"/><br /><sub><b>ysmu</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3Aysmu" title="Bug reports">ð</a></td> <td align="center" valign="top" width="14.28%"><a href="https://samforeman.me"><img src="https://avatars.githubusercontent.com/u/5234251?v=4?s=100" width="100px;" alt="Sam Foreman"/><br /><sub><b>Sam Foreman</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3Asaforem2" title="Bug reports">ð</a></td> <td align="center" valign="top" width="14.28%"><a href="http://maparent.ca/"><img src="https://avatars.githubusercontent.com/u/202691?v=4?s=100" width="100px;" alt="Marc-Antoine Parent"/><br /><sub><b>Marc-Antoine Parent</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3Amaparent" title="Bug reports">ð</a> <a href="https://github.com/frankie567/httpx-ws/commits?author=maparent" title="Code">ð»</a></td> @@ -92,6 +92,8 @@ <td align="center" valign="top" width="14.28%"><a href="http://www.tomchristie.com/"><img src="https://avatars.githubusercontent.com/u/647359?v=4?s=100" width="100px;" alt="Tom Christie"/><br /><sub><b>Tom Christie</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3Atomchristie" title="Bug reports">ð</a> <a href="#research-tomchristie" title="Research">ð¬</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/dmontagu"><img src="https://avatars.githubusercontent.com/u/35119617?v=4?s=100" width="100px;" alt="David Montague"/><br /><sub><b>David Montague</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3Admontagu" title="Bug reports">ð</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/WSH032"><img src="https://avatars.githubusercontent.com/u/126865849?v=4?s=100" width="100px;" alt="Sean Wang"/><br /><sub><b>Sean Wang</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/commits?author=WSH032" title="Code">ð»</a></td> + <td align="center" valign="top" width="14.28%"><a href="https://github.com/agronholm"><img src="https://avatars.githubusercontent.com/u/130003?v=4?s=100" width="100px;" alt="Alex Grönholm"/><br /><sub><b>Alex Grönholm</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3Aagronholm" title="Bug reports">ð</a> <a href="https://github.com/frankie567/httpx-ws/commits?author=agronholm" title="Code">ð»</a></td> + <td align="center" valign="top" width="14.28%"><a href="https://github.com/ro-oliveira95"><img src="https://avatars.githubusercontent.com/u/27009864?v=4?s=100" width="100px;" alt="Rodrigo de Oliveira Neto"/><br /><sub><b>Rodrigo de Oliveira Neto</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3Aro-oliveira95" title="Bug reports">ð</a> <a href="https://github.com/frankie567/httpx-ws/commits?author=ro-oliveira95" title="Code">ð»</a></td> </tr> </tbody> </table> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/httpx_ws-0.6.0/README.md new/httpx_ws-0.6.2/README.md --- old/httpx_ws-0.6.0/README.md 2020-02-02 01:00:00.000000000 +0100 +++ new/httpx_ws-0.6.2/README.md 2020-02-02 01:00:00.000000000 +0100 @@ -55,7 +55,7 @@ <tr> <td align="center" valign="top" width="14.28%"><a href="http://francoisvoron.com"><img src="https://avatars.githubusercontent.com/u/1144727?v=4?s=100" width="100px;" alt="François Voron"/><br /><sub><b>François Voron</b></sub></a><br /><a href="#maintenance-frankie567" title="Maintenance">ð§</a> <a href="https://github.com/frankie567/httpx-ws/commits?author=frankie567" title="Code">ð»</a></td> <td align="center" valign="top" width="14.28%"><a href="http://kousikmitra.github.io"><img src="https://avatars.githubusercontent.com/u/15109533?v=4?s=100" width="100px;" alt="Kousik Mitra"/><br /><sub><b>Kousik Mitra</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/commits?author=kousikmitra" title="Code">ð»</a></td> - <td align="center" valign="top" width="14.28%"><a href="https://github.com/davidbrochart"><img src="https://avatars.githubusercontent.com/u/4711805?v=4?s=100" width="100px;" alt="David Brochart"/><br /><sub><b>David Brochart</b></sub></a><br /><a href="#platform-davidbrochart" title="Packaging/porting to new platform">ð¦</a></td> + <td align="center" valign="top" width="14.28%"><a href="https://github.com/davidbrochart"><img src="https://avatars.githubusercontent.com/u/4711805?v=4?s=100" width="100px;" alt="David Brochart"/><br /><sub><b>David Brochart</b></sub></a><br /><a href="#platform-davidbrochart" title="Packaging/porting to new platform">ð¦</a> <a href="https://github.com/frankie567/httpx-ws/commits?author=davidbrochart" title="Code">ð»</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/ysmu"><img src="https://avatars.githubusercontent.com/u/17018576?v=4?s=100" width="100px;" alt="ysmu"/><br /><sub><b>ysmu</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3Aysmu" title="Bug reports">ð</a></td> <td align="center" valign="top" width="14.28%"><a href="https://samforeman.me"><img src="https://avatars.githubusercontent.com/u/5234251?v=4?s=100" width="100px;" alt="Sam Foreman"/><br /><sub><b>Sam Foreman</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3Asaforem2" title="Bug reports">ð</a></td> <td align="center" valign="top" width="14.28%"><a href="http://maparent.ca/"><img src="https://avatars.githubusercontent.com/u/202691?v=4?s=100" width="100px;" alt="Marc-Antoine Parent"/><br /><sub><b>Marc-Antoine Parent</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3Amaparent" title="Bug reports">ð</a> <a href="https://github.com/frankie567/httpx-ws/commits?author=maparent" title="Code">ð»</a></td> @@ -66,6 +66,8 @@ <td align="center" valign="top" width="14.28%"><a href="http://www.tomchristie.com/"><img src="https://avatars.githubusercontent.com/u/647359?v=4?s=100" width="100px;" alt="Tom Christie"/><br /><sub><b>Tom Christie</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3Atomchristie" title="Bug reports">ð</a> <a href="#research-tomchristie" title="Research">ð¬</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/dmontagu"><img src="https://avatars.githubusercontent.com/u/35119617?v=4?s=100" width="100px;" alt="David Montague"/><br /><sub><b>David Montague</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3Admontagu" title="Bug reports">ð</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/WSH032"><img src="https://avatars.githubusercontent.com/u/126865849?v=4?s=100" width="100px;" alt="Sean Wang"/><br /><sub><b>Sean Wang</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/commits?author=WSH032" title="Code">ð»</a></td> + <td align="center" valign="top" width="14.28%"><a href="https://github.com/agronholm"><img src="https://avatars.githubusercontent.com/u/130003?v=4?s=100" width="100px;" alt="Alex Grönholm"/><br /><sub><b>Alex Grönholm</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3Aagronholm" title="Bug reports">ð</a> <a href="https://github.com/frankie567/httpx-ws/commits?author=agronholm" title="Code">ð»</a></td> + <td align="center" valign="top" width="14.28%"><a href="https://github.com/ro-oliveira95"><img src="https://avatars.githubusercontent.com/u/27009864?v=4?s=100" width="100px;" alt="Rodrigo de Oliveira Neto"/><br /><sub><b>Rodrigo de Oliveira Neto</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3Aro-oliveira95" title="Bug reports">ð</a> <a href="https://github.com/frankie567/httpx-ws/commits?author=ro-oliveira95" title="Code">ð»</a></td> </tr> </tbody> </table> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/httpx_ws-0.6.0/httpx_ws/__init__.py new/httpx_ws-0.6.2/httpx_ws/__init__.py --- old/httpx_ws-0.6.0/httpx_ws/__init__.py 2020-02-02 01:00:00.000000000 +0100 +++ new/httpx_ws-0.6.2/httpx_ws/__init__.py 2020-02-02 01:00:00.000000000 +0100 @@ -1,4 +1,4 @@ -__version__ = "0.6.0" +__version__ = "0.6.2" from ._api import ( AsyncWebSocketSession, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/httpx_ws-0.6.0/httpx_ws/_api.py new/httpx_ws-0.6.2/httpx_ws/_api.py --- old/httpx_ws-0.6.0/httpx_ws/_api.py 2020-02-02 01:00:00.000000000 +0100 +++ new/httpx_ws-0.6.2/httpx_ws/_api.py 2020-02-02 01:00:00.000000000 +0100 @@ -6,11 +6,13 @@ import secrets import threading import typing +from types import TracebackType import anyio import httpcore import httpx import wsproto +from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream from httpcore import AsyncNetworkStream, NetworkStream from wsproto.frame_protocol import CloseReason @@ -80,12 +82,25 @@ self._ping_manager = PingManager() self._should_close = threading.Event() + self._should_close_task: typing.Optional[concurrent.futures.Future[bool]] = None + self._executor: typing.Optional[concurrent.futures.ThreadPoolExecutor] = None self._max_message_size_bytes = max_message_size_bytes self._queue_size = queue_size self._keepalive_ping_interval_seconds = keepalive_ping_interval_seconds self._keepalive_ping_timeout_seconds = keepalive_ping_timeout_seconds + def _get_executor_should_close_task( + self, + ) -> typing.Tuple[ + concurrent.futures.ThreadPoolExecutor, "concurrent.futures.Future[bool]" + ]: + if self._should_close_task is None: + self._executor = concurrent.futures.ThreadPoolExecutor() + self._should_close_task = self._executor.submit(self._should_close.wait) + assert self._executor is not None + return self._executor, self._should_close_task + def __enter__(self) -> "WebSocketSession": self._background_receive_task = threading.Thread( target=self._background_receive, args=(self._max_message_size_bytes,) @@ -424,6 +439,8 @@ ws.close() """ self._should_close.set() + if self._executor is not None: + self._executor.shutdown(False) if self.connection.state not in { wsproto.connection.ConnectionState.LOCAL_CLOSING, wsproto.connection.ConnectionState.CLOSED, @@ -516,20 +533,19 @@ self, callable: typing.Callable[..., TaskResult], *args, **kwargs ) -> TaskResult: try: - executor = concurrent.futures.ThreadPoolExecutor(max_workers=2) - wait_close_task = executor.submit(self._should_close.wait) + executor, should_close_task = self._get_executor_should_close_task() todo_task = executor.submit(callable, *args, **kwargs) except RuntimeError as e: raise ShouldClose() from e - done, pending = concurrent.futures.wait( # type: ignore - (todo_task, wait_close_task), return_when=concurrent.futures.FIRST_COMPLETED - ) - for task in pending: - task.cancel() - if wait_close_task in done and todo_task not in done: - raise ShouldClose() - result = todo_task.result() - executor.shutdown(False) + else: + done, _ = concurrent.futures.wait( + (todo_task, should_close_task), # type: ignore[misc] + return_when=concurrent.futures.FIRST_COMPLETED, + ) + if should_close_task in done: + raise ShouldClose() + assert todo_task in done + result = todo_task.result() return result @@ -546,6 +562,12 @@ subprotocol: typing.Optional[str] response: typing.Optional[httpx.Response] + _send_event: MemoryObjectSendStream[ + typing.Union[wsproto.events.Event, HTTPXWSException] + ] + _receive_event: MemoryObjectReceiveStream[ + typing.Union[wsproto.events.Event, HTTPXWSException] + ] def __init__( self, @@ -569,10 +591,6 @@ else: self.subprotocol = None - self._send_event, self._receive_event = anyio.create_memory_object_stream[ - typing.Union[wsproto.events.Event, HTTPXWSException] - ]() - self._ping_manager = AsyncPingManager() self._should_close = anyio.Event() @@ -587,26 +605,39 @@ self._keepalive_ping_interval_seconds = keepalive_ping_interval_seconds self._keepalive_ping_timeout_seconds = keepalive_ping_timeout_seconds - async def __aenter__(self): - self._exit_stack = contextlib.AsyncExitStack() - self._background_task_group = anyio.create_task_group() - await self._exit_stack.enter_async_context(self._background_task_group) + async def __aenter__(self) -> "AsyncWebSocketSession": + async with contextlib.AsyncExitStack() as exit_stack: + self._send_event, self._receive_event = anyio.create_memory_object_stream[ + typing.Union[wsproto.events.Event, HTTPXWSException] + ]() + exit_stack.enter_context(self._send_event) + exit_stack.enter_context(self._receive_event) + + self._background_task_group = anyio.create_task_group() + await exit_stack.enter_async_context(self._background_task_group) - self._background_task_group.start_soon( - self._background_receive, self._max_message_size_bytes - ) - if self._keepalive_ping_interval_seconds is not None: self._background_task_group.start_soon( - self._background_keepalive_ping, - self._keepalive_ping_interval_seconds, - self._keepalive_ping_timeout_seconds, + self._background_receive, self._max_message_size_bytes ) + if self._keepalive_ping_interval_seconds is not None: + self._background_task_group.start_soon( + self._background_keepalive_ping, + self._keepalive_ping_interval_seconds, + self._keepalive_ping_timeout_seconds, + ) + + exit_stack.callback(self._background_task_group.cancel_scope.cancel) + exit_stack.push_async_callback(self.close) + self._exit_stack = exit_stack.pop_all() return self - async def __aexit__(self, exc_type, exc, tb): - await self.close() - self._background_task_group.cancel_scope.cancel() + async def __aexit__( + self, + exc_type: typing.Optional[typing.Type[BaseException]], + exc: typing.Optional[BaseException], + tb: typing.Optional[TracebackType], + ) -> None: await self._exit_stack.aclose() async def ping(self, payload: bytes = b"") -> anyio.Event: @@ -989,27 +1020,22 @@ except (httpcore.ReadError, httpcore.WriteError): await self.close(CloseReason.INTERNAL_ERROR, "Stream error") await self._send_event.send(WebSocketNetworkError()) - except anyio.get_cancelled_exc_class(): - pass async def _background_keepalive_ping( self, interval_seconds: float, timeout_seconds: typing.Optional[float] = None ) -> None: - try: - while not self._should_close.is_set(): - await anyio.sleep(interval_seconds) - pong_callback = await self.ping() - if timeout_seconds is not None: - try: - with anyio.fail_after(timeout_seconds): - await pong_callback.wait() - except TimeoutError: - await self.close( - CloseReason.INTERNAL_ERROR, "Keepalive ping timeout" - ) - await self._send_event.send(WebSocketNetworkError()) - except anyio.get_cancelled_exc_class(): - pass + while not self._should_close.is_set(): + await anyio.sleep(interval_seconds) + pong_callback = await self.ping() + if timeout_seconds is not None: + try: + with anyio.fail_after(timeout_seconds): + await pong_callback.wait() + except TimeoutError: + await self.close( + CloseReason.INTERNAL_ERROR, "Keepalive ping timeout" + ) + await self._send_event.send(WebSocketNetworkError()) def _get_headers( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/httpx_ws-0.6.0/httpx_ws/transport.py new/httpx_ws-0.6.2/httpx_ws/transport.py --- old/httpx_ws-0.6.0/httpx_ws/transport.py 2020-02-02 01:00:00.000000000 +0100 +++ new/httpx_ws-0.6.2/httpx_ws/transport.py 2020-02-02 01:00:00.000000000 +0100 @@ -48,7 +48,7 @@ self.portal = self.exit_stack.enter_context( anyio.from_thread.start_blocking_portal("asyncio") ) - _: "Future[None]" = self.portal.start_task_soon(self._run) + _: Future[None] = self.portal.start_task_soon(self._run) await self.send({"type": "websocket.connect"}) message = await self.receive() @@ -197,7 +197,7 @@ self.scope = scope self.exit_stack = contextlib.AsyncExitStack() stream, accept_response = await self.exit_stack.enter_async_context( - ASGIWebSocketAsyncNetworkStream(self.app, self.scope) + ASGIWebSocketAsyncNetworkStream(self.app, self.scope) # type: ignore[arg-type] ) accept_response_lines = accept_response.decode("utf-8").splitlines() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/httpx_ws-0.6.0/pyproject.toml new/httpx_ws-0.6.2/pyproject.toml --- old/httpx_ws-0.6.0/pyproject.toml 2020-02-02 01:00:00.000000000 +0100 +++ new/httpx_ws-0.6.2/pyproject.toml 2020-02-02 01:00:00.000000000 +0100 @@ -18,6 +18,7 @@ path = "httpx_ws/__init__.py" [tool.hatch.envs.default] +installer = "uv" dependencies = [ "mypy", "ruff", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/httpx_ws-0.6.0/setup.py new/httpx_ws-0.6.2/setup.py --- old/httpx_ws-0.6.0/setup.py 2020-02-02 01:00:00.000000000 +0100 +++ new/httpx_ws-0.6.2/setup.py 2020-02-02 01:00:00.000000000 +0100 @@ -3,9 +3,9 @@ setup( name='httpx-ws', - version='0.6.0', + version='0.6.2', description='WebSockets support for HTTPX', - long_description='# HTTPX WS\n\n<p align="center">\n <em>WebSockets support for HTTPX</em>\n</p>\n\n[](https://github.com/frankie567/httpx-ws/actions)\n[](https://codecov.io/gh/frankie567/httpx-ws)\n[](#contributors-)\n[](https://badge.fury.io/py/httpx-ws)\n[](https://pepy.tech/project/httpx-ws)\n\n<p align="center">\n<a href="https://polar.sh/frankie567">\n<picture>\n <source media="(prefers-color-scheme: dark)" srcset="https://polar.sh/embed/subscribe.svg?org=frankie567&darkmode=1">\n <img alt="Subscribe" src="https://polar.sh/embed/subscribe.svg?org=frankie567">\n</picture>\n</a>\n</p>\n\n---\n\n**Documentati on**: <a href="https://frankie567.github.io/httpx-ws/" target="_blank">https://frankie567.github.io/httpx-ws/</a>\n\n**Source Code**: <a href="https://github.com/frankie567/httpx-ws" target="_blank">https://github.com/frankie567/httpx-ws</a>\n\n---\n\n## Installation\n\n```bash\npip install httpx-ws\n```\n\n## Features\n\n* [X] Sync and async client\n* [X] Helper methods to send text, binary and JSON data\n* [X] Helper methods to receive text, binary and JSON data\n* [X] Automatic ping/pong answers\n* [X] HTTPX transport to test WebSockets defined in ASGI apps\n* [X] Automatic keepalive ping\n* [X] `asyncio` and [Trio](https://trio.readthedocs.io/) support through [AnyIO](https://anyio.readthedocs.io/)\n\n## Contributors â¨\n\nThanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->\n<!-- prettier-ignore-start -->\n<!-- markdownlint-disable -->\n<table>\n <tbod y>\n <tr>\n <td align="center" valign="top" width="14.28%"><a href="http://francoisvoron.com"><img src="https://avatars.githubusercontent.com/u/1144727?v=4?s=100" width="100px;" alt="François Voron"/><br /><sub><b>François Voron</b></sub></a><br /><a href="#maintenance-frankie567" title="Maintenance">ð§</a> <a href="https://github.com/frankie567/httpx-ws/commits?author=frankie567" title="Code">ð»</a></td>\n <td align="center" valign="top" width="14.28%"><a href="http://kousikmitra.github.io"><img src="https://avatars.githubusercontent.com/u/15109533?v=4?s=100" width="100px;" alt="Kousik Mitra"/><br /><sub><b>Kousik Mitra</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/commits?author=kousikmitra" title="Code">ð»</a></td>\n <td align="center" valign="top" width="14.28%"><a href="https://github.com/davidbrochart"><img src="https://avatars.githubusercontent.com/u/4711805?v=4?s=100" width="100px;" alt="David Brochart"/><br /><sub><b>David Broc hart</b></sub></a><br /><a href="#platform-davidbrochart" title="Packaging/porting to new platform">ð¦</a></td>\n <td align="center" valign="top" width="14.28%"><a href="https://github.com/ysmu"><img src="https://avatars.githubusercontent.com/u/17018576?v=4?s=100" width="100px;" alt="ysmu"/><br /><sub><b>ysmu</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3Aysmu" title="Bug reports">ð</a></td>\n <td align="center" valign="top" width="14.28%"><a href="https://samforeman.me"><img src="https://avatars.githubusercontent.com/u/5234251?v=4?s=100" width="100px;" alt="Sam Foreman"/><br /><sub><b>Sam Foreman</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3Asaforem2" title="Bug reports">ð</a></td>\n <td align="center" valign="top" width="14.28%"><a href="http://maparent.ca/"><img src="https://avatars.githubusercontent.com/u/202691?v=4?s=100" width="100px;" alt="Marc-Antoine Parent"/><br /><sub><b>Ma rc-Antoine Parent</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3Amaparent" title="Bug reports">ð</a> <a href="https://github.com/frankie567/httpx-ws/commits?author=maparent" title="Code">ð»</a></td>\n <td align="center" valign="top" width="14.28%"><a href="https://www.fastapiexpert.com/"><img src="https://avatars.githubusercontent.com/u/7353520?v=4?s=100" width="100px;" alt="Marcelo Trylesinski"/><br /><sub><b>Marcelo Trylesinski</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3AKludex" title="Bug reports">ð</a> <a href="#research-Kludex" title="Research">ð¬</a></td>\n </tr>\n <tr>\n <td align="center" valign="top" width="14.28%"><a href="https://lit.link/MtkN1"><img src="https://avatars.githubusercontent.com/u/51289448?v=4?s=100" width="100px;" alt="MtkN1"/><br /><sub><b>MtkN1</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3AMtkN1" title="Bug report s">ð</a> <a href="#research-MtkN1" title="Research">ð¬</a></td>\n <td align="center" valign="top" width="14.28%"><a href="http://www.tomchristie.com/"><img src="https://avatars.githubusercontent.com/u/647359?v=4?s=100" width="100px;" alt="Tom Christie"/><br /><sub><b>Tom Christie</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3Atomchristie" title="Bug reports">ð</a> <a href="#research-tomchristie" title="Research">ð¬</a></td>\n <td align="center" valign="top" width="14.28%"><a href="https://github.com/dmontagu"><img src="https://avatars.githubusercontent.com/u/35119617?v=4?s=100" width="100px;" alt="David Montague"/><br /><sub><b>David Montague</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3Admontagu" title="Bug reports">ð</a></td>\n <td align="center" valign="top" width="14.28%"><a href="https://github.com/WSH032"><img src="https://avatars.githubusercontent.com/u/126865849?v=4?s=100 " width="100px;" alt="Sean Wang"/><br /><sub><b>Sean Wang</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/commits?author=WSH032" title="Code">ð»</a></td>\n </tr>\n </tbody>\n</table>\n\n<!-- markdownlint-restore -->\n<!-- prettier-ignore-end -->\n\n<!-- ALL-CONTRIBUTORS-LIST:END -->\n\nThis project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!\n\n## Development\n\n### Setup environment\n\nWe use [Hatch](https://hatch.pypa.io/latest/install/) to manage the development environment and production build. Ensure it\'s installed on your system.\n\n### Run unit tests\n\nYou can run all the tests with:\n\n```bash\nhatch run test\n```\n\n### Format the code\n\nExecute the following command to apply linting and check typing:\n\n```bash\nhatch run lint\n```\n\n## License\n\nThis project is licensed under the terms of the MIT license.\n', + long_description='# HTTPX WS\n\n<p align="center">\n <em>WebSockets support for HTTPX</em>\n</p>\n\n[](https://github.com/frankie567/httpx-ws/actions)\n[](https://codecov.io/gh/frankie567/httpx-ws)\n[](#contributors-)\n[](https://badge.fury.io/py/httpx-ws)\n[](https://pepy.tech/project/httpx-ws)\n\n<p align="center">\n<a href="https://polar.sh/frankie567">\n<picture>\n <source media="(prefers-color-scheme: dark)" srcset="https://polar.sh/embed/subscribe.svg?org=frankie567&darkmode=1">\n <img alt="Subscribe" src="https://polar.sh/embed/subscribe.svg?org=frankie567">\n</picture>\n</a>\n</p>\n\n---\n\n**Documentati on**: <a href="https://frankie567.github.io/httpx-ws/" target="_blank">https://frankie567.github.io/httpx-ws/</a>\n\n**Source Code**: <a href="https://github.com/frankie567/httpx-ws" target="_blank">https://github.com/frankie567/httpx-ws</a>\n\n---\n\n## Installation\n\n```bash\npip install httpx-ws\n```\n\n## Features\n\n* [X] Sync and async client\n* [X] Helper methods to send text, binary and JSON data\n* [X] Helper methods to receive text, binary and JSON data\n* [X] Automatic ping/pong answers\n* [X] HTTPX transport to test WebSockets defined in ASGI apps\n* [X] Automatic keepalive ping\n* [X] `asyncio` and [Trio](https://trio.readthedocs.io/) support through [AnyIO](https://anyio.readthedocs.io/)\n\n## Contributors â¨\n\nThanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->\n<!-- prettier-ignore-start -->\n<!-- markdownlint-disable -->\n<table>\n <tbod y>\n <tr>\n <td align="center" valign="top" width="14.28%"><a href="http://francoisvoron.com"><img src="https://avatars.githubusercontent.com/u/1144727?v=4?s=100" width="100px;" alt="François Voron"/><br /><sub><b>François Voron</b></sub></a><br /><a href="#maintenance-frankie567" title="Maintenance">ð§</a> <a href="https://github.com/frankie567/httpx-ws/commits?author=frankie567" title="Code">ð»</a></td>\n <td align="center" valign="top" width="14.28%"><a href="http://kousikmitra.github.io"><img src="https://avatars.githubusercontent.com/u/15109533?v=4?s=100" width="100px;" alt="Kousik Mitra"/><br /><sub><b>Kousik Mitra</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/commits?author=kousikmitra" title="Code">ð»</a></td>\n <td align="center" valign="top" width="14.28%"><a href="https://github.com/davidbrochart"><img src="https://avatars.githubusercontent.com/u/4711805?v=4?s=100" width="100px;" alt="David Brochart"/><br /><sub><b>David Broc hart</b></sub></a><br /><a href="#platform-davidbrochart" title="Packaging/porting to new platform">ð¦</a> <a href="https://github.com/frankie567/httpx-ws/commits?author=davidbrochart" title="Code">ð»</a></td>\n <td align="center" valign="top" width="14.28%"><a href="https://github.com/ysmu"><img src="https://avatars.githubusercontent.com/u/17018576?v=4?s=100" width="100px;" alt="ysmu"/><br /><sub><b>ysmu</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3Aysmu" title="Bug reports">ð</a></td>\n <td align="center" valign="top" width="14.28%"><a href="https://samforeman.me"><img src="https://avatars.githubusercontent.com/u/5234251?v=4?s=100" width="100px;" alt="Sam Foreman"/><br /><sub><b>Sam Foreman</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3Asaforem2" title="Bug reports">ð</a></td>\n <td align="center" valign="top" width="14.28%"><a href="http://maparent.ca/"><img src="https://avatars. githubusercontent.com/u/202691?v=4?s=100" width="100px;" alt="Marc-Antoine Parent"/><br /><sub><b>Marc-Antoine Parent</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3Amaparent" title="Bug reports">ð</a> <a href="https://github.com/frankie567/httpx-ws/commits?author=maparent" title="Code">ð»</a></td>\n <td align="center" valign="top" width="14.28%"><a href="https://www.fastapiexpert.com/"><img src="https://avatars.githubusercontent.com/u/7353520?v=4?s=100" width="100px;" alt="Marcelo Trylesinski"/><br /><sub><b>Marcelo Trylesinski</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3AKludex" title="Bug reports">ð</a> <a href="#research-Kludex" title="Research">ð¬</a></td>\n </tr>\n <tr>\n <td align="center" valign="top" width="14.28%"><a href="https://lit.link/MtkN1"><img src="https://avatars.githubusercontent.com/u/51289448?v=4?s=100" width="100px;" alt="MtkN1"/><br /><sub><b>MtkN1</b></sub> </a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3AMtkN1" title="Bug reports">ð</a> <a href="#research-MtkN1" title="Research">ð¬</a></td>\n <td align="center" valign="top" width="14.28%"><a href="http://www.tomchristie.com/"><img src="https://avatars.githubusercontent.com/u/647359?v=4?s=100" width="100px;" alt="Tom Christie"/><br /><sub><b>Tom Christie</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3Atomchristie" title="Bug reports">ð</a> <a href="#research-tomchristie" title="Research">ð¬</a></td>\n <td align="center" valign="top" width="14.28%"><a href="https://github.com/dmontagu"><img src="https://avatars.githubusercontent.com/u/35119617?v=4?s=100" width="100px;" alt="David Montague"/><br /><sub><b>David Montague</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3Admontagu" title="Bug reports">ð</a></td>\n <td align="center" valign="top" width="14.28%"><a hr ef="https://github.com/WSH032"><img src="https://avatars.githubusercontent.com/u/126865849?v=4?s=100" width="100px;" alt="Sean Wang"/><br /><sub><b>Sean Wang</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/commits?author=WSH032" title="Code">ð»</a></td>\n <td align="center" valign="top" width="14.28%"><a href="https://github.com/agronholm"><img src="https://avatars.githubusercontent.com/u/130003?v=4?s=100" width="100px;" alt="Alex Grönholm"/><br /><sub><b>Alex Grönholm</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3Aagronholm" title="Bug reports">ð</a> <a href="https://github.com/frankie567/httpx-ws/commits?author=agronholm" title="Code">ð»</a></td>\n <td align="center" valign="top" width="14.28%"><a href="https://github.com/ro-oliveira95"><img src="https://avatars.githubusercontent.com/u/27009864?v=4?s=100" width="100px;" alt="Rodrigo de Oliveira Neto"/><br /><sub><b>Rodrigo de Oliveira Neto</b></sub></a><br /><a href="https://github.com/frankie567/httpx-ws/issues?q=author%3Aro-oliveira95" title="Bug reports">ð</a> <a href="https://github.com/frankie567/httpx-ws/commits?author=ro-oliveira95" title="Code">ð»</a></td>\n </tr>\n </tbody>\n</table>\n\n<!-- markdownlint-restore -->\n<!-- prettier-ignore-end -->\n\n<!-- ALL-CONTRIBUTORS-LIST:END -->\n\nThis project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!\n\n## Development\n\n### Setup environment\n\nWe use [Hatch](https://hatch.pypa.io/latest/install/) to manage the development environment and production build. Ensure it\'s installed on your system.\n\n### Run unit tests\n\nYou can run all the tests with:\n\n```bash\nhatch run test\n```\n\n### Format the code\n\nExecute the following command to apply linting and check typing:\n\n```bash\nhatch run lint\n```\n\n## License\n\nThis project is licensed under the terms of the MIT license.\n', author_email='François Voron <fvo...@gmail.com>', classifiers=[ 'Development Status :: 4 - Beta', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/httpx_ws-0.6.0/tests/test_api.py new/httpx_ws-0.6.2/tests/test_api.py --- old/httpx_ws-0.6.0/tests/test_api.py 2020-02-02 01:00:00.000000000 +0100 +++ new/httpx_ws-0.6.2/tests/test_api.py 2020-02-02 01:00:00.000000000 +0100 @@ -1,5 +1,6 @@ import contextlib import queue +import threading import time import typing from unittest.mock import MagicMock, call, patch @@ -330,8 +331,8 @@ @pytest.mark.parametrize( "full_message,send_method", [ - (b"A" * 1024 * 4, "send_bytes"), - ("A" * 1024 * 4, "send_text"), + pytest.param(b"A" * 1024 * 4, "send_bytes", id="bytes"), + pytest.param("A" * 1024 * 4, "send_text", id="text"), ], ) async def test_receive_oversized_message( @@ -780,24 +781,31 @@ @pytest.mark.anyio -async def test_send_close(server_factory: ServerFactoryFixture): +async def test_send_close( + server_factory: ServerFactoryFixture, on_receive_message: MagicMock +): async def websocket_endpoint(websocket: WebSocket): await websocket.accept() try: await websocket.receive_text() - except StarletteWebSocketDisconnect: - pass + except StarletteWebSocketDisconnect as e: + print(e) + on_receive_message(e.code, e.reason) with server_factory(websocket_endpoint) as socket: with httpx.Client(transport=httpx.HTTPTransport(uds=socket)) as client: - with connect_ws("http://socket/ws", client): - pass + with connect_ws("http://socket/ws", client) as ws: + ws.close(code=1001, reason="CLOSE_REASON") async with httpx.AsyncClient( transport=httpx.AsyncHTTPTransport(uds=socket) ) as aclient: - async with aconnect_ws("http://socket/ws", aclient): - pass + async with aconnect_ws("http://socket/ws", aclient) as aws: + await aws.close(code=1001, reason="CLOSE_REASON") + + on_receive_message.assert_has_calls( + [call(1001, "CLOSE_REASON"), call(1001, "CLOSE_REASON")] + ) @pytest.mark.anyio @@ -894,3 +902,35 @@ assert isinstance(aws.response, httpx.Response) assert aws.subprotocol == "custom_protocol" assert aws.response.headers["sec-websocket-protocol"] == aws.subprotocol + + +@pytest.mark.anyio +async def test_threads_wont_hang(server_factory: ServerFactoryFixture) -> None: + """ + Check that all threads spawned in WebSocketSession are properly terminated during + a series of messages exchange. This used to be the cause of a memory leak in the + connect_ws client, see https://github.com/frankie567/httpx-ws/issues/76. + """ + + async def websocket_endpoint(websocket: WebSocket) -> None: + await websocket.accept() + for _ in range(50): + await websocket.send_text("SERVER_MESSAGE") + await websocket.receive_text() + await websocket.close() + + with server_factory(websocket_endpoint) as socket: + with httpx.Client(transport=httpx.HTTPTransport(uds=socket)) as client: + initial_threads_count = threading.active_count() + with connect_ws( + "http://socket/ws", client, keepalive_ping_interval_seconds=None + ) as ws: + for _ in range(50): + ws.receive() + ws.send_text("CLIENT_MESSAGE") + time.sleep(0.1) # Let the websocket endpoint finish its handling. + threads_count = threading.active_count() + assert initial_threads_count + 2 == threads_count + time.sleep(0.1) + final_threads_count = threading.active_count() + assert initial_threads_count == final_threads_count