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