Skip to content

Commit 9df7392

Browse files
[3.13] gh-120868: Fix breaking change in logging.config when using QueueHandler (GH-120872) (GH-121078)
(cherry picked from commit 7d9c685)
1 parent c839974 commit 9df7392

File tree

3 files changed

+81
-17
lines changed

3 files changed

+81
-17
lines changed

Lib/logging/config.py

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -780,25 +780,44 @@ def configure_handler(self, config):
780780
# if 'handlers' not in config:
781781
# raise ValueError('No handlers specified for a QueueHandler')
782782
if 'queue' in config:
783-
from multiprocessing.queues import Queue as MPQueue
784-
from multiprocessing import Manager as MM
785-
proxy_queue = MM().Queue()
786-
proxy_joinable_queue = MM().JoinableQueue()
787783
qspec = config['queue']
788-
if not isinstance(qspec, (queue.Queue, MPQueue,
789-
type(proxy_queue), type(proxy_joinable_queue))):
790-
if isinstance(qspec, str):
791-
q = self.resolve(qspec)
792-
if not callable(q):
793-
raise TypeError('Invalid queue specifier %r' % qspec)
794-
q = q()
795-
elif isinstance(qspec, dict):
796-
if '()' not in qspec:
797-
raise TypeError('Invalid queue specifier %r' % qspec)
798-
q = self.configure_custom(dict(qspec))
799-
else:
784+
785+
if isinstance(qspec, str):
786+
q = self.resolve(qspec)
787+
if not callable(q):
800788
raise TypeError('Invalid queue specifier %r' % qspec)
801-
config['queue'] = q
789+
config['queue'] = q()
790+
elif isinstance(qspec, dict):
791+
if '()' not in qspec:
792+
raise TypeError('Invalid queue specifier %r' % qspec)
793+
config['queue'] = self.configure_custom(dict(qspec))
794+
else:
795+
from multiprocessing.queues import Queue as MPQueue
796+
797+
if not isinstance(qspec, (queue.Queue, MPQueue)):
798+
# Safely check if 'qspec' is an instance of Manager.Queue
799+
# / Manager.JoinableQueue
800+
801+
from multiprocessing import Manager as MM
802+
from multiprocessing.managers import BaseProxy
803+
804+
# if it's not an instance of BaseProxy, it also can't be
805+
# an instance of Manager.Queue / Manager.JoinableQueue
806+
if isinstance(qspec, BaseProxy):
807+
# Sometimes manager or queue creation might fail
808+
# (e.g. see issue gh-120868). In that case, any
809+
# exception during the creation of these queues will
810+
# propagate up to the caller and be wrapped in a
811+
# `ValueError`, whose cause will indicate the details of
812+
# the failure.
813+
mm = MM()
814+
proxy_queue = mm.Queue()
815+
proxy_joinable_queue = mm.JoinableQueue()
816+
if not isinstance(qspec, (type(proxy_queue), type(proxy_joinable_queue))):
817+
raise TypeError('Invalid queue specifier %r' % qspec)
818+
else:
819+
raise TypeError('Invalid queue specifier %r' % qspec)
820+
802821
if 'listener' in config:
803822
lspec = config['listener']
804823
if isinstance(lspec, type):

Lib/test/test_logging.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3927,6 +3927,50 @@ def test_config_queue_handler(self):
39273927
msg = str(ctx.exception)
39283928
self.assertEqual(msg, "Unable to configure handler 'ah'")
39293929

3930+
@threading_helper.requires_working_threading()
3931+
@support.requires_subprocess()
3932+
@patch("multiprocessing.Manager")
3933+
def test_config_queue_handler_does_not_create_multiprocessing_manager(self, manager):
3934+
# gh-120868
3935+
3936+
from multiprocessing import Queue as MQ
3937+
3938+
q1 = {"()": "queue.Queue", "maxsize": -1}
3939+
q2 = MQ()
3940+
q3 = queue.Queue()
3941+
3942+
for qspec in (q1, q2, q3):
3943+
self.apply_config(
3944+
{
3945+
"version": 1,
3946+
"handlers": {
3947+
"queue_listener": {
3948+
"class": "logging.handlers.QueueHandler",
3949+
"queue": qspec,
3950+
},
3951+
},
3952+
}
3953+
)
3954+
manager.assert_not_called()
3955+
3956+
@patch("multiprocessing.Manager")
3957+
def test_config_queue_handler_invalid_config_does_not_create_multiprocessing_manager(self, manager):
3958+
# gh-120868
3959+
3960+
with self.assertRaises(ValueError):
3961+
self.apply_config(
3962+
{
3963+
"version": 1,
3964+
"handlers": {
3965+
"queue_listener": {
3966+
"class": "logging.handlers.QueueHandler",
3967+
"queue": object(),
3968+
},
3969+
},
3970+
}
3971+
)
3972+
manager.assert_not_called()
3973+
39303974
@support.requires_subprocess()
39313975
def test_multiprocessing_queues(self):
39323976
# See gh-119819

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1315,6 +1315,7 @@ Hrvoje Nikšić
13151315
Gregory Nofi
13161316
Jesse Noller
13171317
Bill Noon
1318+
Janek Nouvertné
13181319
Stefan Norberg
13191320
Tim Northover
13201321
Joe Norton

0 commit comments

Comments
 (0)