8000 gh-120868: Fix breaking change in `logging.config` when using `QueueH… · miss-islington/cpython@a28b510 · GitHub
[go: up one dir, main page]

Skip to content

Commit a28b510

Browse files
provinzkrautmiss-islington
authored andcommitted
pythongh-120868: Fix breaking change in logging.config when using QueueHandler (pythonGH-120872)
(cherry picked from commit 7d9c685) Co-authored-by: Janek Nouvertné <provinzkraut@posteo.de>
1 parent 709ef00 commit a28b510

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
@@ -787,25 +787,44 @@ def configure_handler(self, config):
787787
# if 'handlers' not in config:
788788
# raise ValueError('No handlers specified for a QueueHandler')
789789
if 'queue' in config:
790-
from multiprocessing.queues import Queue as MPQueue
791-
from multiprocessing import Manager as MM
792-
proxy_queue = MM().Queue()
793-
proxy_joinable_queue = MM().JoinableQueue()
794790
qspec = config['queue']
795-
if not isinstance(qspec, (queue.Queue, MPQueue,
796-
type(proxy_queue), type(proxy_joinable_queue))):
797-
if isinstance(qspec, str):
798-
q = self.resolve(qspec)
799-
if not callable(q):
800-
raise TypeError('Invalid queue specifier %r' % qspec)
801-
q = q()
802-
elif isinstance(qspec, dict):
803-
if '()' not in qspec:
804-
raise TypeError('Invalid queue specifier %r' % qspec)
805-
q = self.configure_custom(dict(qspec))
806-
else:
791+
792+
if isinstance(qspec, str):
793+
q = self.resolve(qspec)
794+
if not callable(q):
807795
raise TypeError('Invalid queue specifier %r' % qspec)
808-
config['queue'] = q
796+
config['queue'] = q()
797+
elif isinstance(qspec, dict):
798+
if '()' not in qspec:
799+
raise TypeError('Invalid queue specifier %r' % qspec)
800+
config['queue'] = self.configure_custom(dict(qspec))
801+
else:
802+
from multiprocessing.queues import Queue as MPQueue
803+
804+
if not isinstance(qspec, (queue.Queue, MPQueue)):
805+
# Safely check if 'qspec' is an instance of Manager.Queue
806+
# / Manager.JoinableQueue
807+
808+
from multiprocessing import Manager as MM
809+
from multiprocessing.managers import BaseProxy
810+
811+
# if it's not an instance of BaseProxy, it also can't be
812+
# an instance of Manager.Queue / Manager.JoinableQueue
813+
if isinstance(qspec, BaseProxy):
814+
# Sometimes manager or queue creation might fail
815+
# (e.g. see issue gh-120868). In that case, any
816+
# exception during the creation of these queues will
817+
# propagate up to the caller and be wrapped in a
818+
# `ValueError`, whose cause will indicate the details of
819+
# the failure.
820+
mm = MM()
821+
proxy_queue = mm.Queue()
822+
proxy_joinable_queue = mm.JoinableQueue()
823+
if not isinstance(qspec, (type(proxy_queue), type(proxy_joinable_queue))):
824+
raise TypeError('Invalid queue specifier %r' % qspec)
825+
else:
826+
raise TypeError('Invalid queue specifier %r' % qspec)
827+
809828
if 'listener' in config:
810829
lspec = config['listener']
811830
if isinstance(lspec, type):

Lib/test/test_logging.py

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

3898+
@threading_helper.requires_working_threading()
3899+
@support.requires_subprocess()
3900+
@patch("multiprocessing.Manager")
3901+
def test_config_queue_handler_does_not_create_multiprocessing_manager(self, manager):
3902+
# gh-120868
3903+
3904+
from multiprocessing import Queue as MQ
3905+
3906+
q1 = {"()": "queue.Queue", "maxsize": -1}
3907+
q2 = MQ()
3908+
q3 = queue.Queue()
3909+
3910+
for qspec in (q1, q2, q3):
3911+
self.apply_config(
3912+
{
3913+
"version": 1,
3914+
"handlers": {
3915+
"queue_listener": {
3916+
"class": "logging.handlers.QueueHandler",
3917+
"queue": qspec,
3918+
},
3919+
},
3920+
}
3921+
)
3922+
manager.assert_not_called()
3923+
3924+
@patch("multiprocessing.Manager")
3925+
def test_config_queue_handler_invalid_config_does_not_create_multiprocessing_manager(self, manager):
3926+
# gh-120868
3927+
3928+
with self.assertRaises(ValueError):
3929+
self.apply_config(
3930+
{
3931+
"version": 1,
3932+
"handlers": {
3933+
"queue_listener": {
3934+
"class": "logging.handlers.QueueHandler",
3935+
"queue": object(),
3936+
},
3937+
},
3938+
}
3939+
)
3940+
manager.assert_not_called()
3941+
38983942
@support.requires_subprocess()
38993943
def test_multiprocessing_queues(self):
39003944
# See gh-119819

Misc/ACKS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1304,6 +1304,7 @@ Hrvoje Nikšić
13041304
Gregory Nofi
13051305
Jesse Noller
13061306
Bill Noon
1307+
Janek Nouvertné
13071308
Stefan Norberg
13081309
Tim Northover
13091310
Joe Norton

0 commit comments

Comments
 (0)
0