https://github.com/python/cpython/commit/9df7392ebad877fdaa3d6f1c1f1c7504a50efb72
commit: 9df7392ebad877fdaa3d6f1c1f1c7504a50efb72
branch: 3.13
author: Miss Islington (bot) <31488909+miss-isling...@users.noreply.github.com>
committer: vsajip <vinay_sa...@yahoo.co.uk>
date: 2024-06-27T10:09:17+01:00
summary:

[3.13] gh-120868: Fix breaking change in `logging.config` when using 
`QueueHandler` (GH-120872) (GH-121078)

(cherry picked from commit 7d9c68513d112823a9a6cdc7453b998b2c24eb4c)

files:
M Lib/logging/config.py
M Lib/test/test_logging.py
M Misc/ACKS

diff --git a/Lib/logging/config.py b/Lib/logging/config.py
index 9de84e527b18ac..3cc4c57dd8ef80 100644
--- a/Lib/logging/config.py
+++ b/Lib/logging/config.py
@@ -780,25 +780,44 @@ def configure_handler(self, config):
                 # if 'handlers' not in config:
                     # raise ValueError('No handlers specified for a 
QueueHandler')
                 if 'queue' in config:
-                    from multiprocessing.queues import Queue as MPQueue
-                    from multiprocessing import Manager as MM
-                    proxy_queue = MM().Queue()
-                    proxy_joinable_queue = MM().JoinableQueue()
                     qspec = config['queue']
-                    if not isinstance(qspec, (queue.Queue, MPQueue,
-                                      type(proxy_queue), 
type(proxy_joinable_queue))):
-                        if isinstance(qspec, str):
-                            q = self.resolve(qspec)
-                            if not callable(q):
-                                raise TypeError('Invalid queue specifier %r' % 
qspec)
-                            q = q()
-                        elif isinstance(qspec, dict):
-                            if '()' not in qspec:
-                                raise TypeError('Invalid queue specifier %r' % 
qspec)
-                            q = self.configure_custom(dict(qspec))
-                        else:
+
+                    if isinstance(qspec, str):
+                        q = self.resolve(qspec)
+                        if not callable(q):
                             raise TypeError('Invalid queue specifier %r' % 
qspec)
-                        config['queue'] = q
+                        config['queue'] = q()
+                    elif isinstance(qspec, dict):
+                        if '()' not in qspec:
+                            raise TypeError('Invalid queue specifier %r' % 
qspec)
+                        config['queue'] = self.configure_custom(dict(qspec))
+                    else:
+                        from multiprocessing.queues import Queue as MPQueue
+
+                        if not isinstance(qspec, (queue.Queue, MPQueue)):
+                            # Safely check if 'qspec' is an instance of 
Manager.Queue
+                            # / Manager.JoinableQueue
+
+                            from multiprocessing import Manager as MM
+                            from multiprocessing.managers import BaseProxy
+
+                            # if it's not an instance of BaseProxy, it also 
can't be
+                            # an instance of Manager.Queue / 
Manager.JoinableQueue
+                            if isinstance(qspec, BaseProxy):
+                                # Sometimes manager or queue creation might 
fail
+                                # (e.g. see issue gh-120868). In that case, any
+                                # exception during the creation of these 
queues will
+                                # propagate up to the caller and be wrapped in 
a
+                                # `ValueError`, whose cause will indicate the 
details of
+                                # the failure.
+                                mm = MM()
+                                proxy_queue = mm.Queue()
+                                proxy_joinable_queue = mm.JoinableQueue()
+                                if not isinstance(qspec, (type(proxy_queue), 
type(proxy_joinable_queue))):
+                                    raise TypeError('Invalid queue specifier 
%r' % qspec)
+                            else:
+                                raise TypeError('Invalid queue specifier %r' % 
qspec)
+
                 if 'listener' in config:
                     lspec = config['listener']
                     if isinstance(lspec, type):
diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py
index c78e76d16ae5cf..4223d10e79117c 100644
--- a/Lib/test/test_logging.py
+++ b/Lib/test/test_logging.py
@@ -3927,6 +3927,50 @@ def test_config_queue_handler(self):
             msg = str(ctx.exception)
             self.assertEqual(msg, "Unable to configure handler 'ah'")
 
+    @threading_helper.requires_working_threading()
+    @support.requires_subprocess()
+    @patch("multiprocessing.Manager")
+    def 
test_config_queue_handler_does_not_create_multiprocessing_manager(self, 
manager):
+        # gh-120868
+
+        from multiprocessing import Queue as MQ
+
+        q1 = {"()": "queue.Queue", "maxsize": -1}
+        q2 = MQ()
+        q3 = queue.Queue()
+
+        for qspec in (q1, q2, q3):
+            self.apply_config(
+                {
+                    "version": 1,
+                    "handlers": {
+                        "queue_listener": {
+                            "class": "logging.handlers.QueueHandler",
+                            "queue": qspec,
+                        },
+                    },
+                }
+            )
+            manager.assert_not_called()
+
+    @patch("multiprocessing.Manager")
+    def 
test_config_queue_handler_invalid_config_does_not_create_multiprocessing_manager(self,
 manager):
+        # gh-120868
+
+        with self.assertRaises(ValueError):
+            self.apply_config(
+                {
+                    "version": 1,
+                    "handlers": {
+                        "queue_listener": {
+                            "class": "logging.handlers.QueueHandler",
+                            "queue": object(),
+                        },
+                    },
+                }
+            )
+        manager.assert_not_called()
+
     @support.requires_subprocess()
     def test_multiprocessing_queues(self):
         # See gh-119819
diff --git a/Misc/ACKS b/Misc/ACKS
index e439f1945cf275..41ff4fe59aef0a 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1315,6 +1315,7 @@ Hrvoje Nikšić
 Gregory Nofi
 Jesse Noller
 Bill Noon
+Janek Nouvertné
 Stefan Norberg
 Tim Northover
 Joe Norton

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to