-
-
Notifications
You must be signed in to change notification settings - Fork 31.8k
Python 3.12+ breaks backwards compatibility for logging QueueHandler with some Queue classes #119819
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
* wait for python/cpython#119819 * temporarily fix error in gdpy3: ``` Process ForkPoolWorker-246: Traceback (most recent call last): File "/usr/lib/python3.12/logging/config.py", line 581, in configure handler = self.configure_handler(handlers[name]) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3.12/logging/config.py", line 801, in configure_handler raise TypeError('Invalid queue specifier %r' % qspec) TypeError: Invalid queue specifier <AutoProxy[Queue] object, typeid 'Queue' at 0x7f43d2fee7e0> The above exception was the direct cause of the following exception: Traceback (most recent call last): File "/usr/lib/python3.12/multiprocessing/process.py", line 314, in _bootstrap self.run() File "/usr/lib/python3.12/multiprocessing/process.py", line 108, in run self._target(*self._args, **self._kwargs) File "/usr/lib/python3.12/multiprocessing/pool.py", line 109, in worker initializer(*initargs) File "/usr/lib/python3.12/site-packages/gdpy3/glogger.py", line 167, in __call__ logging.config.dictConfig(self.glogger_config) File "/usr/lib/python3.12/logging/config.py", line 914, in dictConfig dictConfigClass(config).configure() File "/usr/lib/python3.12/logging/config.py", line 588, in configure raise ValueError('Unable to configure handler ' ValueError: Unable to configure handler 'queue' ```
I'm not really sure about this but would it actually make sense to only check for protocol-based queues and not the actual types of queues? strictly speaking, we only need a queue-like interface right? If so, I can work on that one. |
After reading the codes above and this pull request, I tend to not check the queue or queue-like classes, as the main purpose of the code from lines 789 to 804 is to handle the special cases of Perhaps we can ask @vsajip for some advice. Is there anything else we should consider? |
Can you explain the use cases which require |
I have only used Using Python 3.12 on Linux, I change Sorry for leaking an example code with logging, because tests on Windows, and installing previous versions of Python, may take a lot of time. However, some information about using use a queue created with a manager to avoid some potential issues can be provided below after I searched:
|
Do you have an actual use case where you're running into problems? Or is it just a theoretical exercise? If an actual use case, please give details. |
Here is an actual use case,and quickly show the problem:
Then I will get errors from more and more ForkPoolWorker-XXX, XXX is an increasing number.
|
--- config.py 2024-05-31 10:16:24.905893630 +0800
+++ config.py-fix3.12 2024-05-31 13:18:07.223555882 +0800
@@ -786,8 +786,11 @@
# raise ValueError('No handlers specified for a QueueHandler')
if 'queue' in config:
from multiprocessing.queues import Queue as MPQueue
+ from multiprocessing.managers import BaseProxy as MPBaseProxy
qspec = config['queue']
- if not isinstance(qspec, (queue.Queue, MPQueue)):
+ print('============', isinstance(qspec, MPBaseProxy))
+ print(qspec, type(qspec))
+ if not isinstance(qspec, (queue.Queue, MPQueue, MPBaseProxy)): |
No, that's not the use case I meant. What I meant is, do you have a real problem where you have to use the proxy and can't use |
No. For me, using logging with |
And I think using the proxy "manager.Queue()" should not be excluded / droped, it was working fine before 3.12. import logging.config
import multiprocessing as mp
import asyncio
def main(i, qd):
print('%d. qspec dict: ' % i, qd)
config = {
'version': 1,
'handlers': {
'sink': {
'class': 'logging.handlers.QueueHandler',
'queue': qd,
},
},
'root': {
'handlers': ['sink'],
},
}
logging.config.dictConfig(config)
l = logging.getLogger()
s = l.handlers[0]
print('USE: ', id(s.queue), s.queue, type(s.queue))
print('------')
def get_mp_queue(manager=None, maxsize=None):
q = manager.Queue(maxsize)
print('GET: ', id(q), q)
return q
def get_asy_queue(maxsize=None):
q = asyncio.Queue(maxsize)
print('GET: ', id(q), q)
return q
if __name__ == '__main__':
m = mp.Manager()
main(1, {'()': get_mp_queue, 'manager': m, 'maxsize': 10})
main(2, {'()': m.Queue, 'maxsize': 20})
main(3, {'()': get_asy_queue, 'maxsize': 10}) # not async, so the user is responsible for his choice. Output:
|
Why should it not be excluded, since |
My 2 cents: one concrete use case I can imagine is when you want to pass that queue to a pool without using a global variable and a custom initializer. AFAIK, you need a manager-based queue since When I suggested the protocol-based approach, it was mostly to deal with the issue arising from the proxy interface because checking the runtime type would not help in that case. |
Except for the mentioned reasons, 1) some people may get errors when updating to py3.12 due to their previous code using proxy queue, 2) py3.12 excludes but doesn't completely exclude proxy queue (dict qspec), I don't have any other new reasons.
Yes, that's true and makes checking the type of proxy indeed tricky.
cpython/Lib/multiprocessing/managers.py Lines 1224 to 1225 in 367adc9
|
…ultiprocessing queue types.
Please check if the changes in the linked PR #120030 fix the problem reported.. |
…ultipr… (pythonGH-120030) (cherry picked from commit 99d945c) Co-authored-by: Vinay Sajip <[email protected]>
…ultipr… (pythonGH-120030) (cherry picked from commit 99d945c) Co-authored-by: Vinay Sajip <[email protected]>
…tiproc… (pythonGH-120090) (cherry picked from commit 983efcf) Co-authored-by: Vinay Sajip <[email protected]> pythongh-119819: Update logging configuration to support joinable multiprocessing manager queues.
…tiproc… (pythonGH-120090) pythongh-119819: Update logging configuration to support joinable multiprocessing manager queues.
…sing subprocess support (#120476) Skip tests that require multiprocessing subprocess support.
…processing subprocess support (pythonGH-120476) Skip tests that require multiprocessing subprocess support. (cherry picked from commit 92f6d40) Co-authored-by: Russell Keith-Magee <[email protected]>
…processing subprocess support (pythonGH-120476) Skip tests that require multiprocessing subprocess support. (cherry picked from commit 92f6d40) Co-authored-by: Russell Keith-Magee <[email protected]>
…iprocessing subprocess support (GH-120476) (#120531) gh-119819: Conditional skip of logging tests that require multiprocessing subprocess support (GH-120476) Skip tests that require multiprocessing subprocess support. (cherry picked from commit 92f6d40) Co-authored-by: Russell Keith-Magee <[email protected]>
…iprocessing subprocess support (GH-120476) (#120532) gh-119819: Conditional skip of logging tests that require multiprocessing subprocess support (GH-120476) Skip tests that require multiprocessing subprocess support. (cherry picked from commit 92f6d40) Co-authored-by: Russell Keith-Magee <[email protected]>
…processing subprocess support (python#120476) Skip tests that require multiprocessing subprocess support.
…tiproc… (pythonGH-120090) pythongh-119819: Update logging configuration to support joinable multiprocessing manager queues.
…processing subprocess support (python#120476) Skip tests that require multiprocessing subprocess support.
multiprocessing.Pool with spawn method breaks logging.handlers.QueueHandler configuration import logging
import logging.config
import multiprocessing
import time
def _init(q):
logging.config.dictConfig({
'version': 1,
'disable_existing_loggers': True,
'handlers': {'log_to_parent': {'class': 'logging.handlers.QueueHandler', 'queue': q}},
'root': {'handlers': ['log_to_parent'], 'level': 'DEBUG'}
})
logging.getLogger().info('log from child')
if __name__ == '__main__':
multiprocessing.set_start_method('spawn')
with multiprocessing.Manager() as manager:
# q = manager.Queue()
q = multiprocessing.Queue()
# listen for log messages from child processes
# ...
with multiprocessing.Pool(processes=1, maxtasksperchild=1, initializer=_init, initargs=(q,)) as pool:
time.sleep(1) got exception (when q = manager.Queue() or q = multiprocessing.Queue())
|
Not sure this is the same error - what exact version of 3.12 is in use? What happens with 3.13? |
it works on 3.12.3 |
…tiproc… (pythonGH-120090) pythongh-119819: Update logging configuration to support joinable multiprocessing manager queues.
…processing subprocess support (python#120476) Skip tests that require multiprocessing subprocess support.
…e multiprocessing subprocess support (python#120476) Skip tests that require multiprocessing subprocess support.
Bug report
Bug description:
Related bug: #111615
Related pull: #111638
Related codes:
cpython/Lib/logging/config.py
Lines 789 to 804 in bd0d97c
reproducible example using Python 3.12.3
error:
Queue classes to check for logging QueueHandler
<queue.Queue at 0x7fb86eeef170>
, works.<multiprocessing.queues.Queue at 0x7fb871790500>
, works.<AutoProxy[Queue] object, typeid 'Queue' at 0x7fb86ef4a840>
, broken.Its class is
multiprocessing.managers.AutoProxy[Queue]
, a subclass ofmultiprocessing.managers.BaseProxy
.<Queue at 0x7fb86f0be4e0 maxsize=0>
, broken.discuss: how to fix
Check all Queue classes mentioned above in
cpython/Lib/logging/config.py
Line 792 in bd0d97c
or just focus on handling special cases: str and dict, while leaving other cases un-checked (e.g., queue.Queue, multiprocessing.queues.Queue).
CPython versions tested on:
3.12
Operating systems tested on:
Linux
Linked PRs
The text was updated successfully, but these errors were encountered: