mirror of
https://github.com/python/cpython.git
synced 2025-07-29 14:15:07 +00:00
[3.13] gh-121723: Relax constraints on queue objects for logging.handlers.QueueHandler
. (GH-122154) (GH-122603)
(cherry picked from commit fb864c76cd
)
This commit is contained in:
parent
9f488f9358
commit
56435a88c4
4 changed files with 123 additions and 49 deletions
|
@ -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']
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue