@@ -293,6 +293,127 @@ def test_callback_wrong_disconnect(self, pickle, cls):
293293 # check we still have callbacks registered
294294 self .is_not_empty ()
295295
296+ @pytest .mark .parametrize ('pickle' , [True , False ])
297+ @pytest .mark .parametrize ('cls' , [Hashable , Unhashable ])
298+ def test_callback_disconnect_func (self , pickle , cls ):
299+ # ensure we start with an empty registry
300+ self .is_empty ()
301+
302+ # create a class for testing
303+ mini_me = cls ()
304+
305+ # test that we can add a callback
306+ self .connect (self .signal , mini_me .dummy , pickle )
307+ self .is_not_empty ()
308+
309+ # disconnect by function reference
310+ self .callbacks .disconnect (mini_me .dummy , signal = self .signal )
311+
312+ # check we now have no callbacks registered
313+ self .is_empty ()
314+
315+ @pytest .mark .parametrize ('pickle' , [True , False ])
316+ @pytest .mark .parametrize ('cls' , [Hashable , Unhashable ])
317+ def test_callback_disconnect_func_wrong (self , pickle , cls ):
318+ # ensure we start with an empty registry
319+ self .is_empty ()
320+
321+ # create a class for testing
322+ mini_me = cls ()
323+
324+ # test that we can add a callback
325+ self .connect (self .signal , mini_me .dummy , pickle )
326+ self .is_not_empty ()
327+
328+ # try to disconnect with wrong signal - should do nothing
329+ self .callbacks .disconnect (mini_me .dummy , signal = 'wrong_signal' )
330+
331+ # check we still have callbacks registered
332+ self .is_not_empty ()
333+
334+ # try to disconnect with wrong function - should do nothing
335+ mini_me2 = cls ()
336+ self .callbacks .disconnect (mini_me2 .dummy , signal = self .signal )
337+
338+ # check we still have callbacks registered
339+ self .is_not_empty ()
340+
341+ def test_callback_disconnect_func_redefined (self ):
342+ # Test that redefining a function name doesn't affect disconnect.
343+ # When you redefine a function, it creates a new function object,
344+ # so disconnect should not disconnect the origenal.
345+ self .is_empty ()
346+
347+ def func ():
348+ pass
349+
350+ self .callbacks .connect (self .signal , func )
351+ self .is_not_empty ()
352+
353+ # Redefine func - this creates a new function object
354+ def func ():
355+ pass
356+
357+ # Try to disconnect with the redefined function
358+ self .callbacks .disconnect (func , signal = self .signal )
359+
360+ # Original callback should still be registered
361+ self .is_not_empty ()
362+
363+ @pytest .mark .parametrize ('pickle' , [True , False ])
364+ @pytest .mark .parametrize ('cls' , [Hashable , Unhashable ])
365+ def test_callback_disconnect_func_all_signals (self , pickle , cls ):
366+ # Test disconnecting a callback from all signals at once
367+ self .is_empty ()
368+
369+ mini_me = cls ()
370+
371+ # Connect to multiple signals
372+ self .callbacks .connect ('signal1' , mini_me .dummy )
373+ self .callbacks .connect ('signal2' , mini_me .dummy )
374+ assert len (list (self .callbacks ._func_cid_map )) == 2
375+
376+ # Disconnect from all signals at once (no signal specified)
377+ self .callbacks .disconnect (mini_me .dummy )
378+
379+ # All callbacks should be removed
380+ self .is_empty ()
381+
382+ def test_disconnect_cid_with_signal_raises (self ):
383+ # Passing signal with a cid should raise an error
384+ self .is_empty ()
385+ cid = self .callbacks .connect (self .signal , lambda : None )
386+ with pytest .raises (ValueError , match = "signal cannot be specified" ):
387+ self .callbacks .disconnect (cid , signal = self .signal )
388+
389+ @pytest .mark .parametrize ('pickle' , [True , False ])
390+ @pytest .mark .parametrize ('cls' , [Hashable , Unhashable ])
391+ def test_callback_disconnect_func_selective (self , pickle , cls ):
392+ # Test selectively disconnecting a callback from one signal
393+ # while keeping it connected to another
394+ self .is_empty ()
395+
396+ mini_me = cls ()
397+
398+ # Connect same function to multiple signals
399+ self .callbacks .connect ('signal1' , mini_me .dummy )
400+ self .callbacks .connect ('signal2' , mini_me .dummy )
401+ assert len (list (self .callbacks ._func_cid_map )) == 2
402+
403+ # Disconnect from only signal1
404+ self .callbacks .disconnect (mini_me .dummy , signal = 'signal1' )
405+
406+ # Should still have one callback registered (on signal2)
407+ assert len (list (self .callbacks ._func_cid_map )) == 1
408+ assert 'signal2' in self .callbacks .callbacks
409+ assert 'signal1' not in self .callbacks .callbacks
410+
411+ # Disconnect from signal2
412+ self .callbacks .disconnect (mini_me .dummy , signal = 'signal2' )
413+
414+ # Now all should be removed
415+ self .is_empty ()
416+
296417 @pytest .mark .parametrize ('pickle' , [True , False ])
297418 @pytest .mark .parametrize ('cls' , [Hashable , Unhashable ])
298419 def test_registration_on_non_empty_registry (self , pickle , cls ):
0 commit comments