@@ -2391,16 +2391,22 @@ def __getattr__(self, attribute):
2391
2391
return getattr (queue , attribute )
2392
2392
2393
2393
class CustomQueueFakeProtocol (CustomQueueProtocol ):
2394
- # An object implementing the Queue API (incorrect signatures).
2394
+ # An object implementing the minimial Queue API for
2395
+ # the logging module but with incorrect signatures.
2396
+ #
2395
2397
# The object will be considered a valid queue class since we
2396
2398
# do not check the signatures (only callability of methods)
2397
2399
# but will NOT be usable in production since a TypeError will
2398
- # be raised due to a missing argument.
2399
- def empty (self , x ):
2400
+ # be raised due to the extra argument in 'put_nowait' .
2401
+ def put_nowait (self ):
2400
2402
pass
2401
2403
2402
2404
class CustomQueueWrongProtocol (CustomQueueProtocol ):
2403
- empty = None
2405
+ put_nowait = None
2406
+
2407
+ class MinimalQueueProtocol :
2408
+ def put_nowait (self , x ): pass
2409
+ def get (self ): pass
2404
2410
2405
2411
def queueMaker ():
2406
2412
return queue .Queue ()
@@ -3914,56 +3920,70 @@ def test_config_queue_handler(self):
3914
3920
msg = str (ctx .exception )
3915
3921
self .assertEqual (msg , "Unable to configure handler 'ah'" )
3916
3922
3923
+ def _apply_simple_queue_listener_configuration (self , qspec ):
3924
+ self .apply_config ({
3925
+ "version" : 1 ,
3926
+ "handlers" : {
3927
+ "queue_listener" : {
3928
+ "class" : "logging.handlers.QueueHandler" ,
3929
+ "queue" : qspec ,
3930
+ },
3931
+ },
3932
+ })
3933
+
3917
3934
@threading_helper .requires_working_threading ()
3918
3935
@support .requires_subprocess ()
3919
3936
@patch ("multiprocessing.Manager" )
3920
3937
def test_config_queue_handler_does_not_create_multiprocessing_manager (self , manager ):
3921
- # gh-120868, gh-121723
3922
-
3923
- from multiprocessing import Queue as MQ
3924
-
3925
- q1 = {"()" : "queue.Queue" , "maxsize" : - 1 }
3926
- q2 = MQ ()
3927
- q3 = queue .Queue ()
3928
- # CustomQueueFakeProtocol passes the checks but will not be usable
3929
- # since the signatures are incompatible. Checking the Queue API
3930
- # without testing the type of the actual queue is a trade-off
3931
- # between usability and the work we need to do in order to safely
3932
- # check that the queue object correctly implements the API.
3933
- q4 = CustomQueueFakeProtocol ()
3934
-
3935
- for qspec in (q1 , q2 , q3 , q4 ):
3936
- self .apply_config (
3937
- {
3938
- "version" : 1 ,
3939
- "handlers" : {
3940
- "queue_listener" : {
3941
- "class" : "logging.handlers.QueueHandler" ,
3942
- "queue" : qspec ,
3943
- },
3944
- },
3945
- }
3946
- )
3947
- manager .assert_not_called ()
3938
+ # gh-120868, gh-121723, gh-124653
3939
+
3940
+ for qspec in [
3941
+ {"()" : "queue.Queue" , "maxsize" : - 1 },
3942
+ queue .Queue (),
3943
+ # queue.SimpleQueue does not inherit from queue.Queue
3944
+ queue .SimpleQueue (),
3945
+ # CustomQueueFakeProtocol passes the checks but will not be usable
3946
+ # since the signatures are incompatible. Checking the Queue API
3947
+ # without testing the type of the actual queue is a trade-off
3948
+ # between usability and the work we need to do in order to safely
3949
+ # check that the queue object correctly implements the API.
3950
+ CustomQueueFakeProtocol (),
3951
+ MinimalQueueProtocol (),
3952
+ ]:
3953
+ with self .subTest (qspec = qspec ):
3954
+ self ._apply_simple_queue_listener_configuration (qspec )
3955
+ manager .assert_not_called ()
3948
3956
3949
3957
@patch ("multiprocessing.Manager" )
3950
3958
def test_config_queue_handler_invalid_config_does_not_create_multiprocessing_manager (self , manager ):
3951
3959
# gh-120868, gh-121723
3952
3960
3953
3961
for qspec in [object (), CustomQueueWrongProtocol ()]:
3954
- with self .assertRaises (ValueError ):
3955
- self .apply_config (
3956
- {
3957
- "version" : 1 ,
3958
- "handlers" : {
3959
- "queue_listener" : {
3960
- "class" : "logging.handlers.QueueHandler" ,
3961
- "queue" : qspec ,
3962
- },
3963
- },
3964
- }
3965
- )
3966
- manager .assert_not_called ()
3962
+ with self .subTest (qspec = qspec ), self .assertRaises (ValueError ):
3963
+ self ._apply_simple_queue_listener_configuration (qspec )
3964
+ manager .assert_not_called ()
3965
+
3966
+ @skip_if_tsan_fork
3967
+ @support .requires_subprocess ()
3968
+ @unittest .skipUnless (support .Py_DEBUG , "requires a debug build for testing"
3969
+ " assertions in multiprocessing" )
3970
+ def test_config_reject_simple_queue_handler_multiprocessing_context (self ):
3971
+ # multiprocessing.SimpleQueue does not implement 'put_nowait'
3972
+ # and thus cannot be used as a queue-like object (gh-124653)
3973
+
3974
+ import multiprocessing
3975
+
3976
+ if support .MS_WINDOWS :
3977
+ start_methods = ['spawn' ]
3978
+ else :
3979
+ start_methods = ['spawn' , 'fork' , 'forkserver' ]
3980
+
3981
+ for start_method in start_methods :
3982
+ with self .subTest (start_method = start_method ):
3983
+ ctx = multiprocessing .get_context (start_method )
3984
+ qspec = ctx .SimpleQueue ()
3985
+ with self .assertRaises (ValueError ):
3986
+ self ._apply_simple_queue_listener_configuration (qspec )
3967
3987
3968
3988
@skip_if_tsan_fork
3969
3989
@support .requires_subprocess ()
0 commit comments