Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-geventhttpclient for
openSUSE:Factory checked in at 2026-03-23 17:15:11
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-geventhttpclient (Old)
and /work/SRC/openSUSE:Factory/.python-geventhttpclient.new.8177 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-geventhttpclient"
Mon Mar 23 17:15:11 2026 rev:15 rq:1342004 version:2.3.9
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-geventhttpclient/python-geventhttpclient.changes
2026-01-08 15:29:23.269953838 +0100
+++
/work/SRC/openSUSE:Factory/.python-geventhttpclient.new.8177/python-geventhttpclient.changes
2026-03-23 17:17:21.163617385 +0100
@@ -1,0 +2,10 @@
+Mon Mar 23 08:24:32 UTC 2026 - John Paul Adrian Glaubitz
<[email protected]>
+
+- Update to 2.3.9
+ * Use select() for socket validation with stdlib SSL support
+ by @devamsheth21 in (#240)
+- from version 2.3.8
+ * feat: Add connection validation to prevent stale connection
+ reuse by @devamsheth21 in (#238)
+
+-------------------------------------------------------------------
Old:
----
geventhttpclient-2.3.7.tar.gz
python-geventhttpclient-2.3.7.tar.gz
New:
----
geventhttpclient-2.3.9.tar.gz
python-geventhttpclient-2.3.9.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-geventhttpclient.spec ++++++
--- /var/tmp/diff_new_pack.WumvCn/_old 2026-03-23 17:17:21.719640509 +0100
+++ /var/tmp/diff_new_pack.WumvCn/_new 2026-03-23 17:17:21.719640509 +0100
@@ -18,7 +18,7 @@
%{?sle15_python_module_pythons}
Name: python-geventhttpclient
-Version: 2.3.7
+Version: 2.3.9
Release: 0
Summary: HTTP client library for gevent
License: MIT
++++++ geventhttpclient-2.3.7.tar.gz -> geventhttpclient-2.3.9.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/geventhttpclient-2.3.7/PKG-INFO
new/geventhttpclient-2.3.9/PKG-INFO
--- old/geventhttpclient-2.3.7/PKG-INFO 2025-12-07 20:15:19.205313700 +0100
+++ new/geventhttpclient-2.3.9/PKG-INFO 2026-03-03 08:35:11.159793900 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: geventhttpclient
-Version: 2.3.7
+Version: 2.3.9
Summary: HTTP client library for gevent
Author-email: Antonin Amand <[email protected]>
License-Expression: MIT
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/geventhttpclient-2.3.7/pyproject.toml
new/geventhttpclient-2.3.9/pyproject.toml
--- old/geventhttpclient-2.3.7/pyproject.toml 2025-12-07 20:15:13.000000000
+0100
+++ new/geventhttpclient-2.3.9/pyproject.toml 2026-03-03 08:35:03.000000000
+0100
@@ -5,7 +5,7 @@
[project]
name = "geventhttpclient"
-version = "2.3.7" # don't forget to update version __init__.py as well
+version = "2.3.9" # don't forget to update version __init__.py as well
description = "HTTP client library for gevent"
readme = "README.md"
requires-python = ">=3.9"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/geventhttpclient-2.3.7/src/geventhttpclient/__init__.py
new/geventhttpclient-2.3.9/src/geventhttpclient/__init__.py
--- old/geventhttpclient-2.3.7/src/geventhttpclient/__init__.py 2025-12-07
20:15:13.000000000 +0100
+++ new/geventhttpclient-2.3.9/src/geventhttpclient/__init__.py 2026-03-03
08:35:03.000000000 +0100
@@ -1,6 +1,6 @@
# package
-__version__ = "2.3.7" # don't forget to update version in pyproject.toml as
well
+__version__ = "2.3.9" # don't forget to update version in pyproject.toml as
well
from geventhttpclient.api import delete, get, head, options, patch, post, put,
request
from geventhttpclient.client import HTTPClient
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/geventhttpclient-2.3.7/src/geventhttpclient/connectionpool.py
new/geventhttpclient-2.3.9/src/geventhttpclient/connectionpool.py
--- old/geventhttpclient-2.3.7/src/geventhttpclient/connectionpool.py
2025-12-07 20:15:13.000000000 +0100
+++ new/geventhttpclient-2.3.9/src/geventhttpclient/connectionpool.py
2026-03-03 08:35:03.000000000 +0100
@@ -1,4 +1,6 @@
import os
+import socket
+import select
import gevent.queue
import gevent.socket
@@ -125,7 +127,7 @@
if first_error:
raise first_error
else:
- raise RuntimeError(f"Cannot resolve {self._host}:{self._port}")
+ raise RuntimeError(f"Cannot resolve
{self._connection_host}:{self._connection_port}")
def after_connect(self, sock):
pass
@@ -149,19 +151,57 @@
if not parts or parts[1] != b"200":
raise RuntimeError(f"Error response from Proxy server :
{resp}")
+ def _is_socket_alive(self, sock):
+ """Check if a socket is still connected and alive.
+
+ Uses select() to check if socket is readable. An idle keep-alive socket
+ should NOT be readable.
+
+ Returns False if connection is closed or broken.
+ """
+ if sock is None:
+ return False
+ try:
+ # Proactive check: A closed socket has a fileno of -1.
+ if sock.fileno() < 0:
+ return False
+ # If the socket is readable while idle, it's either a FIN or dirty.
+ ready_to_read, _, _ = select.select([sock], [], [], 0.0)
+ if ready_to_read:
+ return False
+
+ return True
+ except (OSError, ValueError, socket.error):
+ return False
+
def get_socket(self):
"""get a socket from the pool. This blocks until one is available."""
self._semaphore.acquire()
if self._closed:
raise RuntimeError("connection pool closed")
- try:
- return self._socket_queue.get(block=False)
- except gevent.queue.Empty:
+
+ # Try to get a valid connection from the pool
+ while not self._socket_queue.empty():
try:
- return self._create_socket()
- except: # noqa
- self._semaphore.release()
- raise
+ sock = self._socket_queue.get(block=False)
+ if self._is_socket_alive(sock):
+ # Connection is still alive, return it
+ return sock
+ else:
+ # Connection is dead, close it and try next
+ try:
+ sock.close()
+ except: # noqa
+ pass
+ except gevent.queue.Empty:
+ break
+
+ # No valid connections in pool, create a new one
+ try:
+ return self._create_socket()
+ except: # noqa
+ self._semaphore.release()
+ raise
def return_socket(self, sock):
"""return a socket to the pool."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/geventhttpclient-2.3.7/src/geventhttpclient.egg-info/PKG-INFO
new/geventhttpclient-2.3.9/src/geventhttpclient.egg-info/PKG-INFO
--- old/geventhttpclient-2.3.7/src/geventhttpclient.egg-info/PKG-INFO
2025-12-07 20:15:19.000000000 +0100
+++ new/geventhttpclient-2.3.9/src/geventhttpclient.egg-info/PKG-INFO
2026-03-03 08:35:11.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: geventhttpclient
-Version: 2.3.7
+Version: 2.3.9
Summary: HTTP client library for gevent
Author-email: Antonin Amand <[email protected]>
License-Expression: MIT
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/geventhttpclient-2.3.7/tests/test_client.py
new/geventhttpclient-2.3.9/tests/test_client.py
--- old/geventhttpclient-2.3.7/tests/test_client.py 2025-12-07
20:15:13.000000000 +0100
+++ new/geventhttpclient-2.3.9/tests/test_client.py 2026-03-03
08:35:03.000000000 +0100
@@ -1,4 +1,5 @@
import json
+import socket
import gevent.pool
import gevent.queue
@@ -7,6 +8,7 @@
from geventhttpclient import __version__
from geventhttpclient.client import METHOD_GET, HTTPClient
+from geventhttpclient.connectionpool import ConnectionPool
from tests.common import HTTPBIN_HOST, LISTENER, check_upload, server,
wsgiserver
@@ -350,3 +352,32 @@
assert count == 5
# ensure at least 3 of requests got 200
assert ok_count >= 3
+
+
+class TestIsSocketAlive:
+ """Unit tests for ConnectionPool._is_socket_alive()"""
+
+ def test_closed_socket_returns_false(self):
+ sock = socket.socket()
+ sock.close()
+ pool = ConnectionPool("127.0.0.1", 80, "127.0.0.1", 80)
+ assert sock.fileno() < 0
+ assert pool._is_socket_alive(sock) is False
+
+ def test_healthy_socket_returns_true(self):
+ s1, s2 = socket.socketpair()
+ try:
+ pool = ConnectionPool("127.0.0.1", 80, "127.0.0.1", 80)
+ assert pool._is_socket_alive(s1) is True
+ finally:
+ s1.close()
+ s2.close()
+
+ def test_peer_orderly_close_returns_false(self):
+ s1, s2 = socket.socketpair()
+ try:
+ s2.close()
+ pool = ConnectionPool("127.0.0.1", 80, "127.0.0.1", 80)
+ assert pool._is_socket_alive(s1) is False
+ finally:
+ s1.close()
++++++ python-geventhttpclient-2.3.7.tar.gz ->
python-geventhttpclient-2.3.9.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/geventhttpclient-2.3.7/.github/workflows/publish.yml
new/geventhttpclient-2.3.9/.github/workflows/publish.yml
--- old/geventhttpclient-2.3.7/.github/workflows/publish.yml 2025-12-07
19:55:26.000000000 +0100
+++ new/geventhttpclient-2.3.9/.github/workflows/publish.yml 2026-03-03
08:31:41.000000000 +0100
@@ -24,7 +24,9 @@
- uses: docker/setup-qemu-action@v3
if: ${{ matrix.os == 'ubuntu-latest' }}
name: Set up QEMU
- - run: pipx run cibuildwheel==3.3.0 --output-dir wheelhouse
+ - name: Install pipx
+ run: python -m pip install -U pipx
+ - run: pipx run cibuildwheel --output-dir wheelhouse
name: Run build wheel
env:
CIBW_ARCHS_MACOS: "x86_64 universal2 arm64"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/geventhttpclient-2.3.7/pyproject.toml
new/geventhttpclient-2.3.9/pyproject.toml
--- old/geventhttpclient-2.3.7/pyproject.toml 2025-12-07 19:55:26.000000000
+0100
+++ new/geventhttpclient-2.3.9/pyproject.toml 2026-03-03 08:31:41.000000000
+0100
@@ -5,7 +5,7 @@
[project]
name = "geventhttpclient"
-version = "2.3.7" # don't forget to update version __init__.py as well
+version = "2.3.9" # don't forget to update version __init__.py as well
description = "HTTP client library for gevent"
readme = "README.md"
requires-python = ">=3.9"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/geventhttpclient-2.3.7/release.md
new/geventhttpclient-2.3.9/release.md
--- old/geventhttpclient-2.3.7/release.md 2025-12-07 19:55:26.000000000
+0100
+++ new/geventhttpclient-2.3.9/release.md 2026-03-03 08:31:41.000000000
+0100
@@ -1,6 +1,6 @@
# Making new releases
-- Bump version in src/geventhttpclient/\__init__.py
-- Bump version in setup.py
+- Bump version in `src/geventhttpclient/__init__.py`
+- Bump version in `pyproject.toml`
- Make a GitHub release (which also makes a git tag)
- Trigger the publish action
https://github.com/geventhttpclient/geventhttpclient/actions/workflows/publish.yml
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/geventhttpclient-2.3.7/src/geventhttpclient/__init__.py
new/geventhttpclient-2.3.9/src/geventhttpclient/__init__.py
--- old/geventhttpclient-2.3.7/src/geventhttpclient/__init__.py 2025-12-07
19:55:26.000000000 +0100
+++ new/geventhttpclient-2.3.9/src/geventhttpclient/__init__.py 2026-03-03
08:31:41.000000000 +0100
@@ -1,6 +1,6 @@
# package
-__version__ = "2.3.7" # don't forget to update version in pyproject.toml as
well
+__version__ = "2.3.9" # don't forget to update version in pyproject.toml as
well
from geventhttpclient.api import delete, get, head, options, patch, post, put,
request
from geventhttpclient.client import HTTPClient
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/geventhttpclient-2.3.7/src/geventhttpclient/connectionpool.py
new/geventhttpclient-2.3.9/src/geventhttpclient/connectionpool.py
--- old/geventhttpclient-2.3.7/src/geventhttpclient/connectionpool.py
2025-12-07 19:55:26.000000000 +0100
+++ new/geventhttpclient-2.3.9/src/geventhttpclient/connectionpool.py
2026-03-03 08:31:41.000000000 +0100
@@ -1,4 +1,6 @@
import os
+import socket
+import select
import gevent.queue
import gevent.socket
@@ -125,7 +127,7 @@
if first_error:
raise first_error
else:
- raise RuntimeError(f"Cannot resolve {self._host}:{self._port}")
+ raise RuntimeError(f"Cannot resolve
{self._connection_host}:{self._connection_port}")
def after_connect(self, sock):
pass
@@ -149,19 +151,57 @@
if not parts or parts[1] != b"200":
raise RuntimeError(f"Error response from Proxy server :
{resp}")
+ def _is_socket_alive(self, sock):
+ """Check if a socket is still connected and alive.
+
+ Uses select() to check if socket is readable. An idle keep-alive socket
+ should NOT be readable.
+
+ Returns False if connection is closed or broken.
+ """
+ if sock is None:
+ return False
+ try:
+ # Proactive check: A closed socket has a fileno of -1.
+ if sock.fileno() < 0:
+ return False
+ # If the socket is readable while idle, it's either a FIN or dirty.
+ ready_to_read, _, _ = select.select([sock], [], [], 0.0)
+ if ready_to_read:
+ return False
+
+ return True
+ except (OSError, ValueError, socket.error):
+ return False
+
def get_socket(self):
"""get a socket from the pool. This blocks until one is available."""
self._semaphore.acquire()
if self._closed:
raise RuntimeError("connection pool closed")
- try:
- return self._socket_queue.get(block=False)
- except gevent.queue.Empty:
+
+ # Try to get a valid connection from the pool
+ while not self._socket_queue.empty():
try:
- return self._create_socket()
- except: # noqa
- self._semaphore.release()
- raise
+ sock = self._socket_queue.get(block=False)
+ if self._is_socket_alive(sock):
+ # Connection is still alive, return it
+ return sock
+ else:
+ # Connection is dead, close it and try next
+ try:
+ sock.close()
+ except: # noqa
+ pass
+ except gevent.queue.Empty:
+ break
+
+ # No valid connections in pool, create a new one
+ try:
+ return self._create_socket()
+ except: # noqa
+ self._semaphore.release()
+ raise
def return_socket(self, sock):
"""return a socket to the pool."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/geventhttpclient-2.3.7/tests/test_client.py
new/geventhttpclient-2.3.9/tests/test_client.py
--- old/geventhttpclient-2.3.7/tests/test_client.py 2025-12-07
19:55:26.000000000 +0100
+++ new/geventhttpclient-2.3.9/tests/test_client.py 2026-03-03
08:31:41.000000000 +0100
@@ -1,4 +1,5 @@
import json
+import socket
import gevent.pool
import gevent.queue
@@ -7,6 +8,7 @@
from geventhttpclient import __version__
from geventhttpclient.client import METHOD_GET, HTTPClient
+from geventhttpclient.connectionpool import ConnectionPool
from tests.common import HTTPBIN_HOST, LISTENER, check_upload, server,
wsgiserver
@@ -350,3 +352,32 @@
assert count == 5
# ensure at least 3 of requests got 200
assert ok_count >= 3
+
+
+class TestIsSocketAlive:
+ """Unit tests for ConnectionPool._is_socket_alive()"""
+
+ def test_closed_socket_returns_false(self):
+ sock = socket.socket()
+ sock.close()
+ pool = ConnectionPool("127.0.0.1", 80, "127.0.0.1", 80)
+ assert sock.fileno() < 0
+ assert pool._is_socket_alive(sock) is False
+
+ def test_healthy_socket_returns_true(self):
+ s1, s2 = socket.socketpair()
+ try:
+ pool = ConnectionPool("127.0.0.1", 80, "127.0.0.1", 80)
+ assert pool._is_socket_alive(s1) is True
+ finally:
+ s1.close()
+ s2.close()
+
+ def test_peer_orderly_close_returns_false(self):
+ s1, s2 = socket.socketpair()
+ try:
+ s2.close()
+ pool = ConnectionPool("127.0.0.1", 80, "127.0.0.1", 80)
+ assert pool._is_socket_alive(s1) is False
+ finally:
+ s1.close()