diff options
author | Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> | 2024-06-27 09:09:17 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-27 09:09:17 (GMT) |
commit | 9df7392ebad877fdaa3d6f1c1f1c7504a50efb72 (patch) | |
tree | 9287073ab600672982d8d1b6c992be066ab6524c | |
parent | c83997476f9bcb28af02296c3c74c1549dcd9f35 (diff) | |
download | cpython-9df7392ebad877fdaa3d6f1c1f1c7504a50efb72.zip cpython-9df7392ebad877fdaa3d6f1c1f1c7504a50efb72.tar.gz cpython-9df7392ebad877fdaa3d6f1c1f1c7504a50efb72.tar.bz2 |
[3.13] gh-120868: Fix breaking change in `logging.config` when using `QueueHandler` (GH-120872) (GH-121078)
(cherry picked from commit 7d9c68513d112823a9a6cdc7453b998b2c24eb4c)
-rw-r--r-- | Lib/logging/config.py | 53 | ||||
-rw-r--r-- | Lib/test/test_logging.py | 44 | ||||
-rw-r--r-- | Misc/ACKS | 1 |
3 files changed, 81 insertions, 17 deletions
diff --git a/Lib/logging/config.py b/Lib/logging/config.py index 9de84e5..3cc4c57 100644 --- a/Lib/logging/config.py +++ b/Lib/logging/config.py @@ -780,25 +780,44 @@ class DictConfigurator(BaseConfigurator): # 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 c78e76d..4223d10 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py @@ -3927,6 +3927,50 @@ class ConfigDictTest(BaseTest): 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 @@ -1315,6 +1315,7 @@ Hrvoje Nikšić Gregory Nofi Jesse Noller Bill Noon +Janek Nouvertné Stefan Norberg Tim Northover Joe Norton |