@@ -2377,16 +2377,22 @@ def __getattr__(self, attribute):
2377
2377
return getattr (queue , attribute )
2378
2378
2379
2379
class CustomQueueFakeProtocol (CustomQueueProtocol ):
2380
- # An object implementing the Queue API (incorrect signatures).
2380
+ # An object implementing the minimial Queue API for
2381
+ # the logging module but with incorrect signatures.
2382
+ #
2381
2383
# The object will be considered a valid queue class since we
2382
2384
# do not check the signatures (only callability of methods)
2383
2385
# but will NOT be usable in production since a TypeError will
2384
- # be raised due to a missing argument.
2385
- def empty (self , x ):
2386
+ # be raised due to the extra argument in 'put_nowait' .
2387
+ def put_nowait (self ):
2386
2388
pass
2387
2389
2388
2390
class CustomQueueWrongProtocol (CustomQueueProtocol ):
2389
- empty = None
2391
+ put_nowait = None
2392
+
2393
+ class MinimalQueueProtocol:
2394
+ def put_nowait (self , x ): pass
2395
+ def get (self ): pass
2390
2396
2391
2397
def queueMaker ():
2392
2398
return queue .Queue ()
@@ -3946,56 +3952,70 @@ def test_config_queue_handler(self):
3946
3952
msg = str (ctx .exception )
3947
3953
self .assertEqual (msg , "Unable to configure handler 'ah'" )
3948
3954
3955
+ def _apply_simple_queue_listener_configuration (self , qspec ):
3956
+ self .apply_config ({
3957
+ "version" : 1 ,
3958
+ "handlers" : {
3959
+ "queue_listener" : {
3960
+ "class" : "logging.handlers.QueueHandler" ,
3961
+ "queue" : qspec ,
3962
+ },
3963
+ },
3964
+ })
3965
+
3949
3966
@threading_helper .requires_working_threading ()
3950
3967
@support .requires_subprocess ()
3951
3968
@patch ("multiprocessing.Manager" )
3952
3969
def test_config_queue_handler_does_not_create_multiprocessing_manager (self , manager ):
3953
- # gh-120868, gh-121723
3954
-
3955
- from multiprocessing import Queue as MQ
3956
-
3957
- q1 = {"()" : "queue.Queue" , "maxsize" : - 1 }
3958
- q2 = MQ ()
3959
- q3 = queue .Queue ()
3960
- # CustomQueueFakeProtocol passes the checks but will not be usable
3961
- # since the signatures are incompatible. Checking the Queue API
3962
- # without testing the type of the actual queue is a trade-off
3963
- # between usability and the work we need to do in order to safely
3964
- # check that the queue object correctly implements the API.
3965
- q4 = CustomQueueFakeProtocol ()
3966
-
3967
- for qspec in (q1 , q2 , q3 , q4 ):
3968
- self .apply_config (
3969
- {
3970
- "version" : 1 ,
3971
- "handlers" : {
3972
- "queue_listener" : {
3973
- "class" : "logging.handlers.QueueHandler" ,
3974
- "queue" : qspec ,
3975
- },
3976
- },
3977
- }
3978
- )
3979
- manager .assert_not_called ()
3970
+ # gh-120868, gh-121723, gh-124653
3971
+
3972
+ for qspec in [
3973
+ {"()" : "queue.Queue" , "maxsize" : - 1 },
3974
+ queue .Queue (),
3975
+ # queue.SimpleQueue does not inherit from queue.Queue
3976
+ queue .SimpleQueue (),
3977
+ # CustomQueueFakeProtocol passes the checks but will not be usable
3978
+ # since the signatures are incompatible. Checking the Queue API
3979
+ # without testing the type of the actual queue is a trade-off
3980
+ # between usability and the work we need to do in order to safely
3981
+ # check that the queue object correctly implements the API.
3982
+ CustomQueueFakeProtocol (),
3983
+ MinimalQueueProtocol (),
3984
+ ]:
3985
+ with self .subTest (qspec = qspec ):
3986
+ self ._apply_simple_queue_listener_configuration (qspec )
3987
+ manager .assert_not_called ()
3980
3988
3981
3989
@patch ("multiprocessing.Manager" )
3982
3990
def test_config_queue_handler_invalid_config_does_not_create_multiprocessing_manager (self , manager ):
3983
3991
# gh-120868, gh-121723
3984
3992
3985
3993
for qspec in [object (), CustomQueueWrongProtocol ()]:
3986
- with self .assertRaises (ValueError ):
3987
- self .apply_config (
3988
- {
3989
- "version" : 1 ,
3990
- "handlers" : {
3991
- "queue_listener" : {
3992
- "class" : "logging.handlers.QueueHandler" ,
3993
- "queue" : qspec ,
3994
- },
3995
- },
3996
- }
3997
- )
3998
- manager .assert_not_called ()
3994
+ with self .subTest (qspec = qspec ), self .assertRaises (ValueError ):
3995
+ self ._apply_simple_queue_listener_configuration (qspec )
3996
+ manager .assert_not_called ()
3997
+
3998
+ @skip_if_tsan_fork
3999
+ @support .requires_subprocess ()
4000
+ @unittest .skipUnless (support .Py_DEBUG , "requires a debug build for testing"
4001
+ " assertions in multiprocessing" )
4002
+ def test_config_reject_simple_queue_handler_multiprocessing_context (self ):
4003
+ # multiprocessing.SimpleQueue does not implement 'put_nowait'
4004
+ # and thus cannot be used as a queue-like object (gh-124653)
4005
+
4006
+ import multiprocessing
4007
+
4008
+ if support .MS_WINDOWS :
4009
+ start_methods = ['spawn' ]
4010
+ else :
4011
+ start_methods = ['spawn' , 'fork' , 'forkserver' ]
4012
+
4013
+ for start_method in start_methods :
4014
+ with self .subTest (start_method = start_method ):
4015
+ ctx = multiprocessing .get_context (start_method )
4016
+ qspec = ctx .SimpleQueue ()
4017
+ with self .assertRaises (ValueError ):
4018
+ self ._apply_simple_queue_listener_configuration (qspec )
3999
4019
4000
4020
@skip_if_tsan_fork
4001
4021
@support .requires_subprocess ()
0 commit comments