Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-urllib3_1 for 
openSUSE:Factory checked in at 2023-05-25 23:52:08
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-urllib3_1 (Old)
 and      /work/SRC/openSUSE:Factory/.python-urllib3_1.new.1533 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-urllib3_1"

Thu May 25 23:52:08 2023 rev:3 rq:1088727 version:1.26.16

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-urllib3_1/python-urllib3_1.changes        
2023-05-23 14:53:34.642140196 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-urllib3_1.new.1533/python-urllib3_1.changes  
    2023-05-25 23:52:12.923497797 +0200
@@ -1,0 +2,9 @@
+Tue May 23 20:02:08 UTC 2023 - Dirk Müller <dmuel...@suse.com>
+
+- update to 1.26.16:
+  * Fixed thread-safety issue where accessing a ``PoolManager``
+    with many distinct origins would cause connection pools to
+    be closed while requests are in progress
+- drop support-fixed-ssl-shared_ciphers.patch (obsolete)
+
+-------------------------------------------------------------------

Old:
----
  support-fixed-ssl-shared_ciphers.patch
  urllib3-1.26.15.tar.gz

New:
----
  urllib3-1.26.16.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-urllib3_1.spec ++++++
--- /var/tmp/diff_new_pack.ZN1Gwg/_old  2023-05-25 23:52:13.435500803 +0200
+++ /var/tmp/diff_new_pack.ZN1Gwg/_new  2023-05-25 23:52:13.439500827 +0200
@@ -26,7 +26,7 @@
 %endif
 %{?sle15_python_module_pythons}
 Name:           python-urllib3_1%{psuffix}
-Version:        1.26.15
+Version:        1.26.16
 Release:        0
 Summary:        HTTP library with thread-safe connection pooling, file post, 
and more
 License:        MIT
@@ -36,8 +36,6 @@
 # PATCH-FIX-UPSTREAM remove_mock.patch gh#urllib3/urllib3#2108 mc...@suse.com
 # remove dependency on the external module mock
 Patch0:         remove_mock.patch
-# PATCH-FIX-OPENSUSE New Python versions fixed behaviour of ssl.shared_ciphers
-Patch1:         support-fixed-ssl-shared_ciphers.patch
 BuildRequires:  %{python_module base >= 3.7}
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  %{python_module six}

++++++ remove_mock.patch ++++++
--- /var/tmp/diff_new_pack.ZN1Gwg/_old  2023-05-25 23:52:13.483501085 +0200
+++ /var/tmp/diff_new_pack.ZN1Gwg/_new  2023-05-25 23:52:13.487501108 +0200
@@ -1,7 +1,7 @@
-Index: urllib3-1.26.10/docs/conf.py
+Index: urllib3-1.26.16/docs/conf.py
 ===================================================================
---- urllib3-1.26.10.orig/docs/conf.py
-+++ urllib3-1.26.10/docs/conf.py
+--- urllib3-1.26.16.orig/docs/conf.py
++++ urllib3-1.26.16/docs/conf.py
 @@ -14,7 +14,10 @@ sys.path.insert(0, root_path)
  # Mock some expensive/platform-specific modules so build will work.
  # (https://read-the-docs.readthedocs.io/en/latest/faq.html#\
@@ -14,10 +14,10 @@
  
  
  class MockModule(mock.Mock):
-Index: urllib3-1.26.10/test/contrib/test_pyopenssl.py
+Index: urllib3-1.26.16/test/contrib/test_pyopenssl.py
 ===================================================================
---- urllib3-1.26.10.orig/test/contrib/test_pyopenssl.py
-+++ urllib3-1.26.10/test/contrib/test_pyopenssl.py
+--- urllib3-1.26.16.orig/test/contrib/test_pyopenssl.py
++++ urllib3-1.26.16/test/contrib/test_pyopenssl.py
 @@ -1,7 +1,10 @@
  # -*- coding: utf-8 -*-
  import os
@@ -30,10 +30,10 @@
  import pytest
  
  try:
-Index: urllib3-1.26.10/test/contrib/test_pyopenssl_dependencies.py
+Index: urllib3-1.26.16/test/contrib/test_pyopenssl_dependencies.py
 ===================================================================
---- urllib3-1.26.10.orig/test/contrib/test_pyopenssl_dependencies.py
-+++ urllib3-1.26.10/test/contrib/test_pyopenssl_dependencies.py
+--- urllib3-1.26.16.orig/test/contrib/test_pyopenssl_dependencies.py
++++ urllib3-1.26.16/test/contrib/test_pyopenssl_dependencies.py
 @@ -1,6 +1,9 @@
  # -*- coding: utf-8 -*-
  import pytest
@@ -45,10 +45,10 @@
  
  try:
      from urllib3.contrib.pyopenssl import extract_from_urllib3, 
inject_into_urllib3
-Index: urllib3-1.26.10/test/test_connection.py
+Index: urllib3-1.26.16/test/test_connection.py
 ===================================================================
---- urllib3-1.26.10.orig/test/test_connection.py
-+++ urllib3-1.26.10/test/test_connection.py
+--- urllib3-1.26.16.orig/test/test_connection.py
++++ urllib3-1.26.16/test/test_connection.py
 @@ -1,6 +1,9 @@
  import datetime
  
@@ -60,10 +60,10 @@
  import pytest
  
  from urllib3.connection import RECENT_DATE, CertificateError, _match_hostname
-Index: urllib3-1.26.10/test/test_connectionpool.py
+Index: urllib3-1.26.16/test/test_connectionpool.py
 ===================================================================
---- urllib3-1.26.10.orig/test/test_connectionpool.py
-+++ urllib3-1.26.10/test/test_connectionpool.py
+--- urllib3-1.26.16.orig/test/test_connectionpool.py
++++ urllib3-1.26.16/test/test_connectionpool.py
 @@ -6,7 +6,10 @@ from ssl import SSLError as BaseSSLError
  from test import SHORT_TIMEOUT
  
@@ -76,10 +76,10 @@
  
  from dummyserver.server import DEFAULT_CA
  from urllib3._collections import HTTPHeaderDict
-Index: urllib3-1.26.10/test/test_queue_monkeypatch.py
+Index: urllib3-1.26.16/test/test_queue_monkeypatch.py
 ===================================================================
---- urllib3-1.26.10.orig/test/test_queue_monkeypatch.py
-+++ urllib3-1.26.10/test/test_queue_monkeypatch.py
+--- urllib3-1.26.16.orig/test/test_queue_monkeypatch.py
++++ urllib3-1.26.16/test/test_queue_monkeypatch.py
 @@ -1,6 +1,9 @@
  from __future__ import absolute_import
  
@@ -91,10 +91,10 @@
  import pytest
  
  from urllib3 import HTTPConnectionPool
-Index: urllib3-1.26.10/test/test_response.py
+Index: urllib3-1.26.16/test/test_response.py
 ===================================================================
---- urllib3-1.26.10.orig/test/test_response.py
-+++ urllib3-1.26.10/test/test_response.py
+--- urllib3-1.26.16.orig/test/test_response.py
++++ urllib3-1.26.16/test/test_response.py
 @@ -9,7 +9,10 @@ from base64 import b64decode
  from io import BufferedReader, BytesIO, TextIOWrapper
  from test import onlyBrotlipy
@@ -107,10 +107,10 @@
  import pytest
  import six
  
-Index: urllib3-1.26.10/test/test_retry.py
+Index: urllib3-1.26.16/test/test_retry.py
 ===================================================================
---- urllib3-1.26.10.orig/test/test_retry.py
-+++ urllib3-1.26.10/test/test_retry.py
+--- urllib3-1.26.16.orig/test/test_retry.py
++++ urllib3-1.26.16/test/test_retry.py
 @@ -1,6 +1,9 @@
  import warnings
  
@@ -122,10 +122,10 @@
  import pytest
  
  from urllib3.exceptions import (
-Index: urllib3-1.26.10/test/test_retry_deprecated.py
+Index: urllib3-1.26.16/test/test_retry_deprecated.py
 ===================================================================
---- urllib3-1.26.10.orig/test/test_retry_deprecated.py
-+++ urllib3-1.26.10/test/test_retry_deprecated.py
+--- urllib3-1.26.16.orig/test/test_retry_deprecated.py
++++ urllib3-1.26.16/test/test_retry_deprecated.py
 @@ -1,7 +1,10 @@
  # This is a copy-paste of test_retry.py with extra asserts about deprecated 
options. It will be removed for v2.
  import warnings
@@ -138,10 +138,10 @@
  import pytest
  
  from urllib3.exceptions import (
-Index: urllib3-1.26.10/test/test_ssl.py
+Index: urllib3-1.26.16/test/test_ssl.py
 ===================================================================
---- urllib3-1.26.10.orig/test/test_ssl.py
-+++ urllib3-1.26.10/test/test_ssl.py
+--- urllib3-1.26.16.orig/test/test_ssl.py
++++ urllib3-1.26.16/test/test_ssl.py
 @@ -1,6 +1,9 @@
  from test import notPyPy2
  
@@ -153,10 +153,10 @@
  import pytest
  
  from urllib3.exceptions import SNIMissingWarning
-Index: urllib3-1.26.10/test/test_ssltransport.py
+Index: urllib3-1.26.16/test/test_ssltransport.py
 ===================================================================
---- urllib3-1.26.10.orig/test/test_ssltransport.py
-+++ urllib3-1.26.10/test/test_ssltransport.py
+--- urllib3-1.26.16.orig/test/test_ssltransport.py
++++ urllib3-1.26.16/test/test_ssltransport.py
 @@ -4,7 +4,10 @@ import socket
  import ssl
  import sys
@@ -169,10 +169,10 @@
  import pytest
  
  from dummyserver.server import DEFAULT_CA, DEFAULT_CERTS
-Index: urllib3-1.26.10/test/test_util.py
+Index: urllib3-1.26.16/test/test_util.py
 ===================================================================
---- urllib3-1.26.10.orig/test/test_util.py
-+++ urllib3-1.26.10/test/test_util.py
+--- urllib3-1.26.16.orig/test/test_util.py
++++ urllib3-1.26.16/test/test_util.py
 @@ -9,7 +9,10 @@ from itertools import chain
  from test import notBrotlipy, onlyBrotlipy, onlyPy2, onlyPy3
  
@@ -185,10 +185,10 @@
  
  from urllib3 import add_stderr_logger, disable_warnings, util
  from urllib3.exceptions import (
-Index: urllib3-1.26.10/test/with_dummyserver/test_connectionpool.py
+Index: urllib3-1.26.16/test/with_dummyserver/test_connectionpool.py
 ===================================================================
---- urllib3-1.26.10.orig/test/with_dummyserver/test_connectionpool.py
-+++ urllib3-1.26.10/test/with_dummyserver/test_connectionpool.py
+--- urllib3-1.26.16.orig/test/with_dummyserver/test_connectionpool.py
++++ urllib3-1.26.16/test/with_dummyserver/test_connectionpool.py
 @@ -12,7 +12,10 @@ import warnings
  from test import LONG_TIMEOUT, SHORT_TIMEOUT, onlyPy2
  from threading import Event
@@ -201,10 +201,10 @@
  import pytest
  import six
  
-Index: urllib3-1.26.10/test/with_dummyserver/test_https.py
+Index: urllib3-1.26.16/test/with_dummyserver/test_https.py
 ===================================================================
---- urllib3-1.26.10.orig/test/with_dummyserver/test_https.py
-+++ urllib3-1.26.10/test/with_dummyserver/test_https.py
+--- urllib3-1.26.16.orig/test/with_dummyserver/test_https.py
++++ urllib3-1.26.16/test/with_dummyserver/test_https.py
 @@ -18,7 +18,10 @@ from test import (
      resolvesLocalhostFQDN,
  )
@@ -217,11 +217,11 @@
  import pytest
  import trustme
  
-Index: urllib3-1.26.10/test/with_dummyserver/test_socketlevel.py
+Index: urllib3-1.26.16/test/with_dummyserver/test_socketlevel.py
 ===================================================================
---- urllib3-1.26.10.orig/test/with_dummyserver/test_socketlevel.py
-+++ urllib3-1.26.10/test/with_dummyserver/test_socketlevel.py
-@@ -53,7 +53,10 @@ from test import (
+--- urllib3-1.26.16.orig/test/with_dummyserver/test_socketlevel.py
++++ urllib3-1.26.16/test/with_dummyserver/test_socketlevel.py
+@@ -54,7 +54,10 @@ from test import (
  )
  from threading import Event
  
@@ -233,11 +233,11 @@
  import pytest
  import trustme
  
-Index: urllib3-1.26.10/test/test_poolmanager.py
+Index: urllib3-1.26.16/test/test_poolmanager.py
 ===================================================================
---- urllib3-1.26.10.orig/test/test_poolmanager.py
-+++ urllib3-1.26.10/test/test_poolmanager.py
-@@ -2,7 +2,11 @@ import socket
+--- urllib3-1.26.16.orig/test/test_poolmanager.py
++++ urllib3-1.26.16/test/test_poolmanager.py
+@@ -3,7 +3,11 @@ import socket
  from test import resolvesLocalhostFQDN
  
  import pytest
@@ -249,8 +249,8 @@
 +    import mock
  
  from urllib3 import connection_from_url
- from urllib3.exceptions import ClosedPoolError, LocationValueError
-@@ -383,7 +387,7 @@ class TestPoolManager(object):
+ from urllib3.exceptions import LocationValueError
+@@ -361,7 +365,7 @@ class TestPoolManager(object):
              "http://[a::b%25zone]";,
          ],
      )

++++++ urllib3-1.26.15.tar.gz -> urllib3-1.26.16.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/urllib3-1.26.15/CHANGES.rst 
new/urllib3-1.26.16/CHANGES.rst
--- old/urllib3-1.26.15/CHANGES.rst     2023-03-11 00:57:45.000000000 +0100
+++ new/urllib3-1.26.16/CHANGES.rst     2023-05-23 12:51:05.000000000 +0200
@@ -1,6 +1,13 @@
 Changes
 =======
 
+1.26.16 (2023-05-23)
+--------------------
+
+* Fixed thread-safety issue where accessing a ``PoolManager`` with many 
distinct origins
+  would cause connection pools to be closed while requests are in progress 
(`#2954 <https://github.com/urllib3/urllib3/pull/2954>`_)
+
+
 1.26.15 (2023-03-10)
 --------------------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/urllib3-1.26.15/PKG-INFO new/urllib3-1.26.16/PKG-INFO
--- old/urllib3-1.26.15/PKG-INFO        2023-03-11 00:57:54.565305700 +0100
+++ new/urllib3-1.26.16/PKG-INFO        2023-05-23 12:51:13.747491400 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: urllib3
-Version: 1.26.15
+Version: 1.26.16
 Summary: HTTP library with thread-safe connection pooling, file post, and more.
 Home-page: https://urllib3.readthedocs.io/
 Author: Andrey Petrov
@@ -144,6 +144,13 @@
 Changes
 =======
 
+1.26.16 (2023-05-23)
+--------------------
+
+* Fixed thread-safety issue where accessing a ``PoolManager`` with many 
distinct origins
+  would cause connection pools to be closed while requests are in progress 
(`#2954 <https://github.com/urllib3/urllib3/pull/2954>`_)
+
+
 1.26.15 (2023-03-10)
 --------------------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/urllib3-1.26.15/docs/v2-roadmap.rst 
new/urllib3-1.26.16/docs/v2-roadmap.rst
--- old/urllib3-1.26.15/docs/v2-roadmap.rst     2023-03-11 00:57:45.000000000 
+0100
+++ new/urllib3-1.26.16/docs/v2-roadmap.rst     2023-05-23 12:51:05.000000000 
+0200
@@ -80,15 +80,15 @@
 available.
 
 
-**✨ Optimized for Python 3.6+**
+**✨ Optimized for Python 3.7+**
 --------------------------------
 
 In v2.0 we'll be specifically be targeting
-CPython 3.6+ and PyPy 7.0+ (compatible with CPython 3.6)
-and dropping support Python versions 2.7 and 3.5.
+CPython 3.7+ and PyPy 7.3.10+ (compatible with CPython 3.8)
+and dropping support Python versions 2.7 and 3.6.
 
 By dropping end-of-life Python versions we're able to optimize
-the codebase for Python 3.6+ by using new features to improve
+the codebase for Python 3.7+ by using new features to improve
 performance and reduce the amount of code that needs to be executed
 in order to support legacy versions.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/urllib3-1.26.15/src/urllib3/_version.py 
new/urllib3-1.26.16/src/urllib3/_version.py
--- old/urllib3-1.26.15/src/urllib3/_version.py 2023-03-11 00:57:45.000000000 
+0100
+++ new/urllib3-1.26.16/src/urllib3/_version.py 2023-05-23 12:51:05.000000000 
+0200
@@ -1,2 +1,2 @@
 # This file is protected via CODEOWNERS
-__version__ = "1.26.15"
+__version__ = "1.26.16"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/urllib3-1.26.15/src/urllib3/connectionpool.py 
new/urllib3-1.26.16/src/urllib3/connectionpool.py
--- old/urllib3-1.26.15/src/urllib3/connectionpool.py   2023-03-11 
00:57:45.000000000 +0100
+++ new/urllib3-1.26.16/src/urllib3/connectionpool.py   2023-05-23 
12:51:05.000000000 +0200
@@ -50,6 +50,13 @@
 from .util.url import _normalize_host as normalize_host
 from .util.url import get_host, parse_url
 
+try:  # Platform-specific: Python 3
+    import weakref
+
+    weakref_finalize = weakref.finalize
+except AttributeError:  # Platform-specific: Python 2
+    from .packages.backports.weakref_finalize import weakref_finalize
+
 xrange = six.moves.xrange
 
 log = logging.getLogger(__name__)
@@ -220,6 +227,16 @@
             self.conn_kw["proxy"] = self.proxy
             self.conn_kw["proxy_config"] = self.proxy_config
 
+        # Do not pass 'self' as callback to 'finalize'.
+        # Then the 'finalize' would keep an endless living (leak) to self.
+        # By just passing a reference to the pool allows the garbage collector
+        # to free self if nobody else has a reference to it.
+        pool = self.pool
+
+        # Close all the HTTPConnections in the pool before the
+        # HTTPConnectionPool object is garbage collected.
+        weakref_finalize(self, _close_pool_connections, pool)
+
     def _new_conn(self):
         """
         Return a fresh :class:`HTTPConnection`.
@@ -489,14 +506,8 @@
         # Disable access to the pool
         old_pool, self.pool = self.pool, None
 
-        try:
-            while True:
-                conn = old_pool.get(block=False)
-                if conn:
-                    conn.close()
-
-        except queue.Empty:
-            pass  # Done.
+        # Close all the HTTPConnections in the pool.
+        _close_pool_connections(old_pool)
 
     def is_same_host(self, url):
         """
@@ -1108,3 +1119,14 @@
     if host.startswith("[") and host.endswith("]"):
         host = host[1:-1]
     return host
+
+
+def _close_pool_connections(pool):
+    """Drains a queue of connections and closes each one."""
+    try:
+        while True:
+            conn = pool.get(block=False)
+            if conn:
+                conn.close()
+    except queue.Empty:
+        pass  # Done.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/urllib3-1.26.15/src/urllib3/packages/backports/weakref_finalize.py 
new/urllib3-1.26.16/src/urllib3/packages/backports/weakref_finalize.py
--- old/urllib3-1.26.15/src/urllib3/packages/backports/weakref_finalize.py      
1970-01-01 01:00:00.000000000 +0100
+++ new/urllib3-1.26.16/src/urllib3/packages/backports/weakref_finalize.py      
2023-05-23 12:51:05.000000000 +0200
@@ -0,0 +1,155 @@
+# -*- coding: utf-8 -*-
+"""
+backports.weakref_finalize
+~~~~~~~~~~~~~~~~~~
+
+Backports the Python 3 ``weakref.finalize`` method.
+"""
+from __future__ import absolute_import
+
+import itertools
+import sys
+from weakref import ref
+
+__all__ = ["weakref_finalize"]
+
+
+class weakref_finalize(object):
+    """Class for finalization of weakrefable objects
+    finalize(obj, func, *args, **kwargs) returns a callable finalizer
+    object which will be called when obj is garbage collected. The
+    first time the finalizer is called it evaluates func(*arg, **kwargs)
+    and returns the result. After this the finalizer is dead, and
+    calling it just returns None.
+    When the program exits any remaining finalizers for which the
+    atexit attribute is true will be run in reverse order of creation.
+    By default atexit is true.
+    """
+
+    # Finalizer objects don't have any state of their own.  They are
+    # just used as keys to lookup _Info objects in the registry.  This
+    # ensures that they cannot be part of a ref-cycle.
+
+    __slots__ = ()
+    _registry = {}
+    _shutdown = False
+    _index_iter = itertools.count()
+    _dirty = False
+    _registered_with_atexit = False
+
+    class _Info(object):
+        __slots__ = ("weakref", "func", "args", "kwargs", "atexit", "index")
+
+    def __init__(self, obj, func, *args, **kwargs):
+        if not self._registered_with_atexit:
+            # We may register the exit function more than once because
+            # of a thread race, but that is harmless
+            import atexit
+
+            atexit.register(self._exitfunc)
+            weakref_finalize._registered_with_atexit = True
+        info = self._Info()
+        info.weakref = ref(obj, self)
+        info.func = func
+        info.args = args
+        info.kwargs = kwargs or None
+        info.atexit = True
+        info.index = next(self._index_iter)
+        self._registry[self] = info
+        weakref_finalize._dirty = True
+
+    def __call__(self, _=None):
+        """If alive then mark as dead and return func(*args, **kwargs);
+        otherwise return None"""
+        info = self._registry.pop(self, None)
+        if info and not self._shutdown:
+            return info.func(*info.args, **(info.kwargs or {}))
+
+    def detach(self):
+        """If alive then mark as dead and return (obj, func, args, kwargs);
+        otherwise return None"""
+        info = self._registry.get(self)
+        obj = info and info.weakref()
+        if obj is not None and self._registry.pop(self, None):
+            return (obj, info.func, info.args, info.kwargs or {})
+
+    def peek(self):
+        """If alive then return (obj, func, args, kwargs);
+        otherwise return None"""
+        info = self._registry.get(self)
+        obj = info and info.weakref()
+        if obj is not None:
+            return (obj, info.func, info.args, info.kwargs or {})
+
+    @property
+    def alive(self):
+        """Whether finalizer is alive"""
+        return self in self._registry
+
+    @property
+    def atexit(self):
+        """Whether finalizer should be called at exit"""
+        info = self._registry.get(self)
+        return bool(info) and info.atexit
+
+    @atexit.setter
+    def atexit(self, value):
+        info = self._registry.get(self)
+        if info:
+            info.atexit = bool(value)
+
+    def __repr__(self):
+        info = self._registry.get(self)
+        obj = info and info.weakref()
+        if obj is None:
+            return "<%s object at %#x; dead>" % (type(self).__name__, id(self))
+        else:
+            return "<%s object at %#x; for %r at %#x>" % (
+                type(self).__name__,
+                id(self),
+                type(obj).__name__,
+                id(obj),
+            )
+
+    @classmethod
+    def _select_for_exit(cls):
+        # Return live finalizers marked for exit, oldest first
+        L = [(f, i) for (f, i) in cls._registry.items() if i.atexit]
+        L.sort(key=lambda item: item[1].index)
+        return [f for (f, i) in L]
+
+    @classmethod
+    def _exitfunc(cls):
+        # At shutdown invoke finalizers for which atexit is true.
+        # This is called once all other non-daemonic threads have been
+        # joined.
+        reenable_gc = False
+        try:
+            if cls._registry:
+                import gc
+
+                if gc.isenabled():
+                    reenable_gc = True
+                    gc.disable()
+                pending = None
+                while True:
+                    if pending is None or weakref_finalize._dirty:
+                        pending = cls._select_for_exit()
+                        weakref_finalize._dirty = False
+                    if not pending:
+                        break
+                    f = pending.pop()
+                    try:
+                        # gc is disabled, so (assuming no daemonic
+                        # threads) the following is the only line in
+                        # this function which might trigger creation
+                        # of a new finalizer
+                        f()
+                    except Exception:
+                        sys.excepthook(*sys.exc_info())
+                    assert f not in cls._registry
+        finally:
+            # prevent any more finalizers from executing during shutdown
+            weakref_finalize._shutdown = True
+            if reenable_gc:
+                gc.enable()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/urllib3-1.26.15/src/urllib3/poolmanager.py 
new/urllib3-1.26.16/src/urllib3/poolmanager.py
--- old/urllib3-1.26.15/src/urllib3/poolmanager.py      2023-03-11 
00:57:45.000000000 +0100
+++ new/urllib3-1.26.16/src/urllib3/poolmanager.py      2023-05-23 
12:51:05.000000000 +0200
@@ -171,7 +171,7 @@
     def __init__(self, num_pools=10, headers=None, **connection_pool_kw):
         RequestMethods.__init__(self, headers)
         self.connection_pool_kw = connection_pool_kw
-        self.pools = RecentlyUsedContainer(num_pools, dispose_func=lambda p: 
p.close())
+        self.pools = RecentlyUsedContainer(num_pools)
 
         # Locally set the pool classes and keys so other PoolManagers can
         # override them.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/urllib3-1.26.15/src/urllib3.egg-info/PKG-INFO 
new/urllib3-1.26.16/src/urllib3.egg-info/PKG-INFO
--- old/urllib3-1.26.15/src/urllib3.egg-info/PKG-INFO   2023-03-11 
00:57:54.000000000 +0100
+++ new/urllib3-1.26.16/src/urllib3.egg-info/PKG-INFO   2023-05-23 
12:51:13.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: urllib3
-Version: 1.26.15
+Version: 1.26.16
 Summary: HTTP library with thread-safe connection pooling, file post, and more.
 Home-page: https://urllib3.readthedocs.io/
 Author: Andrey Petrov
@@ -144,6 +144,13 @@
 Changes
 =======
 
+1.26.16 (2023-05-23)
+--------------------
+
+* Fixed thread-safety issue where accessing a ``PoolManager`` with many 
distinct origins
+  would cause connection pools to be closed while requests are in progress 
(`#2954 <https://github.com/urllib3/urllib3/pull/2954>`_)
+
+
 1.26.15 (2023-03-10)
 --------------------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/urllib3-1.26.15/src/urllib3.egg-info/SOURCES.txt 
new/urllib3-1.26.16/src/urllib3.egg-info/SOURCES.txt
--- old/urllib3-1.26.15/src/urllib3.egg-info/SOURCES.txt        2023-03-11 
00:57:54.000000000 +0100
+++ new/urllib3-1.26.16/src/urllib3.egg-info/SOURCES.txt        2023-05-23 
12:51:13.000000000 +0200
@@ -77,6 +77,7 @@
 src/urllib3/packages/six.py
 src/urllib3/packages/backports/__init__.py
 src/urllib3/packages/backports/makefile.py
+src/urllib3/packages/backports/weakref_finalize.py
 src/urllib3/util/__init__.py
 src/urllib3/util/connection.py
 src/urllib3/util/proxy.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/urllib3-1.26.15/test/test_poolmanager.py 
new/urllib3-1.26.16/test/test_poolmanager.py
--- old/urllib3-1.26.15/test/test_poolmanager.py        2023-03-11 
00:57:45.000000000 +0100
+++ new/urllib3-1.26.16/test/test_poolmanager.py        2023-05-23 
12:51:05.000000000 +0200
@@ -1,3 +1,4 @@
+import gc
 import socket
 from test import resolvesLocalhostFQDN
 
@@ -5,7 +6,7 @@
 from mock import patch
 
 from urllib3 import connection_from_url
-from urllib3.exceptions import ClosedPoolError, LocationValueError
+from urllib3.exceptions import LocationValueError
 from urllib3.poolmanager import PoolKey, PoolManager, key_fn_by_scheme
 from urllib3.util import retry, timeout
 
@@ -60,24 +61,12 @@
     def test_manager_clear(self):
         p = PoolManager(5)
 
-        conn_pool = p.connection_from_url("http://google.com";)
+        p.connection_from_url("http://google.com";)
         assert len(p.pools) == 1
 
-        conn = conn_pool._get_conn()
-
         p.clear()
         assert len(p.pools) == 0
 
-        with pytest.raises(ClosedPoolError):
-            conn_pool._get_conn()
-
-        conn_pool._put_conn(conn)
-
-        with pytest.raises(ClosedPoolError):
-            conn_pool._get_conn()
-
-        assert len(p.pools) == 0
-
     @pytest.mark.parametrize("url", ["http://@";, None])
     def test_nohost(self, url):
         p = PoolManager(5)
@@ -86,19 +75,8 @@
 
     def test_contextmanager(self):
         with PoolManager(1) as p:
-            conn_pool = p.connection_from_url("http://google.com";)
+            p.connection_from_url("http://google.com";)
             assert len(p.pools) == 1
-            conn = conn_pool._get_conn()
-
-        assert len(p.pools) == 0
-
-        with pytest.raises(ClosedPoolError):
-            conn_pool._get_conn()
-
-        conn_pool._put_conn(conn)
-
-        with pytest.raises(ClosedPoolError):
-            conn_pool._get_conn()
 
         assert len(p.pools) == 0
 
@@ -397,3 +375,30 @@
         conn.connect()
 
         assert create_connection.call_args[0][0] == ("a::b%zone", 80)
+
+    def test_thread_safty(self):
+        pool_manager = PoolManager(num_pools=2)
+
+        # thread 1 gets a pool for host x
+        pool_1 = pool_manager.connection_from_url("http://host_x:80/";)
+
+        # thread 2 gets a pool for host y
+        pool_2 = pool_manager.connection_from_url("http://host_y:80/";)
+
+        # thread 3 gets a pool for host z
+        pool_3 = pool_manager.connection_from_url("http://host_z:80";)
+
+        # None of the pools should be closed, since all of them are referenced.
+        assert pool_1.pool is not None
+        assert pool_2.pool is not None
+        assert pool_3.pool is not None
+
+        conn_queue = pool_1.pool
+        assert conn_queue.qsize() > 0
+
+        # thread 1 stops.
+        del pool_1
+        gc.collect()
+
+        # Connection should be closed, because reference to pool_1 is gone.
+        assert conn_queue.qsize() == 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/urllib3-1.26.15/test/test_ssltransport.py 
new/urllib3-1.26.16/test/test_ssltransport.py
--- old/urllib3-1.26.15/test/test_ssltransport.py       2023-03-11 
00:57:45.000000000 +0100
+++ new/urllib3-1.26.16/test/test_ssltransport.py       2023-05-23 
12:51:05.000000000 +0200
@@ -202,8 +202,11 @@
             assert ssock.selected_npn_protocol() is None
 
             shared_ciphers = ssock.shared_ciphers()
-            assert type(shared_ciphers) == list
-            assert len(shared_ciphers) > 0
+            # SSLContext.shared_ciphers() changed behavior completely in a 
patch version.
+            # See: https://github.com/python/cpython/issues/96931
+            assert shared_ciphers is None or (
+                type(shared_ciphers) is list and len(shared_ciphers) > 0
+            )
 
             assert ssock.compression() is None
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/urllib3-1.26.15/test/with_dummyserver/test_socketlevel.py 
new/urllib3-1.26.16/test/with_dummyserver/test_socketlevel.py
--- old/urllib3-1.26.15/test/with_dummyserver/test_socketlevel.py       
2023-03-11 00:57:45.000000000 +0100
+++ new/urllib3-1.26.16/test/with_dummyserver/test_socketlevel.py       
2023-05-23 12:51:05.000000000 +0200
@@ -1221,10 +1221,11 @@
             ssl_sock.close()
 
         self._start_server(socket_handler)
-        with HTTPSConnectionPool(self.host, self.port) as pool:
-            with pytest.raises(MaxRetryError) as cm:
-                pool.request("GET", "/", retries=0)
-            assert isinstance(cm.value.reason, SSLError)
+        with HTTPSConnectionPool(self.host, self.port, ca_certs=DEFAULT_CA) as 
pool:
+            with pytest.raises(
+                SSLError, match=r"(wrong version number|record overflow)"
+            ):
+                pool.request("GET", "/", retries=False)
 
     @notSecureTransport
     def test_ssl_read_timeout(self):

Reply via email to