@@ -624,14 +624,12 @@ def _impl_test_interactive_timers():
624
624
# NOTE: We run the timer tests in parallel to avoid longer sequential
625
625
# delays which adds to the testing time. Add new tests to one of
626
626
# the current event loop iterations if possible.
627
+ import time
627
628
from unittest .mock import Mock
628
629
import matplotlib .pyplot as plt
629
630
630
631
fig = plt .figure ()
631
- event_loop_time = 1 # in seconds
632
- expected_200ms_calls = int (event_loop_time / 0.2 )
633
-
634
- # Start at 2s interval (would only get one firing), then update to 200ms
632
+ # Start at 2s interval (wouldn't get any firings), then update to 100ms
635
633
timer_repeating = fig .canvas .new_timer (2000 )
636
634
mock_repeating = Mock ()
637
635
timer_repeating .add_callback (mock_repeating )
@@ -642,42 +640,55 @@ def _impl_test_interactive_timers():
642
640
643
641
timer_repeating .start ()
644
642
# Test updating the interval updates a running timer
645
- timer_repeating .interval = 200
643
+ timer_repeating .interval = 100
646
644
# Start as a repeating timer then change to singleshot via the attribute
647
645
timer_single_shot .start ()
648
646
timer_single_shot .single_shot = True
649
647
650
- fig .canvas .start_event_loop (event_loop_time )
651
- assert 1 < mock_repeating .call_count <= expected_200ms_calls + 1 , \
652
- f"Interval update: Expected between 2 and { expected_200ms_calls + 1 } calls, " \
653
- f"got { mock_repeating .call_count } "
648
+ fig .canvas .start_event_loop (0.5 )
649
+ assert 2 <= mock_repeating .call_count <= 5 , \
650
+ f"Interval update: Expected 2-5 calls, got { mock_repeating .call_count } "
654
651
assert mock_single_shot .call_count == 1 , \
655
652
f"Singleshot: Expected 1 call, got { mock_single_shot .call_count } "
656
653
657
- # 200ms timer triggers and the callback takes 100ms to run
658
- # Test that we don't drift and that we get called on every 200ms
659
- # interval and not every 300ms
660
- mock_repeating .side_effect = lambda : time .sleep (0.1 )
654
+ # 250ms timer triggers and the callback takes 150ms to run
655
+ # Test that we don't drift and that we get called on every 250ms
656
+ # firing and not every 400ms
657
+ timer_repeating .interval = 250
658
+ mock_repeating .side_effect = lambda : time .sleep (0.15 )
659
+ # calling start() again on a repeating timer should remove the old
660
+ # one, so we don't want double the number of calls here either because
661
+ # two timers are potentially running.
662
+ timer_repeating .start ()
661
663
mock_repeating .call_count = 0
662
664
# Make sure we can start the timer after stopping a singleshot timer
663
665
timer_single_shot .stop ()
664
666
timer_single_shot .start ()
665
667
668
+ event_loop_time = 2 # in seconds
669
+ expected_calls = int (event_loop_time / (timer_repeating .interval / 1000 ))
670
+
671
+ t_start = time .perf_counter ()
666
672
fig .canvas .start_event_loop (event_loop_time )
667
- # Not exact timers, so add a little slop. We really want to make sure we are
668
- # getting more than 3 (every 300ms).
669
- assert mock_repeating .call_count >= expected_200ms_calls - 1 , \
670
- f"Slow callback: Expected at least { expected_200ms_calls - 1 } calls, " \
673
+ t_loop = time .perf_counter () - t_start
674
+ # Should be around 2s, but allow for some slop on CI. We want to make sure
675
+ # we aren't getting 2 + (callback time) 0.5s/iteration, which would be 4+ s.
676
+ assert 1.8 < t_loop < 3 , \
677
+ f"Event loop: Expected to run for around 2s, but ran for { t_loop :.2f} s"
678
+ # Not exact timers, so add some slop. (Quite a bit for CI resources)
679
+ assert abs (mock_repeating .call_count - expected_calls ) <= 2 , \
680
+ f"Slow callback: Expected { expected_calls } calls, " \
671
681
f"got { mock_repeating .call_count } "
672
682
assert mock_single_shot .call_count == 2 , \
673
683
f"Singleshot: Expected 2 calls, got { mock_single_shot .call_count } "
674
- plt .close ("all" )
675
684
676
685
677
686
@pytest .mark .parametrize ("env" , _get_testable_interactive_backends ())
678
687
def test_interactive_timers (env ):
679
688
if env ["MPLBACKEND" ] == "wx" :
680
689
pytest .skip ("wx backend is deprecated; tests failed on appveyor" )
690
+ if env ["MPLBACKEND" ].startswith ("gtk3" ) and is_ci_environment ():
691
+ pytest .xfail ("GTK3 backend timer is slow on CI resources" )
681
692
_run_helper (_impl_test_interactive_timers ,
682
693
timeout = _test_timeout , extra_env = env )
683
694
0 commit comments