diff --git a/openlp/core/common/__init__.py b/openlp/core/common/__init__.py index 99e222041..b6d759f42 100644 --- a/openlp/core/common/__init__.py +++ b/openlp/core/common/__init__.py @@ -80,6 +80,7 @@ def extension_loader(glob_pattern, excluded_files=[]): extension_path = extension_path.relative_to(app_dir) if extension_path.name in excluded_files: continue + log.debug('Attempting to import %s', extension_path) module_name = path_to_module(extension_path) try: importlib.import_module(module_name) diff --git a/openlp/core/lib/pluginmanager.py b/openlp/core/lib/pluginmanager.py index d4a02f8c0..c82e26eec 100644 --- a/openlp/core/lib/pluginmanager.py +++ b/openlp/core/lib/pluginmanager.py @@ -71,7 +71,7 @@ class PluginManager(RegistryBase, LogMixin, RegistryProperties): """ Scan a directory for objects inheriting from the ``Plugin`` class. """ - glob_pattern = os.path.join('plugins', '*', '*plugin.py') + glob_pattern = os.path.join('plugins', '*', '[!.]*plugin.py') extension_loader(glob_pattern) plugin_classes = Plugin.__subclasses__() plugin_objects = [] diff --git a/openlp/core/ui/media/mediacontroller.py b/openlp/core/ui/media/mediacontroller.py index 10c384b0c..87d3a3063 100644 --- a/openlp/core/ui/media/mediacontroller.py +++ b/openlp/core/ui/media/mediacontroller.py @@ -181,7 +181,8 @@ class MediaController(RegistryBase, LogMixin, RegistryProperties): """ log.debug('_check_available_media_players') controller_dir = os.path.join('core', 'ui', 'media') - glob_pattern = os.path.join(controller_dir, '*player.py') + # Find all files that do not begin with '.' (lp:#1738047) and end with player.py + glob_pattern = os.path.join(controller_dir, '[!.]*player.py') extension_loader(glob_pattern, ['mediaplayer.py']) player_classes = MediaPlayer.__subclasses__() for player_class in player_classes: diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 29718e09a..875a48fdf 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -370,7 +370,7 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi :rtype: None """ self._service_path = file_path - self.main_window.set_service_modified(self.is_modified(), file_path.name) + self.set_modified(self.is_modified()) Settings().setValue('servicemanager/last file', file_path) if file_path and file_path.suffix == '.oszl': self._save_lite = True diff --git a/openlp/plugins/bibles/forms/bibleimportform.py b/openlp/plugins/bibles/forms/bibleimportform.py index 35dd82eeb..857c48f74 100644 --- a/openlp/plugins/bibles/forms/bibleimportform.py +++ b/openlp/plugins/bibles/forms/bibleimportform.py @@ -336,6 +336,7 @@ class BibleImportForm(OpenLPWizard): self.sword_layout.addWidget(self.sword_tab_widget) self.sword_disabled_label = QtWidgets.QLabel(self.sword_widget) self.sword_disabled_label.setObjectName('SwordDisabledLabel') + self.sword_disabled_label.setWordWrap(True) self.sword_layout.addWidget(self.sword_disabled_label) self.select_stack.addWidget(self.sword_widget) self.wordproject_widget = QtWidgets.QWidget(self.select_page) diff --git a/openlp/plugins/presentations/presentationplugin.py b/openlp/plugins/presentations/presentationplugin.py index a68a22176..c65971f11 100644 --- a/openlp/plugins/presentations/presentationplugin.py +++ b/openlp/plugins/presentations/presentationplugin.py @@ -129,7 +129,8 @@ class PresentationPlugin(Plugin): """ log.debug('check_pre_conditions') controller_dir = os.path.join('plugins', 'presentations', 'lib') - glob_pattern = os.path.join(controller_dir, '*controller.py') + # Find all files that do not begin with '.' (lp:#1738047) and end with controller.py + glob_pattern = os.path.join(controller_dir, '[!.]*controller.py') extension_loader(glob_pattern, ['presentationcontroller.py']) controller_classes = PresentationController.__subclasses__() for controller_class in controller_classes: diff --git a/tests/functional/openlp_core/test_app.py b/tests/functional/openlp_core/test_app.py index 6f5b05803..7878f6c71 100644 --- a/tests/functional/openlp_core/test_app.py +++ b/tests/functional/openlp_core/test_app.py @@ -310,7 +310,7 @@ class TestOpenLP(TestCase): # THEN: assert result is True, "The method should have returned True." - # self.assertFalse(self.openlp.main_window.isMinimized()) + # assert self.openlp.main_window.isMinimized() is False @patch('openlp.core.app.get_version') @patch('openlp.core.app.QtWidgets.QMessageBox.question') diff --git a/tests/functional/openlp_plugins/bibles/test_csvimport.py b/tests/functional/openlp_plugins/bibles/test_csvimport.py index 4d948f53b..7c47f3a80 100644 --- a/tests/functional/openlp_plugins/bibles/test_csvimport.py +++ b/tests/functional/openlp_plugins/bibles/test_csvimport.py @@ -64,9 +64,9 @@ class TestCSVImport(TestCase): CSVBible(mocked_manager, path='.', name='.', books_path=Path('books.csv'), verse_path=Path('verse.csv')) # THEN: The importer should be an instance of BibleImport - self.assertIsInstance(importer, BibleImport) - self.assertEqual(importer.books_path, Path('books.csv')) - self.assertEqual(importer.verses_path, Path('verse.csv')) + assert isinstance(importer, BibleImport) + assert importer.books_path == Path('books.csv') + assert importer.verses_path == Path('verse.csv') def test_book_namedtuple(self): """ @@ -77,10 +77,10 @@ class TestCSVImport(TestCase): result = Book('id', 'testament_id', 'name', 'abbreviation') # THEN: The attributes should match up with the data we used - self.assertEqual(result.id, 'id') - self.assertEqual(result.testament_id, 'testament_id') - self.assertEqual(result.name, 'name') - self.assertEqual(result.abbreviation, 'abbreviation') + assert result.id == 'id' + assert result.testament_id == 'testament_id' + assert result.name == 'name' + assert result.abbreviation == 'abbreviation' def test_verse_namedtuple(self): """ @@ -91,10 +91,10 @@ class TestCSVImport(TestCase): result = Verse('book_id_name', 'chapter_number', 'number', 'text') # THEN: The attributes should match up with the data we used - self.assertEqual(result.book_id_name, 'book_id_name') - self.assertEqual(result.chapter_number, 'chapter_number') - self.assertEqual(result.number, 'number') - self.assertEqual(result.text, 'text') + assert result.book_id_name == 'book_id_name' + assert result.chapter_number == 'chapter_number' + assert result.number == 'number' + assert result.text == 'text' def test_get_book_name_id(self): """ @@ -109,7 +109,7 @@ class TestCSVImport(TestCase): actual_result = CSVBible.get_book_name(name, books) # THEN: get_book_name() should return the book name associated with that id from the books dictionary - self.assertEqual(actual_result, expected_result) + assert actual_result == expected_result def test_get_book_name(self): """ @@ -124,7 +124,7 @@ class TestCSVImport(TestCase): actual_result = CSVBible.get_book_name(name, books) # THEN: get_book_name() should return the input - self.assertEqual(actual_result, expected_result) + assert actual_result == expected_result def test_parse_csv_file(self): """ @@ -144,8 +144,8 @@ class TestCSVImport(TestCase): result = CSVBible.parse_csv_file(Path('file.csv'), TestTuple) # THEN: A list of TestTuple instances with the parsed data should be returned - self.assertEqual(result, [TestTuple('1', 'Line 1', 'Data 1'), TestTuple('2', 'Line 2', 'Data 2'), - TestTuple('3', 'Line 3', 'Data 3')]) + assert result == [TestTuple('1', 'Line 1', 'Data 1'), TestTuple('2', 'Line 2', 'Data 2'), + TestTuple('3', 'Line 3', 'Data 3')] mocked_open.assert_called_once_with('r', encoding='utf-8', newline='') mocked_reader.assert_called_once_with(ANY, delimiter=',', quotechar='"') @@ -162,7 +162,7 @@ class TestCSVImport(TestCase): # THEN: A ValidationError should be raised with self.assertRaises(ValidationError) as context: CSVBible.parse_csv_file(Path('file.csv'), None) - self.assertEqual(context.exception.msg, 'Parsing "file.csv" failed') + assert context.exception.msg == 'Parsing "file.csv" failed' def test_parse_csv_file_csverror(self): """ @@ -178,7 +178,7 @@ class TestCSVImport(TestCase): # THEN: A ValidationError should be raised with self.assertRaises(ValidationError) as context: CSVBible.parse_csv_file(Path('file.csv'), None) - self.assertEqual(context.exception.msg, 'Parsing "file.csv" failed') + assert context.exception.msg == 'Parsing "file.csv" failed' def test_process_books_stopped_import(self): """ @@ -197,8 +197,8 @@ class TestCSVImport(TestCase): result = importer.process_books(['Book 1']) # THEN: increment_progress_bar should not be called and the return value should be an empty dictionary - self.assertFalse(importer.wizard.increment_progress_bar.called) - self.assertEqual(result, {}) + assert importer.wizard.increment_progress_bar.called is False + assert result == {} def test_process_books(self): """ @@ -222,9 +222,9 @@ class TestCSVImport(TestCase): # THEN: translate and find_and_create_book should have been called with both book names. # The returned data should be a dictionary with both song's id and names. - self.assertEqual(importer.find_and_create_book.mock_calls, - [call('1. Mosebog', 2, 10), call('2. Mosebog', 2, 10)]) - self.assertDictEqual(result, {1: '1. Mosebog', 2: '2. Mosebog'}) + assert importer.find_and_create_book.mock_calls == \ + [call('1. Mosebog', 2, 10), call('2. Mosebog', 2, 10)] + assert result == {1: '1. Mosebog', 2: '2. Mosebog'} def test_process_verses_stopped_import(self): """ @@ -244,8 +244,8 @@ class TestCSVImport(TestCase): result = importer.process_verses(['Dummy Verse'], []) # THEN: get_book_name should not be called and the return value should be None - self.assertFalse(importer.get_book_name.called) - self.assertIsNone(result) + assert importer.get_book_name.called is False + assert result is None def test_process_verses_successful(self): """ @@ -272,13 +272,13 @@ class TestCSVImport(TestCase): importer.process_verses(verses, books) # THEN: create_verse is called with the test data - self.assertEqual(importer.get_book_name.mock_calls, [call(1, books), call(1, books)]) + assert importer.get_book_name.mock_calls == [call(1, books), call(1, books)] importer.get_book.assert_called_once_with('1. Mosebog') - self.assertEqual(importer.session.commit.call_count, 2) - self.assertEqual(importer.create_verse.mock_calls, - [call('1', 1, 1, 'I Begyndelsen skabte Gud Himmelen og Jorden.'), - call('1', 1, 2, 'Og Jorden var øde og tom, og der var Mørke over Verdensdybet. ' - 'Men Guds Ånd svævede over Vandene.')]) + assert importer.session.commit.call_count == 2 + assert importer.create_verse.mock_calls == \ + [call('1', 1, 1, 'I Begyndelsen skabte Gud Himmelen og Jorden.'), + call('1', 1, 2, 'Og Jorden var øde og tom, og der var Mørke over Verdensdybet. ' + 'Men Guds Ånd svævede over Vandene.')] def test_do_import_invalid_language_id(self): """ @@ -296,7 +296,7 @@ class TestCSVImport(TestCase): # THEN: The False should be returned. importer.get_language.assert_called_once_with('Bible Name') - self.assertFalse(result) + assert result is False def test_do_import_success(self): """ @@ -320,11 +320,11 @@ class TestCSVImport(TestCase): # THEN: parse_csv_file should be called twice, # and True should be returned. - self.assertEqual(importer.parse_csv_file.mock_calls, - [call(Path('books.csv'), Book), call(Path('verses.csv'), Verse)]) + assert importer.parse_csv_file.mock_calls == \ + [call(Path('books.csv'), Book), call(Path('verses.csv'), Verse)] importer.process_books.assert_called_once_with(['Book 1']) importer.process_verses.assert_called_once_with(['Verse 1'], ['Book 1']) - self.assertTrue(result) + assert result is True def test_file_import(self): """ @@ -353,7 +353,7 @@ class TestCSVImport(TestCase): importer.do_import() # THEN: The create_verse() method should have been called with each verse in the file. - self.assertTrue(importer.create_verse.called) + assert importer.create_verse.called is True for verse_tag, verse_text in test_data['verses']: importer.create_verse.assert_any_call(importer.get_book().id, 1, verse_tag, verse_text) importer.create_book.assert_any_call('1. Mosebog', importer.get_book_ref_id_by_name(), 1) diff --git a/tests/functional/openlp_plugins/bibles/test_osisimport.py b/tests/functional/openlp_plugins/bibles/test_osisimport.py index 02c6c3654..8c1b26abb 100644 --- a/tests/functional/openlp_plugins/bibles/test_osisimport.py +++ b/tests/functional/openlp_plugins/bibles/test_osisimport.py @@ -67,7 +67,7 @@ class TestOsisImport(TestCase): importer = OSISBible(mocked_manager, path='.', name='.', file_path=None) # THEN: The importer should be an instance of BibleDB - self.assertIsInstance(importer, BibleDB) + assert isinstance(importer, BibleDB) def test_process_books_stop_import(self): """ @@ -82,7 +82,7 @@ class TestOsisImport(TestCase): importer.process_books(mocked_data) # THEN: find_and_create_book should not have been called - self.assertFalse(self.mocked_find_and_create_book.called) + assert self.mocked_find_and_create_book.called is False def test_process_books_completes(self): """ @@ -106,11 +106,9 @@ class TestOsisImport(TestCase): importer.process_books(mocked_data) # THEN: find_and_create_book and process_books should be called with the details from the mocked books - self.assertEqual(self.mocked_find_and_create_book.call_args_list, - [call('Name1', 2, 10), call('Name2', 2, 10)]) - self.assertEqual(mocked_process_chapters.call_args_list, - [call('db_book1', book1), call('db_book2', book2)]) - self.assertEqual(importer.session.commit.call_count, 2) + assert self.mocked_find_and_create_book.call_args_list == [call('Name1', 2, 10), call('Name2', 2, 10)] + assert mocked_process_chapters.call_args_list == [call('db_book1', book1), call('db_book2', book2)] + assert importer.session.commit.call_count == 2 def test_process_chapters_verse_in_chapter_verse_text(self): """ @@ -185,8 +183,8 @@ class TestOsisImport(TestCase): importer.process_chapters(test_book, [test_chapter]) # THEN: neither set_current_chapter or process_verse should have been called - self.assertFalse(mocked_set_current_chapter.called) - self.assertFalse(mocked_process_verse.called) + assert mocked_set_current_chapter.called is False + assert mocked_process_verse.called is False def test_process_chapters_milestones_chapter_sid(self): """ @@ -233,7 +231,7 @@ class TestOsisImport(TestCase): importer.process_chapters(test_book, [test_verse]) # THEN: process_verse should have been called with the test data - self.assertFalse(mocked_set_current_chapter.called) + assert mocked_set_current_chapter.called is False mocked_process_verse.assert_called_once_with(test_book, 0, test_verse, use_milestones=True) def test_process_verse_no_osis_id(self): @@ -252,7 +250,7 @@ class TestOsisImport(TestCase): importer.process_verse(test_book, 2, test_verse) # THEN: create_verse should not have been called - self.assertFalse(self.mocked_create_verse.called) + assert self.mocked_create_verse.called is False def test_process_verse_use_milestones_no_s_id(self): """ @@ -271,7 +269,7 @@ class TestOsisImport(TestCase): importer.process_verse(test_book, 2, test_verse) # THEN: create_verse should not have been called - self.assertFalse(self.mocked_create_verse.called) + assert self.mocked_create_verse.called is False def test_process_verse_use_milestones_no_tail(self): """ @@ -289,7 +287,7 @@ class TestOsisImport(TestCase): importer.process_verse(test_book, 2, test_verse, use_milestones=True) # THEN: create_verse should not have been called - self.assertFalse(self.mocked_create_verse.called) + assert self.mocked_create_verse.called is False def test_process_verse_use_milestones_success(self): """ @@ -327,7 +325,7 @@ class TestOsisImport(TestCase): importer.process_verse(test_book, 2, test_verse) # THEN: create_verse should not have been called - self.assertFalse(self.mocked_create_verse.called) + assert self.mocked_create_verse.called is False def test_process_verse_success(self): """ @@ -363,8 +361,8 @@ class TestOsisImport(TestCase): result = importer.do_import() # THEN: do_import should return False and get_language_id should have not been called - self.assertFalse(result) - self.assertFalse(mocked_language_id.called) + assert result is False + assert mocked_language_id.called is False def test_do_import_no_language(self): """ @@ -382,8 +380,8 @@ class TestOsisImport(TestCase): result = importer.do_import() # THEN: do_import should return False and process_books should have not been called - self.assertFalse(result) - self.assertFalse(mocked_process_books.called) + assert result is False + assert mocked_process_books.called is False def test_do_import_completes(self): """ @@ -401,7 +399,7 @@ class TestOsisImport(TestCase): result = importer.do_import() # THEN: do_import should return True - self.assertTrue(result) + assert result is True class TestOsisImportFileImports(TestCase): @@ -442,7 +440,7 @@ class TestOsisImportFileImports(TestCase): importer.do_import() # THEN: The create_verse() method should have been called with each verse in the file. - self.assertTrue(importer.create_verse.called) + assert importer.create_verse.called is True for verse_tag, verse_text in test_data['verses']: importer.create_verse.assert_any_call(importer.create_book().id, 1, verse_tag, verse_text) @@ -472,7 +470,7 @@ class TestOsisImportFileImports(TestCase): importer.do_import() # THEN: The create_verse() method should have been called with each verse in the file. - self.assertTrue(importer.create_verse.called) + assert importer.create_verse.called is True for verse_tag, verse_text in test_data['verses']: importer.create_verse.assert_any_call(importer.create_book().id, 1, verse_tag, verse_text) @@ -502,7 +500,7 @@ class TestOsisImportFileImports(TestCase): importer.do_import() # THEN: The create_verse() method should have been called with each verse in the file. - self.assertTrue(importer.create_verse.called) + assert importer.create_verse.called for verse_tag, verse_text in test_data['verses']: importer.create_verse.assert_any_call(importer.create_book().id, 1, verse_tag, verse_text) @@ -532,6 +530,6 @@ class TestOsisImportFileImports(TestCase): importer.do_import() # THEN: The create_verse() method should have been called with each verse in the file. - self.assertTrue(importer.create_verse.called) + assert importer.create_verse.called is True for verse_tag, verse_text in test_data['verses']: importer.create_verse.assert_any_call(importer.create_book().id, 1, verse_tag, verse_text) diff --git a/tests/functional/openlp_plugins/bibles/test_swordimport.py b/tests/functional/openlp_plugins/bibles/test_swordimport.py index 34e011498..3ca1cba87 100644 --- a/tests/functional/openlp_plugins/bibles/test_swordimport.py +++ b/tests/functional/openlp_plugins/bibles/test_swordimport.py @@ -67,7 +67,7 @@ class TestSwordImport(TestCase): importer = SwordBible(mocked_manager, path='.', name='.', file_path=None, sword_key='', sword_path='') # THEN: The importer should be an instance of BibleDB - self.assertIsInstance(importer, BibleDB) + assert isinstance(importer, BibleDB) @patch('openlp.plugins.bibles.lib.importers.sword.SwordBible.application') @patch('openlp.plugins.bibles.lib.importers.sword.modules') @@ -106,6 +106,6 @@ class TestSwordImport(TestCase): importer.do_import() # THEN: The create_verse() method should have been called with each verse in the file. - self.assertTrue(importer.create_verse.called) + assert importer.create_verse.called is True for verse_tag, verse_text in test_data['verses']: importer.create_verse.assert_any_call(importer.create_book().id, 1, int(verse_tag), verse_text) diff --git a/tests/functional/openlp_plugins/presentations/test_impresscontroller.py b/tests/functional/openlp_plugins/presentations/test_impresscontroller.py index f08e0b8ac..9e15a0c79 100644 --- a/tests/functional/openlp_plugins/presentations/test_impresscontroller.py +++ b/tests/functional/openlp_plugins/presentations/test_impresscontroller.py @@ -23,7 +23,7 @@ Functional tests to test the Impress class and related methods. """ from unittest import TestCase -from unittest.mock import MagicMock +from unittest.mock import MagicMock, patch import shutil from tempfile import mkdtemp @@ -72,6 +72,60 @@ class TestImpressController(TestCase, TestMixin): self.assertEqual('Impress', controller.name, 'The name of the presentation controller should be correct') + @patch('openlp.plugins.presentations.lib.impresscontroller.log') + def test_check_available(self, mocked_log): + """ + Test `ImpressController.check_available` on Windows + """ + # GIVEN: An instance of :class:`ImpressController` + controller = ImpressController(plugin=self.mock_plugin) + + # WHEN: `check_available` is called on Windows and `get_com_servicemanager` returns None + with patch('openlp.plugins.presentations.lib.impresscontroller.is_win', return_value=True), \ + patch.object(controller, 'get_com_servicemanager', return_value=None) as mocked_get_com_servicemanager: + result = controller.check_available() + + # THEN: `check_available` should return False + assert mocked_get_com_servicemanager.called is True + assert result is False + + @patch('openlp.plugins.presentations.lib.impresscontroller.log') + def test_check_available1(self, mocked_log): + """ + Test `ImpressController.check_available` on Windows + """ + # GIVEN: An instance of :class:`ImpressController` + controller = ImpressController(plugin=self.mock_plugin) + + # WHEN: `check_available` is called on Windows and `get_com_servicemanager` returns an object + mocked_com_object = MagicMock() + with patch('openlp.plugins.presentations.lib.impresscontroller.is_win', return_value=True), \ + patch.object(controller, 'get_com_servicemanager', return_value=mocked_com_object) \ + as mocked_get_com_servicemanager: + result = controller.check_available() + + # THEN: `check_available` should return True + assert mocked_get_com_servicemanager.called is True + assert result is True + + @patch('openlp.plugins.presentations.lib.impresscontroller.log') + @patch('openlp.plugins.presentations.lib.impresscontroller.is_win', return_value=False) + def test_check_available2(self, mocked_is_win, mocked_log): + """ + Test `ImpressController.check_available` when not on Windows + """ + # GIVEN: An instance of :class:`ImpressController` + controller = ImpressController(plugin=self.mock_plugin) + + # WHEN: `check_available` is called on Windows and `uno_available` is True + with patch('openlp.plugins.presentations.lib.impresscontroller.uno_available', True), \ + patch.object(controller, 'get_com_servicemanager') as mocked_get_com_servicemanager: + result = controller.check_available() + + # THEN: `check_available` should return True + assert mocked_get_com_servicemanager.called is False + assert result is True + class TestImpressDocument(TestCase): """