diff --git a/openlp/core/ui/media/systemplayer.py b/openlp/core/ui/media/systemplayer.py index a36ce445b..e632f9b7b 100644 --- a/openlp/core/ui/media/systemplayer.py +++ b/openlp/core/ui/media/systemplayer.py @@ -95,6 +95,16 @@ class SystemPlayer(MediaPlayer): mime_type_list.append(ext) log.info('MediaPlugin: %s extensions: %s', mime_type, ' '.join(extensions)) + def disconnect_slots(self, signal): + """ + Safely disconnect the slots from `signal` + """ + try: + signal.disconnect() + except TypeError: + # If disconnect() is called on a signal without slots, it throws a TypeError + pass + def setup(self, display): """ Set up the player widgets @@ -160,6 +170,7 @@ class SystemPlayer(MediaPlayer): if start_time > 0: self.seek(display, controller.media_info.start_time * 1000) self.volume(display, controller.media_info.volume) + self.disconnect_slots(display.media_player.durationChanged) display.media_player.durationChanged.connect(functools.partial(self.set_duration, controller)) self.set_state(MediaState.Playing, display) display.video_widget.raise_() diff --git a/tests/functional/openlp_core_ui_media/test_systemplayer.py b/tests/functional/openlp_core_ui_media/test_systemplayer.py index d1873d2df..2bac0089b 100644 --- a/tests/functional/openlp_core_ui_media/test_systemplayer.py +++ b/tests/functional/openlp_core_ui_media/test_systemplayer.py @@ -107,6 +107,22 @@ class TestSystemPlayer(TestCase): mocked_video_widget.hide.assert_called_once_with() self.assertTrue(player.has_own_widget) + def test_disconnect_slots(self): + """ + Test that we the disconnect slots method catches the TypeError + """ + # GIVEN: A SystemPlayer class and a signal that throws a TypeError + player = SystemPlayer(self) + mocked_signal = MagicMock() + mocked_signal.disconnect.side_effect = \ + TypeError('disconnect() failed between \'durationChanged\' and all its connections') + + # WHEN: disconnect_slots() is called + player.disconnect_slots(mocked_signal) + + # THEN: disconnect should have been called and the exception should have been ignored + mocked_signal.disconnect.assert_called_once_with() + def test_check_available(self): """ Test the check_available() method on SystemPlayer @@ -198,7 +214,8 @@ class TestSystemPlayer(TestCase): with patch.object(player, 'get_live_state') as mocked_get_live_state, \ patch.object(player, 'seek') as mocked_seek, \ patch.object(player, 'volume') as mocked_volume, \ - patch.object(player, 'set_state') as mocked_set_state: + patch.object(player, 'set_state') as mocked_set_state, \ + patch.object(player, 'disconnect_slots') as mocked_disconnect_slots: mocked_get_live_state.return_value = QtMultimedia.QMediaPlayer.PlayingState result = player.play(mocked_display) @@ -207,6 +224,7 @@ class TestSystemPlayer(TestCase): mocked_display.media_player.play.assert_called_once_with() mocked_seek.assert_called_once_with(mocked_display, 1000) mocked_volume.assert_called_once_with(mocked_display, 1) + mocked_disconnect_slots.assert_called_once_with(mocked_display.media_player.durationChanged) mocked_display.media_player.durationChanged.connect.assert_called_once_with('function') mocked_set_state.assert_called_once_with(MediaState.Playing, mocked_display) mocked_display.video_widget.raise_.assert_called_once_with()