summaryrefslogtreecommitdiffstats
path: root/Lib/logging
diff options
context:
space:
mode:
authorBénédikt Tran <10796600+picnixz@users.noreply.github.com>2024-08-02 11:16:32 (GMT)
committerGitHub <noreply@github.com>2024-08-02 11:16:32 (GMT)
commitfb864c76cd5e450e789a7b4095832e118cc49a39 (patch)
treedf02db9e2ebdae479fb26f4f728e4110504d2d2a /Lib/logging
parentaddbb73927f55855dfcc62fd47b0018de8a814ed (diff)
downloadcpython-fb864c76cd5e450e789a7b4095832e118cc49a39.zip
cpython-fb864c76cd5e450e789a7b4095832e118cc49a39.tar.gz
cpython-fb864c76cd5e450e789a7b4095832e118cc49a39.tar.bz2
gh-121723: Relax constraints on queue objects for `logging.handlers.QueueHandler`. (GH-122154)
Diffstat (limited to 'Lib/logging')
-rw-r--r--Lib/logging/config.py55
1 files changed, 29 insertions, 26 deletions
diff --git a/Lib/logging/config.py b/Lib/logging/config.py
index 95e129a..3781cb1 100644
--- a/Lib/logging/config.py
+++ b/Lib/logging/config.py
@@ -497,6 +497,33 @@ class BaseConfigurator(object):
value = tuple(value)
return value
+def _is_queue_like_object(obj):
+ """Check that *obj* implements the Queue API."""
+ if isinstance(obj, queue.Queue):
+ return True
+ # defer importing multiprocessing as much as possible
+ from multiprocessing.queues import Queue as MPQueue
+ if isinstance(obj, MPQueue):
+ return True
+ # Depending on the multiprocessing start context, we cannot create
+ # a multiprocessing.managers.BaseManager instance 'mm' to get the
+ # runtime type of mm.Queue() or mm.JoinableQueue() (see gh-119819).
+ #
+ # Since we only need an object implementing the Queue API, we only
+ # do a protocol check, but we do not use typing.runtime_checkable()
+ # and typing.Protocol to reduce import time (see gh-121723).
+ #
+ # Ideally, we would have wanted to simply use strict type checking
+ # instead of a protocol-based type checking since the latter does
+ # not check the method signatures.
+ queue_interface = [
+ 'empty', 'full', 'get', 'get_nowait',
+ 'put', 'put_nowait', 'join', 'qsize',
+ 'task_done',
+ ]
+ return all(callable(getattr(obj, method, None))
+ for method in queue_interface)
+
class DictConfigurator(BaseConfigurator):
"""
Configure logging using a dictionary-like object to describe the
@@ -791,32 +818,8 @@ class DictConfigurator(BaseConfigurator):
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)
+ elif not _is_queue_like_object(qspec):
+ raise TypeError('Invalid queue specifier %r' % qspec)
if 'listener' in config:
lspec = config['listener']