From 2f8b12934b8bcd90271cfe92c39104fa92257873 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Tue, 17 May 2016 22:28:27 +0100 Subject: [PATCH 01/62] fix theme display in servicemanager --- openlp/core/ui/servicemanager.py | 4 ++-- openlp/plugins/remotes/lib/httprouter.py | 16 +++++++++------- openlp/plugins/remotes/lib/httpserver.py | 1 - scripts/check_dependencies.py | 1 + 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index a59f94377..0e464f287 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -1324,8 +1324,8 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa The theme may have changed in the settings dialog so make sure the theme combo box is in the correct state. """ visible = not self.renderer.theme_level == ThemeLevel.Global - self.theme_label.setVisible(visible) - self.theme_combo_box.setVisible(visible) + self.toolbar.actions['theme_combo_box'].setVisible(visible) + self.toolbar.actions['theme_label'].setVisible(visible) def regenerate_service_items(self, changed=False): """ diff --git a/openlp/plugins/remotes/lib/httprouter.py b/openlp/plugins/remotes/lib/httprouter.py index d5e8cda1c..5d14a5637 100644 --- a/openlp/plugins/remotes/lib/httprouter.py +++ b/openlp/plugins/remotes/lib/httprouter.py @@ -221,9 +221,13 @@ class HttpRouter(RegistryProperties): self.request_data = None url_path_split = urlparse(url_path) url_query = parse_qs(url_path_split.query) - # GET - if 'data' in url_query.keys(): - self.request_data = url_query['data'][0] + # Get data from HTTP request + if self.command == 'GET': + if 'data' in url_query.keys(): + self.request_data = url_query['data'][0] + elif self.command == 'POST': + content_len = int(self.headers['content-length']) + self.request_data = self.rfile.read(content_len).decode("utf-8") for route, func in self.routes: match = re.match(route, url_path_split.path) if match: @@ -401,10 +405,8 @@ class HttpRouter(RegistryProperties): log.debug('serve file request %s' % file_name) if not file_name: file_name = 'index.html' - elif file_name == 'stage': - file_name = 'stage.html' - elif file_name == 'main': - file_name = 'main.html' + if '.' not in file_name: + file_name += '.html' if file_name.startswith('/'): file_name = file_name[1:] path = os.path.normpath(os.path.join(self.html_dir, file_name)) diff --git a/openlp/plugins/remotes/lib/httpserver.py b/openlp/plugins/remotes/lib/httpserver.py index 26f00c359..88d1097dc 100644 --- a/openlp/plugins/remotes/lib/httpserver.py +++ b/openlp/plugins/remotes/lib/httpserver.py @@ -167,7 +167,6 @@ class HTTPSServer(HTTPServer): local_data = AppLocation.get_directory(AppLocation.DataDir) self.socket = ssl.SSLSocket( sock=socket.socket(self.address_family, self.socket_type), - ssl_version=ssl.PROTOCOL_TLSv1_2, certfile=os.path.join(local_data, 'remotes', 'openlp.crt'), keyfile=os.path.join(local_data, 'remotes', 'openlp.key'), server_side=True) diff --git a/scripts/check_dependencies.py b/scripts/check_dependencies.py index e6f7d2c37..fb0d024ae 100755 --- a/scripts/check_dependencies.py +++ b/scripts/check_dependencies.py @@ -93,6 +93,7 @@ MODULES = [ 'bs4', 'mako', 'uno', + 'six' ] From 7c1e922f10961720111f40a65c3ea83c32994908 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Wed, 18 May 2016 18:06:25 +0100 Subject: [PATCH 02/62] pep8 --- openlp/core/ui/servicemanager.py | 1 - tests/functional/openlp_core_lib/test_lib.py | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 5b75aad63..35ec1bb9e 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -1328,7 +1328,6 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa self.toolbar.actions['theme_label'].setVisible(visible) self.regenerate_service_items() - def regenerate_service_items(self, changed=False): """ Rebuild the service list as things have changed and a repaint is the easiest way to do this. diff --git a/tests/functional/openlp_core_lib/test_lib.py b/tests/functional/openlp_core_lib/test_lib.py index c8493d005..d519837bf 100644 --- a/tests/functional/openlp_core_lib/test_lib.py +++ b/tests/functional/openlp_core_lib/test_lib.py @@ -431,7 +431,6 @@ class TestLib(TestCase): thumb_size = QtCore.QSize(-1, 100) expected_size_1 = QtCore.QSize(88, 88) expected_size_2 = QtCore.QSize(100, 100) - # Remove the thumb so that the test actually tests if the thumb will be created. Maybe it was not deleted in the # last test. @@ -458,7 +457,7 @@ class TestLib(TestCase): with patch('openlp.core.lib.QtGui.QImageReader.size') as mocked_size: mocked_size.return_value = QtCore.QSize(0, 0) icon = create_thumb(image_path, thumb_path, size=thumb_size) - + # THEN: Check if the thumb was created with aspect ratio of 1. self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon') self.assertFalse(icon.isNull(), 'The icon should not be null') From fd33d9a0c5ed31c4861b663fd5ad91370aab831c Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Wed, 18 May 2016 18:16:40 +0100 Subject: [PATCH 03/62] fixes --- .../openlp_plugins/remotes/test_router.py | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/functional/openlp_plugins/remotes/test_router.py b/tests/functional/openlp_plugins/remotes/test_router.py index 28af5f2c1..d1715ab8d 100644 --- a/tests/functional/openlp_plugins/remotes/test_router.py +++ b/tests/functional/openlp_plugins/remotes/test_router.py @@ -94,6 +94,7 @@ class TestRouter(TestCase, TestMixin): (r'^/stage/api/poll$', {'function': mocked_function, 'secure': False}), ] self.router.routes = test_route + self.router.command = 'GET' # WHEN: called with a poll route function, args = self.router.process_http_request('/stage/api/poll', None) @@ -121,6 +122,7 @@ class TestRouter(TestCase, TestMixin): self.router.send_header = MagicMock() self.router.end_headers = MagicMock() self.router.wfile = MagicMock() + self.router.command = 'GET' # WHEN: called with a poll route self.router.do_post_processor() @@ -211,6 +213,29 @@ class TestRouter(TestCase, TestMixin): self.router.send_header.assert_called_once_with('Content-type', 'text/html') self.assertEqual(self.router.end_headers.call_count, 1, 'end_headers called once') + def serve_file_with_partial_params_test(self): + """ + Test the serve_file method with an existing file + """ + # GIVEN: mocked environment + self.router.send_response = MagicMock() + self.router.send_header = MagicMock() + self.router.end_headers = MagicMock() + self.router.wfile = MagicMock() + self.router.html_dir = os.path.normpath('test/dir') + self.router.template_vars = MagicMock() + with patch('openlp.core.lib.os.path.exists') as mocked_exists, \ + patch('builtins.open', mock_open(read_data='123')): + mocked_exists.return_value = True + + # WHEN: call serve_file with an existing html file + self.router.serve_file(os.path.normpath('test/dir/test')) + + # THEN: it should return a 200 and the file + self.router.send_response.assert_called_once_with(200) + self.router.send_header.assert_called_once_with('Content-type', 'text/html') + self.assertEqual(self.router.end_headers.call_count, 1, 'end_headers called once') + def serve_thumbnail_without_params_test(self): """ Test the serve_thumbnail routine without params From 8507d3e26348c335ba4677564c0f1624ba8fffee Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Wed, 18 May 2016 18:25:16 +0100 Subject: [PATCH 04/62] fixes --- tests/functional/openlp_core_common/test_actions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/openlp_core_common/test_actions.py b/tests/functional/openlp_core_common/test_actions.py index 92f030df2..afdc89c34 100644 --- a/tests/functional/openlp_core_common/test_actions.py +++ b/tests/functional/openlp_core_common/test_actions.py @@ -118,7 +118,7 @@ class TestCategoryActionList(TestCase): # GIVEN: The list including two actions self.list.add(self.action1) self.list.add(self.action2) - + # WHEN: Iterating over the list l = [a for a in self.list] # THEN: Make sure they are returned in correct order From 3ae5240d157509915d42d68762d5aa8ffefbb761 Mon Sep 17 00:00:00 2001 From: Ian Knight Date: Thu, 19 May 2016 04:10:27 +0930 Subject: [PATCH 05/62] Implemented auto option & updated settings to use combo box --- openlp/core/common/settings.py | 2 +- openlp/core/ui/advancedtab.py | 27 ++++++++++++++++--------- openlp/core/ui/lib/listpreviewwidget.py | 23 ++++++++++++++------- 3 files changed, 35 insertions(+), 17 deletions(-) diff --git a/openlp/core/common/settings.py b/openlp/core/common/settings.py index 7bbd4349d..d4e114c74 100644 --- a/openlp/core/common/settings.py +++ b/openlp/core/common/settings.py @@ -129,7 +129,7 @@ class Settings(QtCore.QSettings): 'advanced/recent file count': 4, 'advanced/save current plugin': False, 'advanced/slide limits': SlideLimits.End, - 'advanced/slide max height': 0, + 'advanced/slide max height': -4, 'advanced/single click preview': False, 'advanced/single click service preview': False, 'advanced/x11 bypass wm': X11_BYPASS_DEFAULT, diff --git a/openlp/core/ui/advancedtab.py b/openlp/core/ui/advancedtab.py index 97e2d3617..ed720b5df 100644 --- a/openlp/core/ui/advancedtab.py +++ b/openlp/core/ui/advancedtab.py @@ -87,11 +87,14 @@ class AdvancedTab(SettingsTab): self.ui_layout.addRow(self.expand_service_item_check_box) self.slide_max_height_label = QtWidgets.QLabel(self.ui_group_box) self.slide_max_height_label.setObjectName('slide_max_height_label') - self.slide_max_height_spin_box = QtWidgets.QSpinBox(self.ui_group_box) - self.slide_max_height_spin_box.setObjectName('slide_max_height_spin_box') - self.slide_max_height_spin_box.setRange(0, 1000) - self.slide_max_height_spin_box.setSingleStep(20) - self.ui_layout.addRow(self.slide_max_height_label, self.slide_max_height_spin_box) + self.slide_max_height_combo_box = QtWidgets.QComboBox(self.ui_group_box) + self.slide_max_height_combo_box.addItem('', userData=0) + self.slide_max_height_combo_box.addItem('', userData=-4) + # Generate numeric values for combo box dynamically + for px in range(60,801,5): + self.slide_max_height_combo_box.addItem(str(px)+'px', userData=px) + self.slide_max_height_combo_box.setObjectName('slide_max_height_combo_box') + self.ui_layout.addRow(self.slide_max_height_label, self.slide_max_height_combo_box) self.autoscroll_label = QtWidgets.QLabel(self.ui_group_box) self.autoscroll_label.setObjectName('autoscroll_label') self.autoscroll_combo_box = QtWidgets.QComboBox(self.ui_group_box) @@ -265,7 +268,8 @@ class AdvancedTab(SettingsTab): 'Expand new service items on creation')) self.slide_max_height_label.setText(translate('OpenLP.AdvancedTab', 'Max height for non-text slides\nin slide controller:')) - self.slide_max_height_spin_box.setSpecialValueText(translate('OpenLP.AdvancedTab', 'Disabled')) + self.slide_max_height_combo_box.setItemText(0, translate('OpenLP.AdvancedTab', 'Disabled')) + self.slide_max_height_combo_box.setItemText(1, translate('OpenLP.AdvancedTab', 'Automatic')) self.autoscroll_label.setText(translate('OpenLP.AdvancedTab', 'When changing slides:')) self.autoscroll_combo_box.setItemText(0, translate('OpenLP.AdvancedTab', 'Do not auto-scroll')) @@ -355,10 +359,13 @@ class AdvancedTab(SettingsTab): self.single_click_preview_check_box.setChecked(settings.value('single click preview')) self.single_click_service_preview_check_box.setChecked(settings.value('single click service preview')) self.expand_service_item_check_box.setChecked(settings.value('expand service item')) - self.slide_max_height_spin_box.setValue(settings.value('slide max height')) + slide_max_height_value = settings.value('slide max height') + for i in range(0, self.slide_max_height_combo_box.count()): + if self.slide_max_height_combo_box.itemData(i) == slide_max_height_value: + self.slide_max_height_combo_box.setCurrentIndex(i) autoscroll_value = settings.value('autoscrolling') for i in range(0, len(self.autoscroll_map)): - if self.autoscroll_map[i] == autoscroll_value: + if self.autoscroll_map[i] == autoscroll_value and i < self.autoscroll_combo_box.count(): self.autoscroll_combo_box.setCurrentIndex(i) self.enable_auto_close_check_box.setChecked(settings.value('enable exit confirmation')) self.hide_mouse_check_box.setChecked(settings.value('hide mouse')) @@ -439,7 +446,9 @@ class AdvancedTab(SettingsTab): settings.setValue('single click preview', self.single_click_preview_check_box.isChecked()) settings.setValue('single click service preview', self.single_click_service_preview_check_box.isChecked()) settings.setValue('expand service item', self.expand_service_item_check_box.isChecked()) - settings.setValue('slide max height', self.slide_max_height_spin_box.value()) + slide_max_height_index = self.slide_max_height_combo_box.currentIndex() + slide_max_height_value = self.slide_max_height_combo_box.itemData(slide_max_height_index) + settings.setValue('slide max height', slide_max_height_value) settings.setValue('autoscrolling', self.autoscroll_map[self.autoscroll_combo_box.currentIndex()]) settings.setValue('enable exit confirmation', self.enable_auto_close_check_box.isChecked()) settings.setValue('hide mouse', self.hide_mouse_check_box.isChecked()) diff --git a/openlp/core/ui/lib/listpreviewwidget.py b/openlp/core/ui/lib/listpreviewwidget.py index 2383cc35f..0edab337f 100644 --- a/openlp/core/ui/lib/listpreviewwidget.py +++ b/openlp/core/ui/lib/listpreviewwidget.py @@ -63,6 +63,7 @@ class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties): # Initialize variables. self.service_item = ServiceItem() self.screen_ratio = screen_ratio + self.auto_row_height = 100 # Connect signals self.verticalHeader().sectionResized.connect(self.row_resized) @@ -87,8 +88,14 @@ class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties): height = self.viewport().width() // self.screen_ratio max_img_row_height = Settings().value('advanced/slide max height') # Adjust for row height cap if in use. - if isinstance(max_img_row_height, int) and max_img_row_height > 0 and height > max_img_row_height: - height = max_img_row_height + if isinstance(max_img_row_height, int): + if max_img_row_height > 0 and height > max_img_row_height: + height = max_img_row_height + elif max_img_row_height < 0: + # If auto setting, show that number of slides, or if the resulting slides too small, 100px. + # E.g. If setting is -4, 4 slides will be visible, unless those slides are < 100px high. + self.auto_row_height = max(self.viewport().height() / (-1 * max_img_row_height), 100) + height = min(height, self.auto_row_height) # Apply new height to slides for frame_number in range(len(self.service_item.get_frames())): self.setRowHeight(frame_number, height) @@ -99,7 +106,7 @@ class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties): """ # Only for non-text slides when row height cap in use max_img_row_height = Settings().value('advanced/slide max height') - if self.service_item.is_text() or not isinstance(max_img_row_height, int) or max_img_row_height <= 0: + if self.service_item.is_text() or not isinstance(max_img_row_height, int) or max_img_row_height == 0: return # Get and validate label widget containing slide & adjust max width try: @@ -165,11 +172,13 @@ class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties): slide_height = width // self.screen_ratio # Setup and validate row height cap if in use. max_img_row_height = Settings().value('advanced/slide max height') - if isinstance(max_img_row_height, int) and max_img_row_height > 0: - if slide_height > max_img_row_height: + if isinstance(max_img_row_height, int) and max_img_row_height != 0: + if max_img_row_height > 0 and slide_height > max_img_row_height: slide_height = max_img_row_height - label.setMaximumWidth(max_img_row_height * self.screen_ratio) - label.resize(max_img_row_height * self.screen_ratio, max_img_row_height) + elif max_img_row_height < 0 and slide_height > self.auto_row_height: + slide_height = self.auto_row_height + label.setMaximumWidth(slide_height * self.screen_ratio) + label.resize(slide_height * self.screen_ratio, slide_height) # Build widget with stretch padding container = QtWidgets.QWidget() hbox = QtWidgets.QHBoxLayout() From 656af1e90ed5cb629af5408c0a01d9d02ac4729e Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Thu, 19 May 2016 15:14:24 -0700 Subject: [PATCH 06/62] core_ui_aboutdialog strings conversions --- openlp/core/ui/aboutdialog.py | 206 +++++++++++++++++----------------- 1 file changed, 105 insertions(+), 101 deletions(-) diff --git a/openlp/core/ui/aboutdialog.py b/openlp/core/ui/aboutdialog.py index df821e15e..918e48e64 100644 --- a/openlp/core/ui/aboutdialog.py +++ b/openlp/core/ui/aboutdialog.py @@ -88,7 +88,7 @@ class UiAboutDialog(object): :param about_dialog: The QDialog object to translate """ - about_dialog.setWindowTitle('%s OpenLP' % UiStrings().About) + about_dialog.setWindowTitle('{about} OpenLP'.format(about=UiStrings().About)) self.about_text_edit.setPlainText( translate('OpenLP.AboutForm', 'OpenLP - Open Source Lyrics Projection\n' @@ -200,115 +200,115 @@ class UiAboutDialog(object): ' bring this software to you for free because\n' ' He has set us free.') self.credits_text_edit.setPlainText( - '%s\n' - ' %s\n' + '{titleLead}\n' + ' {nameLead}\n' '\n' - '%s\n' - ' %s\n' + '{titleDevs}\n' + ' {nameDevs}\n' '\n' - '%s\n' - ' %s\n' + '{titleContrib}\n' + ' {nameContrib}\n' '\n' - '%s\n' - ' %s\n' + '{titleTesters}\n' + ' {nameTesters}\n' '\n' - '%s\n' - ' %s\n' + '{titlePackagers}\n' + ' {namePackagers}\n' '\n' - '%s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' - ' %s\n' + '{titleTranslators}\n' + ' {titleAF}\n' + ' {nameAF}\n' + ' {titleCS}\n' + ' {nameCS}\n' + ' {titleDA}\n' + ' {nameDA}\n' + ' {titleDE}\n' + ' {nameDE}\n' + ' {titleEL}\n' + ' {nameEL}\n' + ' {titleGB}\n' + ' {nameGB}\n' + ' {titleENZA}\n' + ' {nameENZA}\n' + ' {titleES}\n' + ' {nameES}\n' + ' {titleET}\n' + ' {nameET}\n' + ' {titleFI}\n' + ' {nameFI}\n' + ' {titleFR}\n' + ' {nameFR}\n' + ' {titleHU}\n' + ' {nameHU}\n' + ' {titleIND}\n' + ' {nameIND}\n' + ' {titleJA}\n' + ' {nameJA}\n' + ' {titleNB}\n' + ' {nameNB}\n' + ' {titleNL}\n' + ' {nameNL}\n' + ' {titlePL}\n' + ' {namePL}\n' + ' {titlePTBR}\n' + ' {namePTBR}\n' + ' {titleRU}\n' + ' {nameRU}\n' + ' {titleSV}\n' + ' {nameSV}\n' + ' {titleTALK}\n' + ' {nameTALK}\n' + ' {titleZHCN}\n' + ' {nameZHCN}\n' '\n' - '%s\n' - ' %s\n' + '{titleDOCS}\n' + ' {nameDOCS}\n' '\n' - '%s\n%s' % - (project_lead, lead, - devs, '\n '.join(developers), - cons, '\n '.join(contributors), - tests, '\n '.join(testers), - packs, '\n '.join(packagers), - laters, - af, '\n '.join(translators['af']), - cs, '\n '.join(translators['cs']), - da, '\n '.join(translators['da']), - de, '\n '.join(translators['de']), - el, '\n '.join(translators['el']), - gb, '\n '.join(translators['en_GB']), - enza, '\n '.join(translators['en_ZA']), - es, '\n '.join(translators['es']), - et, '\n '.join(translators['et']), - fi, '\n '.join(translators['fi']), - fr, '\n '.join(translators['fr']), - hu, '\n '.join(translators['hu']), - ind, '\n '.join(translators['id']), - ja, '\n '.join(translators['ja']), - nb, '\n '.join(translators['nb']), - nl, '\n '.join(translators['nl']), - pl, '\n '.join(translators['pl']), - ptbr, '\n '.join(translators['pt_BR']), - ru, '\n '.join(translators['ru']), - sv, '\n '.join(translators['sv']), - talk, '\n '.join(translators['ta_LK']), - zhcn, '\n '.join(translators['zh_CN']), - documentation, '\n '.join(documentors), - built_with, final_credit)) + '{build}\n{final}'.format(titleLead=project_lead, nameLead=lead, + titleDevs=devs, nameDevs='\n '.join(developers), + titleContrib=cons, nameContrib='\n '.join(contributors), + titleTesters=tests, nameTesters='\n '.join(testers), + titlePackagers=packs, namePackagers='\n '.join(packagers), + titleTranslators=laters, + titleAF=af, nameAF='\n '.join(translators['af']), + titleCS=cs, nameCS='\n '.join(translators['cs']), + titleDA=da, nameDA='\n '.join(translators['da']), + titleDE=de, nameDE='\n '.join(translators['de']), + titleEL=el, nameEL='\n '.join(translators['el']), + titleGB=gb, nameGB='\n '.join(translators['en_GB']), + titleENZA=enza, nameENZA='\n '.join(translators['en_ZA']), + titleES=es, nameES='\n '.join(translators['es']), + titleET=et, nameET='\n '.join(translators['et']), + titleFI=fi, nameFI='\n '.join(translators['fi']), + titleFR=fr, nameFR='\n '.join(translators['fr']), + titleHU=hu, nameHU='\n '.join(translators['hu']), + titleIND=ind, nameIND='\n '.join(translators['id']), + titleJA=ja, nameJA='\n '.join(translators['ja']), + titleNB=nb, nameNB='\n '.join(translators['nb']), + titleNL=nl, nameNL='\n '.join(translators['nl']), + titlePL=pl, namePL='\n '.join(translators['pl']), + titlePTBR=ptbr, namePTBR='\n '.join(translators['pt_BR']), + titleRU=ru, nameRU='\n '.join(translators['ru']), + titleSV=sv, nameSV='\n '.join(translators['sv']), + titleTALK=talk, nameTALK='\n '.join(translators['ta_LK']), + titleZHCN=zhcn, nameZHCN='\n '.join(translators['zh_CN']), + titleDOCS=documentation, nameDOCS='\n '.join(documentors), + build=built_with, + final=final_credit)) self.about_notebook.setTabText(self.about_notebook.indexOf(self.credits_tab), translate('OpenLP.AboutForm', 'Credits')) + cr_others = ('Tim Bentley, Gerald Britton, Jonathan Corwin, Samuel Findlay, ' + 'Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, ' + 'Armin K\xf6hler, Erik Lundin, Edwin Lunando, Joshua Miller, ' + 'Brian T. Meyer, Stevan Pettit, Andreas Preikschat, ' + 'Mattias P\xf5ldaru, Christian Richter, Philip Ridout, ' + 'Ken Roberts, Simon Scudder, Jeffrey Smith, Maikel Stuivenberg, ' + 'Martin Thompson, Jon Tibble, Dave Warnock, Frode Woldsund, ' + 'Martin Zibricky, Patrick Zimmermann') copyright_note = translate('OpenLP.AboutForm', - 'Copyright \xa9 2004-2016 %s\n' - 'Portions copyright \xa9 2004-2016 %s') % \ - ('Raoul Snyman', - 'Tim Bentley, Gerald Britton, Jonathan Corwin, Samuel Findlay, ' - 'Michael Gorven, Scott Guerrieri, Matthias Hub, Meinert Jordan, ' - 'Armin K\xf6hler, Erik Lundin, Edwin Lunando, Joshua Miller, ' - 'Brian T. Meyer, Stevan Pettit, Andreas Preikschat, ' - 'Mattias P\xf5ldaru, Christian Richter, ' - 'Philip Ridout, Simon Scudder, Jeffrey Smith, Maikel Stuivenberg, ' - 'Martin Thompson, Jon Tibble, Dave Warnock, Frode Woldsund, ' - 'Martin Zibricky, Patrick Zimmermann') + 'Copyright \xa9 2004-2016 {cr}\n\n' + 'Portions copyright \xa9 2004-2016 {others}').format(cr='Raoul Snyman', + others=cr_others) licence = translate('OpenLP.AboutForm', 'This program is free software; you can redistribute it and/or ' 'modify it under the terms of the GNU General Public License as ' @@ -690,7 +690,11 @@ class UiAboutDialog(object): 'linking proprietary applications with the library. If this is ' 'what you want to do, use the GNU Lesser General Public License ' 'instead of this License.') - self.license_text_edit.setPlainText('%s\n\n%s\n\n%s\n\n\n%s' % (copyright_note, licence, disclaimer, gpl_text)) + self.license_text_edit.setPlainText('{crnote}\n\n{license}\n\n{disclaimer}' + '\n\n\n{gpl}'.format(crnote=copyright_note, + license=licence, + disclaimer=disclaimer, + gpl=gpl_text)) self.about_notebook.setTabText(self.about_notebook.indexOf(self.license_tab), translate('OpenLP.AboutForm', 'License')) self.volunteer_button.setText(translate('OpenLP.AboutForm', 'Volunteer')) From 812c1245283d036fb05bd452f494e71786607072 Mon Sep 17 00:00:00 2001 From: Ian Knight Date: Fri, 20 May 2016 22:06:59 +0930 Subject: [PATCH 07/62] Added test case for Auto option. --- .../test_listpreviewwidget.py | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py b/tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py index 704acc544..b6834d24b 100644 --- a/tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py +++ b/tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py @@ -225,6 +225,44 @@ class TestListPreviewWidget(TestCase): calls = [call(0, 100), call(1, 100), call(0, 100), call(1, 100)] mocked_setRowHeight.assert_has_calls(calls) + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight') + def replace_recalculate_layout_test_img_auto(self, mocked_setRowHeight, mocked_resizeRowsToContents): + """ + Test if "Max height for non-text slides..." auto, img slides resized in replace_service_item & __recalc... + """ + # GIVEN: A setting to adjust "Max height for non-text slides in slide controller", + # an image ServiceItem and a ListPreviewWidget. + + # Mock Settings().value('advanced/slide max height') + self.mocked_Settings_obj.value.return_value = -4 + # Mock self.viewport().width() + self.mocked_viewport_obj.width.return_value = 200 + self.mocked_viewport_obj.height.return_value = 600 + # Mock image service item + service_item = MagicMock() + service_item.is_text.return_value = False + service_item.is_capable.return_value = False + service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None}, + {'title': None, 'path': None, 'image': None}] + # init ListPreviewWidget and load service item + list_preview_widget = ListPreviewWidget(None, 1) + list_preview_widget.replace_service_item(service_item, 200, 0) + # Change viewport width before forcing a resize + self.mocked_viewport_obj.width.return_value = 400 + + # WHEN: __recalculate_layout() is called (via resizeEvent) + list_preview_widget.resizeEvent(None) + self.mocked_viewport_obj.height.return_value = 200 + list_preview_widget.resizeEvent(None) + + # THEN: resizeRowsToContents() should not be called, while setRowHeight() should be called + # twice for each slide. + self.assertEquals(mocked_resizeRowsToContents.call_count, 0, 'Should not be called') + self.assertEquals(mocked_setRowHeight.call_count, 6, 'Should be called 3 times for each slide') + calls = [call(0, 100), call(1, 100), call(0, 150), call(1, 150), call(0, 100), call(1, 100)] + mocked_setRowHeight.assert_has_calls(calls) + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.cellWidget') From 3b48a4b8175bb23b162f231b0650f3df91c5e39f Mon Sep 17 00:00:00 2001 From: Ian Knight Date: Fri, 20 May 2016 22:08:36 +0930 Subject: [PATCH 08/62] Housekeeping --- openlp/core/ui/lib/listpreviewwidget.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openlp/core/ui/lib/listpreviewwidget.py b/openlp/core/ui/lib/listpreviewwidget.py index 0edab337f..2ea004160 100644 --- a/openlp/core/ui/lib/listpreviewwidget.py +++ b/openlp/core/ui/lib/listpreviewwidget.py @@ -174,8 +174,10 @@ class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties): max_img_row_height = Settings().value('advanced/slide max height') if isinstance(max_img_row_height, int) and max_img_row_height != 0: if max_img_row_height > 0 and slide_height > max_img_row_height: + # Manual Setting slide_height = max_img_row_height elif max_img_row_height < 0 and slide_height > self.auto_row_height: + # Auto Setting slide_height = self.auto_row_height label.setMaximumWidth(slide_height * self.screen_ratio) label.resize(slide_height * self.screen_ratio, slide_height) From 2c1c7810b9bf710de2af8db4ba498be43d97d295 Mon Sep 17 00:00:00 2001 From: Ian Knight Date: Fri, 20 May 2016 22:57:52 +0930 Subject: [PATCH 09/62] Improved test coverage. --- .../test_listpreviewwidget.py | 41 +++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py b/tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py index b6834d24b..64239373a 100644 --- a/tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py +++ b/tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py @@ -251,10 +251,10 @@ class TestListPreviewWidget(TestCase): # Change viewport width before forcing a resize self.mocked_viewport_obj.width.return_value = 400 - # WHEN: __recalculate_layout() is called (via resizeEvent) - list_preview_widget.resizeEvent(None) + # WHEN: __recalculate_layout() is called (via screen_size_changed) + list_preview_widget.screen_size_changed(1) self.mocked_viewport_obj.height.return_value = 200 - list_preview_widget.resizeEvent(None) + list_preview_widget.screen_size_changed(1) # THEN: resizeRowsToContents() should not be called, while setRowHeight() should be called # twice for each slide. @@ -369,6 +369,41 @@ class TestListPreviewWidget(TestCase): # THEN: self.cellWidget(row, 0).children()[1].setMaximumWidth() should be called mocked_cellWidget_child.setMaximumWidth.assert_called_once_with(150) + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight') + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.cellWidget') + def row_resized_test_setting_changed(self, mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents): + """ + Test if "Max height for non-text slides..." enabled while item live, program doesn't crash on row_resized. + """ + # GIVEN: A setting to adjust "Max height for non-text slides in slide controller", + # an image ServiceItem and a ListPreviewWidget. + + # Mock Settings().value('advanced/slide max height') + self.mocked_Settings_obj.value.return_value = 0 + # Mock self.viewport().width() + self.mocked_viewport_obj.width.return_value = 200 + # Mock image service item + service_item = MagicMock() + service_item.is_text.return_value = False + service_item.is_capable.return_value = False + service_item.get_frames.return_value = [{'title': None, 'path': None, 'image': None}, + {'title': None, 'path': None, 'image': None}] + # Mock self.cellWidget().children() + mocked_cellWidget_obj = MagicMock() + mocked_cellWidget_obj.children.return_value = None + mocked_cellWidget.return_value = mocked_cellWidget_obj + # init ListPreviewWidget and load service item + list_preview_widget = ListPreviewWidget(None, 1) + list_preview_widget.replace_service_item(service_item, 200, 0) + self.mocked_Settings_obj.value.return_value = 100 + + # WHEN: row_resized() is called + list_preview_widget.row_resized(0, 100, 150) + + # THEN: self.cellWidget(row, 0).children()[1].setMaximumWidth() should fail + self.assertRaises(Exception) + @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.selectRow') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.scrollToItem') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.item') From e09e867ad1b89f7a5b56eee891d55b6331d1aa77 Mon Sep 17 00:00:00 2001 From: Ian Knight Date: Fri, 20 May 2016 23:07:23 +0930 Subject: [PATCH 10/62] Pep8 Errors --- openlp/core/ui/advancedtab.py | 4 ++-- tests/functional/openlp_core_common/test_actions.py | 2 +- tests/functional/openlp_core_lib/test_lib.py | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/openlp/core/ui/advancedtab.py b/openlp/core/ui/advancedtab.py index ed720b5df..10e6056d1 100644 --- a/openlp/core/ui/advancedtab.py +++ b/openlp/core/ui/advancedtab.py @@ -91,8 +91,8 @@ class AdvancedTab(SettingsTab): self.slide_max_height_combo_box.addItem('', userData=0) self.slide_max_height_combo_box.addItem('', userData=-4) # Generate numeric values for combo box dynamically - for px in range(60,801,5): - self.slide_max_height_combo_box.addItem(str(px)+'px', userData=px) + for px in range(60, 801, 5): + self.slide_max_height_combo_box.addItem(str(px) + 'px', userData=px) self.slide_max_height_combo_box.setObjectName('slide_max_height_combo_box') self.ui_layout.addRow(self.slide_max_height_label, self.slide_max_height_combo_box) self.autoscroll_label = QtWidgets.QLabel(self.ui_group_box) diff --git a/tests/functional/openlp_core_common/test_actions.py b/tests/functional/openlp_core_common/test_actions.py index 92f030df2..afdc89c34 100644 --- a/tests/functional/openlp_core_common/test_actions.py +++ b/tests/functional/openlp_core_common/test_actions.py @@ -118,7 +118,7 @@ class TestCategoryActionList(TestCase): # GIVEN: The list including two actions self.list.add(self.action1) self.list.add(self.action2) - + # WHEN: Iterating over the list l = [a for a in self.list] # THEN: Make sure they are returned in correct order diff --git a/tests/functional/openlp_core_lib/test_lib.py b/tests/functional/openlp_core_lib/test_lib.py index c8493d005..d519837bf 100644 --- a/tests/functional/openlp_core_lib/test_lib.py +++ b/tests/functional/openlp_core_lib/test_lib.py @@ -431,7 +431,6 @@ class TestLib(TestCase): thumb_size = QtCore.QSize(-1, 100) expected_size_1 = QtCore.QSize(88, 88) expected_size_2 = QtCore.QSize(100, 100) - # Remove the thumb so that the test actually tests if the thumb will be created. Maybe it was not deleted in the # last test. @@ -458,7 +457,7 @@ class TestLib(TestCase): with patch('openlp.core.lib.QtGui.QImageReader.size') as mocked_size: mocked_size.return_value = QtCore.QSize(0, 0) icon = create_thumb(image_path, thumb_path, size=thumb_size) - + # THEN: Check if the thumb was created with aspect ratio of 1. self.assertIsInstance(icon, QtGui.QIcon, 'The icon should be a QIcon') self.assertFalse(icon.isNull(), 'The icon should not be null') From 7f5096d0f9426b92f297cdedd769813efddb03d7 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Fri, 20 May 2016 09:22:06 -0700 Subject: [PATCH 11/62] core_lib files string conversions --- openlp/core/lib/projector/db.py | 2 +- openlp/core/ui/aboutform.py | 2 +- openlp/core/ui/advancedtab.py | 26 +++--- openlp/core/ui/exceptionform.py | 34 ++++--- openlp/core/ui/firsttimeform.py | 91 +++++++++++-------- openlp/core/ui/firsttimewizard.py | 20 ++-- openlp/core/ui/formattingtagcontroller.py | 23 +++-- openlp/core/ui/formattingtagform.py | 7 +- openlp/core/ui/generaltab.py | 2 +- openlp/core/ui/mainwindow.py | 9 +- openlp/core/ui/plugindialog.py | 2 +- openlp/core/ui/pluginform.py | 4 +- openlp/core/ui/servicemanager.py | 52 ++++++----- openlp/core/ui/settingsform.py | 2 +- openlp/core/ui/shortcutlistform.py | 9 +- openlp/core/ui/slidecontroller.py | 80 +++++++++------- openlp/core/ui/starttimeform.py | 6 +- openlp/core/ui/themeform.py | 10 +- openlp/core/ui/thememanager.py | 55 ++++++----- openlp/core/ui/themewizard.py | 8 +- .../openlp_core_lib/test_projectordb.py | 18 +++- 21 files changed, 263 insertions(+), 199 deletions(-) diff --git a/openlp/core/lib/projector/db.py b/openlp/core/lib/projector/db.py index 2b41ea69c..98778e695 100644 --- a/openlp/core/lib/projector/db.py +++ b/openlp/core/lib/projector/db.py @@ -131,7 +131,7 @@ class Source(CommonBase, Base): """ Return basic representation of Source table entry. """ - return ''.format(name=self.pjlink_name, + return ''.format(name=self.pjlink_name, code=self.pjlink_code, text=self.text) model_id = Column(Integer, ForeignKey('model.id')) diff --git a/openlp/core/ui/aboutform.py b/openlp/core/ui/aboutform.py index fc29f968c..3b509bdbd 100644 --- a/openlp/core/ui/aboutform.py +++ b/openlp/core/ui/aboutform.py @@ -52,7 +52,7 @@ class AboutForm(QtWidgets.QDialog, UiAboutDialog): about_text = self.about_text_edit.toPlainText() about_text = about_text.replace('', application_version['version']) if application_version['build']: - build_text = translate('OpenLP.AboutForm', ' build %s') % application_version['build'] + build_text = translate('OpenLP.AboutForm', ' build {version}').format(version=application_version['build']) else: build_text = '' about_text = about_text.replace('', build_text) diff --git a/openlp/core/ui/advancedtab.py b/openlp/core/ui/advancedtab.py index 97e2d3617..e6f2dee49 100644 --- a/openlp/core/ui/advancedtab.py +++ b/openlp/core/ui/advancedtab.py @@ -308,8 +308,8 @@ class AdvancedTab(SettingsTab): self.service_name_label.setText(translate('OpenLP.AdvancedTab', 'Name:')) self.service_name_edit.setToolTip(translate('OpenLP.AdvancedTab', 'Consult the OpenLP manual for usage.')) self.service_name_revert_button.setToolTip( - translate('OpenLP.AdvancedTab', 'Revert to the default service name "%s".') % - UiStrings().DefaultServiceName) + translate('OpenLP.AdvancedTab', + 'Revert to the default service name "{name}".').format(name=UiStrings().DefaultServiceName)) self.service_name_example_label.setText(translate('OpenLP.AdvancedTab', 'Example:')) self.hide_mouse_group_box.setTitle(translate('OpenLP.AdvancedTab', 'Mouse Cursor')) self.hide_mouse_check_box.setText(translate('OpenLP.AdvancedTab', 'Hide mouse cursor when over display window')) @@ -391,16 +391,16 @@ class AdvancedTab(SettingsTab): # Since data location can be changed, make sure the path is present. self.current_data_path = AppLocation.get_data_path() if not os.path.exists(self.current_data_path): - log.error('Data path not found %s' % self.current_data_path) + log.error('Data path not found {path}'.format(path=self.current_data_path)) answer = QtWidgets.QMessageBox.critical( self, translate('OpenLP.AdvancedTab', 'Data Directory Error'), - translate('OpenLP.AdvancedTab', 'OpenLP data directory was not found\n\n%s\n\n' + translate('OpenLP.AdvancedTab', 'OpenLP data directory was not found\n\n{path}\n\n' 'This data directory was previously changed from the OpenLP ' 'default location. If the new location was on removable ' 'media, that media needs to be made available.\n\n' 'Click "No" to stop loading OpenLP. allowing you to fix the the problem.\n\n' 'Click "Yes" to reset the data directory to the default ' - 'location.').replace('%s', self.current_data_path), + 'location.').format(path=self.current_data_path), QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No), QtWidgets.QMessageBox.No) if answer == QtWidgets.QMessageBox.No: @@ -410,7 +410,7 @@ class AdvancedTab(SettingsTab): # Set data location to default. settings.remove('advanced/data path') self.current_data_path = AppLocation.get_data_path() - log.warning('User requested data path set to default %s' % self.current_data_path) + log.warning('User requested data path set to default {path}'.format(path=self.current_data_path)) self.data_directory_label.setText(os.path.abspath(self.current_data_path)) # Don't allow data directory move if running portable. if settings.value('advanced/is portable'): @@ -542,9 +542,9 @@ class AdvancedTab(SettingsTab): # Make sure they want to change the data. answer = QtWidgets.QMessageBox.question(self, translate('OpenLP.AdvancedTab', 'Confirm Data Directory Change'), translate('OpenLP.AdvancedTab', 'Are you sure you want to change the ' - 'location of the OpenLP data directory to:\n\n%s\n\nThe data ' - 'directory will be changed when OpenLP is closed.'). - replace('%s', new_data_path), + 'location of the OpenLP data directory to:\n\n{path}' + '\n\nThe data directory will be changed when OpenLP is ' + 'closed.').format(path=new_data_path), QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No), QtWidgets.QMessageBox.No) @@ -608,10 +608,10 @@ class AdvancedTab(SettingsTab): answer = QtWidgets.QMessageBox.warning(self, translate('OpenLP.AdvancedTab', 'Overwrite Existing Data'), translate('OpenLP.AdvancedTab', - 'WARNING: \n\nThe location you have selected \n\n%s\n\n' - 'appears to contain OpenLP data files. Do you wish to ' - 'replace these files with the current data files?'). - replace('%s', os.path.abspath(data_path,)), + 'WARNING: \n\nThe location you have selected \n\n{path}' + '\n\nappears to contain OpenLP data files. Do you wish to ' + 'replace these files with the current data ' + 'files?').format(path=os.path.abspath(data_path,)), QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No), QtWidgets.QMessageBox.No) diff --git a/openlp/core/ui/exceptionform.py b/openlp/core/ui/exceptionform.py index 68dd9705f..216780584 100644 --- a/openlp/core/ui/exceptionform.py +++ b/openlp/core/ui/exceptionform.py @@ -91,6 +91,7 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties): super(ExceptionForm, self).__init__(None, QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.WindowTitleHint) self.setupUi(self) self.settings_section = 'crashreport' + # TODO: Need to see how to format strings when string with tags is actually a variable self.report_text = '**OpenLP Bug Report**\n' \ 'Version: %s\n\n' \ '--- Details of the Exception. ---\n\n%s\n\n ' \ @@ -114,21 +115,17 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties): openlp_version = get_application_version() description = self.description_text_edit.toPlainText() traceback = self.exception_text_edit.toPlainText() - system = translate('OpenLP.ExceptionForm', 'Platform: %s\n') % platform.platform() - libraries = 'Python: %s\n' % platform.python_version() + \ - 'Qt5: %s\n' % Qt.qVersion() + \ - 'PyQt5: %s\n' % Qt.PYQT_VERSION_STR + \ - 'QtWebkit: %s\n' % WEBKIT_VERSION + \ - 'SQLAlchemy: %s\n' % sqlalchemy.__version__ + \ - 'SQLAlchemy Migrate: %s\n' % MIGRATE_VERSION + \ - 'BeautifulSoup: %s\n' % bs4.__version__ + \ - 'lxml: %s\n' % etree.__version__ + \ - 'Chardet: %s\n' % CHARDET_VERSION + \ - 'PyEnchant: %s\n' % ENCHANT_VERSION + \ - 'Mako: %s\n' % MAKO_VERSION + \ - 'pyICU: %s\n' % ICU_VERSION + \ - 'pyUNO bridge: %s\n' % self._pyuno_import() + \ - 'VLC: %s\n' % VLC_VERSION + system = translate('OpenLP.ExceptionForm', 'Platform: {platform}\n').format(platform=platform.platform()) + libraries = ('Python: {python}\nQt5: {qt5}\nPyQt5: {pyqt5}\nQtWebkit: {qtwebkit}\nSQLAlchemy: {sqalchemy}\n' + 'SQLAlchemy Migrate: {migrate}\nBeautifulSoup: {soup}\nlxml: {etree}\nChardet: {chardet}\n' + 'PyEnchant: {enchant}\nMako: {mako}\npyICU: {icu}\npyUNO bridge: {uno}\n' + 'VLC: {vlc}\n').format(python=platform.python_version(), qt5=Qt.qVersion(), + pyqt5=Qt.PYQT_VERSION_STR, qtwebkit=WEBKIT_VERSION, + sqalchemy=sqlalchemy.__version__, migrate=MIGRATE_VERSION, + soup=bs4.__version__, etree=etree.__version__, chardet=CHARDET_VERSION, + enchant=ENCHANT_VERSION, mako=MAKO_VERSION, icu=ICU_VERSION, + uno=self._pyuno_import(), vlc=VLC_VERSION) + if is_linux(): if os.environ.get('KDE_FULL_SESSION') == 'true': system += 'Desktop: KDE SC\n' @@ -178,9 +175,10 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties): source = re.sub(r'.*[/\\]openlp[/\\](.*)".*', r'\1', line) if ':' in line: exception = line.split('\n')[-1].split(':')[0] - subject = 'Bug report: %s in %s' % (exception, source) + subject = 'Bug report: {error} in {source}'.format(error=exception, source=source) mail_urlquery = QtCore.QUrlQuery() mail_urlquery.addQueryItem('subject', subject) + # TODO: Find out how to format() text that is in a variable mail_urlquery.addQueryItem('body', self.report_text % content) if self.file_attachment: mail_urlquery.addQueryItem('attach', self.file_attachment) @@ -199,7 +197,7 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties): else: self.__button_state(False) self.description_word_count.setText( - translate('OpenLP.ExceptionDialog', 'Description characters to enter : %s') % count) + translate('OpenLP.ExceptionDialog', 'Description characters to enter : {count}').format(count=count)) def on_attach_file_button_clicked(self): """ @@ -210,7 +208,7 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties): 'Select Attachment'), Settings().value(self.settings_section + '/last directory'), - '%s (*)' % UiStrings().AllFiles) + '{text} (*)'.format(text=UiStrings().AllFiles)) log.info('New files(s) %s', str(files)) if files: self.file_attachment = str(files) diff --git a/openlp/core/ui/firsttimeform.py b/openlp/core/ui/firsttimeform.py index f2be3b29c..cadb4814f 100644 --- a/openlp/core/ui/firsttimeform.py +++ b/openlp/core/ui/firsttimeform.py @@ -72,7 +72,7 @@ class ThemeScreenshotWorker(QtCore.QObject): if self.was_download_cancelled: return try: - urllib.request.urlretrieve('%s%s' % (self.themes_url, self.screenshot), + urllib.request.urlretrieve('{host}{name}'.format(host=self.themes_url, name=self.screenshot), os.path.join(gettempdir(), 'openlp', self.screenshot)) # Signal that the screenshot has been downloaded self.screenshot_downloaded.emit(self.title, self.filename, self.sha256) @@ -180,11 +180,13 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties): user_agent = 'OpenLP/' + Registry().get('application').applicationVersion() self.application.process_events() try: - web_config = get_web_page('%s%s' % (self.web, 'download.cfg'), header=('User-Agent', user_agent)) + web_config = get_web_page('{host}{name}'.format(host=self.web, name='download.cfg'), + header=('User-Agent', user_agent)) except (urllib.error.URLError, ConnectionError) as err: msg = QtWidgets.QMessageBox() title = translate('OpenLP.FirstTimeWizard', 'Network Error') - msg.setText('{} {}'.format(title, err.code if hasattr(err, 'code') else '')) + msg.setText('{title} {error}'.format(title=title, + error=err.code if hasattr(err, 'code') else '')) msg.setInformativeText(translate('OpenLP.FirstTimeWizard', 'There was a network error attempting to ' 'connect to retrieve initial configuration information')) @@ -205,6 +207,7 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties): trace_error_handler(log) self.update_screen_list_combo() self.application.process_events() + # TODO: Figure out how to use a variable with format() self.downloading = translate('OpenLP.FirstTimeWizard', 'Downloading %s...') if self.has_run_wizard: self.songs_check_box.setChecked(self.plugin_manager.get_plugin_by_name('songs').is_active()) @@ -223,9 +226,9 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties): songs = songs.split(',') for song in songs: self.application.process_events() - title = self.config.get('songs_%s' % song, 'title') - filename = self.config.get('songs_%s' % song, 'filename') - sha256 = self.config.get('songs_%s' % song, 'sha256', fallback='') + title = self.config.get('songs_{song}'.format(song=song), 'title') + filename = self.config.get('songs_{song}'.format(song=song), 'filename') + sha256 = self.config.get('songs_{song}'.format(song=song), 'sha256', fallback='') item = QtWidgets.QListWidgetItem(title, self.songs_list_widget) item.setData(QtCore.Qt.UserRole, (filename, sha256)) item.setCheckState(QtCore.Qt.Unchecked) @@ -234,15 +237,15 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties): bible_languages = bible_languages.split(',') for lang in bible_languages: self.application.process_events() - language = self.config.get('bibles_%s' % lang, 'title') + language = self.config.get('bibles_{lang}'.format(lang=lang), 'title') lang_item = QtWidgets.QTreeWidgetItem(self.bibles_tree_widget, [language]) - bibles = self.config.get('bibles_%s' % lang, 'translations') + bibles = self.config.get('bibles_{lang}'.format(lang=lang), 'translations') bibles = bibles.split(',') for bible in bibles: self.application.process_events() - title = self.config.get('bible_%s' % bible, 'title') - filename = self.config.get('bible_%s' % bible, 'filename') - sha256 = self.config.get('bible_%s' % bible, 'sha256', fallback='') + title = self.config.get('bible_{bible}'.format(bible=bible), 'title') + filename = self.config.get('bible_{bible}'.format(bible=bible), 'filename') + sha256 = self.config.get('bible_{bible}'.format(bible=bible), 'sha256', fallback='') item = QtWidgets.QTreeWidgetItem(lang_item, [title]) item.setData(0, QtCore.Qt.UserRole, (filename, sha256)) item.setCheckState(0, QtCore.Qt.Unchecked) @@ -252,10 +255,10 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties): # Download the theme screenshots themes = self.config.get('themes', 'files').split(',') for theme in themes: - title = self.config.get('theme_%s' % theme, 'title') - filename = self.config.get('theme_%s' % theme, 'filename') - sha256 = self.config.get('theme_%s' % theme, 'sha256', fallback='') - screenshot = self.config.get('theme_%s' % theme, 'screenshot') + title = self.config.get('theme_{theme}'.format(theme=theme), 'title') + filename = self.config.get('theme_{theme}'.format(theme=theme), 'filename') + sha256 = self.config.get('theme_{theme}'.format(theme=theme), 'sha256', fallback='') + screenshot = self.config.get('theme_{theme}'.format(theme=theme), 'screenshot') worker = ThemeScreenshotWorker(self.themes_url, title, filename, sha256, screenshot) self.theme_screenshot_workers.append(worker) worker.screenshot_downloaded.connect(self.on_screenshot_downloaded) @@ -421,7 +424,7 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties): self._download_progress(block_count, block_size) filename.close() if sha256 and hasher.hexdigest() != sha256: - log.error('sha256 sums did not match for file: {}'.format(f_path)) + log.error('sha256 sums did not match for file: {file}'.format(file=f_path)) os.remove(f_path) return False except (urllib.error.URLError, socket.timeout) as err: @@ -447,7 +450,7 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties): themes = self.config.get('themes', 'files') themes = themes.split(',') for index, theme in enumerate(themes): - screenshot = self.config.get('theme_%s' % theme, 'screenshot') + screenshot = self.config.get('theme_{theme}'.format(theme=theme), 'screenshot') item = self.themes_list_widget.item(index) if item: item.setIcon(build_icon(os.path.join(gettempdir(), 'openlp', screenshot))) @@ -507,7 +510,7 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties): item = self.songs_list_widget.item(i) if item.checkState() == QtCore.Qt.Checked: filename, sha256 = item.data(QtCore.Qt.UserRole) - size = self._get_file_size('%s%s' % (self.songs_url, filename)) + size = self._get_file_size('{path}{name}'.format(path=self.songs_url, name=filename)) self.max_progress += size # Loop through the Bibles list and increase for each selected item iterator = QtWidgets.QTreeWidgetItemIterator(self.bibles_tree_widget) @@ -516,7 +519,7 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties): item = iterator.value() if item.parent() and item.checkState(0) == QtCore.Qt.Checked: filename, sha256 = item.data(0, QtCore.Qt.UserRole) - size = self._get_file_size('%s%s' % (self.bibles_url, filename)) + size = self._get_file_size('{path}{name}'.format(path=self.bibles_url, name=filename)) self.max_progress += size iterator += 1 # Loop through the themes list and increase for each selected item @@ -525,7 +528,7 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties): item = self.themes_list_widget.item(i) if item.checkState() == QtCore.Qt.Checked: filename, sha256 = item.data(QtCore.Qt.UserRole) - size = self._get_file_size('%s%s' % (self.themes_url, filename)) + size = self._get_file_size('{path}{name}'.format(path=self.themes_url, name=filename)) self.max_progress += size except urllib.error.URLError: trace_error_handler(log) @@ -560,22 +563,26 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties): if self.max_progress: self.progress_bar.setValue(self.progress_bar.maximum()) if self.has_run_wizard: - self.progress_label.setText(translate('OpenLP.FirstTimeWizard', - 'Download complete. Click the %s button to return to OpenLP.') % - clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton))) + text = translate('OpenLP.FirstTimeWizard', + 'Download complete. Click the {button} button to return to OpenLP.' + ).format(text=clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton))) + self.progress_label.setText(text) else: - self.progress_label.setText(translate('OpenLP.FirstTimeWizard', - 'Download complete. Click the %s button to start OpenLP.') % - clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton))) + text = translate('OpenLP.FirstTimeWizard', + 'Download complete. Click the {button} button to start OpenLP.' + ).format(button=clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton))) + self.progress_label.setText() else: if self.has_run_wizard: - self.progress_label.setText(translate('OpenLP.FirstTimeWizard', - 'Click the %s button to return to OpenLP.') % - clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton))) + text = translate('OpenLP.FirstTimeWizard', + 'Click the {button} button to return to OpenLP.' + ).format(button=clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton))) + self.progress_label.setText(text) else: - self.progress_label.setText(translate('OpenLP.FirstTimeWizard', - 'Click the %s button to start OpenLP.') % - clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton))) + text = translate('OpenLP.FirstTimeWizard', + 'Click the {button} button to start OpenLP.' + ).format(button=clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton))) + self.progress_label.setText() self.finish_button.setVisible(True) self.finish_button.setEnabled(True) self.cancel_button.setVisible(False) @@ -628,8 +635,9 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties): self._increment_progress_bar(self.downloading % filename, 0) self.previous_size = 0 destination = os.path.join(songs_destination, str(filename)) - if not self.url_get_file('%s%s' % (self.songs_url, filename), destination, sha256): - missed_files.append('Song: {}'.format(filename)) + if not self.url_get_file('{path}{name}'.format(path=self.songs_url, name=filename), + destination, sha256): + missed_files.append('Song: {name}'.format(name=filename)) # Download Bibles bibles_iterator = QtWidgets.QTreeWidgetItemIterator(self.bibles_tree_widget) while bibles_iterator.value(): @@ -638,31 +646,34 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties): bible, sha256 = item.data(0, QtCore.Qt.UserRole) self._increment_progress_bar(self.downloading % bible, 0) self.previous_size = 0 - if not self.url_get_file('%s%s' % (self.bibles_url, bible), os.path.join(bibles_destination, bible), + if not self.url_get_file('{path}{name}'.format(path=self.bibles_url, name=bible), + os.path.join(bibles_destination, bible), sha256): - missed_files.append('Bible: {}'.format(bible)) + missed_files.append('Bible: {name}'.format(name=bible)) bibles_iterator += 1 # Download themes for i in range(self.themes_list_widget.count()): item = self.themes_list_widget.item(i) if item.checkState() == QtCore.Qt.Checked: theme, sha256 = item.data(QtCore.Qt.UserRole) + # TODO: Verify how to use format() with strings in a variable self._increment_progress_bar(self.downloading % theme, 0) self.previous_size = 0 - if not self.url_get_file('%s%s' % (self.themes_url, theme), os.path.join(themes_destination, theme), + if not self.url_get_file('{path}{name}'.format(path=self.themes_url, name=theme), + os.path.join(themes_destination, theme), sha256): - missed_files.append('Theme: {}'.format(theme)) + missed_files.append('Theme: {name}'.format(name=theme)) if missed_files: file_list = '' for entry in missed_files: - file_list += '{}
'.format(entry) + file_list += '{text}
'.format(text=entry) msg = QtWidgets.QMessageBox() msg.setIcon(QtWidgets.QMessageBox.Warning) msg.setWindowTitle(translate('OpenLP.FirstTimeWizard', 'Network Error')) msg.setText(translate('OpenLP.FirstTimeWizard', 'Unable to download some files')) msg.setInformativeText(translate('OpenLP.FirstTimeWizard', 'The following files were not able to be ' - 'downloaded:
{}'.format(file_list))) + 'downloaded:
{text}'.format(text=file_list))) msg.setStandardButtons(msg.Ok) ans = msg.exec() return True diff --git a/openlp/core/ui/firsttimewizard.py b/openlp/core/ui/firsttimewizard.py index 9f740e5cf..7b93c1680 100644 --- a/openlp/core/ui/firsttimewizard.py +++ b/openlp/core/ui/firsttimewizard.py @@ -228,12 +228,13 @@ class UiFirstTimeWizard(object): :param first_time_wizard: The wizard form """ first_time_wizard.setWindowTitle(translate('OpenLP.FirstTimeWizard', 'First Time Wizard')) - first_time_wizard.title_label.setText('%s' % - translate('OpenLP.FirstTimeWizard', 'Welcome to the First Time Wizard')) + text = translate('OpenLP.FirstTimeWizard', 'Welcome to the First Time Wizard') + first_time_wizard.title_label.setText('{text}' + ''.format(text=text)) + button = clean_button_text(first_time_wizard.buttonText(QtWidgets.QWizard.NextButton)) first_time_wizard.information_label.setText( translate('OpenLP.FirstTimeWizard', 'This wizard will help you to configure OpenLP for initial use. ' - 'Click the %s button below to start.') % - clean_button_text(first_time_wizard.buttonText(QtWidgets.QWizard.NextButton))) + 'Click the {button} button below to start.').format(button=button)) self.download_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Downloading Resource Index')) self.download_page.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Please wait while the resource index is ' 'downloaded.')) @@ -264,18 +265,19 @@ class UiFirstTimeWizard(object): self.no_internet_page.setTitle(translate('OpenLP.FirstTimeWizard', 'No Internet Connection')) self.no_internet_page.setSubTitle( translate('OpenLP.FirstTimeWizard', 'Unable to detect an Internet connection.')) + button = clean_button_text(first_time_wizard.buttonText(QtWidgets.QWizard.FinishButton)) self.no_internet_text = translate('OpenLP.FirstTimeWizard', 'No Internet connection was found. The First Time Wizard needs an Internet ' 'connection in order to be able to download sample songs, Bibles and themes.' - ' Click the %s button now to start OpenLP with initial settings and ' + ' Click the {button} button now to start OpenLP with initial settings and ' 'no sample data.\n\nTo re-run the First Time Wizard and import this sample ' 'data at a later time, check your Internet connection and re-run this ' - 'wizard by selecting "Tools/Re-run First Time Wizard" from OpenLP.') % \ - clean_button_text(first_time_wizard.buttonText(QtWidgets.QWizard.FinishButton)) + 'wizard by selecting "Tools/Re-run First Time Wizard" from OpenLP.' + ).format(button=button) + button = clean_button_text(first_time_wizard.buttonText(QtWidgets.QWizard.CancelButton)) self.cancel_wizard_text = translate('OpenLP.FirstTimeWizard', '\n\nTo cancel the First Time Wizard completely (and not start OpenLP), ' - 'click the %s button now.') % \ - clean_button_text(first_time_wizard.buttonText(QtWidgets.QWizard.CancelButton)) + 'click the {button} button now.').format(button=button) self.songs_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Sample Songs')) self.songs_page.setSubTitle(translate('OpenLP.FirstTimeWizard', 'Select and download public domain songs.')) self.bibles_page.setTitle(translate('OpenLP.FirstTimeWizard', 'Sample Bibles')) diff --git a/openlp/core/ui/formattingtagcontroller.py b/openlp/core/ui/formattingtagcontroller.py index b56f5009c..161930cb6 100644 --- a/openlp/core/ui/formattingtagcontroller.py +++ b/openlp/core/ui/formattingtagcontroller.py @@ -72,19 +72,19 @@ class FormattingTagController(object): """ for line_number, html1 in enumerate(self.protected_tags): if self._strip(html1['start tag']) == tag: - return translate('OpenLP.FormattingTagForm', 'Tag %s already defined.') % tag + return translate('OpenLP.FormattingTagForm', 'Tag {tag} already defined.').format(tag=tag) if self._strip(html1['desc']) == desc: - return translate('OpenLP.FormattingTagForm', 'Description %s already defined.') % tag + return translate('OpenLP.FormattingTagForm', 'Description {tag} already defined.').format(tag=tag) for line_number, html1 in enumerate(self.custom_tags): if self._strip(html1['start tag']) == tag: - return translate('OpenLP.FormattingTagForm', 'Tag %s already defined.') % tag + return translate('OpenLP.FormattingTagForm', 'Tag {tag} already defined.').format(tag=tag) if self._strip(html1['desc']) == desc: - return translate('OpenLP.FormattingTagForm', 'Description %s already defined.') % tag + return translate('OpenLP.FormattingTagForm', 'Description {tag} already defined.').format(tag=tag) tag = { 'desc': desc, - 'start tag': '{%s}' % tag, + 'start tag': '{{{tag}}}'.format(tag=tag), 'start html': start_html, - 'end tag': '{/%s}' % tag, + 'end tag': '{/{tag}}}'.format(tag=tag), 'end html': end_html, 'protected': False, 'temporary': False @@ -130,6 +130,7 @@ class FormattingTagController(object): elif not match.group('empty'): end_tags.append(tag) match = self.html_tag_regex.search(start_html, match.end()) + # TODO: Verify format() works with lambda return ''.join(map(lambda tag: '' % tag, reversed(end_tags))) def start_tag_changed(self, start_html, end_html): @@ -146,7 +147,8 @@ class FormattingTagController(object): end = self.start_html_to_end_html(start_html) if not end_html: if not end: - return translate('OpenLP.FormattingTagForm', 'Start tag %s is not valid HTML') % start_html, None + return translate('OpenLP.FormattingTagForm', + 'Start tag {tag} is not valid HTML').format(tag=start_html), None return None, end return None, None @@ -165,7 +167,8 @@ class FormattingTagController(object): if not end_html: return None, end if end and end != end_html: - return translate('OpenLP.FormattingTagForm', - 'End tag %(end)s does not match end tag for start tag %(start)s') % \ - {'end': end, 'start': start_html}, None + return (translate('OpenLP.FormattingTagForm', + 'End tag {end} does not match end tag for start tag {start}').format(end=end, + start=start_html), + None) return None, None diff --git a/openlp/core/ui/formattingtagform.py b/openlp/core/ui/formattingtagform.py index 6fb658f06..658653875 100644 --- a/openlp/core/ui/formattingtagform.py +++ b/openlp/core/ui/formattingtagform.py @@ -90,9 +90,10 @@ class FormattingTagForm(QtWidgets.QDialog, Ui_FormattingTagDialog, FormattingTag """ new_row = self.tag_table_widget.rowCount() self.tag_table_widget.insertRow(new_row) - self.tag_table_widget.setItem(new_row, 0, QtWidgets.QTableWidgetItem(translate('OpenLP.FormattingTagForm', - 'New Tag %d' % new_row))) - self.tag_table_widget.setItem(new_row, 1, QtWidgets.QTableWidgetItem('n%d' % new_row)) + self.tag_table_widget.setItem(new_row, 0, + QtWidgets.QTableWidgetItem(translate('OpenLP.FormattingTagForm', + 'New Tag {row:d}').format(row=new_row))) + self.tag_table_widget.setItem(new_row, 1, QtWidgets.QTableWidgetItem('n{row:d}'.format(row=new_row))) self.tag_table_widget.setItem(new_row, 2, QtWidgets.QTableWidgetItem(translate('OpenLP.FormattingTagForm', ''))) self.tag_table_widget.setItem(new_row, 3, QtWidgets.QTableWidgetItem('')) diff --git a/openlp/core/ui/generaltab.py b/openlp/core/ui/generaltab.py index 816e947ba..9fdc7d297 100644 --- a/openlp/core/ui/generaltab.py +++ b/openlp/core/ui/generaltab.py @@ -400,7 +400,7 @@ class GeneralTab(SettingsTab): """ Select the logo file """ - file_filters = '%s;;%s (*.*)' % (get_images_filter(), UiStrings().AllFiles) + file_filters = '{text};;{names} (*.*)'.format(text=get_images_filter(), names=UiStrings().AllFiles) filename, filter_used = QtWidgets.QFileDialog.getOpenFileName(self, translate('OpenLP.AdvancedTab', 'Open File'), '', file_filters) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index a0235bb9b..ccd12727c 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -471,7 +471,8 @@ class Ui_MainWindow(object): self.web_site_item.setText(translate('OpenLP.MainWindow', '&Web Site')) for item in self.language_group.actions(): item.setText(item.objectName()) - item.setStatusTip(translate('OpenLP.MainWindow', 'Set the interface language to %s') % item.objectName()) + item.setStatusTip(translate('OpenLP.MainWindow', + 'Set the interface language to {name}').format(name=item.objectName())) self.auto_language_item.setText(translate('OpenLP.MainWindow', '&Autodetect')) self.auto_language_item.setStatusTip(translate('OpenLP.MainWindow', 'Use the system language, if available.')) self.tools_add_tool_item.setText(translate('OpenLP.MainWindow', 'Add &Tool...')) @@ -1334,8 +1335,10 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, RegistryProperties): for file_id, filename in enumerate(recent_files_to_display): log.debug('Recent file name: {name}'.format(name=filename)) # TODO: Verify ''.format() before committing - action = create_action(self, '', text='&%d %s' % (file_id + 1, - os.path.splitext(os.path.basename(str(filename)))[0]), data=filename, + action = create_action(self, '', + text='&{n} {name}'.format(n=file_id + 1, + name=os.path.splitext(os.path.basename(str(filename)))[0]), + data=filename, triggers=self.service_manager_contents.on_recent_service_clicked) self.recent_files_menu.addAction(action) clear_recent_files_action = create_action(self, '', diff --git a/openlp/core/ui/plugindialog.py b/openlp/core/ui/plugindialog.py index 583728fcd..ad461cd44 100644 --- a/openlp/core/ui/plugindialog.py +++ b/openlp/core/ui/plugindialog.py @@ -74,6 +74,6 @@ class Ui_PluginViewDialog(object): """ plugin_view_dialog.setWindowTitle(translate('OpenLP.PluginForm', 'Manage Plugins')) self.plugin_info_group_box.setTitle(translate('OpenLP.PluginForm', 'Plugin Details')) - self.about_label.setText('%s:' % UiStrings().About) + self.about_label.setText('{about}:'.format(about=UiStrings().About)) self.status_label.setText(translate('OpenLP.PluginForm', 'Status:')) self.status_checkbox.setText(translate('OpenLP.PluginForm', 'Active')) diff --git a/openlp/core/ui/pluginform.py b/openlp/core/ui/pluginform.py index cb6dd70aa..4280bcd25 100644 --- a/openlp/core/ui/pluginform.py +++ b/openlp/core/ui/pluginform.py @@ -60,6 +60,7 @@ class PluginForm(QtWidgets.QDialog, Ui_PluginViewDialog, RegistryProperties): self._clear_details() self.programatic_change = True plugin_list_width = 0 + # TODO: See how to use format() with variables for plugin in self.plugin_manager.plugins: item = QtWidgets.QListWidgetItem(self.plugin_list_widget) # We do this just to make 100% sure the status is an integer as @@ -94,7 +95,7 @@ class PluginForm(QtWidgets.QDialog, Ui_PluginViewDialog, RegistryProperties): """ Set the details of the currently selected plugin """ - log.debug('PluginStatus: %s', str(self.active_plugin.status)) + log.debug('PluginStatus: {status}'.format(status=str(self.active_plugin.status))) self.about_text_browser.setHtml(self.active_plugin.about()) self.programatic_change = True if self.active_plugin.status != PluginStatus.Disabled: @@ -136,6 +137,7 @@ class PluginForm(QtWidgets.QDialog, Ui_PluginViewDialog, RegistryProperties): self.active_plugin.app_startup() else: self.active_plugin.toggle_status(PluginStatus.Inactive) + # TODO: Verify using format() with a variable status_text = translate('OpenLP.PluginForm', '%s (Inactive)') if self.active_plugin.status == PluginStatus.Active: status_text = translate('OpenLP.PluginForm', '%s (Active)') diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 35ec1bb9e..907cb49a6 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -118,7 +118,7 @@ class Ui_ServiceManager(object): tooltip=translate('OpenLP.ServiceManager', 'Save this service.'), triggers=self.decide_save_method) self.toolbar.addSeparator() - self.theme_label = QtWidgets.QLabel('%s:' % UiStrings().Theme, widget) + self.theme_label = QtWidgets.QLabel('{theme}:'.format(theme=UiStrings().Theme), widget) self.theme_label.setContentsMargins(3, 3, 3, 3) self.theme_label.setObjectName('theme_label') self.toolbar.add_toolbar_widget(self.theme_label) @@ -503,8 +503,8 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa path_file_name = str(self.file_name()) path, file_name = os.path.split(path_file_name) base_name = os.path.splitext(file_name)[0] - service_file_name = '%s.osj' % base_name - self.log_debug('ServiceManager.save_file - %s' % path_file_name) + service_file_name = '{name}.osj'.format(name=base_name) + self.log_debug('ServiceManager.save_file - {name}'.format(name=path_file_name)) Settings().setValue(self.main_window.service_manager_settings_section + '/last directory', path) service = self.create_basic_service() write_list = [] @@ -530,8 +530,9 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa self.application.set_normal_cursor() title = translate('OpenLP.ServiceManager', 'Service File(s) Missing') message = translate('OpenLP.ServiceManager', - 'The following file(s) in the service are missing: %s\n\n' - 'These files will be removed if you continue to save.') % "\n\t".join(missing_list) + 'The following file(s) in the service are missing: {name}\n\n' + 'These files will be removed if you continue to save.' + ).format(name="\n\t".join(missing_list)) answer = QtWidgets.QMessageBox.critical(self, title, message, QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel)) @@ -561,7 +562,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa service_content = json.dumps(service) # Usual Zip file cannot exceed 2GiB, file with Zip64 cannot be extracted using unzip in UNIX. allow_zip_64 = (total_size > 2147483648 + len(service_content)) - self.log_debug('ServiceManager.save_file - allowZip64 is %s' % allow_zip_64) + self.log_debug('ServiceManager.save_file - allowZip64 is {text}'.format(text=allow_zip_64)) zip_file = None success = True self.main_window.increment_progress_bar() @@ -584,7 +585,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa shutil.copy(audio_from, save_file) zip_file.write(audio_from, audio_to) except IOError: - self.log_exception('Failed to save service to disk: %s' % temp_file_name) + self.log_exception('Failed to save service to disk: {name}'.format(name=temp_file_name)) self.main_window.error_message(translate('OpenLP.ServiceManager', 'Error Saving File'), translate('OpenLP.ServiceManager', 'There was an error saving your file.')) success = False @@ -601,7 +602,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa except OSError as ose: QtWidgets.QMessageBox.critical(self, translate('OpenLP.ServiceManager', 'Error Saving File'), translate('OpenLP.ServiceManager', 'An error occurred while writing the ' - 'service file: %s') % ose.strerror, + 'service file: {error}').format(error=ose.strerror), QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Ok)) success = False self.main_window.add_recent_file(path_file_name) @@ -623,8 +624,8 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa path_file_name = str(self.file_name()) path, file_name = os.path.split(path_file_name) base_name = os.path.splitext(file_name)[0] - service_file_name = '%s.osj' % base_name - self.log_debug('ServiceManager.save_file - %s' % path_file_name) + service_file_name = '{name}.osj'.format(name=base_name) + self.log_debug('ServiceManager.save_file - {name}'.format(name=path_file_name)) Settings().setValue(self.main_window.service_manager_settings_section + '/last directory', path) service = self.create_basic_service() self.application.set_busy_cursor() @@ -645,7 +646,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa # First we add service contents. zip_file.writestr(service_file_name, service_content) except IOError: - self.log_exception('Failed to save service to disk: %s', temp_file_name) + self.log_exception('Failed to save service to disk: {name}'.format(name=temp_file_name)) self.main_window.error_message(translate('OpenLP.ServiceManager', 'Error Saving File'), translate('OpenLP.ServiceManager', 'There was an error saving your file.')) success = False @@ -740,13 +741,13 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa try: ucs_file = zip_info.filename except UnicodeDecodeError: - self.log_exception('file_name "%s" is not valid UTF-8' % zip_info.file_name) + self.log_exception('file_name "{name}" is not valid UTF-8'.format(name=zip_info.file_name)) critical_error_message_box(message=translate('OpenLP.ServiceManager', 'File is not a valid service.\n The content encoding is not UTF-8.')) continue os_file = ucs_file.replace('/', os.path.sep) os_file = os.path.basename(os_file) - self.log_debug('Extract file: %s' % os_file) + self.log_debug('Extract file: {name}'.format(name=os_file)) zip_info.filename = os_file zip_file.extract(zip_info, self.service_path) if os_file.endswith('osj') or os_file.endswith('osd'): @@ -774,18 +775,18 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa critical_error_message_box(message=translate('OpenLP.ServiceManager', 'File is not a valid service.')) self.log_error('File contains no service data') except (IOError, NameError, zipfile.BadZipfile): - self.log_exception('Problem loading service file %s' % file_name) + self.log_exception('Problem loading service file {name}'.format(name=file_name)) critical_error_message_box(message=translate('OpenLP.ServiceManager', 'File could not be opened because it is corrupt.')) except zipfile.BadZipfile: if os.path.getsize(file_name) == 0: - self.log_exception('Service file is zero sized: %s' % file_name) + self.log_exception('Service file is zero sized: {name}'.format(name=file_name)) QtWidgets.QMessageBox.information(self, translate('OpenLP.ServiceManager', 'Empty File'), translate('OpenLP.ServiceManager', 'This service file does not contain ' 'any data.')) else: - self.log_exception('Service file is cannot be extracted as zip: %s' % file_name) + self.log_exception('Service file is cannot be extracted as zip: {name}'.format(name=file_name)) QtWidgets.QMessageBox.information(self, translate('OpenLP.ServiceManager', 'Corrupt File'), translate('OpenLP.ServiceManager', 'This file is either corrupt or it is not an OpenLP 2 ' @@ -874,7 +875,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa self.auto_play_slides_loop.setChecked(service_item['service_item'].auto_play_slides_loop) self.timed_slide_interval.setChecked(service_item['service_item'].timed_slide_interval > 0) if service_item['service_item'].timed_slide_interval > 0: - delay_suffix = ' %s s' % str(service_item['service_item'].timed_slide_interval) + delay_suffix = ' {text} s'.format(text=str(service_item['service_item'].timed_slide_interval)) else: delay_suffix = ' ...' self.timed_slide_interval.setText( @@ -1268,14 +1269,17 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa tree_widget_item.setText(0, service_item_from_item.get_display_title()) tips = [] if service_item_from_item.temporary_edit: - tips.append('%s: %s' % (translate('OpenLP.ServiceManager', 'Edit'), - (translate('OpenLP.ServiceManager', 'Service copy only')))) + text1 = translate('OpenLP.ServiceManager', 'Edit') + text2 = translate('OpenLP.ServiceManager', 'Service copy only') + tips.append('{text1}: {text2}'.format(text1=text1, text2=text2)) if service_item_from_item.theme and service_item_from_item.theme != -1: - tips.append('%s: %s' % - (translate('OpenLP.ServiceManager', 'Slide theme'), service_item_from_item.theme)) + text = translate('OpenLP.ServiceManager', 'Slide theme') + tips.append('{text1}: {text2}'.format(text1=text, + text2=service_item_from_item.theme)) if service_item_from_item.notes: - tips.append('%s: %s' % - (translate('OpenLP.ServiceManager', 'Notes'), html.escape(service_item_from_item.notes))) + text1 = translate('OpenLP.ServiceManager', 'Notes') + text2 = html.escape(service_item_from_item.notes) + tips.append('{text1}: {text2}'.format(text1=text1, text2=text2)) if item['service_item'].is_capable(ItemCapabilities.HasVariableStartTime): tips.append(item['service_item'].get_media_time()) tree_widget_item.setToolTip(0, '
'.join(tips)) @@ -1637,7 +1641,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa replace = True else: self.drop_position = get_parent_item_data(item) - 1 - Registry().execute('%s_add_service_item' % plugin, replace) + Registry().execute('{plugin}_add_service_item'.format(plugin=plugin), replace) def update_theme_list(self, theme_list): """ diff --git a/openlp/core/ui/settingsform.py b/openlp/core/ui/settingsform.py index 82d72694c..42558b830 100644 --- a/openlp/core/ui/settingsform.py +++ b/openlp/core/ui/settingsform.py @@ -85,7 +85,7 @@ class SettingsForm(QtWidgets.QDialog, Ui_SettingsDialog, RegistryProperties): :param tab_widget: The widget to add :param is_visible: If this tab should be visible """ - log.debug('Inserting %s tab' % tab_widget.tab_title) + log.debug('Inserting {text} tab'.format(text=tab_widget.tab_title)) # add the tab to get it to display in the correct part of the screen self.stacked_layout.addWidget(tab_widget) if is_visible: diff --git a/openlp/core/ui/shortcutlistform.py b/openlp/core/ui/shortcutlistform.py index e0d72d9e1..1266d1cc4 100644 --- a/openlp/core/ui/shortcutlistform.py +++ b/openlp/core/ui/shortcutlistform.py @@ -425,11 +425,12 @@ class ShortcutListForm(QtWidgets.QDialog, Ui_ShortcutListDialog, RegistryPropert if changing_action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]: is_valid = False if not is_valid: + text = translate('OpenLP.ShortcutListDialog', + 'The shortcut "{key}" is already assigned to another action, please' + ' use a different shortcut.' + ).format(key=self.get_shortcut_string(key_sequence)) self.main_window.warning_message(translate('OpenLP.ShortcutListDialog', 'Duplicate Shortcut'), - translate('OpenLP.ShortcutListDialog', - 'The shortcut "%s" is already assigned to another action, please' - ' use a different shortcut.') % - self.get_shortcut_string(key_sequence, for_display=True)) + text, for_display=True) self.dialog_was_shown = True return is_valid diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index c06860057..9379bb96f 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -98,7 +98,7 @@ class DisplayController(QtWidgets.QWidget): """ sender = self.sender().objectName() if self.sender().objectName() else self.sender().text() controller = self - Registry().execute('%s' % sender, [controller, args]) + Registry().execute('{text}'.format(text=sender), [controller, args]) class InfoLabel(QtWidgets.QLabel): @@ -395,7 +395,7 @@ class SlideController(DisplayController, RegistryProperties): {'key': 'O', 'configurable': True, 'text': translate('OpenLP.SlideController', 'Go to "Other"')} ] shortcuts.extend([{'key': str(number)} for number in range(10)]) - self.controller.addActions([create_action(self, 'shortcutAction_%s' % s['key'], + self.controller.addActions([create_action(self, 'shortcutAction_{key}'.format(key=s['key']), text=s.get('text'), can_shortcuts=True, context=QtCore.Qt.WidgetWithChildrenShortcut, @@ -417,14 +417,20 @@ class SlideController(DisplayController, RegistryProperties): self.preview_widget.doubleClicked.connect(self.on_preview_double_click) self.toolbar.set_widget_visible(['editSong'], False) self.controller.addActions([self.next_item, self.previous_item]) - Registry().register_function('slidecontroller_%s_stop_loop' % self.type_prefix, self.on_stop_loop) - Registry().register_function('slidecontroller_%s_change' % self.type_prefix, self.on_slide_change) - Registry().register_function('slidecontroller_%s_blank' % self.type_prefix, self.on_slide_blank) - Registry().register_function('slidecontroller_%s_unblank' % self.type_prefix, self.on_slide_unblank) + Registry().register_function('slidecontroller_{text}_stop_loop'.format(text=self.type_prefix), + self.on_stop_loop) + Registry().register_function('slidecontroller_{text}_change'.format(text=self.type_prefix), + self.on_slide_change) + Registry().register_function('slidecontroller_{text}_blank'.format(text=self.type_prefix), + self.on_slide_blank) + Registry().register_function('slidecontroller_{text}_unblank'.format(text=self.type_prefix), + self.on_slide_unblank) Registry().register_function('slidecontroller_update_slide_limits', self.update_slide_limits) - getattr(self, 'slidecontroller_%s_set' % self.type_prefix).connect(self.on_slide_selected_index) - getattr(self, 'slidecontroller_%s_next' % self.type_prefix).connect(self.on_slide_selected_next) - getattr(self, 'slidecontroller_%s_previous' % self.type_prefix).connect(self.on_slide_selected_previous) + getattr(self, 'slidecontroller_{text}_set'.format(text=self.type_prefix)).connect(self.on_slide_selected_index) + getattr(self, 'slidecontroller_{text}_next'.format(text=self.type_prefix)).connect(self.on_slide_selected_next) + # NOTE: {t} used to keep line length < maxline + getattr(self, + 'slidecontroller_{t}_previous'.format(t=self.type_prefix)).connect(self.on_slide_selected_previous) def _slide_shortcut_activated(self): """ @@ -841,7 +847,8 @@ class SlideController(DisplayController, RegistryProperties): self.service_item = copy.copy(service_item) if self.service_item.is_command(): Registry().execute( - '%s_start' % service_item.name.lower(), [self.service_item, self.is_live, self.hide_mode(), slide_no]) + '{text}_start'.format(text=service_item.name.lower()), + [self.service_item, self.is_live, self.hide_mode(), slide_no]) # Reset blanking if needed if old_item and self.is_live and (old_item.is_capable(ItemCapabilities.ProvidesOwnDisplay) or self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay)): @@ -879,8 +886,8 @@ class SlideController(DisplayController, RegistryProperties): if frame['verseTag']: # These tags are already translated. verse_def = frame['verseTag'] - verse_def = '%s%s' % (verse_def[0], verse_def[1:]) - two_line_def = '%s\n%s' % (verse_def[0], verse_def[1:]) + verse_def = '{def1}{def2}'.format(def1=verse_def[0], def2=verse_def[1:]) + two_line_def = '{def1}\n{def2}'.format(def1=verse_def[0], def2=verse_def[1:]) row = two_line_def if verse_def not in self.slide_list: self.slide_list[verse_def] = frame_number @@ -915,10 +922,10 @@ class SlideController(DisplayController, RegistryProperties): # close the previous, so make sure we don't close the new one. if old_item.is_command() and not self.service_item.is_command() or \ old_item.is_command() and not old_item.is_media() and self.service_item.is_media(): - Registry().execute('%s_stop' % old_item.name.lower(), [old_item, self.is_live]) + Registry().execute('{name}_stop'.format(name=old_item.name.lower()), [old_item, self.is_live]) if old_item.is_media() and not self.service_item.is_media(): self.on_media_close() - Registry().execute('slidecontroller_%s_started' % self.type_prefix, [self.service_item]) + Registry().execute('slidecontroller_{item}_started'.format(item=self.type_prefix), [self.service_item]) def on_slide_selected_index(self, message): """ @@ -930,7 +937,8 @@ class SlideController(DisplayController, RegistryProperties): if not self.service_item: return if self.service_item.is_command(): - Registry().execute('%s_slide' % self.service_item.name.lower(), [self.service_item, self.is_live, index]) + Registry().execute('{name}_slide'.format(name=self.service_item.name.lower()), + [self.service_item, self.is_live, index]) self.update_preview() self.selected_row = index else: @@ -975,7 +983,7 @@ class SlideController(DisplayController, RegistryProperties): """ if checked is None: checked = self.blank_screen.isChecked() - self.log_debug('on_blank_display %s' % checked) + self.log_debug('on_blank_display {text}'.format(text=checked)) self.hide_menu.setDefaultAction(self.blank_screen) self.blank_screen.setChecked(checked) self.theme_screen.setChecked(False) @@ -996,7 +1004,7 @@ class SlideController(DisplayController, RegistryProperties): """ if checked is None: checked = self.theme_screen.isChecked() - self.log_debug('on_theme_display %s' % checked) + self.log_debug('on_theme_display {text}'.format(text=checked)) self.hide_menu.setDefaultAction(self.theme_screen) self.blank_screen.setChecked(False) self.theme_screen.setChecked(checked) @@ -1017,7 +1025,7 @@ class SlideController(DisplayController, RegistryProperties): """ if checked is None: checked = self.desktop_screen.isChecked() - self.log_debug('on_hide_display %s' % checked) + self.log_debug('on_hide_display {text}'.format(text=checked)) self.hide_menu.setDefaultAction(self.desktop_screen) self.blank_screen.setChecked(False) self.theme_screen.setChecked(False) @@ -1035,17 +1043,18 @@ class SlideController(DisplayController, RegistryProperties): Blank/Hide the display screen within a plugin if required. """ hide_mode = self.hide_mode() - self.log_debug('blank_plugin %s ' % hide_mode) + self.log_debug('blank_plugin {text}'.format(text=hide_mode)) if self.service_item is not None: if hide_mode: if not self.service_item.is_command(): Registry().execute('live_display_hide', hide_mode) - Registry().execute('%s_blank' % - self.service_item.name.lower(), [self.service_item, self.is_live, hide_mode]) + Registry().execute('{text}_blank'.format(text=self.service_item.name.lower()), + [self.service_item, self.is_live, hide_mode]) else: if not self.service_item.is_command(): Registry().execute('live_display_show') - Registry().execute('%s_unblank' % self.service_item.name.lower(), [self.service_item, self.is_live]) + Registry().execute('{text}_unblank'.format(text=self.service_item.name.lower()), + [self.service_item, self.is_live]) else: if hide_mode: Registry().execute('live_display_hide', hide_mode) @@ -1056,15 +1065,17 @@ class SlideController(DisplayController, RegistryProperties): """ Tell the plugin to hide the display screen. """ - self.log_debug('hide_plugin %s ' % hide) + self.log_debug('hide_plugin {text}'.format(text=hide)) if self.service_item is not None: if hide: Registry().execute('live_display_hide', HideMode.Screen) - Registry().execute('%s_hide' % self.service_item.name.lower(), [self.service_item, self.is_live]) + Registry().execute('{text}_hide'.format(text=self.service_item.name.lower()), + [self.service_item, self.is_live]) else: if not self.service_item.is_command(): Registry().execute('live_display_show') - Registry().execute('%s_unblank' % self.service_item.name.lower(), [self.service_item, self.is_live]) + Registry().execute('{text}_unblank'.format(text=self.service_item.name.lower()), + [self.service_item, self.is_live]) else: if hide: Registry().execute('live_display_hide', HideMode.Screen) @@ -1099,8 +1110,8 @@ class SlideController(DisplayController, RegistryProperties): if -1 < row < self.preview_widget.slide_count(): if self.service_item.is_command(): if self.is_live and not start: - Registry().execute('%s_slide' % - self.service_item.name.lower(), [self.service_item, self.is_live, row]) + Registry().execute('{text}_slide'.format(text=self.service_item.name.lower()), + [self.service_item, self.is_live, row]) else: to_display = self.service_item.get_rendered_frame(row) if self.service_item.is_text(): @@ -1133,7 +1144,7 @@ class SlideController(DisplayController, RegistryProperties): """ This updates the preview frame, for example after changing a slide or using *Blank to Theme*. """ - self.log_debug('update_preview %s ' % self.screens.current['primary']) + self.log_debug('update_preview {text} '.format(text=self.screens.current['primary'])) if self.service_item and self.service_item.is_capable(ItemCapabilities.ProvidesOwnDisplay): if self.is_live: # If live, grab screen-cap of main display now @@ -1185,7 +1196,8 @@ class SlideController(DisplayController, RegistryProperties): if not self.service_item: return if self.service_item.is_command(): - Registry().execute('%s_next' % self.service_item.name.lower(), [self.service_item, self.is_live]) + Registry().execute('{text}_next'.format(text=self.service_item.name.lower()), + [self.service_item, self.is_live]) if self.is_live: self.update_preview() else: @@ -1213,7 +1225,8 @@ class SlideController(DisplayController, RegistryProperties): if not self.service_item: return if self.service_item.is_command(): - Registry().execute('%s_previous' % self.service_item.name.lower(), [self.service_item, self.is_live]) + Registry().execute('{text}_previous'.format(text=self.service_item.name.lower()), + [self.service_item, self.is_live]) if self.is_live: self.update_preview() else: @@ -1265,7 +1278,7 @@ class SlideController(DisplayController, RegistryProperties): checked = self.play_slides_loop.isChecked() else: self.play_slides_loop.setChecked(checked) - self.log_debug('on_play_slides_loop %s' % checked) + self.log_debug('on_play_slides_loop {text}'.format(text=checked)) if checked: self.play_slides_loop.setIcon(build_icon(':/media/media_stop.png')) self.play_slides_loop.setText(UiStrings().StopPlaySlidesInLoop) @@ -1288,7 +1301,7 @@ class SlideController(DisplayController, RegistryProperties): checked = self.play_slides_once.isChecked() else: self.play_slides_once.setChecked(checked) - self.log_debug('on_play_slides_once %s' % checked) + self.log_debug('on_play_slides_once {text}'.format(text=checked)) if checked: self.play_slides_once.setIcon(build_icon(':/media/media_stop.png')) self.play_slides_once.setText(UiStrings().StopPlaySlidesToEnd) @@ -1354,7 +1367,8 @@ class SlideController(DisplayController, RegistryProperties): # Live and Preview have issues if we have video or presentations # playing in both at the same time. if self.service_item.is_command(): - Registry().execute('%s_stop' % self.service_item.name.lower(), [self.service_item, self.is_live]) + Registry().execute('{text}_stop'.format(text=self.service_item.name.lower()), + [self.service_item, self.is_live]) if self.service_item.is_media(): self.on_media_close() self.on_go_live() diff --git a/openlp/core/ui/starttimeform.py b/openlp/core/ui/starttimeform.py index f6238a340..386608970 100644 --- a/openlp/core/ui/starttimeform.py +++ b/openlp/core/ui/starttimeform.py @@ -56,9 +56,9 @@ class StartTimeForm(QtWidgets.QDialog, Ui_StartTimeDialog, RegistryProperties): self.hour_finish_spin_box.setValue(hours) self.minute_finish_spin_box.setValue(minutes) self.second_finish_spin_box.setValue(seconds) - self.hour_finish_label.setText('%s%s' % (str(hour), UiStrings().Hours)) - self.minute_finish_label.setText('%s%s' % (str(minutes), UiStrings().Minutes)) - self.second_finish_label.setText('%s%s' % (str(seconds), UiStrings().Seconds)) + self.hour_finish_label.setText('{val:d}{text}'.format(val=hour, text=UiStrings().Hours)) + self.minute_finish_label.setText('{val:d}{text}'.format(val=minutes, text=UiStrings().Minutes)) + self.second_finish_label.setText('{val:d}{text}'.format(val=seconds, text=UiStrings().Seconds)) return QtWidgets.QDialog.exec(self) def accept(self): diff --git a/openlp/core/ui/themeform.py b/openlp/core/ui/themeform.py index 2ec733629..475bfc0b7 100644 --- a/openlp/core/ui/themeform.py +++ b/openlp/core/ui/themeform.py @@ -263,7 +263,7 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties): """ Run the wizard. """ - log.debug('Editing theme %s' % self.theme.theme_name) + log.debug('Editing theme {name}'.format(name=self.theme.theme_name)) self.temp_background_filename = '' self.update_theme_allowed = False self.set_defaults() @@ -272,7 +272,8 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties): self.theme_name_edit.setVisible(not edit) self.edit_mode = edit if edit: - self.setWindowTitle(translate('OpenLP.ThemeWizard', 'Edit Theme - %s') % self.theme.theme_name) + self.setWindowTitle(translate('OpenLP.ThemeWizard', 'Edit Theme - {name}' + ).format(name=self.theme.theme_name)) self.next() else: self.setWindowTitle(UiStrings().NewTheme) @@ -282,7 +283,7 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties): """ Set up the pages for Initial run through dialog """ - log.debug('initializePage %s' % page_id) + log.debug('initializePage {page}'.format(page=page_id)) wizard_page = self.page(page_id) if wizard_page == self.background_page: self.set_background_page_values() @@ -445,7 +446,7 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties): Background Image button pushed. """ images_filter = get_images_filter() - images_filter = '%s;;%s (*.*)' % (images_filter, UiStrings().AllFiles) + images_filter = '{name};;{text} (*.*)'.format(name=images_filter, text=UiStrings().AllFiles) filename, filter_used = QtWidgets.QFileDialog.getOpenFileName( self, translate('OpenLP.ThemeWizard', 'Select Image'), self.image_file_edit.text(), images_filter) @@ -463,6 +464,7 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties): """ Background video button pushed. """ + # TODO: Check this before converting visible_formats = '(%s)' % '; '.join(VIDEO_EXT) actual_formats = '(%s)' % ' '.join(VIDEO_EXT) video_filter = '{trans} {visible} {actual}'.format(trans=translate('OpenLP', 'Video Files'), diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index 14a4663f4..70ca9fd88 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -203,7 +203,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage Change the global theme when it is changed through the Themes settings tab """ self.global_theme = Settings().value(self.settings_section + '/global theme') - self.log_debug('change_global_from_tab %s' % self.global_theme) + self.log_debug('change_global_from_tab {text}'.format(text=self.global_theme)) for count in range(0, self.theme_list_widget.count()): # reset the old name item = self.theme_list_widget.item(count) @@ -213,7 +213,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage self.theme_list_widget.item(count).setText(new_name) # Set the new name if self.global_theme == new_name: - name = translate('OpenLP.ThemeManager', '%s (default)') % new_name + name = translate('OpenLP.ThemeManager', '{text} (default)').format(text=new_name) self.theme_list_widget.item(count).setText(name) self.delete_toolbar_action.setVisible(item not in self.theme_list_widget.selectedItems()) @@ -233,7 +233,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage # Set the new name if count == selected_row: self.global_theme = self.theme_list_widget.item(count).text() - name = translate('OpenLP.ThemeManager', '%s (default)') % self.global_theme + name = translate('OpenLP.ThemeManager', '{text} (default)').format(text=self.global_theme) self.theme_list_widget.item(count).setText(name) Settings().setValue(self.settings_section + '/global theme', self.global_theme) Registry().execute('theme_update_global') @@ -256,6 +256,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage Renames an existing theme to a new name :param field: """ + # TODO: Check for delayed format() conversions if self._validate_theme_action(translate('OpenLP.ThemeManager', 'You must select a theme to rename.'), translate('OpenLP.ThemeManager', 'Rename Confirmation'), translate('OpenLP.ThemeManager', 'Rename %s theme?'), False, False): @@ -284,7 +285,8 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage item = self.theme_list_widget.currentItem() old_theme_name = item.data(QtCore.Qt.UserRole) self.file_rename_form.file_name_edit.setText(translate('OpenLP.ThemeManager', - 'Copy of %s', 'Copy of ') % old_theme_name) + 'Copy of {name}', + 'Copy of ').format(name=old_theme_name)) if self.file_rename_form.exec(True): new_theme_name = self.file_rename_form.file_name_edit.text() if self.check_if_theme_exists(new_theme_name): @@ -331,6 +333,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage Delete a theme triggered by the UI. :param field: """ + # TODO: Verify delayed format() conversions if self._validate_theme_action(translate('OpenLP.ThemeManager', 'You must select a theme to delete.'), translate('OpenLP.ThemeManager', 'Delete Confirmation'), translate('OpenLP.ThemeManager', 'Delete %s theme?')): @@ -351,7 +354,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage :param theme: The theme to delete. """ self.theme_list.remove(theme) - thumb = '%s.png' % theme + thumb = '{name}.png'.format(name=theme) delete_file(os.path.join(self.path, thumb)) delete_file(os.path.join(self.thumb_path, thumb)) try: @@ -363,7 +366,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage shutil.rmtree(os.path.join(self.path, theme).encode(encoding)) except OSError as os_error: shutil.Error = os_error - self.log_exception('Error deleting theme %s' % theme) + self.log_exception('Error deleting theme {name}'.format(name=theme)) def on_export_theme(self, field=None): """ @@ -376,7 +379,8 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage return theme = item.data(QtCore.Qt.UserRole) path = QtWidgets.QFileDialog.getExistingDirectory(self, - translate('OpenLP.ThemeManager', 'Save Theme - (%s)') % theme, + translate('OpenLP.ThemeManager', + 'Save Theme - ({name})').format(name=theme), Settings().value(self.settings_section + '/last directory export')) self.application.set_busy_cursor() @@ -409,7 +413,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage self.log_exception('Export Theme Failed') critical_error_message_box(translate('OpenLP.ThemeManager', 'Theme Export Failed'), translate('OpenLP.ThemeManager', 'The theme export failed because this error ' - 'occurred: %s') % ose.strerror) + 'occurred: {err}').format(err=ose.strerror)) if theme_zip: theme_zip.close() shutil.rmtree(theme_path, True) @@ -425,7 +429,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage translate('OpenLP.ThemeManager', 'Select Theme Import File'), Settings().value(self.settings_section + '/last directory import'), translate('OpenLP.ThemeManager', 'OpenLP Themes (*.otz)')) - self.log_info('New Themes %s' % str(files)) + self.log_info('New Themes {name}'.format(name=str(files))) if not files: return self.application.set_busy_cursor() @@ -472,10 +476,10 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage if os.path.exists(theme): text_name = os.path.splitext(name)[0] if text_name == self.global_theme: - name = translate('OpenLP.ThemeManager', '%s (default)') % text_name + name = translate('OpenLP.ThemeManager', '{name} (default)').format(name=text_name) else: name = text_name - thumb = os.path.join(self.thumb_path, '%s.png' % text_name) + thumb = os.path.join(self.thumb_path, '{name}.png'.format(name=text_name)) item_name = QtWidgets.QListWidgetItem(name) if validate_thumb(theme, thumb): icon = build_icon(thumb) @@ -506,7 +510,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage :param theme_name: Name of the theme to load from file :return: The theme object. """ - self.log_debug('get theme data for theme %s' % theme_name) + self.log_debug('get theme data for theme {name}'.format(name=theme_name)) xml_file = os.path.join(self.path, str(theme_name), str(theme_name) + '.xml') xml = get_text_file_string(xml_file) if not xml: @@ -524,8 +528,8 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage """ ret = QtWidgets.QMessageBox.question(self, translate('OpenLP.ThemeManager', 'Theme Already Exists'), translate('OpenLP.ThemeManager', - 'Theme %s already exists. Do you want to replace it?') - .replace('%s', theme_name), + 'Theme {name} already exists. ' + 'Do you want to replace it?').format(name=theme_name), QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No), QtWidgets.QMessageBox.No) @@ -538,7 +542,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage :param file_name: :param directory: """ - self.log_debug('Unzipping theme %s' % file_name) + self.log_debug('Unzipping theme {name}'.format(name=file_name)) theme_zip = None out_file = None file_xml = None @@ -547,7 +551,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage theme_zip = zipfile.ZipFile(file_name) xml_file = [name for name in theme_zip.namelist() if os.path.splitext(name)[1].lower() == '.xml'] if len(xml_file) != 1: - self.log_error('Theme contains "%s" XML files' % len(xml_file)) + self.log_error('Theme contains "{val:d}" XML files'.format(val=len(xml_file))) raise ValidationError xml_tree = ElementTree(element=XML(theme_zip.read(xml_file[0]))).getroot() theme_version = xml_tree.get('version', default=None) @@ -579,7 +583,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage out_file.write(theme_zip.read(name)) out_file.close() except (IOError, zipfile.BadZipfile): - self.log_exception('Importing theme from zip failed %s' % file_name) + self.log_exception('Importing theme from zip failed {name|'.format(name=file_name)) raise ValidationError except ValidationError: critical_error_message_box(translate('OpenLP.ThemeManager', 'Validation Error'), @@ -601,7 +605,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage critical_error_message_box( translate('OpenLP.ThemeManager', 'Validation Error'), translate('OpenLP.ThemeManager', 'File is not a valid theme.')) - self.log_error('Theme file does not contain XML data %s' % file_name) + self.log_error('Theme file does not contain XML data {name}'.format(name=file_name)) def check_if_theme_exists(self, theme_name): """ @@ -682,7 +686,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage if os.path.exists(sample_path_name): os.unlink(sample_path_name) frame.save(sample_path_name, 'png') - thumb = os.path.join(self.thumb_path, '%s.png' % name) + thumb = os.path.join(self.thumb_path, '{name}.png'.format(name=name)) create_thumb(sample_path_name, thumb, False) def update_preview_images(self): @@ -760,14 +764,17 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage for plugin in self.plugin_manager.plugins: used_count = plugin.uses_theme(theme) if used_count: - plugin_usage = "%s%s" % (plugin_usage, (translate('OpenLP.ThemeManager', - '%(count)s time(s) by %(plugin)s') % - {'count': used_count, 'plugin': plugin.name})) + plugin_usage = "{plug}{text}".format(plug=plugin_usage, + text=(translate('OpenLP.ThemeManager', + '{count} time(s) by {plugin}' + ).format(name=used_count, + plugin=plugin.name))) plugin_usage = "%s\n" % plugin_usage if plugin_usage: critical_error_message_box(translate('OpenLP.ThemeManager', 'Unable to delete theme'), - translate('OpenLP.ThemeManager', 'Theme is currently used \n\n%s') % - plugin_usage) + translate('OpenLP.ThemeManager', + 'Theme is currently used \n\n{text}' + ).format(text=plugin_usage)) return False return True diff --git a/openlp/core/ui/themewizard.py b/openlp/core/ui/themewizard.py index b546c1872..e1ef1dd78 100644 --- a/openlp/core/ui/themewizard.py +++ b/openlp/core/ui/themewizard.py @@ -405,8 +405,8 @@ class Ui_ThemeWizard(object): Translate the UI on the fly """ theme_wizard.setWindowTitle(translate('OpenLP.ThemeWizard', 'Theme Wizard')) - self.title_label.setText('%s' % - translate('OpenLP.ThemeWizard', 'Welcome to the Theme Wizard')) + text = translate('OpenLP.ThemeWizard', 'Welcome to the Theme Wizard') + self.title_label.setText('{text}'.format(text=text)) self.information_label.setText( translate('OpenLP.ThemeWizard', 'This wizard will help you to create and edit your themes. Click the next ' 'button below to start the process by setting up your background.')) @@ -435,9 +435,9 @@ class Ui_ThemeWizard(object): self.gradient_combo_box.setItemText(BackgroundGradientType.LeftBottom, translate('OpenLP.ThemeWizard', 'Bottom Left - Top Right')) self.image_color_label.setText(translate('OpenLP.ThemeWizard', 'Background color:')) - self.image_label.setText('%s:' % UiStrings().Image) + self.image_label.setText('{text}:'.format(text=UiStrings().Image)) self.video_color_label.setText(translate('OpenLP.ThemeWizard', 'Background color:')) - self.video_label.setText('%s:' % UiStrings().Video) + self.video_label.setText('{text}:'.format(text=UiStrings().Video)) self.main_area_page.setTitle(translate('OpenLP.ThemeWizard', 'Main Area Font Details')) self.main_area_page.setSubTitle(translate('OpenLP.ThemeWizard', 'Define the font and display ' 'characteristics for the Display text')) diff --git a/tests/functional/openlp_core_lib/test_projectordb.py b/tests/functional/openlp_core_lib/test_projectordb.py index c1b9ce3d1..a6ecb617d 100644 --- a/tests/functional/openlp_core_lib/test_projectordb.py +++ b/tests/functional/openlp_core_lib/test_projectordb.py @@ -28,7 +28,7 @@ PREREQUISITE: add_record() and get_all() functions validated. import os from unittest import TestCase -from openlp.core.lib.projector.db import Manufacturer, Model, Projector, ProjectorDB, ProjectorSource +from openlp.core.lib.projector.db import Manufacturer, Model, Projector, ProjectorDB, ProjectorSource, Source from tests.functional import MagicMock, patch from tests.resources.projector.data import TEST_DB, TEST1_DATA, TEST2_DATA, TEST3_DATA @@ -220,3 +220,19 @@ class TestProjectorDB(TestCase): # THEN: __repr__ should return a proper string self.assertEqual(str(model), '', 'Model.__repr__() should have returned a proper representation string') + + def source_repr_test(self): + """ + Test source.__repr__ text + """ + # GIVEN: Test object + source = Source() + + # WHEN: Source() information is set + source.pjlink_name = 'Test object' + source.pjlink_code = '11' + source.text = 'Input text' + + # THEN: __repr__ should return a proper string + self.assertEqual(str(source), '', + 'Source.__repr__() should have returned a proper representation string') From 1ea5d72d1e9da7e5f7805ad889042a7f0bf302f5 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sat, 21 May 2016 06:02:31 +0100 Subject: [PATCH 12/62] fix formatting tags and move SpellText Edit --- openlp/core/lib/__init__.py | 4 +- openlp/core/lib/spelltextedit.py | 203 ------------------ openlp/core/ui/lib/__init__.py | 3 +- openlp/core/ui/printservicedialog.py | 3 +- openlp/core/ui/servicenoteform.py | 2 +- .../custom/forms/editcustomslidedialog.py | 3 +- openlp/plugins/songs/forms/editversedialog.py | 3 +- 7 files changed, 10 insertions(+), 211 deletions(-) delete mode 100644 openlp/core/lib/spelltextedit.py diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index 59053e283..a7e01bd24 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -24,13 +24,12 @@ The :mod:`lib` module contains most of the components and libraries that make OpenLP work. """ -from distutils.version import LooseVersion import logging import os +from distutils.version import LooseVersion from PyQt5 import QtCore, QtGui, Qt, QtWidgets - from openlp.core.common import translate log = logging.getLogger(__name__ + '.__init__') @@ -342,7 +341,6 @@ from .exceptions import ValidationError from .filedialog import FileDialog from .screen import ScreenList from .formattingtags import FormattingTags -from .spelltextedit import SpellTextEdit from .plugin import PluginStatus, StringContent, Plugin from .pluginmanager import PluginManager from .settingstab import SettingsTab diff --git a/openlp/core/lib/spelltextedit.py b/openlp/core/lib/spelltextedit.py deleted file mode 100644 index 3b97323af..000000000 --- a/openlp/core/lib/spelltextedit.py +++ /dev/null @@ -1,203 +0,0 @@ -# -*- coding: utf-8 -*- -# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 - -############################################################################### -# OpenLP - Open Source Lyrics Projection # -# --------------------------------------------------------------------------- # -# Copyright (c) 2008-2016 OpenLP Developers # -# --------------------------------------------------------------------------- # -# This program is free software; you can redistribute it and/or modify it # -# under the terms of the GNU General Public License as published by the Free # -# Software Foundation; version 2 of the License. # -# # -# This program is distributed in the hope that it will be useful, but WITHOUT # -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # -# more details. # -# # -# You should have received a copy of the GNU General Public License along # -# with this program; if not, write to the Free Software Foundation, Inc., 59 # -# Temple Place, Suite 330, Boston, MA 02111-1307 USA # -############################################################################### -""" -The :mod:`~openlp.core.lib.spelltextedit` module contains a classes to add spell checking to an edit widget. -""" - -import logging -import re - -try: - import enchant - from enchant import DictNotFoundError - from enchant.errors import Error - ENCHANT_AVAILABLE = True -except ImportError: - ENCHANT_AVAILABLE = False - -# based on code from http://john.nachtimwald.com/2009/08/22/qplaintextedit-with-in-line-spell-check - -from PyQt5 import QtCore, QtGui, QtWidgets - -from openlp.core.lib import translate, FormattingTags -from openlp.core.lib.ui import create_action - -log = logging.getLogger(__name__) - - -class SpellTextEdit(QtWidgets.QPlainTextEdit): - """ - Spell checking widget based on QPlanTextEdit. - """ - def __init__(self, parent=None, formatting_tags_allowed=True): - """ - Constructor. - """ - global ENCHANT_AVAILABLE - super(SpellTextEdit, self).__init__(parent) - self.formatting_tags_allowed = formatting_tags_allowed - # Default dictionary based on the current locale. - if ENCHANT_AVAILABLE: - try: - self.dictionary = enchant.Dict() - self.highlighter = Highlighter(self.document()) - self.highlighter.spelling_dictionary = self.dictionary - except (Error, DictNotFoundError): - ENCHANT_AVAILABLE = False - log.debug('Could not load default dictionary') - - def mousePressEvent(self, event): - """ - Handle mouse clicks within the text edit region. - """ - if event.button() == QtCore.Qt.RightButton: - # Rewrite the mouse event to a left button event so the cursor is moved to the location of the pointer. - event = QtGui.QMouseEvent(QtCore.QEvent.MouseButtonPress, - event.pos(), QtCore.Qt.LeftButton, QtCore.Qt.LeftButton, QtCore.Qt.NoModifier) - QtWidgets.QPlainTextEdit.mousePressEvent(self, event) - - def contextMenuEvent(self, event): - """ - Provide the context menu for the text edit region. - """ - popup_menu = self.createStandardContextMenu() - # Select the word under the cursor. - cursor = self.textCursor() - # only select text if not already selected - if not cursor.hasSelection(): - cursor.select(QtGui.QTextCursor.WordUnderCursor) - self.setTextCursor(cursor) - # Add menu with available languages. - if ENCHANT_AVAILABLE: - lang_menu = QtWidgets.QMenu(translate('OpenLP.SpellTextEdit', 'Language:')) - for lang in enchant.list_languages(): - action = create_action(lang_menu, lang, text=lang, checked=lang == self.dictionary.tag) - lang_menu.addAction(action) - popup_menu.insertSeparator(popup_menu.actions()[0]) - popup_menu.insertMenu(popup_menu.actions()[0], lang_menu) - lang_menu.triggered.connect(self.set_language) - # Check if the selected word is misspelled and offer spelling suggestions if it is. - if ENCHANT_AVAILABLE and self.textCursor().hasSelection(): - text = self.textCursor().selectedText() - if not self.dictionary.check(text): - spell_menu = QtWidgets.QMenu(translate('OpenLP.SpellTextEdit', 'Spelling Suggestions')) - for word in self.dictionary.suggest(text): - action = SpellAction(word, spell_menu) - action.correct.connect(self.correct_word) - spell_menu.addAction(action) - # Only add the spelling suggests to the menu if there are suggestions. - if spell_menu.actions(): - popup_menu.insertMenu(popup_menu.actions()[0], spell_menu) - tag_menu = QtWidgets.QMenu(translate('OpenLP.SpellTextEdit', 'Formatting Tags')) - if self.formatting_tags_allowed: - for html in FormattingTags.get_html_tags(): - action = SpellAction(html['desc'], tag_menu) - action.correct.connect(self.html_tag) - tag_menu.addAction(action) - popup_menu.insertSeparator(popup_menu.actions()[0]) - popup_menu.insertMenu(popup_menu.actions()[0], tag_menu) - popup_menu.exec(event.globalPos()) - - def set_language(self, action): - """ - Changes the language for this spelltextedit. - - :param action: The action. - """ - self.dictionary = enchant.Dict(action.text()) - self.highlighter.spelling_dictionary = self.dictionary - self.highlighter.highlightBlock(self.toPlainText()) - self.highlighter.rehighlight() - - def correct_word(self, word): - """ - Replaces the selected text with word. - """ - cursor = self.textCursor() - cursor.beginEditBlock() - cursor.removeSelectedText() - cursor.insertText(word) - cursor.endEditBlock() - - def html_tag(self, tag): - """ - Replaces the selected text with word. - """ - for html in FormattingTags.get_html_tags(): - if tag == html['desc']: - cursor = self.textCursor() - if self.textCursor().hasSelection(): - text = cursor.selectedText() - cursor.beginEditBlock() - cursor.removeSelectedText() - cursor.insertText(html['start tag']) - cursor.insertText(text) - cursor.insertText(html['end tag']) - cursor.endEditBlock() - else: - cursor = self.textCursor() - cursor.insertText(html['start tag']) - cursor.insertText(html['end tag']) - - -class Highlighter(QtGui.QSyntaxHighlighter): - """ - Provides a text highlighter for pointing out spelling errors in text. - """ - WORDS = '(?iu)[\w\']+' - - def __init__(self, *args): - """ - Constructor - """ - super(Highlighter, self).__init__(*args) - self.spelling_dictionary = None - - def highlightBlock(self, text): - """ - Highlight mis spelt words in a block of text. - - Note, this is a Qt hook. - """ - if not self.spelling_dictionary: - return - text = str(text) - char_format = QtGui.QTextCharFormat() - char_format.setUnderlineColor(QtCore.Qt.red) - char_format.setUnderlineStyle(QtGui.QTextCharFormat.SpellCheckUnderline) - for word_object in re.finditer(self.WORDS, text): - if not self.spelling_dictionary.check(word_object.group()): - self.setFormat(word_object.start(), word_object.end() - word_object.start(), char_format) - - -class SpellAction(QtWidgets.QAction): - """ - A special QAction that returns the text in a signal. - """ - correct = QtCore.pyqtSignal(str) - - def __init__(self, *args): - """ - Constructor - """ - super(SpellAction, self).__init__(*args) - self.triggered.connect(lambda x: self.correct.emit(self.text())) diff --git a/openlp/core/ui/lib/__init__.py b/openlp/core/ui/lib/__init__.py index 6cdeac8a6..ae81b10ad 100644 --- a/openlp/core/ui/lib/__init__.py +++ b/openlp/core/ui/lib/__init__.py @@ -28,6 +28,7 @@ from .dockwidget import OpenLPDockWidget from .wizard import OpenLPWizard, WizardStrings from .mediadockmanager import MediaDockManager from .listpreviewwidget import ListPreviewWidget +from .spelltextedit import SpellTextEdit __all__ = ['ColorButton', 'ListPreviewWidget', 'ListWidgetWithDnD', 'OpenLPToolbar', 'OpenLPDockWidget', - 'OpenLPWizard', 'WizardStrings', 'MediaDockManager', 'ListPreviewWidget'] + 'OpenLPWizard', 'WizardStrings', 'MediaDockManager', 'ListPreviewWidget', 'SpellTextEdit'] diff --git a/openlp/core/ui/printservicedialog.py b/openlp/core/ui/printservicedialog.py index 93a42e2a8..c658d1496 100644 --- a/openlp/core/ui/printservicedialog.py +++ b/openlp/core/ui/printservicedialog.py @@ -25,7 +25,8 @@ The UI widgets of the print service dialog. from PyQt5 import QtCore, QtWidgets, QtPrintSupport from openlp.core.common import UiStrings, translate -from openlp.core.lib import SpellTextEdit, build_icon +from openlp.core.lib import build_icon +from openlp.core.ui.lib import SpellTextEdit class ZoomSize(object): diff --git a/openlp/core/ui/servicenoteform.py b/openlp/core/ui/servicenoteform.py index e998304f8..383c47048 100644 --- a/openlp/core/ui/servicenoteform.py +++ b/openlp/core/ui/servicenoteform.py @@ -25,7 +25,7 @@ The :mod:`~openlp.core.ui.servicenoteform` module contains the `ServiceNoteForm` from PyQt5 import QtCore, QtWidgets from openlp.core.common import Registry, RegistryProperties, translate -from openlp.core.lib import SpellTextEdit +from openlp.core.ui.lib import SpellTextEdit from openlp.core.lib.ui import create_button_box diff --git a/openlp/plugins/custom/forms/editcustomslidedialog.py b/openlp/plugins/custom/forms/editcustomslidedialog.py index c5212c84e..5f46c6f28 100644 --- a/openlp/plugins/custom/forms/editcustomslidedialog.py +++ b/openlp/plugins/custom/forms/editcustomslidedialog.py @@ -23,8 +23,9 @@ from PyQt5 import QtWidgets from openlp.core.common import UiStrings, translate -from openlp.core.lib import SpellTextEdit, build_icon +from openlp.core.lib import build_icon from openlp.core.lib.ui import create_button, create_button_box +from openlp.core.ui.lib import SpellTextEdit class Ui_CustomSlideEditDialog(object): diff --git a/openlp/plugins/songs/forms/editversedialog.py b/openlp/plugins/songs/forms/editversedialog.py index 144d59efc..6819f3ca6 100644 --- a/openlp/plugins/songs/forms/editversedialog.py +++ b/openlp/plugins/songs/forms/editversedialog.py @@ -22,7 +22,8 @@ from PyQt5 import QtWidgets -from openlp.core.lib import SpellTextEdit, build_icon, translate +from openlp.core.ui.lib import SpellTextEdit +from openlp.core.lib import build_icon, translate from openlp.core.lib.ui import UiStrings, create_button_box from openlp.plugins.songs.lib import VerseType From d0f6d21774e8b6f0f7b00699cd8b4f22584e18d9 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sat, 21 May 2016 06:24:05 +0100 Subject: [PATCH 13/62] Add Working flags --- openlp/core/common/registry.py | 41 +++- openlp/core/ui/lib/spelltextedit.py | 204 ++++++++++++++++++ .../openlp_core_common/test_registry.py | 38 +++- 3 files changed, 280 insertions(+), 3 deletions(-) create mode 100644 openlp/core/ui/lib/spelltextedit.py diff --git a/openlp/core/common/registry.py b/openlp/core/common/registry.py index b904d627c..65547819a 100644 --- a/openlp/core/common/registry.py +++ b/openlp/core/common/registry.py @@ -55,6 +55,7 @@ class Registry(object): registry = cls() registry.service_list = {} registry.functions_list = {} + registry.working_flags = {} # Allow the tests to remove Registry entries but not the live system registry.running_under_test = 'nose' in sys.argv[0] registry.initialising = True @@ -90,8 +91,7 @@ class Registry(object): def remove(self, key): """ - Removes the registry value from the list based on the key passed in (Only valid and active for testing - framework). + Removes the registry value from the list based on the key passed in. :param key: The service to be deleted. """ @@ -145,3 +145,40 @@ class Registry(object): trace_error_handler(log) log.error("Event {event} called but not registered".format(event=event)) return results + + def get_flag(self, key): + """ + Extracts the working_flag value from the list based on the key passed in + + :param key: The flag to be retrieved. + """ + if key in self.working_flags: + return self.working_flags[key] + else: + trace_error_handler(log) + log.error('Working Flag {key} not found in list'.format(key=key)) + raise KeyError('Working Flag {key} not found in list'.format(key=key)) + + def set_flag(self, key, reference): + """ + Sets a working_flag based on the key passed in. + + :param key: The working_flag to be created this is usually a major class like "renderer" or "main_window" . + :param reference: The data to be saved. + """ + if key in self.working_flags: + trace_error_handler(log) + log.error('Duplicate Working Flag exception {key}'.format(key=key)) + raise KeyError('Duplicate Working Flag exception {key}'.format(key=key)) + else: + self.working_flags[key] = reference + + def remove_flag(self, key): + """ + Removes the working flags value from the list based on the key passed. + + :param key: The working_flag to be deleted. + """ + if key in self.working_flags: + del self.working_flags[key] + diff --git a/openlp/core/ui/lib/spelltextedit.py b/openlp/core/ui/lib/spelltextedit.py new file mode 100644 index 000000000..c16bd0bca --- /dev/null +++ b/openlp/core/ui/lib/spelltextedit.py @@ -0,0 +1,204 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2016 OpenLP Developers # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### +""" +The :mod:`~openlp.core.lib.spelltextedit` module contains a classes to add spell checking to an edit widget. +""" + +import logging +import re + +try: + import enchant + from enchant import DictNotFoundError + from enchant.errors import Error + ENCHANT_AVAILABLE = True +except ImportError: + ENCHANT_AVAILABLE = False + +# based on code from http://john.nachtimwald.com/2009/08/22/qplaintextedit-with-in-line-spell-check + +from PyQt5 import QtCore, QtGui, QtWidgets + +from openlp.core.lib import translate, FormattingTags +from openlp.core.lib.ui import create_action + +log = logging.getLogger(__name__) + + +class SpellTextEdit(QtWidgets.QPlainTextEdit): + """ + Spell checking widget based on QPlanTextEdit. + """ + def __init__(self, parent=None, formatting_tags_allowed=True): + """ + Constructor. + """ + global ENCHANT_AVAILABLE + super(SpellTextEdit, self).__init__(parent) + self.formatting_tags_allowed = formatting_tags_allowed + # Default dictionary based on the current locale. + if ENCHANT_AVAILABLE: + try: + self.dictionary = enchant.Dict() + self.highlighter = Highlighter(self.document()) + self.highlighter.spelling_dictionary = self.dictionary + except (Error, DictNotFoundError): + ENCHANT_AVAILABLE = False + log.debug('Could not load default dictionary') + + def mousePressEvent(self, event): + """ + Handle mouse clicks within the text edit region. + """ + if event.button() == QtCore.Qt.RightButton: + # Rewrite the mouse event to a left button event so the cursor is moved to the location of the pointer. + event = QtGui.QMouseEvent(QtCore.QEvent.MouseButtonPress, + event.pos(), QtCore.Qt.LeftButton, QtCore.Qt.LeftButton, QtCore.Qt.NoModifier) + QtWidgets.QPlainTextEdit.mousePressEvent(self, event) + + def contextMenuEvent(self, event): + """ + Provide the context menu for the text edit region. + """ + popup_menu = self.createStandardContextMenu() + # Select the word under the cursor. + cursor = self.textCursor() + # only select text if not already selected + if not cursor.hasSelection(): + cursor.select(QtGui.QTextCursor.WordUnderCursor) + self.setTextCursor(cursor) + # Add menu with available languages. + if ENCHANT_AVAILABLE: + lang_menu = QtWidgets.QMenu(translate('OpenLP.SpellTextEdit', 'Language:')) + for lang in enchant.list_languages(): + action = create_action(lang_menu, lang, text=lang, checked=lang == self.dictionary.tag) + lang_menu.addAction(action) + popup_menu.insertSeparator(popup_menu.actions()[0]) + popup_menu.insertMenu(popup_menu.actions()[0], lang_menu) + lang_menu.triggered.connect(self.set_language) + # Check if the selected word is misspelled and offer spelling suggestions if it is. + if ENCHANT_AVAILABLE and self.textCursor().hasSelection(): + text = self.textCursor().selectedText() + if not self.dictionary.check(text): + spell_menu = QtWidgets.QMenu(translate('OpenLP.SpellTextEdit', 'Spelling Suggestions')) + for word in self.dictionary.suggest(text): + action = SpellAction(word, spell_menu) + action.correct.connect(self.correct_word) + spell_menu.addAction(action) + # Only add the spelling suggests to the menu if there are suggestions. + if spell_menu.actions(): + popup_menu.insertMenu(popup_menu.actions()[0], spell_menu) + tag_menu = QtWidgets.QMenu(translate('OpenLP.SpellTextEdit', 'Formatting Tags')) + if self.formatting_tags_allowed: + for html in FormattingTags.get_html_tags(): + action = SpellAction(html['desc'], tag_menu) + action.correct.connect(self.html_tag) + tag_menu.addAction(action) + popup_menu.insertSeparator(popup_menu.actions()[0]) + popup_menu.insertMenu(popup_menu.actions()[0], tag_menu) + popup_menu.exec(event.globalPos()) + + def set_language(self, action): + """ + Changes the language for this spelltextedit. + + :param action: The action. + """ + self.dictionary = enchant.Dict(action.text()) + self.highlighter.spelling_dictionary = self.dictionary + self.highlighter.highlightBlock(self.toPlainText()) + self.highlighter.rehighlight() + + def correct_word(self, word): + """ + Replaces the selected text with word. + """ + cursor = self.textCursor() + cursor.beginEditBlock() + cursor.removeSelectedText() + cursor.insertText(word) + cursor.endEditBlock() + + def html_tag(self, tag): + """ + Replaces the selected text with word. + """ + for html in FormattingTags.get_html_tags(): + tag = tag.replace('&', '') + if tag == html['desc']: + cursor = self.textCursor() + if self.textCursor().hasSelection(): + text = cursor.selectedText() + cursor.beginEditBlock() + cursor.removeSelectedText() + cursor.insertText(html['start tag']) + cursor.insertText(text) + cursor.insertText(html['end tag']) + cursor.endEditBlock() + else: + cursor = self.textCursor() + cursor.insertText(html['start tag']) + cursor.insertText(html['end tag']) + + +class Highlighter(QtGui.QSyntaxHighlighter): + """ + Provides a text highlighter for pointing out spelling errors in text. + """ + WORDS = '(?iu)[\w\']+' + + def __init__(self, *args): + """ + Constructor + """ + super(Highlighter, self).__init__(*args) + self.spelling_dictionary = None + + def highlightBlock(self, text): + """ + Highlight mis spelt words in a block of text. + + Note, this is a Qt hook. + """ + if not self.spelling_dictionary: + return + text = str(text) + char_format = QtGui.QTextCharFormat() + char_format.setUnderlineColor(QtCore.Qt.red) + char_format.setUnderlineStyle(QtGui.QTextCharFormat.SpellCheckUnderline) + for word_object in re.finditer(self.WORDS, text): + if not self.spelling_dictionary.check(word_object.group()): + self.setFormat(word_object.start(), word_object.end() - word_object.start(), char_format) + + +class SpellAction(QtWidgets.QAction): + """ + A special QAction that returns the text in a signal. + """ + correct = QtCore.pyqtSignal(str) + + def __init__(self, *args): + """ + Constructor + """ + super(SpellAction, self).__init__(*args) + self.triggered.connect(lambda x: self.correct.emit(self.text())) diff --git a/tests/functional/openlp_core_common/test_registry.py b/tests/functional/openlp_core_common/test_registry.py index db46f3239..0cac19bcd 100644 --- a/tests/functional/openlp_core_common/test_registry.py +++ b/tests/functional/openlp_core_common/test_registry.py @@ -59,7 +59,7 @@ class TestRegistry(TestCase): temp = Registry().get('test2') self.assertEqual(temp, None, 'None should have been returned for missing service') - # WHEN I try to replace a component I should be allowed (testing only) + # WHEN I try to replace a component I should be allowed Registry().remove('test1') # THEN I will get an exception temp = Registry().get('test1') @@ -93,6 +93,42 @@ class TestRegistry(TestCase): # THEN: I expect then function to have been called and a return given self.assertEqual(return_value[0], 'function_2', 'A return value is provided and matches') + def registry_working_flags_test(self): + """ + Test the registry working flags creation and its usage + """ + # GIVEN: A new registry + Registry.create() + + # WHEN: I add a working flag it should save it + my_data = 'Lamas' + Registry().set_flag('test1', my_data) + + # THEN: we should be able retrieve the saved component + assert Registry().get_flag('test1') == my_data, 'The working flag can be retrieved and matches' + + # WHEN: I add a component for the second time I am mad. + # THEN and I will get an exception + with self.assertRaises(KeyError) as context: + Registry().set_flag('test1', my_data) + self.assertEqual(context.exception.args[0], 'Duplicate Working Flag exception test1', + 'KeyError exception should have been thrown for duplicate working flag') + + # WHEN I try to get back a non existent Working Flag + # THEN I will get an exception + with self.assertRaises(KeyError) as context1: + temp = Registry().get_flag('test2') + self.assertEqual(context1.exception.args[0], 'Working Flag test2 not found in list', + 'KeyError exception should have been thrown for missing working flag') + + # WHEN I try to replace a working flag I should be allowed + Registry().remove_flag('test1') + # THEN I will get an exception + with self.assertRaises(KeyError) as context: + temp = Registry().get_flag('test1') + self.assertEqual(context.exception.args[0], 'Working Flag test1 not found in list', + 'KeyError exception should have been thrown for duplicate working flag') + def remove_function_test(self): """ Test the remove_function() method From af36dc4c41eeb1f36c3bbec27e4daa0a350442e3 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sat, 21 May 2016 06:28:13 +0100 Subject: [PATCH 14/62] pep8 --- openlp/core/common/registry.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openlp/core/common/registry.py b/openlp/core/common/registry.py index 65547819a..ee322d87d 100644 --- a/openlp/core/common/registry.py +++ b/openlp/core/common/registry.py @@ -181,4 +181,3 @@ class Registry(object): """ if key in self.working_flags: del self.working_flags[key] - From d52cebdfcaafb6d4c3824b393f0980c91fab919d Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Sat, 21 May 2016 01:31:24 -0700 Subject: [PATCH 15/62] Update strings in alerts and bible plugins to python3 --- openlp/plugins/alerts/alertsplugin.py | 10 ++- openlp/plugins/alerts/lib/alertsmanager.py | 2 +- openlp/plugins/alerts/lib/alertstab.py | 3 +- .../plugins/bibles/forms/bibleimportform.py | 15 +++- .../plugins/bibles/forms/bibleupgradeform.py | 70 +++++++++------ .../plugins/bibles/forms/editbibledialog.py | 9 +- openlp/plugins/bibles/forms/editbibleform.py | 15 ++-- openlp/plugins/bibles/lib/csvbible.py | 12 +-- openlp/plugins/bibles/lib/db.py | 60 ++++++------- openlp/plugins/bibles/lib/http.py | 87 +++++++++++-------- openlp/plugins/bibles/lib/manager.py | 36 ++++---- openlp/plugins/bibles/lib/mediaitem.py | 78 ++++++++++------- openlp/plugins/bibles/lib/opensong.py | 14 +-- openlp/plugins/bibles/lib/osis.py | 9 +- openlp/plugins/bibles/lib/sword.py | 6 +- openlp/plugins/bibles/lib/upgrade.py | 10 +-- .../plugins/bibles/lib/versereferencelist.py | 22 +++-- openlp/plugins/bibles/lib/zefania.py | 11 +-- .../openlp_core_lib/test_projectordb.py | 35 +++++++- .../openlp_plugins/bibles/test_http.py | 6 +- 20 files changed, 309 insertions(+), 201 deletions(-) diff --git a/openlp/plugins/alerts/alertsplugin.py b/openlp/plugins/alerts/alertsplugin.py index 61640262b..828b0c566 100644 --- a/openlp/plugins/alerts/alertsplugin.py +++ b/openlp/plugins/alerts/alertsplugin.py @@ -88,6 +88,7 @@ JAVASCRIPT = """ } } """ +# TODO: Verify format() with variable templates CSS = """ #alert { position: absolute; @@ -244,6 +245,9 @@ class AlertsPlugin(Plugin): :param frame: The Web frame holding the page. """ align = VerticalType.Names[self.settings_tab.location] - frame.evaluateJavaScript('update_css("%s", "%s", "%s", "%s", "%s")' % - (align, self.settings_tab.font_face, self.settings_tab.font_size, - self.settings_tab.font_color, self.settings_tab.background_color)) + frame.evaluateJavaScript('update_css("{align}", "{face}", "{size}", "{color}", ' + '"{background}")'.format(align=align, + face=self.settings_tab.font_face, + size=self.settings_tab.font_size, + color=self.settings_tab.font_color, + background=self.settings_tab.background_color)) diff --git a/openlp/plugins/alerts/lib/alertsmanager.py b/openlp/plugins/alerts/lib/alertsmanager.py index fd9fbaf09..1bc3413f9 100644 --- a/openlp/plugins/alerts/lib/alertsmanager.py +++ b/openlp/plugins/alerts/lib/alertsmanager.py @@ -62,7 +62,7 @@ class AlertsManager(OpenLPMixin, RegistryMixin, QtCore.QObject, RegistryProperti :param text: The text to display """ - self.log_debug('display alert called %s' % text) + self.log_debug('display alert called {text}'.format(text=text)) if text: self.alert_list.append(text) if self.timer_id != 0: diff --git a/openlp/plugins/alerts/lib/alertstab.py b/openlp/plugins/alerts/lib/alertstab.py index 2859a71ce..5240b7fa8 100644 --- a/openlp/plugins/alerts/lib/alertstab.py +++ b/openlp/plugins/alerts/lib/alertstab.py @@ -197,5 +197,6 @@ class AlertsTab(SettingsTab): font.setBold(True) font.setPointSize(self.font_size) self.font_preview.setFont(font) - self.font_preview.setStyleSheet('background-color: %s; color: %s' % (self.background_color, self.font_color)) + self.font_preview.setStyleSheet('background-color: {back}; color: {front}'.format(back=self.background_color, + front=self.font_color)) self.changed = True diff --git a/openlp/plugins/bibles/forms/bibleimportform.py b/openlp/plugins/bibles/forms/bibleimportform.py index 3289e66e9..e1407404c 100644 --- a/openlp/plugins/bibles/forms/bibleimportform.py +++ b/openlp/plugins/bibles/forms/bibleimportform.py @@ -593,22 +593,27 @@ class BibleImportForm(OpenLPWizard): """ Show the file open dialog for the books CSV file. """ + # TODO: Verify format() with varible template self.get_file_name( - WizardStrings.OpenTypeFile % WizardStrings.CSV, self.csv_books_edit, 'last directory import', '%s (*.csv)' % - translate('BiblesPlugin.ImportWizardForm', 'CSV File')) + WizardStrings.OpenTypeFile % WizardStrings.CSV, + self.csv_books_edit, + 'last directory import', + '{name} (*.csv)'.format(name=translate('BiblesPlugin.ImportWizardForm', 'CSV File'))) def on_csv_verses_browse_button_clicked(self): """ Show the file open dialog for the verses CSV file. """ + # TODO: Verify format() with variable template self.get_file_name(WizardStrings.OpenTypeFile % WizardStrings.CSV, self.csv_verses_edit, - 'last directory import', '%s (*.csv)' % - translate('BiblesPlugin.ImportWizardForm', 'CSV File')) + 'last directory import', + '{name} (*.csv)'.format(name=translate('BiblesPlugin.ImportWizardForm', 'CSV File'))) def on_open_song_browse_button_clicked(self): """ Show the file open dialog for the OpenSong file. """ + # TODO: Verify format() with variable template self.get_file_name(WizardStrings.OpenTypeFile % WizardStrings.OS, self.open_song_file_edit, 'last directory import') @@ -616,6 +621,7 @@ class BibleImportForm(OpenLPWizard): """ Show the file open dialog for the Zefania file. """ + # TODO: Verify format() with variable template self.get_file_name(WizardStrings.OpenTypeFile % WizardStrings.ZEF, self.zefania_file_edit, 'last directory import') @@ -631,6 +637,7 @@ class BibleImportForm(OpenLPWizard): self.web_progress_bar.setVisible(True) self.web_progress_bar.setValue(0) proxy_server = self.field('proxy_server') + # TODO: Where does critical_error_message_box get %s string from? for (download_type, extractor) in ((WebDownload.Crosswalk, CWExtract(proxy_server)), (WebDownload.BibleGateway, BGExtract(proxy_server)), (WebDownload.Bibleserver, BSExtract(proxy_server))): diff --git a/openlp/plugins/bibles/forms/bibleupgradeform.py b/openlp/plugins/bibles/forms/bibleupgradeform.py index 11771e9aa..fc246b93d 100644 --- a/openlp/plugins/bibles/forms/bibleupgradeform.py +++ b/openlp/plugins/bibles/forms/bibleupgradeform.py @@ -209,7 +209,7 @@ class BibleUpgradeForm(OpenLPWizard): for number, filename in enumerate(self.files): bible = OldBibleDB(self.media_item, path=self.path, file=filename[0]) self.checkBox[number] = QtWidgets.QCheckBox(self.scrollAreaContents) - self.checkBox[number].setObjectName('checkBox[%d]' % number) + self.checkBox[number].setObjectName('checkBox[{count:d}]'.format(count=number)) self.checkBox[number].setText(bible.get_name()) self.checkBox[number].setCheckState(QtCore.Qt.Checked) self.formLayout.addWidget(self.checkBox[number]) @@ -364,7 +364,10 @@ class BibleUpgradeForm(OpenLPWizard): name = filename[1] self.progress_label.setText( translate('BiblesPlugin.UpgradeWizardForm', - 'Upgrading Bible %s of %s: "%s"\nUpgrading ...') % (number + 1, max_bibles, name)) + 'Upgrading Bible {count} of {total}: "{name}"\n' + 'Upgrading ...').format(count=number + 1, + total=max_bibles, + name=name)) self.new_bibles[number] = BibleDB(self.media_item, path=self.path, name=name, file=filename[0]) self.new_bibles[number].register(self.plugin.upgrade_wizard) metadata = old_bible.get_metadata() @@ -394,17 +397,19 @@ class BibleUpgradeForm(OpenLPWizard): handler = BSExtract(proxy_server) books = handler.get_books_from_http(meta_data['download_name']) if not books: - log.error('Upgrading books from %s - download name: "%s" failed' % ( - meta_data['download_source'], meta_data['download_name'])) + log.error('Upgrading books from {uri} - ' + 'download name: "{name}" failed'.format(uri=meta_data['download_source'], + name=meta_data['download_name'])) self.new_bibles[number].session.close() del self.new_bibles[number] critical_error_message_box( translate('BiblesPlugin.UpgradeWizardForm', 'Download Error'), translate('BiblesPlugin.UpgradeWizardForm', 'To upgrade your Web Bibles an Internet connection is required.')) - self.increment_progress_bar(translate( - 'BiblesPlugin.UpgradeWizardForm', 'Upgrading Bible %s of %s: "%s"\nFailed') % - (number + 1, max_bibles, name), self.progress_bar.maximum() - self.progress_bar.value()) + text = translate('BiblesPlugin.UpgradeWizardForm', + 'Upgrading Bible {count} of {total}: "{name}"\n' + 'Failed').format(count=number + 1, total=max_bibles, name=name) + self.increment_progress_bar(text, self.progress_bar.maximum() - self.progress_bar.value()) self.success[number] = False continue bible = BiblesResourcesDB.get_webbible( @@ -416,12 +421,13 @@ class BibleUpgradeForm(OpenLPWizard): else: language_id = self.new_bibles[number].get_language(name) if not language_id: - log.warning('Upgrading from "%s" failed' % filename[0]) + log.warning('Upgrading from "{name}" failed'.format(name=filename[0])) self.new_bibles[number].session.close() del self.new_bibles[number] self.increment_progress_bar( translate('BiblesPlugin.UpgradeWizardForm', - 'Upgrading Bible %s of %s: "%s"\nFailed') % (number + 1, max_bibles, name), + 'Upgrading Bible {count} of {total}: "{name}"\n' + 'Failed').format(count=number + 1, total=max_bibles, name=name), self.progress_bar.maximum() - self.progress_bar.value()) self.success[number] = False continue @@ -432,13 +438,15 @@ class BibleUpgradeForm(OpenLPWizard): break self.increment_progress_bar( translate('BiblesPlugin.UpgradeWizardForm', - 'Upgrading Bible %s of %s: "%s"\nUpgrading %s ...') % - (number + 1, max_bibles, name, book)) + 'Upgrading Bible {count} of {total}: "{name}"\n' + 'Upgrading {book} ...').format(count=number + 1, total=max_bibles, + name=name, book=book)) book_ref_id = self.new_bibles[number].\ get_book_ref_id_by_name(book, len(books), language_id) if not book_ref_id: - log.warning('Upgrading books from %s - download name: "%s" aborted by user' % ( - meta_data['download_source'], meta_data['download_name'])) + log.warning('Upgrading books from {source} - download name: "{name}" ' + 'aborted by user'.format(source=meta_data['download_source'], + name=meta_data['download_name'])) self.new_bibles[number].session.close() del self.new_bibles[number] self.success[number] = False @@ -450,7 +458,7 @@ class BibleUpgradeForm(OpenLPWizard): if oldbook: verses = old_bible.get_verses(oldbook['id']) if not verses: - log.warning('No verses found to import for book "%s"', book) + log.warning('No verses found to import for book "{book}"'.format(book=book)) continue for verse in verses: if self.stop_import_flag: @@ -465,12 +473,13 @@ class BibleUpgradeForm(OpenLPWizard): if not language_id: language_id = self.new_bibles[number].get_language(name) if not language_id: - log.warning('Upgrading books from "%s" failed' % name) + log.warning('Upgrading books from "{name}" failed'.format(name=name)) self.new_bibles[number].session.close() del self.new_bibles[number] self.increment_progress_bar( translate('BiblesPlugin.UpgradeWizardForm', - 'Upgrading Bible %s of %s: "%s"\nFailed') % (number + 1, max_bibles, name), + 'Upgrading Bible {count} of {total}: "{name}"\n' + 'Failed').format(count=number + 1, total=max_bibles, name=name), self.progress_bar.maximum() - self.progress_bar.value()) self.success[number] = False continue @@ -482,11 +491,12 @@ class BibleUpgradeForm(OpenLPWizard): break self.increment_progress_bar( translate('BiblesPlugin.UpgradeWizardForm', - 'Upgrading Bible %s of %s: "%s"\nUpgrading %s ...') % - (number + 1, max_bibles, name, book['name'])) + 'Upgrading Bible {count} of {total}: "{name}"\n' + 'Upgrading {book} ...').format(count=number + 1, total=max_bibles, + name=name, book=book['name'])) book_ref_id = self.new_bibles[number].get_book_ref_id_by_name(book['name'], len(books), language_id) if not book_ref_id: - log.warning('Upgrading books from %s " failed - aborted by user' % name) + log.warning('Upgrading books from {name} " failed - aborted by user'.format(name=name)) self.new_bibles[number].session.close() del self.new_bibles[number] self.success[number] = False @@ -496,7 +506,7 @@ class BibleUpgradeForm(OpenLPWizard): book_details['testament_id']) verses = old_bible.get_verses(book['id']) if not verses: - log.warning('No verses found to import for book "%s"', book['name']) + log.warning('No verses found to import for book "{book}"'.format(book=book['name'])) self.new_bibles[number].delete_book(db_book) continue for verse in verses: @@ -510,14 +520,16 @@ class BibleUpgradeForm(OpenLPWizard): if not self.success.get(number, True): self.increment_progress_bar( translate('BiblesPlugin.UpgradeWizardForm', - 'Upgrading Bible %s of %s: "%s"\nFailed') % (number + 1, max_bibles, name), + 'Upgrading Bible {count} of {total}: "{name}"\n' + 'Failed').format(count=number + 1, total=max_bibles, name=name), self.progress_bar.maximum() - self.progress_bar.value()) else: self.success[number] = True self.new_bibles[number].save_meta('name', name) self.increment_progress_bar( translate('BiblesPlugin.UpgradeWizardForm', - 'Upgrading Bible %s of %s: "%s"\nComplete') % (number + 1, max_bibles, name)) + 'Upgrading Bible {count} of {total}: "{name}"\n' + 'Complete').format(count=number + 1, total=max_bibles, name=name)) if number in self.new_bibles: self.new_bibles[number].session.close() # Close the last bible's connection if possible. @@ -540,20 +552,22 @@ class BibleUpgradeForm(OpenLPWizard): # Copy not upgraded bible back. shutil.move(os.path.join(self.temp_dir, filename[0]), self.path) if failed_import > 0: - failed_import_text = translate('BiblesPlugin.UpgradeWizardForm', ', %s failed') % failed_import + failed_import_text = translate('BiblesPlugin.UpgradeWizardForm', + ', {name} failed').format(name=failed_import) else: failed_import_text = '' if successful_import > 0: if self.includeWebBible: self.progress_label.setText( translate('BiblesPlugin.UpgradeWizardForm', - 'Upgrading Bible(s): %(success)d successful%(failed_text)s\nPlease note that verses ' - 'from Web Bibles will be downloaded on demand and so an Internet connection is required.') - % {'success': successful_import, 'failed_text': failed_import_text}) + 'Upgrading Bible(s): {count:d} successful{failed}\nPlease note that verses ' + 'from Web Bibles will be downloaded on demand and so an Internet connection is required.' + ).format(count=successful_import, failed=failed_import_text)) else: self.progress_label.setText( - translate('BiblesPlugin.UpgradeWizardForm', 'Upgrading Bible(s): %s successful%s') % ( - successful_import, failed_import_text)) + translate('BiblesPlugin.UpgradeWizardForm', + 'Upgrading Bible(s): {count:d} successful{failed}').format(count=successful_import, + failed=failed_import_text)) else: self.progress_label.setText(translate('BiblesPlugin.UpgradeWizardForm', 'Upgrade failed.')) # Remove temp directory. diff --git a/openlp/plugins/bibles/forms/editbibledialog.py b/openlp/plugins/bibles/forms/editbibledialog.py index 978f019ad..ca3bea4ed 100644 --- a/openlp/plugins/bibles/forms/editbibledialog.py +++ b/openlp/plugins/bibles/forms/editbibledialog.py @@ -103,9 +103,11 @@ class Ui_EditBibleDialog(object): self.book_name_edit = {} for book in BiblesResourcesDB.get_books(): self.book_name_label[book['abbreviation']] = QtWidgets.QLabel(self.book_name_widget) - self.book_name_label[book['abbreviation']].setObjectName('book_name_label[%s]' % book['abbreviation']) + self.book_name_label[book['abbreviation']].setObjectName( + 'book_name_label[{name}]'.format(book=book['abbreviation'])) self.book_name_edit[book['abbreviation']] = QtWidgets.QLineEdit(self.book_name_widget) - self.book_name_edit[book['abbreviation']].setObjectName('book_name_edit[%s]' % book['abbreviation']) + self.book_name_edit[book['abbreviation']].setObjectName( + 'book_name_edit[{name}]'.format(name=book['abbreviation'])) self.book_name_widget_layout.addRow( self.book_name_label[book['abbreviation']], self.book_name_edit[book['abbreviation']]) @@ -148,4 +150,5 @@ class Ui_EditBibleDialog(object): self.bible_tab_widget.indexOf(self.book_name_tab), translate('SongsPlugin.EditBibleForm', 'Custom Book Names')) for book in BiblesResourcesDB.get_books(): - self.book_name_label[book['abbreviation']].setText('%s:' % str(self.book_names[book['abbreviation']])) + self.book_name_label[book['abbreviation']].setText( + '{text}:'.format(text=self.book_names[book['abbreviation']])) diff --git a/openlp/plugins/bibles/forms/editbibleform.py b/openlp/plugins/bibles/forms/editbibleform.py index 9eb64ee19..c6afbabb6 100644 --- a/openlp/plugins/bibles/forms/editbibleform.py +++ b/openlp/plugins/bibles/forms/editbibleform.py @@ -39,7 +39,7 @@ class EditBibleForm(QtWidgets.QDialog, Ui_EditBibleDialog, RegistryProperties): """ Class to manage the editing of a bible """ - log.info('%s EditBibleForm loaded', __name__) + log.info('{name} EditBibleForm loaded'.format(name=__name__)) def __init__(self, media_item, parent, manager): """ @@ -168,16 +168,17 @@ class EditBibleForm(QtWidgets.QDialog, Ui_EditBibleDialog, RegistryProperties): self.book_name_edit[abbreviation].setFocus() critical_error_message_box( UiStrings().EmptyField, - translate('BiblesPlugin.BibleEditForm', 'You need to specify a book name for "%s".') % - self.book_names[abbreviation]) + translate('BiblesPlugin.BibleEditForm', + 'You need to specify a book name for "{text}".').format(text=self.book_names[abbreviation])) return False elif not book_regex.match(new_book_name): self.book_name_edit[abbreviation].setFocus() critical_error_message_box( UiStrings().EmptyField, translate('BiblesPlugin.BibleEditForm', - 'The book name "%s" is not correct.\nNumbers can only be used at the beginning and must\nbe ' - 'followed by one or more non-numeric characters.') % new_book_name) + 'The book name "{name}" is not correct.\n' + 'Numbers can only be used at the beginning and must\nbe ' + 'followed by one or more non-numeric characters.').format(name=new_book_name)) return False for abbr, book in self.books.items(): if book: @@ -187,7 +188,7 @@ class EditBibleForm(QtWidgets.QDialog, Ui_EditBibleDialog, RegistryProperties): self.book_name_edit[abbreviation].setFocus() critical_error_message_box( translate('BiblesPlugin.BibleEditForm', 'Duplicate Book Name'), - translate('BiblesPlugin.BibleEditForm', 'The Book Name "%s" has been entered more than once.') - % new_book_name) + translate('BiblesPlugin.BibleEditForm', + 'The Book Name "{name}" has been entered more than once.').format(name=new_book_name)) return False return True diff --git a/openlp/plugins/bibles/lib/csvbible.py b/openlp/plugins/bibles/lib/csvbible.py index 2e95697e3..ef8616051 100644 --- a/openlp/plugins/bibles/lib/csvbible.py +++ b/openlp/plugins/bibles/lib/csvbible.py @@ -86,7 +86,7 @@ class CSVBible(BibleDB): success = True language_id = self.get_language(bible_name) if not language_id: - log.error('Importing books from "%s" failed' % self.filename) + log.error('Importing books from "{name}" failed'.format(name=self.filename)) return False books_file = None book_list = {} @@ -98,11 +98,11 @@ class CSVBible(BibleDB): for line in books_reader: if self.stop_import_flag: break - self.wizard.increment_progress_bar(translate('BiblesPlugin.CSVBible', 'Importing books... %s') - % line[2]) + self.wizard.increment_progress_bar(translate('BiblesPlugin.CSVBible', + 'Importing books... {text}').format(text=line[2])) book_ref_id = self.get_book_ref_id_by_name(line[2], 67, language_id) if not book_ref_id: - log.error('Importing books from "%s" failed' % self.books_file) + log.error('Importing books from "{name}" failed'.format(name=self.books_file)) return False book_details = BiblesResourcesDB.get_book_by_id(book_ref_id) self.create_book(line[2], book_ref_id, book_details['testament_id']) @@ -134,9 +134,11 @@ class CSVBible(BibleDB): if book_ptr != line_book: book = self.get_book(line_book) book_ptr = book.name + # TODO: Check out this conversion in translations self.wizard.increment_progress_bar( translate('BiblesPlugin.CSVBible', - 'Importing verses from %s...' % book.name, 'Importing verses from ...')) + 'Importing verses from {name}...'.format(name=book.name), + 'Importing verses from ...')) self.session.commit() verse_text = line[3] self.create_verse(book.id, line[1], line[2], verse_text) diff --git a/openlp/plugins/bibles/lib/db.py b/openlp/plugins/bibles/lib/db.py index 8dcf8c042..c23ade4a7 100644 --- a/openlp/plugins/bibles/lib/db.py +++ b/openlp/plugins/bibles/lib/db.py @@ -185,7 +185,7 @@ class BibleDB(Manager, RegistryProperties): :param testament: *Defaults to 1.* The testament_reference_id from bibles_resources.sqlite of the testament this book belongs to. """ - log.debug('BibleDB.create_book("%s", "%s")' % (name, bk_ref_id)) + log.debug('BibleDB.create_book("{name}", "{number}")'.format(name=name, number=bk_ref_id)) book = Book.populate(name=name, book_reference_id=bk_ref_id, testament_reference_id=testament) self.save_object(book) return book @@ -196,7 +196,7 @@ class BibleDB(Manager, RegistryProperties): :param book: The book object """ - log.debug('BibleDB.update_book("%s")' % book.name) + log.debug('BibleDB.update_book("{name}")'.format(name=book.name)) return self.save_object(book) def delete_book(self, db_book): @@ -205,7 +205,7 @@ class BibleDB(Manager, RegistryProperties): :param db_book: The book object. """ - log.debug('BibleDB.delete_book("%s")' % db_book.name) + log.debug('BibleDB.delete_book("{name}")'.format(name=db_book.name)) if self.delete_object(Book, db_book.id): return True return False @@ -219,7 +219,7 @@ class BibleDB(Manager, RegistryProperties): :param text_list: A dict of the verses to be inserted. The key is the verse number, and the value is the verse text. """ - log.debug('BibleDBcreate_chapter("%s", "%s")' % (book_id, chapter)) + log.debug('BibleDBcreate_chapter("{number}", "{chapter}")'.format(number=book_id, chapter=chapter)) # Text list has book and chapter as first two elements of the array. for verse_number, verse_text in text_list.items(): verse = Verse.populate( @@ -266,7 +266,7 @@ class BibleDB(Manager, RegistryProperties): """ if not isinstance(value, str): value = str(value) - log.debug('BibleDB.save_meta("%s/%s")' % (key, value)) + log.debug('BibleDB.save_meta("{key}/{val}")'.format(key=key, val=value)) meta = self.get_object(BibleMeta, key) if meta: meta.value = value @@ -280,7 +280,7 @@ class BibleDB(Manager, RegistryProperties): :param book: The name of the book to return. """ - log.debug('BibleDB.get_book("%s")' % book) + log.debug('BibleDB.get_book("{book}")'.format(book=book)) return self.get_object_filtered(Book, Book.name.like(book + '%')) def get_books(self): @@ -297,11 +297,11 @@ class BibleDB(Manager, RegistryProperties): :param ref_id: The reference id of the book to return. """ - log.debug('BibleDB.get_book_by_book_ref_id("%s")' % ref_id) + log.debug('BibleDB.get_book_by_book_ref_id("{ref}")'.format(ref=ref_id)) return self.get_object_filtered(Book, Book.book_reference_id.like(ref_id)) def get_book_ref_id_by_name(self, book, maxbooks, language_id=None): - log.debug('BibleDB.get_book_ref_id_by_name:("%s", "%s")' % (book, language_id)) + log.debug('BibleDB.get_book_ref_id_by_name:("{book}", "{lang}")'.format(book=book, lang=language_id)) book_id = None if BiblesResourcesDB.get_book(book, True): book_temp = BiblesResourcesDB.get_book(book, True) @@ -327,13 +327,14 @@ class BibleDB(Manager, RegistryProperties): :param book: The name of the book, according to the selected language. :param language_selection: The language selection the user has chosen in the settings section of the Bible. """ - log.debug('get_book_ref_id_by_localised_name("%s", "%s")' % (book, language_selection)) + log.debug('get_book_ref_id_by_localised_name("{book}", "{lang}")'.format(book=book, lang=language_selection)) from openlp.plugins.bibles.lib import LanguageSelection, BibleStrings book_names = BibleStrings().BookNames # escape reserved characters book_escaped = book for character in RESERVED_CHARACTERS: book_escaped = book_escaped.replace(character, '\\' + character) + # TODO: Verify regex patters before using format() regex_book = re.compile('\s*%s\s*' % '\s*'.join( book_escaped.split()), re.UNICODE | re.IGNORECASE) if language_selection == LanguageSelection.Bible: @@ -374,14 +375,14 @@ class BibleDB(Manager, RegistryProperties): [('35', 1, 1, 1), ('35', 2, 2, 3)] :param show_error: """ - log.debug('BibleDB.get_verses("%s")' % reference_list) + log.debug('BibleDB.get_verses("{ref}")'.format(ref=reference_list)) verse_list = [] book_error = False for book_id, chapter, start_verse, end_verse in reference_list: db_book = self.get_book_by_book_ref_id(book_id) if db_book: book_id = db_book.book_reference_id - log.debug('Book name corrected to "%s"' % db_book.name) + log.debug('Book name corrected to "{book}"'.format(book=db_book.name)) if end_verse == -1: end_verse = self.get_verse_count(book_id, chapter) verses = self.session.query(Verse) \ @@ -393,7 +394,7 @@ class BibleDB(Manager, RegistryProperties): .all() verse_list.extend(verses) else: - log.debug('OpenLP failed to find book with id "%s"' % book_id) + log.debug('OpenLP failed to find book with id "{book}"'.format(book=book_id)) book_error = True if book_error and show_error: critical_error_message_box( @@ -412,8 +413,9 @@ class BibleDB(Manager, RegistryProperties): contains spaces, it will split apart and AND'd on the list of values. """ - log.debug('BibleDB.verse_search("%s")' % text) + log.debug('BibleDB.verse_search("{text}")'.format(text=text)) verses = self.session.query(Verse) + # TODO: Find out what this is doing before converting to format() if text.find(',') > -1: keywords = ['%%%s%%' % keyword.strip() for keyword in text.split(',')] or_clause = [Verse.text.like(keyword) for keyword in keywords] @@ -431,7 +433,7 @@ class BibleDB(Manager, RegistryProperties): :param book: The book object to get the chapter count for. """ - log.debug('BibleDB.get_chapter_count("%s")' % book.name) + log.debug('BibleDB.get_chapter_count("{book}")'.format(book=book.name)) count = self.session.query(func.max(Verse.chapter)).join(Book).filter( Book.book_reference_id == book.book_reference_id).scalar() if not count: @@ -445,7 +447,7 @@ class BibleDB(Manager, RegistryProperties): :param book_ref_id: The book reference id. :param chapter: The chapter to get the verse count for. """ - log.debug('BibleDB.get_verse_count("%s", "%s")' % (book_ref_id, chapter)) + log.debug('BibleDB.get_verse_count("{ref}", "{chapter}")'.format(ref=book_ref_id, chapter=chapter)) count = self.session.query(func.max(Verse.verse)).join(Book) \ .filter(Book.book_reference_id == book_ref_id) \ .filter(Verse.chapter == chapter) \ @@ -551,7 +553,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager): :param name: The name or abbreviation of the book. :param lower: True if the comparison should be only lowercase """ - log.debug('BiblesResourcesDB.get_book("%s")' % name) + log.debug('BiblesResourcesDB.get_book("{name}")'.format(name=name)) if not isinstance(name, str): name = str(name) if lower: @@ -580,7 +582,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager): :param string: The string to search for in the book names or abbreviations. """ - log.debug('BiblesResourcesDB.get_book_like("%s")' % string) + log.debug('BiblesResourcesDB.get_book_like("{text}")'.format(text=string)) if not isinstance(string, str): name = str(string) books = BiblesResourcesDB.run_sql( @@ -605,7 +607,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager): :param book_id: The id of the book. """ - log.debug('BiblesResourcesDB.get_book_by_id("%s")' % book_id) + log.debug('BiblesResourcesDB.get_book_by_id("{book}")'.format(book=book_id)) if not isinstance(book_id, int): book_id = int(book_id) books = BiblesResourcesDB.run_sql( @@ -629,7 +631,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager): :param book_ref_id: The id of a book. :param chapter: The chapter number. """ - log.debug('BiblesResourcesDB.get_chapter("%s", "%s")' % (book_ref_id, chapter)) + log.debug('BiblesResourcesDB.get_chapter("{book}", "{ref}")'.format(book=book_ref_id, ref=chapter)) if not isinstance(chapter, int): chapter = int(chapter) chapters = BiblesResourcesDB.run_sql( @@ -652,7 +654,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager): :param book_ref_id: The id of the book. """ - log.debug('BiblesResourcesDB.get_chapter_count("%s")' % book_ref_id) + log.debug('BiblesResourcesDB.get_chapter_count("{ref}")'.format(ref=book_ref_id)) details = BiblesResourcesDB.get_book_by_id(book_ref_id) if details: return details['chapters'] @@ -666,7 +668,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager): :param book_ref_id: The id of the book. :param chapter: The number of the chapter. """ - log.debug('BiblesResourcesDB.get_verse_count("%s", "%s")' % (book_ref_id, chapter)) + log.debug('BiblesResourcesDB.get_verse_count("{ref}", "{chapter}")'.format(ref=book_ref_id, chapter=chapter)) details = BiblesResourcesDB.get_chapter(book_ref_id, chapter) if details: return details['verse_count'] @@ -679,7 +681,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager): :param source: The name or abbreviation of the book. """ - log.debug('BiblesResourcesDB.get_download_source("%s")' % source) + log.debug('BiblesResourcesDB.get_download_source("{source}")'.format(source=source)) if not isinstance(source, str): source = str(source) source = source.title() @@ -700,7 +702,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager): :param source: The source of the web_bible. """ - log.debug('BiblesResourcesDB.get_webbibles("%s")' % source) + log.debug('BiblesResourcesDB.get_webbibles("{source}")'.format(source=source)) if not isinstance(source, str): source = str(source) source = BiblesResourcesDB.get_download_source(source) @@ -725,7 +727,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager): :param abbreviation: The abbreviation of the web_bible. :param source: The source of the web_bible. """ - log.debug('BiblesResourcesDB.get_webbibles("%s", "%s")' % (abbreviation, source)) + log.debug('BiblesResourcesDB.get_webbibles("{text}", "{source}")'.format(text=abbreviation, source=source)) if not isinstance(abbreviation, str): abbreviation = str(abbreviation) if not isinstance(source, str): @@ -753,7 +755,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager): :param name: The name to search the id. :param language_id: The language_id for which language should be searched """ - log.debug('BiblesResourcesDB.get_alternative_book_name("%s", "%s")' % (name, language_id)) + log.debug('BiblesResourcesDB.get_alternative_book_name("{name}", "{lang}")'.format(name=name, lang=language_id)) if language_id: books = BiblesResourcesDB.run_sql( 'SELECT book_reference_id, name FROM alternative_book_names WHERE language_id = ? ORDER BY id', @@ -772,7 +774,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager): :param name: The name or abbreviation of the language. """ - log.debug('BiblesResourcesDB.get_language("%s")' % name) + log.debug('BiblesResourcesDB.get_language("{name}")'.format(name=name)) if not isinstance(name, str): name = str(name) language = BiblesResourcesDB.run_sql( @@ -868,7 +870,7 @@ class AlternativeBookNamesDB(QtCore.QObject, Manager): :param name: The name to search the id. :param language_id: The language_id for which language should be searched """ - log.debug('AlternativeBookNamesDB.get_book_reference_id("%s", "%s")' % (name, language_id)) + log.debug('AlternativeBookNamesDB.get_book_reference_id("{name}", "{ref}")'.format(name=name, ref=language_id)) if language_id: books = AlternativeBookNamesDB.run_sql( 'SELECT book_reference_id, name FROM alternative_book_names WHERE language_id = ?', (language_id, )) @@ -889,8 +891,8 @@ class AlternativeBookNamesDB(QtCore.QObject, Manager): :param book_reference_id: The book_reference_id of the book. :param language_id: The language to which the alternative book name belong. """ - log.debug('AlternativeBookNamesDB.create_alternative_book_name("%s", "%s", "%s")' % - (name, book_reference_id, language_id)) + log.debug('AlternativeBookNamesDB.create_alternative_book_name("{name}", ' + '"{ref}", "{lang}")'.format(name=name, ref=book_reference_id, lang=language_id)) return AlternativeBookNamesDB.run_sql( 'INSERT INTO alternative_book_names(book_reference_id, language_id, name) ' 'VALUES (?, ?, ?)', (book_reference_id, language_id, name), True) diff --git a/openlp/plugins/bibles/lib/http.py b/openlp/plugins/bibles/lib/http.py index 2076bec87..c50745c2f 100644 --- a/openlp/plugins/bibles/lib/http.py +++ b/openlp/plugins/bibles/lib/http.py @@ -90,7 +90,7 @@ class BGExtract(RegistryProperties): Extract verses from BibleGateway """ def __init__(self, proxy_url=None): - log.debug('BGExtract.init("%s")', proxy_url) + log.debug('BGExtract.init("{url}")'.format(url=proxy_url)) self.proxy_url = proxy_url socket.setdefaulttimeout(30) @@ -188,7 +188,7 @@ class BGExtract(RegistryProperties): if len(verse_parts) > 1: verse = int(verse_parts[0]) except TypeError: - log.warning('Illegal verse number: %s', str(verse)) + log.warning('Illegal verse number: {verse:d}'.format(verse=verse)) verses.append((verse, text)) verse_list = {} for verse, text in verses[::-1]: @@ -221,7 +221,7 @@ class BGExtract(RegistryProperties): if len(verse_parts) > 1: clean_verse_num = int(verse_parts[0]) except TypeError: - log.warning('Illegal verse number: %s', str(raw_verse_num)) + log.warning('Illegal verse number: {verse:d}'.format(verse=raw_verse_num)) if clean_verse_num: verse_text = raw_verse_num.next_element part = raw_verse_num.next_element.next_element @@ -244,11 +244,15 @@ class BGExtract(RegistryProperties): :param book_name: Name of the Book. :param chapter: Chapter number. """ - log.debug('BGExtract.get_bible_chapter("%s", "%s", "%s")', version, book_name, chapter) + log.debug('BGExtract.get_bible_chapter("{version}", "{name}", "{chapter}")'.format(version=version, + name=book_name, + chapter=chapter)) url_book_name = urllib.parse.quote(book_name.encode("utf-8")) - url_params = 'search=%s+%s&version=%s' % (url_book_name, chapter, version) + url_params = 'search={name}+{chapter}&version={version}'.format(name=url_book_name, + chapter=chapter, + version=version) soup = get_soup_for_bible_ref( - 'http://legacy.biblegateway.com/passage/?%s' % url_params, + 'http://legacy.biblegateway.com/passage/?{url}'.format(url=url_params), pre_parse_regex=r'', pre_parse_substitute='') if not soup: return None @@ -257,7 +261,7 @@ class BGExtract(RegistryProperties): return None self._clean_soup(div) span_list = div.find_all('span', 'text') - log.debug('Span list: %s', span_list) + log.debug('Span list: {span}'.format(span=span_list)) if not span_list: # If we don't get any spans then we must have the old HTML format verse_list = self._extract_verses_old(div) @@ -275,9 +279,9 @@ class BGExtract(RegistryProperties): :param version: The version of the Bible like NIV for New International Version """ - log.debug('BGExtract.get_books_from_http("%s")', version) - url_params = urllib.parse.urlencode({'action': 'getVersionInfo', 'vid': '%s' % version}) - reference_url = 'http://legacy.biblegateway.com/versions/?%s#books' % url_params + log.debug('BGExtract.get_books_from_http("{version}")'.format(version=version)) + url_params = urllib.parse.urlencode({'action': 'getVersionInfo', 'vid': '{version}'.format(version=version)}) + reference_url = 'http://legacy.biblegateway.com/versions/?{url}#books'.format(url=url_params) page = get_web_page(reference_url) if not page: send_error_message('download') @@ -353,7 +357,7 @@ class BSExtract(RegistryProperties): Extract verses from Bibleserver.com """ def __init__(self, proxy_url=None): - log.debug('BSExtract.init("%s")', proxy_url) + log.debug('BSExtract.init("{url}")'.format(url=proxy_url)) self.proxy_url = proxy_url socket.setdefaulttimeout(30) @@ -365,10 +369,14 @@ class BSExtract(RegistryProperties): :param book_name: Text name of bible book e.g. Genesis, 1. John, 1John or Offenbarung :param chapter: Chapter number """ - log.debug('BSExtract.get_bible_chapter("%s", "%s", "%s")', version, book_name, chapter) + log.debug('BSExtract.get_bible_chapter("{version}", "{book}", "{chapter}")'.format(version=version, + book=book_name, + chapter=chapter)) url_version = urllib.parse.quote(version.encode("utf-8")) url_book_name = urllib.parse.quote(book_name.encode("utf-8")) - chapter_url = 'http://m.bibleserver.com/text/%s/%s%d' % (url_version, url_book_name, chapter) + chapter_url = 'http://m.bibleserver.com/text/{version}/{name}{chapter:d}'.format(version=url_version, + name=url_book_name, + chapter=chapter) header = ('Accept-Language', 'en') soup = get_soup_for_bible_ref(chapter_url, header) if not soup: @@ -393,9 +401,9 @@ class BSExtract(RegistryProperties): :param version: The version of the Bible like NIV for New International Version """ - log.debug('BSExtract.get_books_from_http("%s")', version) + log.debug('BSExtract.get_books_from_http("{version}")'.format(version=version)) url_version = urllib.parse.quote(version.encode("utf-8")) - chapter_url = 'http://m.bibleserver.com/overlay/selectBook?translation=%s' % url_version + chapter_url = 'http://m.bibleserver.com/overlay/selectBook?translation={version}'.format(version=url_version) soup = get_soup_for_bible_ref(chapter_url) if not soup: return None @@ -450,7 +458,7 @@ class CWExtract(RegistryProperties): Extract verses from CrossWalk/BibleStudyTools """ def __init__(self, proxy_url=None): - log.debug('CWExtract.init("%s")', proxy_url) + log.debug('CWExtract.init("{url}")'.format(url=proxy_url)) self.proxy_url = proxy_url socket.setdefaulttimeout(30) @@ -462,11 +470,15 @@ class CWExtract(RegistryProperties): :param book_name: Text name of in english e.g. 'gen' for Genesis :param chapter: Chapter number """ - log.debug('CWExtract.get_bible_chapter("%s", "%s", "%s")', version, book_name, chapter) + log.debug('CWExtract.get_bible_chapter("{version}", "{book}", "{chapter}")'.format(version=version, + book=book_name, + chapter=chapter)) url_book_name = book_name.replace(' ', '-') url_book_name = url_book_name.lower() url_book_name = urllib.parse.quote(url_book_name.encode("utf-8")) - chapter_url = 'http://www.biblestudytools.com/%s/%s/%s.html' % (version, url_book_name, chapter) + chapter_url = 'http://www.biblestudytools.com/{version}/{book}/{chapter}.html'.format(version=version, + book=url_book_name, + chapter=chapter) soup = get_soup_for_bible_ref(chapter_url) if not soup: return None @@ -499,8 +511,8 @@ class CWExtract(RegistryProperties): :param version: The version of the bible like NIV for New International Version """ - log.debug('CWExtract.get_books_from_http("%s")', version) - chapter_url = 'http://www.biblestudytools.com/%s/' % version + log.debug('CWExtract.get_books_from_http("{version}")'.format(version=version)) + chapter_url = 'http://www.biblestudytools.com/{version}/'.format(version=version) soup = get_soup_for_bible_ref(chapter_url) if not soup: return None @@ -559,7 +571,7 @@ class CWExtract(RegistryProperties): class HTTPBible(BibleDB, RegistryProperties): - log.info('%s HTTPBible loaded', __name__) + log.info('{name} HTTPBible loaded'.format(name=__name__)) def __init__(self, parent, **kwargs): """ @@ -615,8 +627,8 @@ class HTTPBible(BibleDB, RegistryProperties): handler = BSExtract(self.proxy_server) books = handler.get_books_from_http(self.download_name) if not books: - log.error('Importing books from %s - download name: "%s" failed' % - (self.download_source, self.download_name)) + log.error('Importing books from {source} - download name: "{name}" ' + 'failed'.format(source=self.download_source, name=self.download_name)) return False self.wizard.progress_bar.setMaximum(len(books) + 2) self.wizard.increment_progress_bar(translate('BiblesPlugin.HTTPBible', 'Registering Language...')) @@ -625,21 +637,24 @@ class HTTPBible(BibleDB, RegistryProperties): else: self.language_id = self.get_language(bible_name) if not self.language_id: - log.error('Importing books from %s failed' % self.filename) + log.error('Importing books from {name} failed'.format(name=self.filename)) return False for book in books: if self.stop_import_flag: break - self.wizard.increment_progress_bar(translate( - 'BiblesPlugin.HTTPBible', 'Importing %s...', 'Importing ...') % book) + self.wizard.increment_progress_bar(translate('BiblesPlugin.HTTPBible', + 'Importing {book}...', + 'Importing ...').format(book=book)) book_ref_id = self.get_book_ref_id_by_name(book, len(books), self.language_id) if not book_ref_id: - log.error('Importing books from %s - download name: "%s" failed' % - (self.download_source, self.download_name)) + log.error('Importing books from {source} - download name: "{name}" ' + 'failed'.format(source=self.download_source, name=self.download_name)) return False book_details = BiblesResourcesDB.get_book_by_id(book_ref_id) - log.debug('Book details: Name:%s; id:%s; testament_id:%s', - book, book_ref_id, book_details['testament_id']) + log.debug('Book details: Name:{book}; id:{ref}; ' + 'testament_id:{detail}'.format(book=book, + ref=book_ref_id, + detail=book_details['testament_id'])) self.create_book(book, book_ref_id, book_details['testament_id']) if self.stop_import_flag: return False @@ -664,7 +679,7 @@ class HTTPBible(BibleDB, RegistryProperties): [('35', 1, 1, 1), ('35', 2, 2, 3)] """ - log.debug('HTTPBible.get_verses("%s")', reference_list) + log.debug('HTTPBible.get_verses("{ref}")'.format(ref=reference_list)) for reference in reference_list: book_id = reference[0] db_book = self.get_book_by_book_ref_id(book_id) @@ -698,8 +713,8 @@ class HTTPBible(BibleDB, RegistryProperties): """ Receive the request and call the relevant handler methods. """ - log.debug('HTTPBible.get_chapter("%s", "%s")', book, chapter) - log.debug('source = %s', self.download_source) + log.debug('HTTPBible.get_chapter("{book}", "{chapter}")'.format(book=book, chapter=chapter)) + log.debug('source = {source}'.format(source=self.download_source)) if self.download_source.lower() == 'crosswalk': handler = CWExtract(self.proxy_server) elif self.download_source.lower() == 'biblegateway': @@ -712,7 +727,7 @@ class HTTPBible(BibleDB, RegistryProperties): """ Return the list of books. """ - log.debug('HTTPBible.get_books("%s")', Book.name) + log.debug('HTTPBible.get_books("{name}")'.format(name=Book.name)) return self.get_all_objects(Book, order_by_ref=Book.id) def get_chapter_count(self, book): @@ -721,7 +736,7 @@ class HTTPBible(BibleDB, RegistryProperties): :param book: The book object to get the chapter count for. """ - log.debug('HTTPBible.get_chapter_count("%s")', book.name) + log.debug('HTTPBible.get_chapter_count("{name}")'.format(name=book.name)) return BiblesResourcesDB.get_chapter_count(book.book_reference_id) def get_verse_count(self, book_id, chapter): @@ -731,7 +746,7 @@ class HTTPBible(BibleDB, RegistryProperties): :param book_id: The name of the book. :param chapter: The chapter whose verses are being counted. """ - log.debug('HTTPBible.get_verse_count("%s", %s)', book_id, chapter) + log.debug('HTTPBible.get_verse_count("{ref}", {chapter})'.format(ref=book_id, chapter=chapter)) return BiblesResourcesDB.get_verse_count(book_id, chapter) diff --git a/openlp/plugins/bibles/lib/manager.py b/openlp/plugins/bibles/lib/manager.py index 85521402c..d1465475d 100644 --- a/openlp/plugins/bibles/lib/manager.py +++ b/openlp/plugins/bibles/lib/manager.py @@ -122,7 +122,7 @@ class BibleManager(RegistryProperties): files = AppLocation.get_files(self.settings_section, self.suffix) if 'alternative_book_names.sqlite' in files: files.remove('alternative_book_names.sqlite') - log.debug('Bible Files %s', files) + log.debug('Bible Files {text}'.format(text=files)) self.db_cache = {} self.old_bible_databases = [] for filename in files: @@ -135,7 +135,7 @@ class BibleManager(RegistryProperties): bible.session.close() delete_file(os.path.join(self.path, filename)) continue - log.debug('Bible Name: "%s"', name) + log.debug('Bible Name: "{name}"'.format(name=name)) self.db_cache[name] = bible # Look to see if lazy load bible exists and get create getter. source = self.db_cache[name].get_object(BibleMeta, 'download_source') @@ -177,7 +177,7 @@ class BibleManager(RegistryProperties): :param name: The name of the bible. """ - log.debug('BibleManager.delete_bible("%s")', name) + log.debug('BibleManager.delete_bible("{name}")'.format(name=name)) bible = self.db_cache[name] bible.session.close() bible.session = None @@ -196,7 +196,7 @@ class BibleManager(RegistryProperties): :param bible: Unicode. The Bible to get the list of books from. """ - log.debug('BibleManager.get_books("%s")', bible) + log.debug('BibleManager.get_books("{bible}")'.format(bible=bible)) return [ { 'name': book.name, @@ -213,7 +213,7 @@ class BibleManager(RegistryProperties): :param bible: Unicode. The Bible to get the list of books from. :param id: Unicode. The book_reference_id to get the book for. """ - log.debug('BibleManager.get_book_by_id("%s", "%s")', bible, id) + log.debug('BibleManager.get_book_by_id("{bible}", "{ref}")'.format(bible=bible, ref=id)) return self.db_cache[bible].get_book_by_book_ref_id(id) def get_chapter_count(self, bible, book): @@ -223,14 +223,16 @@ class BibleManager(RegistryProperties): :param bible: Unicode. The Bible to get the list of books from. :param book: The book object to get the chapter count for. """ - log.debug('BibleManager.get_book_chapter_count ("%s", "%s")', bible, book.name) + log.debug('BibleManager.get_book_chapter_count ("{bible}", "{name}")'.format(bible=bible, name=book.name)) return self.db_cache[bible].get_chapter_count(book) def get_verse_count(self, bible, book, chapter): """ Returns all the number of verses for a given book and chapterMaxBibleBookVerses. """ - log.debug('BibleManager.get_verse_count("%s", "%s", %s)', bible, book, chapter) + log.debug('BibleManager.get_verse_count("{bible}", "{book}", {chapter})'.format(bible=bible, + book=book, + chapter=chapter)) language_selection = self.get_language_selection(bible) book_ref_id = self.db_cache[bible].get_book_ref_id_by_localised_name(book, language_selection) return self.db_cache[bible].get_verse_count(book_ref_id, chapter) @@ -240,7 +242,8 @@ class BibleManager(RegistryProperties): Returns all the number of verses for a given book_ref_id and chapterMaxBibleBookVerses. """ - log.debug('BibleManager.get_verse_count_by_book_ref_id("%s", "%s", "%s")', bible, book_ref_id, chapter) + log.debug('BibleManager.get_verse_count_by_book_ref_id("{bible}", ' + '"{book}", "{chapter}")'.format(bible=bible, book=book_ref_id, chapter=chapter)) return self.db_cache[bible].get_verse_count(book_ref_id, chapter) def get_verses(self, bible, verse_text, book_ref_id=False, show_error=True): @@ -264,7 +267,7 @@ class BibleManager(RegistryProperties): For second bible this is necessary. :param show_error: """ - log.debug('BibleManager.get_verses("%s", "%s")', bible, verse_text) + log.debug('BibleManager.get_verses("{bible}", "{verse}")'.format(bible=bible, verse=verse_text)) if not bible: if show_error: self.main_window.information_message( @@ -308,7 +311,7 @@ class BibleManager(RegistryProperties): :param bible: Unicode. The Bible to get the language selection from. """ - log.debug('BibleManager.get_language_selection("%s")', bible) + log.debug('BibleManager.get_language_selection("{bible}")'.format(bible=bible)) language_selection = self.get_meta_data(bible, 'book_name_language') if not language_selection or language_selection.value == "None" or language_selection.value == "-1": # If None is returned, it's not the singleton object but a @@ -330,7 +333,7 @@ class BibleManager(RegistryProperties): :param second_bible: The second bible (unicode). We do not search in this bible. :param text: The text to search for (unicode). """ - log.debug('BibleManager.verse_search("%s", "%s")', bible, text) + log.debug('BibleManager.verse_search("{bible}", "{text}")'.format(bible=bible, text=text)) if not bible: self.main_window.information_message( translate('BiblesPlugin.BibleManager', 'No Bibles Available'), @@ -365,7 +368,10 @@ class BibleManager(RegistryProperties): """ Saves the bibles meta data. """ - log.debug('save_meta data %s, %s, %s, %s', bible, version, copyright, permissions) + log.debug('save_meta data {bible}, {version}, {copyright}, {perms}'.format(bible=bible, + version=version, + cr=copyright, + perms=permissions)) self.db_cache[bible].save_meta('name', version) self.db_cache[bible].save_meta('copyright', copyright) self.db_cache[bible].save_meta('permissions', permissions) @@ -375,14 +381,14 @@ class BibleManager(RegistryProperties): """ Returns the meta data for a given key. """ - log.debug('get_meta %s,%s', bible, key) + log.debug('get_meta {bible},{key}'.format(bible=bible, key=key)) return self.db_cache[bible].get_object(BibleMeta, key) def update_book(self, bible, book): """ Update a book of the bible. """ - log.debug('BibleManager.update_book("%s", "%s")', bible, book.name) + log.debug('BibleManager.update_book("{bible}", "{name}")'.format(bible=bible, name=book.name)) self.db_cache[bible].update_book(book) def exists(self, name): @@ -392,7 +398,7 @@ class BibleManager(RegistryProperties): if not isinstance(name, str): name = str(name) for bible in list(self.db_cache.keys()): - log.debug('Bible from cache in is_new_bible %s', bible) + log.debug('Bible from cache in is_new_bible {bible}'.format(bible=bible)) if not isinstance(bible, str): bible = str(bible) if bible == name: diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index 1d7b5a897..d6e7eb62e 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -280,7 +280,7 @@ class BibleMediaItem(MediaManagerItem): def retranslateUi(self): log.debug('retranslateUi') self.quick_search_label.setText(translate('BiblesPlugin.MediaItem', 'Find:')) - self.quickVersionLabel.setText('%s:' % UiStrings().Version) + self.quickVersionLabel.setText('{version}:'.format(version=UiStrings().Version)) self.quickSecondLabel.setText(translate('BiblesPlugin.MediaItem', 'Second:')) self.quickStyleLabel.setText(UiStrings().LayoutStyle) self.quickStyleComboBox.setItemText(LayoutStyle.VersePerSlide, UiStrings().VersePerSlide) @@ -294,7 +294,7 @@ class BibleMediaItem(MediaManagerItem): self.advanced_verse_label.setText(translate('BiblesPlugin.MediaItem', 'Verse:')) self.advanced_from_label.setText(translate('BiblesPlugin.MediaItem', 'From:')) self.advanced_to_label.setText(translate('BiblesPlugin.MediaItem', 'To:')) - self.advancedVersionLabel.setText('%s:' % UiStrings().Version) + self.advancedVersionLabel.setText('{version}:'.format(version=UiStrings().Version)) self.advancedSecondLabel.setText(translate('BiblesPlugin.MediaItem', 'Second:')) self.advancedStyleLabel.setText(UiStrings().LayoutStyle) self.advancedStyleComboBox.setItemText(LayoutStyle.VersePerSlide, UiStrings().VersePerSlide) @@ -316,7 +316,8 @@ class BibleMediaItem(MediaManagerItem): translate('BiblesPlugin.MediaItem', 'Text Search'), translate('BiblesPlugin.MediaItem', 'Search Text...')) ]) - self.quick_search_edit.set_current_search_type(Settings().value('%s/last search type' % self.settings_section)) + text = self.settings_section + self.quick_search_edit.set_current_search_type(Settings().value('{text}/last search type'.format(text=text))) self.config_update() log.debug('bible manager initialise complete') @@ -364,7 +365,7 @@ class BibleMediaItem(MediaManagerItem): :param bible: The bible to initialise (unicode). :param last_book_id: The "book reference id" of the book which is chosen at the moment. (int) """ - log.debug('initialise_advanced_bible %s, %s', bible, last_book_id) + log.debug('initialise_advanced_bible {bible}, {ref}'.format(bible=bible, ref=last_book_id)) book_data = self.plugin.manager.get_books(bible) second_bible = self.advancedSecondComboBox.currentText() if second_bible != '': @@ -406,7 +407,7 @@ class BibleMediaItem(MediaManagerItem): self.initialise_chapter_verse(bible, first_book['name'], first_book['book_reference_id']) def initialise_chapter_verse(self, bible, book, book_ref_id): - log.debug('initialise_chapter_verse %s, %s, %s', bible, book, book_ref_id) + log.debug('initialise_chapter_verse {bible}, {book), {ref}'.format(bible=bible, book=book, ref=book_ref_id)) book = self.plugin.manager.get_book_by_id(bible, book_ref_id) self.chapter_count = self.plugin.manager.get_chapter_count(bible, book) verse_count = self.plugin.manager.get_verse_count_by_book_ref_id(bible, book_ref_id, 1) @@ -427,9 +428,11 @@ class BibleMediaItem(MediaManagerItem): """ log.debug('update_auto_completer') # Save the current search type to the configuration. - Settings().setValue('%s/last search type' % self.settings_section, self.quick_search_edit.current_search_type()) + Settings().setValue('{section}/last search type'.format(section=self.settings_section), + self.quick_search_edit.current_search_type()) # Save the current bible to the configuration. - Settings().setValue(self.settings_section + '/quick bible', self.quickVersionComboBox.currentText()) + Settings().setValue('{section}/quick bible'.format(section=self.settings_section), + self.quickVersionComboBox.currentText()) books = [] # We have to do a 'Reference Search'. if self.quick_search_edit.current_search_type() == BibleSearch.Reference: @@ -502,9 +505,10 @@ class BibleMediaItem(MediaManagerItem): if bible: if QtWidgets.QMessageBox.question( self, UiStrings().ConfirmDelete, - translate('BiblesPlugin.MediaItem', 'Are you sure you want to completely delete "%s" Bible from ' - 'OpenLP?\n\nYou will need to re-import this Bible to use it ' - 'again.') % bible, + translate('BiblesPlugin.MediaItem', + 'Are you sure you want to completely delete "{bible}" Bible ' + 'from OpenLP?\n\nYou will need to re-import this Bible to use it ' + 'again.').format(bible=bible), QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No), QtWidgets.QMessageBox.Yes) == QtWidgets.QMessageBox.No: return @@ -606,7 +610,7 @@ class BibleMediaItem(MediaManagerItem): :param combo: The combo box itself (QComboBox). :param restore: If True, then the combo's currentText will be restored after adjusting (if possible). """ - log.debug('adjust_combo_box %s, %s, %s', combo, range_from, range_to) + log.debug('adjust_combo_box {box}, {start}, {end}'.format(box=combo, start=range_from, end=range_to)) if restore: old_text = combo.currentText() combo.clear() @@ -633,7 +637,7 @@ class BibleMediaItem(MediaManagerItem): range_separator = get_reference_separator('sep_r_display') verse_range = chapter_from + verse_separator + verse_from + range_separator + chapter_to + \ verse_separator + verse_to - verse_text = '%s %s' % (book, verse_range) + verse_text = '{book} {verse}'.format(book=book, verse=verse_range) self.application.set_busy_cursor() self.search_results = self.plugin.manager.get_verses(bible, verse_text, book_ref_id) if second_bible: @@ -678,8 +682,8 @@ class BibleMediaItem(MediaManagerItem): for verse in self.search_results: db_book = bibles[second_bible].get_book_by_book_ref_id(verse.book.book_reference_id) if not db_book: - log.debug('Passage "%s %d:%d" not found in Second Bible' % - (verse.book.name, verse.chapter, verse.verse)) + log.debug('Passage "{name} {chapter:d}:{verse:d}" not found in ' + 'Second Bible'.format(name=verse.book.name, chapter=verse.chapter, verse=verse.verse)) passage_not_found = True count += 1 continue @@ -688,9 +692,10 @@ class BibleMediaItem(MediaManagerItem): if passage_not_found: QtWidgets.QMessageBox.information( self, translate('BiblesPlugin.MediaItem', 'Information'), - translate('BiblesPlugin.MediaItem', 'The second Bible does not contain all the verses ' - 'that are in the main Bible. Only verses found in both Bibles will be shown. %d ' - 'verses have not been included in the results.') % count, + translate('BiblesPlugin.MediaItem', + 'The second Bible does not contain all the verses that are in the main Bible. ' + 'Only verses found in both Bibles will be shown. {count:d} verses have not been ' + 'included in the results.').format(count=count), QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Ok)) self.search_results = new_search_results self.second_search_results = bibles[second_bible].get_verses(text) @@ -767,10 +772,19 @@ class BibleMediaItem(MediaManagerItem): except TypeError: log.exception('The second_search_results does not have this book.') break - bible_text = '%s %d%s%d (%s, %s)' % (book, verse.chapter, verse_separator, verse.verse, version, - second_version) + bible_text = ('{book} {chapter:d}{sep}{verse:d} ' + '({version1}, {version2})').format(book=book, + chapter=verse.chapter, + sep=verse_separator, + verse=verse.verse, + version1=version, + version2=second_version) else: - bible_text = '%s %d%s%d (%s)' % (book, verse.chapter, verse_separator, verse.verse, version) + bible_text = '{book} {chapter:d}{sep}{verse:d} ({version})'.format(book=book, + chapter=verse.chapter, + sep=verse_separator, + verse=verse.verse, + version=version) bible_verse = QtWidgets.QListWidgetItem(bible_text) bible_verse.setData(QtCore.Qt.UserRole, data) items.append(bible_verse) @@ -817,20 +831,22 @@ class BibleMediaItem(MediaManagerItem): verses.add(book, chapter, verse, version, copyright, permissions) verse_text = self.format_verse(old_chapter, chapter, verse) if second_bible: - bible_text = '%s%s\n\n%s %s' % (verse_text, text, verse_text, second_text) + bible_text = '{verse}{text1}\n\n{verse} {text2}'.format(verse=verse_text, + text1=text, + text2=second_text) raw_slides.append(bible_text.rstrip()) bible_text = '' # If we are 'Verse Per Slide' then create a new slide. elif self.settings.layout_style == LayoutStyle.VersePerSlide: - bible_text = '%s%s' % (verse_text, text) + bible_text = '{verse}{text}'.format(verse=verse_text, text=text) raw_slides.append(bible_text.rstrip()) bible_text = '' # If we are 'Verse Per Line' then force a new line. elif self.settings.layout_style == LayoutStyle.VersePerLine: - bible_text = '%s%s%s\n' % (bible_text, verse_text, text) + bible_text = '{bible}{verse}{text}\n'.format(bible=bible_text, verse=verse_text, text=text) # We have to be 'Continuous'. else: - bible_text = '%s %s%s\n' % (bible_text, verse_text, text) + bible_text = '{bible} {verse}{text}\n'.format(bible=bible_text, verse=verse_text, text=text) bible_text = bible_text.strip(' ') if not old_item: start_item = bitem @@ -857,7 +873,7 @@ class BibleMediaItem(MediaManagerItem): service_item.add_capability(ItemCapabilities.CanWordSplit) service_item.add_capability(ItemCapabilities.CanEditTitle) # Service Item: Title - service_item.title = '%s %s' % (verses.format_verses(), verses.format_versions()) + service_item.title = '{verse} {version}'.format(verse=verses.format_verses(), version=verses.format_versions()) # Service Item: Theme if not self.settings.bible_theme: service_item.theme = None @@ -885,7 +901,7 @@ class BibleMediaItem(MediaManagerItem): start_bible = self._decode_qt_object(start_bitem, 'bible') start_second_bible = self._decode_qt_object(start_bitem, 'second_bible') if start_second_bible: - bibles = '%s, %s' % (start_bible, start_second_bible) + bibles = '{bible1}, {bible2}'.format(bible1=start_bible, bible2=start_second_bible) else: bibles = start_bible if start_chapter == old_chapter: @@ -896,7 +912,7 @@ class BibleMediaItem(MediaManagerItem): else: verse_range = start_chapter + verse_separator + start_verse + \ range_separator + old_chapter + verse_separator + old_verse - return '%s %s (%s)' % (start_book, verse_range, bibles) + return '{book} {verse} ({bible})'.format(book=start_book, verse=verse_range, bible=bibles) def check_title(self, bitem, old_bitem): """ @@ -949,12 +965,12 @@ class BibleMediaItem(MediaManagerItem): else: verse_text = str(verse) if self.settings.display_style == DisplayStyle.Round: - return '{su}(%s){/su} ' % verse_text + return '{{su}}({verse}){{/su}} '.format(verse=verse_text) if self.settings.display_style == DisplayStyle.Curly: - return '{su}{%s}{/su} ' % verse_text + return '{{su}}{{{verse}}}{{/su}} '.format(verse=verse_text) if self.settings.display_style == DisplayStyle.Square: - return '{su}[%s]{/su} ' % verse_text - return '{su}%s{/su} ' % verse_text + return '{{su}}[{verse}]{{/su}} '.format(verse=verse_text) + return '{{su}}{verse}{{/su}} '.format(verse=verse_text) def search(self, string, showError): """ diff --git a/openlp/plugins/bibles/lib/opensong.py b/openlp/plugins/bibles/lib/opensong.py index b2836dcd4..af3ef64c0 100644 --- a/openlp/plugins/bibles/lib/opensong.py +++ b/openlp/plugins/bibles/lib/opensong.py @@ -63,7 +63,7 @@ class OpenSongBible(BibleDB): """ Loads a Bible from file. """ - log.debug('Starting OpenSong import from "%s"' % self.filename) + log.debug('Starting OpenSong import from "{name}"'.format(name=self.filename)) if not isinstance(self.filename, str): self.filename = str(self.filename, 'utf8') import_file = None @@ -84,14 +84,14 @@ class OpenSongBible(BibleDB): # No language info in the opensong format, so ask the user language_id = self.get_language(bible_name) if not language_id: - log.error('Importing books from "%s" failed' % self.filename) + log.error('Importing books from "{name}" failed'.format(name=self.filename)) return False for book in bible.b: if self.stop_import_flag: break book_ref_id = self.get_book_ref_id_by_name(str(book.attrib['n']), len(bible.b), language_id) if not book_ref_id: - log.error('Importing books from "%s" failed' % self.filename) + log.error('Importing books from "{name}" failed'.format(name=self.filename)) return False book_details = BiblesResourcesDB.get_book_by_id(book_ref_id) db_book = self.create_book(book.attrib['n'], book_ref_id, book_details['testament_id']) @@ -117,14 +117,14 @@ class OpenSongBible(BibleDB): if len(verse_parts) > 1: number = int(verse_parts[0]) except TypeError: - log.warning('Illegal verse number: %s', str(verse.attrib['n'])) + log.warning('Illegal verse number: {verse:d}'.format(verse.attrib['n'])) verse_number = number else: verse_number += 1 self.create_verse(db_book.id, chapter_number, verse_number, self.get_text(verse)) - self.wizard.increment_progress_bar( - translate('BiblesPlugin.Opensong', 'Importing %(bookname)s %(chapter)s...') % - {'bookname': db_book.name, 'chapter': chapter_number}) + self.wizard.increment_progress_bar(translate('BiblesPlugin.Opensong', + 'Importing {name} {chapter}...' + ).format(name=db_book.name, chapter=chapter_number)) self.session.commit() self.application.process_events() except etree.XMLSyntaxError as inst: diff --git a/openlp/plugins/bibles/lib/osis.py b/openlp/plugins/bibles/lib/osis.py index acba710c1..c0a3bec81 100644 --- a/openlp/plugins/bibles/lib/osis.py +++ b/openlp/plugins/bibles/lib/osis.py @@ -49,7 +49,7 @@ class OSISBible(BibleDB): """ Loads a Bible from file. """ - log.debug('Starting OSIS import from "%s"' % self.filename) + log.debug('Starting OSIS import from "{name}"'.format(name=self.filename)) if not isinstance(self.filename, str): self.filename = str(self.filename, 'utf8') import_file = None @@ -69,7 +69,7 @@ class OSISBible(BibleDB): if not language_id: language_id = self.get_language(bible_name) if not language_id: - log.error('Importing books from "%s" failed' % self.filename) + log.error('Importing books from "{name}" failed'.format(name=self.filename)) return False self.save_meta('language_id', language_id) num_books = int(osis_bible_tree.xpath("count(//ns:div[@type='book'])", namespaces=namespace)) @@ -129,7 +129,7 @@ class OSISBible(BibleDB): if not book_ref_id: book_ref_id = self.get_book_ref_id_by_localised_name(book.get('osisID')) if not book_ref_id: - log.error('Importing books from "%s" failed' % self.filename) + log.error('Importing books from "{name}" failed'.format(name=self.filename)) return False book_details = BiblesResourcesDB.get_book_by_id(book_ref_id) db_book = self.create_book(book_details['name'], book_ref_id, book_details['testament_id']) @@ -187,7 +187,8 @@ class OSISBible(BibleDB): trace_error_handler(log) success = False critical_error_message_box(message=translate('BiblesPlugin.OsisImport', - 'The file is not a valid OSIS-XML file: \n%s' % e.msg)) + 'The file is not a valid OSIS-XML file:' + '\n{text}').format(text=e.msg)) finally: if import_file: import_file.close() diff --git a/openlp/plugins/bibles/lib/sword.py b/openlp/plugins/bibles/lib/sword.py index 6f91803a6..77f08cb47 100644 --- a/openlp/plugins/bibles/lib/sword.py +++ b/openlp/plugins/bibles/lib/sword.py @@ -51,7 +51,7 @@ class SwordBible(BibleDB): """ Loads a Bible from SWORD module. """ - log.debug('Starting SWORD import from "%s"' % self.sword_key) + log.debug('Starting SWORD import from "{key}"'.format(key=self.sword_key)) success = True try: pysword_modules = modules.SwordModules(self.sword_path) @@ -84,14 +84,14 @@ class SwordBible(BibleDB): verse_number += 1 self.create_verse(db_book.id, chapter_number, verse_number, verse) self.wizard.increment_progress_bar( - translate('BiblesPlugin.Sword', 'Importing %s...') % db_book.name) + translate('BiblesPlugin.Sword', 'Importing {name}...').format(name=db_book.name)) self.session.commit() self.application.process_events() except Exception as e: critical_error_message_box( message=translate('BiblesPlugin.SwordImport', 'An unexpected error happened while importing the SWORD ' 'bible, please report this to the OpenLP developers.\n' - '%s' % e)) + '{error}').format(error=e)) log.exception(str(e)) success = False if self.stop_import_flag: diff --git a/openlp/plugins/bibles/lib/upgrade.py b/openlp/plugins/bibles/lib/upgrade.py index 7cc58ef7b..aebd088e8 100644 --- a/openlp/plugins/bibles/lib/upgrade.py +++ b/openlp/plugins/bibles/lib/upgrade.py @@ -101,7 +101,7 @@ def upgrade_1(session, metadata): metadata_table.c.key == 'download source' ) ).scalar() - log.debug('download source: %s', value_count) + log.debug('download source: {count}'.format(count=value_count)) if value_count > 0: session.execute(insert(metadata_table).values( key='download_source', @@ -121,7 +121,7 @@ def upgrade_1(session, metadata): metadata_table.c.key == 'download name' ) ).scalar() - log.debug('download name: %s', value_count) + log.debug('download name: {count}'.format(count=value_count)) if value_count > 0: session.execute(insert(metadata_table).values( key='download_name', @@ -141,7 +141,7 @@ def upgrade_1(session, metadata): metadata_table.c.key == 'proxy server' ) ).scalar() - log.debug('proxy server: %s', value_count) + log.debug('proxy server: {count}'.format(count=value_count)) if value_count > 0: session.execute(insert(metadata_table).values( key='proxy_server', @@ -161,7 +161,7 @@ def upgrade_1(session, metadata): metadata_table.c.key == 'proxy username' ) ).scalar() - log.debug('proxy username: %s', value_count) + log.debug('proxy username: {count}'.format(count=value_count)) if value_count > 0: session.execute(insert(metadata_table).values( key='proxy_username', @@ -181,7 +181,7 @@ def upgrade_1(session, metadata): metadata_table.c.key == 'proxy password' ) ).scalar() - log.debug('proxy password: %s', value_count) + log.debug('proxy password: {count}'.format(count=value_count)) if value_count > 0: session.execute(insert(metadata_table).values( key='proxy_password', diff --git a/openlp/plugins/bibles/lib/versereferencelist.py b/openlp/plugins/bibles/lib/versereferencelist.py index a7f143b21..e46b8b357 100644 --- a/openlp/plugins/bibles/lib/versereferencelist.py +++ b/openlp/plugins/bibles/lib/versereferencelist.py @@ -61,23 +61,29 @@ class VerseReferenceList(object): result = '' for index, verse in enumerate(self.verse_list): if index == 0: - result = '%s %s%s%s' % (verse['book'], verse['chapter'], verse_sep, verse['start']) + result = '{book} {chapter}{sep}{verse}'.format(book=verse['book'], + chapter=verse['chapter'], + sep=verse_sep, + verse=verse['start']) if verse['start'] != verse['end']: - result = '%s%s%s' % (result, range_sep, verse['end']) + result = '{result}{sep}{end}'.format(result=result, sep=range_sep, end=verse['end']) continue prev = index - 1 if self.verse_list[prev]['version'] != verse['version']: - result = '%s (%s)' % (result, self.verse_list[prev]['version']) - result += '%s ' % list_sep + result = '{result} ({version})'.format(result=result, version=self.verse_list[prev]['version']) + result += '{sep} '.format(sep=list_sep) if self.verse_list[prev]['book'] != verse['book']: - result = '%s%s %s%s' % (result, verse['book'], verse['chapter'], verse_sep) + result = '{result}{book} {chapter}{sep}'.format(result=result, + book=verse['book'], + chapter=verse['chapter'], + sep=verse_sep) elif self.verse_list[prev]['chapter'] != verse['chapter']: - result = '%s%s%s' % (result, verse['chapter'], verse_sep) + result = '{result}{chapter}{sep}'.format(result=result, chapter=verse['chapter'], sep=verse_sep) result += str(verse['start']) if verse['start'] != verse['end']: - result = '%s%s%s' % (result, range_sep, verse['end']) + result = '{result}{sep}{end}'.format(result=result, sep=range_sep, end=verse['end']) if len(self.version_list) > 1: - result = '%s (%s)' % (result, verse['version']) + result = '{result} ({version})'.format(result=result, version=verse['version']) return result def format_versions(self, copyright=True, permission=True): diff --git a/openlp/plugins/bibles/lib/zefania.py b/openlp/plugins/bibles/lib/zefania.py index 9b44cdf26..0ea96a2a3 100644 --- a/openlp/plugins/bibles/lib/zefania.py +++ b/openlp/plugins/bibles/lib/zefania.py @@ -48,7 +48,7 @@ class ZefaniaBible(BibleDB): """ Loads a Bible from file. """ - log.debug('Starting Zefania import from "%s"' % self.filename) + log.debug('Starting Zefania import from "{name}"'.format(name=self.filename)) if not isinstance(self.filename, str): self.filename = str(self.filename, 'utf8') import_file = None @@ -67,7 +67,7 @@ class ZefaniaBible(BibleDB): if not language_id: language_id = self.get_language(bible_name) if not language_id: - log.error('Importing books from "%s" failed' % self.filename) + log.error('Importing books from "{name}" failed'.format(name=self.filename)) return False self.save_meta('language_id', language_id) num_books = int(zefania_bible_tree.xpath('count(//BIBLEBOOK)')) @@ -92,7 +92,7 @@ class ZefaniaBible(BibleDB): log.debug('Could not find a name, will use number, basically a guess.') book_ref_id = int(bnumber) if not book_ref_id: - log.error('Importing books from "%s" failed' % self.filename) + log.error('Importing books from "{name}" failed'.format(name=self.filename)) return False book_details = BiblesResourcesDB.get_book_by_id(book_ref_id) db_book = self.create_book(book_details['name'], book_ref_id, book_details['testament_id']) @@ -104,8 +104,9 @@ class ZefaniaBible(BibleDB): verse_number = VERS.get("vnumber") self.create_verse(db_book.id, chapter_number, verse_number, VERS.text.replace('
', '\n')) self.wizard.increment_progress_bar( - translate('BiblesPlugin.Zefnia', 'Importing %(bookname)s %(chapter)s...') % - {'bookname': db_book.name, 'chapter': chapter_number}) + translate('BiblesPlugin.Zefnia', + 'Importing {book} {chapter}...').format(book=db_book.name, + chapter=chapter_number)) self.session.commit() self.application.process_events() except Exception as e: diff --git a/tests/functional/openlp_core_lib/test_projectordb.py b/tests/functional/openlp_core_lib/test_projectordb.py index a6ecb617d..7f3f927aa 100644 --- a/tests/functional/openlp_core_lib/test_projectordb.py +++ b/tests/functional/openlp_core_lib/test_projectordb.py @@ -29,6 +29,7 @@ import os from unittest import TestCase from openlp.core.lib.projector.db import Manufacturer, Model, Projector, ProjectorDB, ProjectorSource, Source +from openlp.core.lib.projector.constants import PJLINK_PORT from tests.functional import MagicMock, patch from tests.resources.projector.data import TEST_DB, TEST1_DATA, TEST2_DATA, TEST3_DATA @@ -195,7 +196,7 @@ class TestProjectorDB(TestCase): def manufacturer_repr_test(self): """ - Test manufacturer class __repr__ text + Test Manufacturer.__repr__ text """ # GIVEN: Test object manufacturer = Manufacturer() @@ -209,7 +210,7 @@ class TestProjectorDB(TestCase): def model_repr_test(self): """ - Test model class __repr__ text + Test Model.__repr__ text """ # GIVEN: Test object model = Model() @@ -223,7 +224,7 @@ class TestProjectorDB(TestCase): def source_repr_test(self): """ - Test source.__repr__ text + Test Source.__repr__ text """ # GIVEN: Test object source = Source() @@ -236,3 +237,31 @@ class TestProjectorDB(TestCase): # THEN: __repr__ should return a proper string self.assertEqual(str(source), '', 'Source.__repr__() should have returned a proper representation string') + + def projector_repr_test(self): + """ + Test Projector.__repr__() text + """ + # GIVEN: Test object + projector = Projector() + + # WHEN: projector() is populated + # NOTE: projector.pin, projector.other, projector.sources should all return None + # projector.source_list should return an empty list + projector.id = 0 + projector.ip = '127.0.0.1' + projector.port = PJLINK_PORT + projector.name = 'Test One' + projector.location = 'Somewhere over the rainbow' + projector.notes = 'Not again' + projector.pjlink_name = 'TEST' + projector.manufacturer = 'IN YOUR DREAMS' + projector.model = 'OpenLP' + + # THEN: __repr__ should return a proper string + self.assertEqual(str(projector), + '< Projector(id="0", ip="127.0.0.1", port="4352", pin="None", name="Test One", ' + 'location="Somewhere over the rainbow", notes="Not again", pjlink_name="TEST", ' + 'manufacturer="IN YOUR DREAMS", model="OpenLP", other="None", sources="None", ' + 'source_list="[]") >', + 'Projector.__repr__() should have returned a proper representation string') diff --git a/tests/functional/openlp_plugins/bibles/test_http.py b/tests/functional/openlp_plugins/bibles/test_http.py index 54289a163..56df57c3d 100644 --- a/tests/functional/openlp_plugins/bibles/test_http.py +++ b/tests/functional/openlp_plugins/bibles/test_http.py @@ -104,7 +104,7 @@ class TestBSExtract(TestCase): result = instance.get_books_from_http('NIV') # THEN: The rest mocks should be called with known values and get_books_from_http should return None - self.mock_log.debug.assert_called_once_with('BSExtract.get_books_from_http("%s")', 'NIV') + self.mock_log.debug.assert_called_once_with('BSExtract.get_books_from_http("{book}")'.format(book='NIV')) self.mock_urllib.parse.quote.assert_called_once_with(b'NIV') self.mock_get_soup_for_bible_ref.assert_called_once_with( 'http://m.bibleserver.com/overlay/selectBook?translation=NIV') @@ -132,7 +132,7 @@ class TestBSExtract(TestCase): result = instance.get_books_from_http('NIV') # THEN: The rest mocks should be called with known values and get_books_from_http should return None - self.mock_log.debug.assert_called_once_with('BSExtract.get_books_from_http("%s")', 'NIV') + self.mock_log.debug.assert_called_once_with('BSExtract.get_books_from_http("{book}")'.format(book='NIV')) self.mock_urllib.parse.quote.assert_called_once_with(b'NIV') self.mock_get_soup_for_bible_ref.assert_called_once_with( 'http://m.bibleserver.com/overlay/selectBook?translation=NIV') @@ -167,7 +167,7 @@ class TestBSExtract(TestCase): # THEN: The rest mocks should be called with known values and get_books_from_http should return the two books # in the test data - self.mock_log.debug.assert_called_once_with('BSExtract.get_books_from_http("%s")', 'NIV') + self.mock_log.debug.assert_called_once_with('BSExtract.get_books_from_http("{book}")'.format(book='NIV')) self.mock_urllib.parse.quote.assert_called_once_with(b'NIV') self.mock_get_soup_for_bible_ref.assert_called_once_with( 'http://m.bibleserver.com/overlay/selectBook?translation=NIV') From 801f508a72af8ef114651dadf846037fea734a16 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Sat, 21 May 2016 11:19:18 -0700 Subject: [PATCH 16/62] Convert strings in plugins part 2 --- openlp/plugins/custom/lib/customxmlhandler.py | 2 +- openlp/plugins/custom/lib/mediaitem.py | 15 ++++---- openlp/plugins/images/lib/mediaitem.py | 31 +++++++++-------- .../media/forms/mediaclipselectorform.py | 33 +++++++++++------- openlp/plugins/media/lib/mediaitem.py | 24 ++++++++----- openlp/plugins/media/mediaplugin.py | 2 +- .../presentations/lib/impresscontroller.py | 8 ++--- openlp/plugins/presentations/lib/mediaitem.py | 21 +++++++----- .../presentations/lib/messagelistener.py | 34 +++++++++---------- .../presentations/lib/pdfcontroller.py | 5 ++- .../presentations/lib/powerpointcontroller.py | 27 ++++++++++----- .../presentations/lib/pptviewcontroller.py | 2 +- .../lib/presentationcontroller.py | 7 ++-- .../presentations/lib/presentationtab.py | 3 +- .../presentations/presentationplugin.py | 4 +-- .../openlp_core_lib/test_projector_pjlink1.py | 14 ++++++++ 16 files changed, 141 insertions(+), 91 deletions(-) diff --git a/openlp/plugins/custom/lib/customxmlhandler.py b/openlp/plugins/custom/lib/customxmlhandler.py index 7ae04d123..a540e9ace 100644 --- a/openlp/plugins/custom/lib/customxmlhandler.py +++ b/openlp/plugins/custom/lib/customxmlhandler.py @@ -128,7 +128,7 @@ class CustomXMLParser(object): try: self.custom_xml = objectify.fromstring(xml) except etree.XMLSyntaxError: - log.exception('Invalid xml %s', xml) + log.exception('Invalid xml {xml}'.format(xml=xml)) def get_verses(self): """ diff --git a/openlp/plugins/custom/lib/mediaitem.py b/openlp/plugins/custom/lib/mediaitem.py index 225226f7d..e9e26111f 100644 --- a/openlp/plugins/custom/lib/mediaitem.py +++ b/openlp/plugins/custom/lib/mediaitem.py @@ -94,7 +94,7 @@ class CustomMediaItem(MediaManagerItem): """ """ - self.search_text_label.setText('%s:' % UiStrings().Search) + self.search_text_label.setText('{text}:'.format(text=UiStrings().Search)) self.search_text_button.setText(UiStrings().Search) def initialise(self): @@ -105,7 +105,8 @@ class CustomMediaItem(MediaManagerItem): [(CustomSearch.Titles, ':/songs/song_search_title.png', translate('SongsPlugin.MediaItem', 'Titles'), translate('SongsPlugin.MediaItem', 'Search Titles...')), (CustomSearch.Themes, ':/slides/slide_theme.png', UiStrings().Themes, UiStrings().SearchThemes)]) - self.search_text_edit.set_current_search_type(Settings().value('%s/last search type' % self.settings_section)) + text = '{section}/last search type'.format(section=self.settings_section) + self.search_text_edit.set_current_search_type(Settings().value(text)) self.load_list(self.plugin.db_manager.get_all_objects(CustomSlide, order_by_ref=CustomSlide.title)) self.config_update() @@ -190,7 +191,8 @@ class CustomMediaItem(MediaManagerItem): if QtWidgets.QMessageBox.question( self, UiStrings().ConfirmDelete, translate('CustomPlugin.MediaItem', - 'Are you sure you want to delete the "%d" selected custom slide(s)?') % len(items), + 'Are you sure you want to delete the "{items:d}" ' + 'selected custom slide(s)?').format(items=len(items)), QtWidgets.QMessageBox.StandardButtons( QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No), QtWidgets.QMessageBox.Yes) == QtWidgets.QMessageBox.No: @@ -249,10 +251,11 @@ class CustomMediaItem(MediaManagerItem): Search the plugin database """ # Save the current search type to the configuration. - Settings().setValue('%s/last search type' % self.settings_section, self.search_text_edit.current_search_type()) + Settings().setValue('{section}/last search type'.format(section=self.settings_section), + self.search_text_edit.current_search_type()) # Reload the list considering the new search type. search_type = self.search_text_edit.current_search_type() - search_keywords = '%' + self.whitespace.sub(' ', self.search_text_edit.displayText()) + '%' + search_keywords = '%{search}%'.format(search=self.whitespace.sub(' ', self.search_text_edit.displayText())) if search_type == CustomSearch.Titles: log.debug('Titles Search') search_results = self.plugin.db_manager.get_all_objects(CustomSlide, @@ -347,7 +350,7 @@ class CustomMediaItem(MediaManagerItem): :param string: The search string :param show_error: The error string to be show. """ - search = '%' + string.lower() + '%' + search = '%{search}%'.forma(search=string.lower()) search_results = self.plugin.db_manager.get_all_objects(CustomSlide, or_(func.lower(CustomSlide.title).like(search), func.lower(CustomSlide.text).like(search)), diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py index d127fba4b..ad13a477d 100644 --- a/openlp/plugins/images/lib/mediaitem.py +++ b/openlp/plugins/images/lib/mediaitem.py @@ -74,7 +74,7 @@ class ImageMediaItem(MediaManagerItem): def retranslateUi(self): self.on_new_prompt = translate('ImagePlugin.MediaItem', 'Select Image(s)') file_formats = get_images_filter() - self.on_new_file_masks = '%s;;%s (*)' % (file_formats, UiStrings().AllFiles) + self.on_new_file_masks = '{formats};;{files} (*)'.format(formats=file_formats, files=UiStrings().AllFiles) self.add_group_action.setText(UiStrings().AddGroup) self.add_group_action.setToolTip(UiStrings().AddGroup) self.replace_action.setText(UiStrings().ReplaceBG) @@ -113,7 +113,7 @@ class ImageMediaItem(MediaManagerItem): self.list_view = TreeWidgetWithDnD(self, self.plugin.name) self.list_view.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) self.list_view.setAlternatingRowColors(True) - self.list_view.setObjectName('%sTreeView' % self.plugin.name) + self.list_view.setObjectName('{name}TreeView'.format(name=self.plugin.name)) # Add to pageLayout self.page_layout.addWidget(self.list_view) # define and add the context menu @@ -127,21 +127,21 @@ class ImageMediaItem(MediaManagerItem): create_widget_action(self.list_view, separator=True) create_widget_action( self.list_view, - 'listView%s%sItem' % (self.plugin.name.title(), StringContent.Preview.title()), + 'listView{name}{preview}Item'.format(name=self.plugin.name.title(), preview=StringContent.Preview.title()), text=self.plugin.get_string(StringContent.Preview)['title'], icon=':/general/general_preview.png', can_shortcuts=True, triggers=self.on_preview_click) create_widget_action( self.list_view, - 'listView%s%sItem' % (self.plugin.name.title(), StringContent.Live.title()), + 'listView{name}{live}Item'.format(name=self.plugin.name.title(), live=StringContent.Live.title()), text=self.plugin.get_string(StringContent.Live)['title'], icon=':/general/general_live.png', can_shortcuts=True, triggers=self.on_live_click) create_widget_action( self.list_view, - 'listView%s%sItem' % (self.plugin.name.title(), StringContent.Service.title()), + 'listView{name}{service}Item'.format(name=self.plugin.name.title(), service=StringContent.Service.title()), can_shortcuts=True, text=self.plugin.get_string(StringContent.Service)['title'], icon=':/general/general_add.png', @@ -157,7 +157,7 @@ class ImageMediaItem(MediaManagerItem): if self.has_delete_icon: create_widget_action( self.list_view, - 'listView%s%sItem' % (self.plugin.name.title(), StringContent.Delete.title()), + 'listView{name}{delete}Item'.format(name=self.plugin.name.title(), delete=StringContent.Delete.title()), text=self.plugin.get_string(StringContent.Delete)['title'], icon=':/general/general_delete.png', can_shortcuts=True, triggers=self.on_delete_click) @@ -245,8 +245,8 @@ class ImageMediaItem(MediaManagerItem): self.list_view.parent(), translate('ImagePlugin.MediaItem', 'Remove group'), translate('ImagePlugin.MediaItem', - 'Are you sure you want to remove "%s" and everything in it?') % - item_data.group_name, + 'Are you sure you want to remove "{name}" and everything in it?' + ).format(name=item_data.group_name), QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No) ) == QtWidgets.QMessageBox.Yes: @@ -355,7 +355,7 @@ class ImageMediaItem(MediaManagerItem): # characters. images.sort(key=lambda image_object: get_locale_key(os.path.split(str(image_object.filename))[1])) for image_file in images: - log.debug('Loading image: %s', image_file.filename) + log.debug('Loading image: {name}'.format(name=image_file.filename)) filename = os.path.split(image_file.filename)[1] thumb = self.generate_thumbnail_path(image_file) if not os.path.exists(image_file.filename): @@ -481,7 +481,7 @@ class ImageMediaItem(MediaManagerItem): for filename in images_list: if not isinstance(filename, str): continue - log.debug('Adding new image: %s', filename) + log.debug('Adding new image: {name}'.format(name=filename)) image_file = ImageFilenames() image_file.group_id = group_id image_file.filename = str(filename) @@ -589,14 +589,15 @@ class ImageMediaItem(MediaManagerItem): if not remote: critical_error_message_box( translate('ImagePlugin.MediaItem', 'Missing Image(s)'), - translate('ImagePlugin.MediaItem', 'The following image(s) no longer exist: %s') - % '\n'.join(missing_items_file_names)) + translate('ImagePlugin.MediaItem', 'The following image(s) no longer exist: {names}' + ).format(names='\n'.join(missing_items_file_names))) return False # We have missing as well as existing images. We ask what to do. elif missing_items_file_names and QtWidgets.QMessageBox.question( self, translate('ImagePlugin.MediaItem', 'Missing Image(s)'), - translate('ImagePlugin.MediaItem', 'The following image(s) no longer exist: %s\n' - 'Do you want to add the other images anyway?') % '\n'.join(missing_items_file_names), + translate('ImagePlugin.MediaItem', 'The following image(s) no longer exist: {names}\n' + 'Do you want to add the other images anyway?' + ).format(names='\n'.join(missing_items_file_names)), QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.No | QtWidgets.QMessageBox.Yes)) == \ QtWidgets.QMessageBox.No: return False @@ -688,7 +689,7 @@ class ImageMediaItem(MediaManagerItem): critical_error_message_box( UiStrings().LiveBGError, translate('ImagePlugin.MediaItem', 'There was a problem replacing your background, ' - 'the image file "%s" no longer exists.') % filename) + 'the image file "{name}" no longer exists.').format(name=filename)) def search(self, string, show_error=True): """ diff --git a/openlp/plugins/media/forms/mediaclipselectorform.py b/openlp/plugins/media/forms/mediaclipselectorform.py index 435129f10..0f3d1c7db 100644 --- a/openlp/plugins/media/forms/mediaclipselectorform.py +++ b/openlp/plugins/media/forms/mediaclipselectorform.py @@ -46,7 +46,7 @@ class MediaClipSelectorForm(QtWidgets.QDialog, Ui_MediaClipSelector, RegistryPro """ Class to manage the clip selection """ - log.info('%s MediaClipSelectorForm loaded', __name__) + log.info('{name} MediaClipSelectorForm loaded'.format(name=__name__)) def __init__(self, media_item, parent, manager): """ @@ -265,7 +265,8 @@ class MediaClipSelectorForm(QtWidgets.QDialog, Ui_MediaClipSelector, RegistryPro # Enable audio track combobox if anything is in it if len(titles) > 0: self.titles_combo_box.setDisabled(False) - log.debug('load_disc_button end - vlc_media_player state: %s' % self.vlc_media_player.get_state()) + log.debug('load_disc_button end - ' + 'vlc_media_player state: {state}'.format(state=self.vlc_media_player.get_state())) @QtCore.pyqtSlot(bool) def on_play_button_clicked(self, clicked): @@ -374,7 +375,7 @@ class MediaClipSelectorForm(QtWidgets.QDialog, Ui_MediaClipSelector, RegistryPro :param index: The index of the newly chosen title track. """ - log.debug('in on_titles_combo_box_changed, index: %d', index) + log.debug('in on_titles_combo_box_changed, index: {index:d}'.format(index=index)) vlc = get_vlc() if not self.vlc_media_player: log.error('vlc_media_player was None') @@ -407,7 +408,7 @@ class MediaClipSelectorForm(QtWidgets.QDialog, Ui_MediaClipSelector, RegistryPro self.vlc_media_player.audio_set_mute(True) # Get audio tracks audio_tracks = self.vlc_media_player.audio_get_track_description() - log.debug('number of audio tracks: %d' % len(audio_tracks)) + log.debug('number of audio tracks: {tracks:d}'.format(tracks=len(audio_tracks))) # Clear the audio track combobox, insert new tracks self.audio_tracks_combobox.clear() for audio_track in audio_tracks: @@ -433,14 +434,14 @@ class MediaClipSelectorForm(QtWidgets.QDialog, Ui_MediaClipSelector, RegistryPro self.toggle_disable_player(False) # Set media length info self.playback_length = self.vlc_media_player.get_length() - log.debug('playback_length: %d ms' % self.playback_length) + log.debug('playback_length: {length:d} ms'.format(length=self.playback_length)) # if length is 0, wait a bit, maybe vlc will change its mind... loop_count = 0 while self.playback_length == 0 and loop_count < 20: sleep(0.1) self.playback_length = self.vlc_media_player.get_length() loop_count += 1 - log.debug('in loop, playback_length: %d ms' % self.playback_length) + log.debug('in loop, playback_length: {length:d} ms'.format(length=self.playback_length)) self.position_slider.setMaximum(self.playback_length) # setup start and end time rounded_vlc_ms_length = int(round(self.playback_length / 100.0) * 100.0) @@ -455,7 +456,8 @@ class MediaClipSelectorForm(QtWidgets.QDialog, Ui_MediaClipSelector, RegistryPro sleep(0.1) self.vlc_media_player.set_pause(1) loop_count += 1 - log.debug('titles_combo_box end - vlc_media_player state: %s' % self.vlc_media_player.get_state()) + log.debug('titles_combo_box end - ' + 'vlc_media_player state: {state}'.format(state=self.vlc_media_player.get_state())) self.application.set_normal_cursor() @QtCore.pyqtSlot(int) @@ -468,7 +470,8 @@ class MediaClipSelectorForm(QtWidgets.QDialog, Ui_MediaClipSelector, RegistryPro if not self.vlc_media_player: return audio_track = self.audio_tracks_combobox.itemData(index) - log.debug('in on_audio_tracks_combobox_currentIndexChanged, index: %d audio_track: %s' % (index, audio_track)) + log.debug('in on_audio_tracks_combobox_currentIndexChanged, ' + 'index: {index:d} audio_track: {tracks}'.format(index=index, tracks=audio_track)) if audio_track and int(audio_track) > 0: self.vlc_media_player.audio_set_track(int(audio_track)) @@ -566,7 +569,9 @@ class MediaClipSelectorForm(QtWidgets.QDialog, Ui_MediaClipSelector, RegistryPro translate('MediaPlugin.MediaClipSelectorForm', 'The CD was not loaded correctly, please re-load and try again.')) return - optical = 'optical:%d:-1:-1:%d:%d:' % (title, start_time_ms, end_time_ms) + optical = 'optical:{title:d}:-1:-1:{start:d}:{end:d}:'.format(title=title, + start=start_time_ms, + end=end_time_ms) else: audio_track = self.audio_tracks_combobox.itemData(self.audio_tracks_combobox.currentIndex()) subtitle_track = self.subtitle_tracks_combobox.itemData(self.subtitle_tracks_combobox.currentIndex()) @@ -577,7 +582,11 @@ class MediaClipSelectorForm(QtWidgets.QDialog, Ui_MediaClipSelector, RegistryPro translate('MediaPlugin.MediaClipSelectorForm', 'The DVD was not loaded correctly, please re-load and try again.')) return - optical = 'optical:%d:%d:%d:%d:%d:' % (title, audio_track, subtitle_track, start_time_ms, end_time_ms) + optical = 'optical:{title:d}:{audio:d}:{sub:d}:{start:d}:{end:d}:'.format(title=title, + audio=audio_track, + sub=subtitle_track, + start=start_time_ms, + end=end_time_ms) # Ask for an alternative name for the mediaclip while True: new_optical_name, ok = QtWidgets.QInputDialog.getText(self, translate('MediaPlugin.MediaClipSelectorForm', @@ -634,10 +643,10 @@ class MediaClipSelectorForm(QtWidgets.QDialog, Ui_MediaClipSelector, RegistryPro # use win api to find optical drives fso = Dispatch('scripting.filesystemobject') for drive in fso.Drives: - log.debug('Drive %s has type %d' % (drive.DriveLetter, drive.DriveType)) + log.debug('Drive {drive} has type {types:d}'.format(drive=drive.DriveLetter, types=drive.DriveType)) # if type is 4, it is a cd-rom drive if drive.DriveType == 4: - self.media_path_combobox.addItem('%s:\\' % drive.DriveLetter) + self.media_path_combobox.addItem('{drive}:\\'.format(drive=drive.DriveLetter)) elif is_linux(): # Get disc devices from dbus and find the ones that are optical bus = dbus.SystemBus() diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index 507196395..ac3636010 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -51,7 +51,7 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): """ media_go_live = QtCore.pyqtSignal(list) media_add_to_service = QtCore.pyqtSignal(list) - log.info('%s MediaMediaItem loaded', __name__) + log.info('{name} MediaMediaItem loaded'.format(name=__name__)) def __init__(self, parent, plugin): self.setup() @@ -232,7 +232,7 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): critical_error_message_box(UiStrings().LiveBGError, translate('MediaPlugin.MediaItem', 'There was a problem replacing your background, ' - 'the media file "%s" no longer exists.') % filename) + 'the media file "{name}" no longer exists.').format(name=filename)) def generate_slide_data(self, service_item, item=None, xml_version=False, remote=False, context=ServiceItemContext.Service): @@ -258,7 +258,8 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): # Optical disc is no longer present critical_error_message_box( translate('MediaPlugin.MediaItem', 'Missing Media File'), - translate('MediaPlugin.MediaItem', 'The optical disc %s is no longer available.') % name) + translate('MediaPlugin.MediaItem', + 'The optical disc {name} is no longer available.').format(name=name)) return False service_item.processor = self.display_type_combo_box.currentText() service_item.add_from_command(filename, name, CLAPPERBOARD) @@ -275,7 +276,7 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): # File is no longer present critical_error_message_box( translate('MediaPlugin.MediaItem', 'Missing Media File'), - translate('MediaPlugin.MediaItem', 'The file %s no longer exists.') % filename) + translate('MediaPlugin.MediaItem', 'The file {name} no longer exists.').format(name=filename)) return False (path, name) = os.path.split(filename) service_item.title = name @@ -308,9 +309,11 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): Rebuild the tab in the media manager when changes are made in the settings. """ self.populate_display_types() - self.on_new_file_masks = translate('MediaPlugin.MediaItem', 'Videos (%s);;Audio (%s);;%s (*)') % ( - ' '.join(self.media_controller.video_extensions_list), - ' '.join(self.media_controller.audio_extensions_list), UiStrings().AllFiles) + self.on_new_file_masks = translate('MediaPlugin.MediaItem', + 'Videos ({video});;Audio ({audio});;{files} ' + '(*)').format(video=' '.join(self.media_controller.video_extensions_list), + audio=' '.join(self.media_controller.audio_extensions_list), + files=UiStrings().AllFiles) def populate_display_types(self): """ @@ -365,7 +368,9 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): item_name = QtWidgets.QListWidgetItem(clip_name) item_name.setIcon(self.optical_icon) item_name.setData(QtCore.Qt.UserRole, track) - item_name.setToolTip('%s@%s-%s' % (file_name, format_milliseconds(start), format_milliseconds(end))) + item_name.setToolTip('{name}@{start}-{end}'.format(name=file_name, + start=format_milliseconds(start), + end=format_milliseconds(end))) elif not os.path.exists(track): # File doesn't exist, mark as error. file_name = os.path.split(str(track))[1] @@ -377,7 +382,8 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): # Normal media file handling. file_name = os.path.split(str(track))[1] item_name = QtWidgets.QListWidgetItem(file_name) - if '*.%s' % (file_name.split('.')[-1].lower()) in self.media_controller.audio_extensions_list: + search = file_name.split('.')[-1].lower() + if '*.{text}'.format(text=search) in self.media_controller.audio_extensions_list: item_name.setIcon(self.audio_icon) else: item_name.setIcon(self.video_icon) diff --git a/openlp/plugins/media/mediaplugin.py b/openlp/plugins/media/mediaplugin.py index f9874c57b..2efbfb595 100644 --- a/openlp/plugins/media/mediaplugin.py +++ b/openlp/plugins/media/mediaplugin.py @@ -49,7 +49,7 @@ class MediaPlugin(Plugin): """ The media plugin adds the ability to playback audio and video content. """ - log.info('%s MediaPlugin loaded', __name__) + log.info('{name} MediaPlugin loaded'.format(name=__name__)) def __init__(self): super(MediaPlugin, self).__init__('media', __default_settings__, MediaMediaItem) diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py index 29af3a375..e9d048e45 100644 --- a/openlp/plugins/presentations/lib/impresscontroller.py +++ b/openlp/plugins/presentations/lib/impresscontroller.py @@ -236,7 +236,7 @@ class ImpressDocument(PresentationDocument): try: self.document = desktop.loadComponentFromURL(url, '_blank', 0, properties) except: - log.warning('Failed to load presentation %s' % url) + log.warning('Failed to load presentation {url}'.format(url=url)) return False self.presentation = self.document.getPresentation() self.presentation.Display = ScreenList().current['number'] + 1 @@ -269,16 +269,16 @@ class ImpressDocument(PresentationDocument): for index in range(pages.getCount()): page = pages.getByIndex(index) doc.getCurrentController().setCurrentPage(page) - url_path = '%s/%s.png' % (thumb_dir_url, str(index + 1)) + url_path = '{path}/{name}.png'.format(path=thumb_dir_url, name=str(index + 1)) path = os.path.join(self.get_temp_folder(), str(index + 1) + '.png') try: doc.storeToURL(url_path, properties) self.convert_thumbnail(path, index + 1) delete_file(path) except ErrorCodeIOException as exception: - log.exception('ERROR! ErrorCodeIOException %d' % exception.ErrCode) + log.exception('ERROR! ErrorCodeIOException {error:d}'.format(error=exception.ErrCode)) except: - log.exception('%s - Unable to store openoffice preview' % path) + log.exception('{path} - Unable to store openoffice preview'.format(path=path)) def create_property(self, name, value): """ diff --git a/openlp/plugins/presentations/lib/mediaitem.py b/openlp/plugins/presentations/lib/mediaitem.py index b64c552b8..f9788d180 100644 --- a/openlp/plugins/presentations/lib/mediaitem.py +++ b/openlp/plugins/presentations/lib/mediaitem.py @@ -88,9 +88,10 @@ class PresentationMediaItem(MediaManagerItem): file_types = self.controllers[controller].supports + self.controllers[controller].also_supports for file_type in file_types: if file_type not in file_type_string: - file_type_string += '*.%s ' % file_type + file_type_string += '*.{text} '.format(text=file_type) self.service_manager.supported_suffixes(file_type) - self.on_new_file_masks = translate('PresentationPlugin.MediaItem', 'Presentations (%s)') % file_type_string + self.on_new_file_masks = translate('PresentationPlugin.MediaItem', + 'Presentations ({text})').format(text=file_type_string) def required_icons(self): """ @@ -306,13 +307,13 @@ class PresentationMediaItem(MediaManagerItem): os.path.join(doc.get_temp_folder(), 'mainslide001.png')): doc.load_presentation() i = 1 - image = os.path.join(doc.get_temp_folder(), 'mainslide%03d.png' % i) + image = os.path.join(doc.get_temp_folder(), 'mainslide{number:0>3d}.png'.format(number=i)) thumbnail = os.path.join(doc.get_thumbnail_folder(), 'slide%d.png' % i) while os.path.isfile(image): service_item.add_from_image(image, name, thumbnail=thumbnail) i += 1 - image = os.path.join(doc.get_temp_folder(), 'mainslide%03d.png' % i) - thumbnail = os.path.join(doc.get_thumbnail_folder(), 'slide%d.png' % i) + image = os.path.join(doc.get_temp_folder(), 'mainslide{number:0>3d}.png'.format(number=i)) + thumbnail = os.path.join(doc.get_thumbnail_folder(), 'slide{number:d}.png'.format(number=i)) service_item.add_capability(ItemCapabilities.HasThumbnails) doc.close_presentation() return True @@ -321,7 +322,8 @@ class PresentationMediaItem(MediaManagerItem): if not remote: critical_error_message_box(translate('PresentationPlugin.MediaItem', 'Missing Presentation'), translate('PresentationPlugin.MediaItem', - 'The presentation %s no longer exists.') % filename) + 'The presentation {name} no longer exists.' + ).format(name=filename)) return False else: service_item.processor = self.display_type_combo_box.currentText() @@ -367,15 +369,16 @@ class PresentationMediaItem(MediaManagerItem): critical_error_message_box(translate('PresentationPlugin.MediaItem', 'Missing Presentation'), translate('PresentationPlugin.MediaItem', - 'The presentation %s is incomplete, please reload.') - % filename) + 'The presentation {name} is incomplete, ' + 'please reload.').format(name=filename)) return False else: # File is no longer present if not remote: critical_error_message_box(translate('PresentationPlugin.MediaItem', 'Missing Presentation'), translate('PresentationPlugin.MediaItem', - 'The presentation %s no longer exists.') % filename) + 'The presentation {name} no longer exists.' + ).format(name=filename)) return False def find_controller_by_type(self, filename): diff --git a/openlp/plugins/presentations/lib/messagelistener.py b/openlp/plugins/presentations/lib/messagelistener.py index cc5a6f05e..992ba9b5c 100644 --- a/openlp/plugins/presentations/lib/messagelistener.py +++ b/openlp/plugins/presentations/lib/messagelistener.py @@ -48,14 +48,14 @@ class Controller(object): self.is_live = live self.doc = None self.hide_mode = None - log.info('%s controller loaded' % live) + log.info('{name} controller loaded'.format(name=live)) def add_handler(self, controller, file, hide_mode, slide_no): """ Add a handler, which is an instance of a presentation and slidecontroller combination. If the slidecontroller has a display then load the presentation. """ - log.debug('Live = %s, add_handler %s' % (self.is_live, file)) + log.debug('Live = {live}, add_handler {handler}'.format(live=self.is_live, handler=file)) self.controller = controller if self.doc is not None: self.shutdown() @@ -67,7 +67,7 @@ class Controller(object): return self.doc.slidenumber = slide_no self.hide_mode = hide_mode - log.debug('add_handler, slide_number: %d' % slide_no) + log.debug('add_handler, slide_number: {slide:d}'.format(slide=slide_no)) if self.is_live: if hide_mode == HideMode.Screen: Registry().execute('live_display_hide', HideMode.Screen) @@ -87,14 +87,14 @@ class Controller(object): """ Active the presentation, and show it on the screen. Use the last slide number. """ - log.debug('Live = %s, activate' % self.is_live) + log.debug('Live = {live}, activate'.format(live=self.is_live)) if not self.doc: return False if self.doc.is_active(): return True if not self.doc.is_loaded(): if not self.doc.load_presentation(): - log.warning('Failed to activate %s' % self.doc.file_path) + log.warning('Failed to activate {path}'.format(path=self.doc.file_path)) return False if self.is_live: self.doc.start_presentation() @@ -105,14 +105,14 @@ class Controller(object): if self.doc.is_active(): return True else: - log.warning('Failed to activate %s' % self.doc.file_path) + log.warning('Failed to activate {path}'.format(path=self.doc.file_path)) return False def slide(self, slide): """ Go to a specific slide """ - log.debug('Live = %s, slide' % self.is_live) + log.debug('Live = {live}, slide'.format(live=self.is_live)) if not self.doc: return if not self.is_live: @@ -130,7 +130,7 @@ class Controller(object): """ Based on the handler passed at startup triggers the first slide. """ - log.debug('Live = %s, first' % self.is_live) + log.debug('Live = {live}, first'.format(live=self.is_live)) if not self.doc: return if not self.is_live: @@ -148,7 +148,7 @@ class Controller(object): """ Based on the handler passed at startup triggers the last slide. """ - log.debug('Live = %s, last' % self.is_live) + log.debug('Live = {live}, last'.format(live=self.is_live)) if not self.doc: return if not self.is_live: @@ -166,7 +166,7 @@ class Controller(object): """ Based on the handler passed at startup triggers the next slide event. """ - log.debug('Live = %s, next' % self.is_live) + log.debug('Live = {live}, next'.format(live=self.is_live)) if not self.doc: return if not self.is_live: @@ -191,7 +191,7 @@ class Controller(object): """ Based on the handler passed at startup triggers the previous slide event. """ - log.debug('Live = %s, previous' % self.is_live) + log.debug('Live = {live}, previous'.formta(live=self.is_live)) if not self.doc: return if not self.is_live: @@ -212,7 +212,7 @@ class Controller(object): """ Based on the handler passed at startup triggers slide show to shut down. """ - log.debug('Live = %s, shutdown' % self.is_live) + log.debug('Live = {live}, shutdown'.format(live=self.is_live)) if not self.doc: return self.doc.close_presentation() @@ -222,7 +222,7 @@ class Controller(object): """ Instruct the controller to blank the presentation. """ - log.debug('Live = %s, blank' % self.is_live) + log.debug('Live = {live}, blank'.format(live=self.is_live)) self.hide_mode = hide_mode if not self.doc: return @@ -243,7 +243,7 @@ class Controller(object): """ Instruct the controller to stop and hide the presentation. """ - log.debug('Live = %s, stop' % self.is_live) + log.debug('Live = {live}, stop'.format(live=self.is_live)) # The document has not been loaded yet, so don't do anything. This can happen when going live with a # presentation while blanked to desktop. if not self.doc: @@ -266,7 +266,7 @@ class Controller(object): """ Instruct the controller to unblank the presentation. """ - log.debug('Live = %s, unblank' % self.is_live) + log.debug('Live = {live}, unblank'.format(live=self.is_live)) self.hide_mode = None if not self.doc: return @@ -321,7 +321,7 @@ class MessageListener(object): """ Start of new presentation. Save the handler as any new presentations start here """ - log.debug('Startup called with message %s' % message) + log.debug('Startup called with message {text}'.format(text=message)) is_live = message[1] item = message[0] hide_mode = message[2] @@ -332,7 +332,7 @@ class MessageListener(object): # the conversion has already been done at this point. file_type = os.path.splitext(file.lower())[1][1:] if file_type in PDF_CONTROLLER_FILETYPES: - log.debug('Converting from pdf/xps/oxps to images for serviceitem with file %s', file) + log.debug('Converting from pdf/xps/oxps to images for serviceitem with file {name}'.format(name=file)) # Create a copy of the original item, and then clear the original item so it can be filled with images item_cpy = copy.copy(item) item.__init__(None) diff --git a/openlp/plugins/presentations/lib/pdfcontroller.py b/openlp/plugins/presentations/lib/pdfcontroller.py index cf89d8d32..dd67031bd 100644 --- a/openlp/plugins/presentations/lib/pdfcontroller.py +++ b/openlp/plugins/presentations/lib/pdfcontroller.py @@ -87,7 +87,7 @@ class PdfController(PresentationController): if found_gs: program_type = 'gs' break - log.debug('in check_binary, found: %s', program_type) + log.debug('in check_binary, found: {text}'.format(text=program_type)) return program_type def check_available(self): @@ -255,11 +255,13 @@ class PdfDocument(PresentationDocument): os.makedirs(self.get_temp_folder()) if self.controller.mudrawbin: log.debug('loading presentation using mudraw') + # TODO: Find out where the string conversion actually happens runlog = check_output([self.controller.mudrawbin, '-w', str(size.width()), '-h', str(size.height()), '-o', os.path.join(self.get_temp_folder(), 'mainslide%03d.png'), self.file_path], startupinfo=self.startupinfo) elif self.controller.mutoolbin: log.debug('loading presentation using mutool') + # TODO: Find out where the string convertsion actually happens runlog = check_output([self.controller.mutoolbin, 'draw', '-w', str(size.width()), '-h', str(size.height()), '-o', os.path.join(self.get_temp_folder(), 'mainslide%03d.png'), self.file_path], @@ -267,6 +269,7 @@ class PdfDocument(PresentationDocument): elif self.controller.gsbin: log.debug('loading presentation using gs') resolution = self.gs_get_resolution(size) + # TODO: Find out where the string conversion actually happens runlog = check_output([self.controller.gsbin, '-dSAFER', '-dNOPAUSE', '-dBATCH', '-sDEVICE=png16m', '-r' + str(resolution), '-dTextAlphaBits=4', '-dGraphicsAlphaBits=4', '-sOutputFile=' + os.path.join(self.get_temp_folder(), 'mainslide%03d.png'), diff --git a/openlp/plugins/presentations/lib/powerpointcontroller.py b/openlp/plugins/presentations/lib/powerpointcontroller.py index 6cc6a8450..ebc394623 100644 --- a/openlp/plugins/presentations/lib/powerpointcontroller.py +++ b/openlp/plugins/presentations/lib/powerpointcontroller.py @@ -179,7 +179,7 @@ class PowerpointDocument(PresentationDocument): if not self.presentation.Slides(num + 1).SlideShowTransition.Hidden: self.index_map[key] = num + 1 self.presentation.Slides(num + 1).Export( - os.path.join(self.get_thumbnail_folder(), 'slide%d.png' % (key)), 'png', 320, 240) + os.path.join(self.get_thumbnail_folder(), 'slide{key:d}.png'.format(key=key)), 'png', 320, 240) key += 1 self.slide_count = key - 1 @@ -345,8 +345,9 @@ class PowerpointDocument(PresentationDocument): # Find the presentation window and save the handle for later self.presentation_hwnd = None if ppt_window: - log.debug('main display size: y=%d, height=%d, x=%d, width=%d' - % (size.y(), size.height(), size.x(), size.width())) + log.debug('main display size: y={y:d}, height={height:d}, ' + 'x={x:d}, width={width:d}'.format(y=size.y(), height=size.height(), + x=size.x(), width=size.width())) win32gui.EnumWindows(self._window_enum_callback, size) # Make sure powerpoint doesn't steal focus, unless we're on a single screen setup if len(ScreenList().screen_list) > 1: @@ -361,10 +362,18 @@ class PowerpointDocument(PresentationDocument): # it is the powerpoint presentation window. (left, top, right, bottom) = win32gui.GetWindowRect(hwnd) window_title = win32gui.GetWindowText(hwnd) - log.debug('window size: left=%d, top=%d, right=%d, width=%d' % (left, top, right, bottom)) - log.debug('compare size: %d and %d, %d and %d, %d and %d, %d and %d' - % (size.y(), top, size.height(), (bottom - top), size.x(), left, size.width(), (right - left))) - log.debug('window title: %s' % window_title) + log.debug('window size: left=left:d}, top={top:d}, ' + 'right={right:d}, bottom={bottom:d}'.format(left=left, top=top, right=right, bottom=bottom)) + log.debug('compare size: {y:d} and {top:d}, {height:d} and {vertical:d}, ' + '{x:d} and {left}, {width:d} and {horizontal:d}'.format(y=size.y(), + top=top, + height=size.height(), + vertical=(bottom - top), + x=size.x(), + left=left, + width=size.width(), + horizontal=(right - left))) + log.debug('window title: {title}'.format(title=window_title)) filename_root, filename_ext = os.path.splitext(os.path.basename(self.file_path)) if size.y() == top and size.height() == (bottom - top) and size.x() == left and \ size.width() == (right - left) and filename_root in window_title: @@ -416,8 +425,8 @@ class PowerpointDocument(PresentationDocument): and self.get_slide_number() == slide_no: click_index = self.presentation.SlideShowWindow.View.GetClickIndex() click_count = self.presentation.SlideShowWindow.View.GetClickCount() - log.debug('We are already on this slide - go to next effect if any left, idx: %d, count: %d' - % (click_index, click_count)) + log.debug('We are already on this slide - go to next effect if any left, idx: ' + '{index:d}, count: {count:d}'.format(index=click_index, count=click_count)) if click_index < click_count: self.next_step() else: diff --git a/openlp/plugins/presentations/lib/pptviewcontroller.py b/openlp/plugins/presentations/lib/pptviewcontroller.py index c5e1b351f..54d8f5170 100644 --- a/openlp/plugins/presentations/lib/pptviewcontroller.py +++ b/openlp/plugins/presentations/lib/pptviewcontroller.py @@ -148,7 +148,7 @@ class PptviewDocument(PresentationDocument): return log.debug('create_thumbnails proceeding') for idx in range(self.get_slide_count()): - path = '%s\\slide%s.bmp' % (self.get_temp_folder(), str(idx + 1)) + path = '{folder}\\slide{index}.bmp'.format(folder=self.get_temp_folder(), index=str(idx + 1)) self.convert_thumbnail(path, idx + 1) def create_titles_and_notes(self): diff --git a/openlp/plugins/presentations/lib/presentationcontroller.py b/openlp/plugins/presentations/lib/presentationcontroller.py index fc90ddb0d..7c26462fd 100644 --- a/openlp/plugins/presentations/lib/presentationcontroller.py +++ b/openlp/plugins/presentations/lib/presentationcontroller.py @@ -278,7 +278,7 @@ class PresentationDocument(object): prefix = 'live' else: prefix = 'preview' - Registry().execute('slidecontroller_%s_change' % prefix, self.slide_number - 1) + Registry().execute('slidecontroller_{prefix}_change'.format(prefix=prefix), self.slide_number - 1) def get_slide_text(self, slide_no): """ @@ -312,7 +312,7 @@ class PresentationDocument(object): log.exception('Failed to open/read existing titles file') titles = [] for slide_no, title in enumerate(titles, 1): - notes_file = os.path.join(self.get_thumbnail_folder(), 'slideNotes%d.txt' % slide_no) + notes_file = os.path.join(self.get_thumbnail_folder(), 'slideNotes{number:d}.txt'.format(number=slide_no)) note = '' if os.path.exists(notes_file): try: @@ -335,7 +335,8 @@ class PresentationDocument(object): fo.writelines(titles) if notes: for slide_no, note in enumerate(notes, 1): - notes_file = os.path.join(self.get_thumbnail_folder(), 'slideNotes%d.txt' % slide_no) + notes_file = os.path.join(self.get_thumbnail_folder(), + 'slideNotes{number:d}.txt'.format(number=slide_no)) with open(notes_file, mode='wt', encoding='utf-8') as fn: fn.write(note) diff --git a/openlp/plugins/presentations/lib/presentationtab.py b/openlp/plugins/presentations/lib/presentationtab.py index 8076b33fe..25771713d 100644 --- a/openlp/plugins/presentations/lib/presentationtab.py +++ b/openlp/plugins/presentations/lib/presentationtab.py @@ -137,7 +137,8 @@ class PresentationTab(SettingsTab): if checkbox.isEnabled(): checkbox.setText(controller.name) else: - checkbox.setText(translate('PresentationPlugin.PresentationTab', '%s (unavailable)') % controller.name) + checkbox.setText(translate('PresentationPlugin.PresentationTab', + '{name} (unavailable)').format(name=controller.name)) def load(self): """ diff --git a/openlp/plugins/presentations/presentationplugin.py b/openlp/plugins/presentations/presentationplugin.py index ff14d821c..dc0614086 100644 --- a/openlp/plugins/presentations/presentationplugin.py +++ b/openlp/plugins/presentations/presentationplugin.py @@ -128,11 +128,11 @@ class PresentationPlugin(Plugin): path = os.path.join(controller_dir, filename) if os.path.isfile(path): module_name = 'openlp.plugins.presentations.lib.' + os.path.splitext(filename)[0] - log.debug('Importing controller %s', module_name) + log.debug('Importing controller {name}'.format(name=module_name)) try: __import__(module_name, globals(), locals(), []) except ImportError: - log.warning('Failed to import %s on path %s', module_name, path) + log.warning('Failed to import {name} on path {path}'.format(name=module_name, path=path)) controller_classes = PresentationController.__subclasses__() for controller_class in controller_classes: controller = controller_class(self) diff --git a/tests/functional/openlp_core_lib/test_projector_pjlink1.py b/tests/functional/openlp_core_lib/test_projector_pjlink1.py index 6c2f3c1d5..ac1059656 100644 --- a/tests/functional/openlp_core_lib/test_projector_pjlink1.py +++ b/tests/functional/openlp_core_lib/test_projector_pjlink1.py @@ -250,3 +250,17 @@ class TestPJLink(TestCase): # THEN: Shutter should be closed and mute should be True self.assertTrue(pjlink.shutter, 'Shutter should have been set to closed') self.assertTrue(pjlink.mute, 'Audio should be on') + + def projector_process_input_test(self): + """ + Test input source status shows current input + """ + # GIVEN: Test object + pjlink = pjlink_test + pjlink.source = '0' + + # WHEN: Called with input source + pjlink.process_inpt('1') + + # THEN: Input selected should reflect current input + self.assertEquals(pjlink.source, '1', 'Input source should be set to "1"') From 6d3ad3af3f54bab10651c182f0509929d97d07de Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Sat, 21 May 2016 20:01:50 +0100 Subject: [PATCH 17/62] Improve performance --- openlp/core/ui/lib/spelltextedit.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/core/ui/lib/spelltextedit.py b/openlp/core/ui/lib/spelltextedit.py index c16bd0bca..8b6b552be 100644 --- a/openlp/core/ui/lib/spelltextedit.py +++ b/openlp/core/ui/lib/spelltextedit.py @@ -142,8 +142,8 @@ class SpellTextEdit(QtWidgets.QPlainTextEdit): """ Replaces the selected text with word. """ + tag = tag.replace('&', '') for html in FormattingTags.get_html_tags(): - tag = tag.replace('&', '') if tag == html['desc']: cursor = self.textCursor() if self.textCursor().hasSelection(): From 90f927ae7ff93baf6bb5b57968467dfbea122416 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 24 May 2016 13:40:01 +0200 Subject: [PATCH 18/62] Fix traceback while handling traceback in videopsalm import --- openlp/plugins/songs/lib/importers/videopsalm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/plugins/songs/lib/importers/videopsalm.py b/openlp/plugins/songs/lib/importers/videopsalm.py index 0bc581239..6723fb4c1 100644 --- a/openlp/plugins/songs/lib/importers/videopsalm.py +++ b/openlp/plugins/songs/lib/importers/videopsalm.py @@ -117,6 +117,6 @@ class VideoPsalmImport(SongImport): if not self.finish(): self.log_error('Could not import %s' % self.title) except Exception as e: - self.log_error(translate('SongsPlugin.VideoPsalmImport', 'File %s' % file.name), + self.log_error(translate('SongsPlugin.VideoPsalmImport', 'File %s') % song_file.name, translate('SongsPlugin.VideoPsalmImport', 'Error: %s') % e) song_file.close() From 72120d8b2fd29167cc156598df6277ae26769ca9 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 24 May 2016 13:49:08 +0200 Subject: [PATCH 19/62] Skip PresentationManager files we do not support. --- openlp/plugins/songs/lib/importers/presentationmanager.py | 8 +++++++- openlp/plugins/songs/lib/importers/videopsalm.py | 3 +-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/openlp/plugins/songs/lib/importers/presentationmanager.py b/openlp/plugins/songs/lib/importers/presentationmanager.py index c26f11312..5d8db4d26 100644 --- a/openlp/plugins/songs/lib/importers/presentationmanager.py +++ b/openlp/plugins/songs/lib/importers/presentationmanager.py @@ -55,7 +55,13 @@ class PresentationManagerImport(SongImport): # Open file with detected encoding and remove encoding declaration text = open(file_path, mode='r', encoding=encoding).read() text = re.sub('.+\?>\n', '', text) - tree = etree.fromstring(text, parser=etree.XMLParser(recover=True)) + try: + tree = etree.fromstring(text, parser=etree.XMLParser(recover=True)) + except ValueError: + self.log_error(file_path, + translate('SongsPlugin.PresentationManagerImport', + 'File is not in XML-format, which is the only format supported.')) + continue root = objectify.fromstring(etree.tostring(tree)) self.process_song(root) diff --git a/openlp/plugins/songs/lib/importers/videopsalm.py b/openlp/plugins/songs/lib/importers/videopsalm.py index 6723fb4c1..edf5e89a8 100644 --- a/openlp/plugins/songs/lib/importers/videopsalm.py +++ b/openlp/plugins/songs/lib/importers/videopsalm.py @@ -117,6 +117,5 @@ class VideoPsalmImport(SongImport): if not self.finish(): self.log_error('Could not import %s' % self.title) except Exception as e: - self.log_error(translate('SongsPlugin.VideoPsalmImport', 'File %s') % song_file.name, - translate('SongsPlugin.VideoPsalmImport', 'Error: %s') % e) + self.log_error(song_file.name, translate('SongsPlugin.VideoPsalmImport', 'Error: %s') % e) song_file.close() From 32ef88f8074df58fce1a343011ae15c05c669289 Mon Sep 17 00:00:00 2001 From: Tim Bentley Date: Tue, 24 May 2016 17:28:11 +0100 Subject: [PATCH 20/62] Fix set_value and adjust tests --- openlp/core/common/registry.py | 7 +------ .../openlp_core_common/test_registry.py | 15 ++++++++------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/openlp/core/common/registry.py b/openlp/core/common/registry.py index ee322d87d..85fca6912 100644 --- a/openlp/core/common/registry.py +++ b/openlp/core/common/registry.py @@ -166,12 +166,7 @@ class Registry(object): :param key: The working_flag to be created this is usually a major class like "renderer" or "main_window" . :param reference: The data to be saved. """ - if key in self.working_flags: - trace_error_handler(log) - log.error('Duplicate Working Flag exception {key}'.format(key=key)) - raise KeyError('Duplicate Working Flag exception {key}'.format(key=key)) - else: - self.working_flags[key] = reference + self.working_flags[key] = reference def remove_flag(self, key): """ diff --git a/tests/functional/openlp_core_common/test_registry.py b/tests/functional/openlp_core_common/test_registry.py index 0cac19bcd..0642ff93c 100644 --- a/tests/functional/openlp_core_common/test_registry.py +++ b/tests/functional/openlp_core_common/test_registry.py @@ -102,17 +102,18 @@ class TestRegistry(TestCase): # WHEN: I add a working flag it should save it my_data = 'Lamas' + my_data2 = 'More Lamas' Registry().set_flag('test1', my_data) # THEN: we should be able retrieve the saved component - assert Registry().get_flag('test1') == my_data, 'The working flag can be retrieved and matches' + temp = Registry().get_flag('test1') + self.assertEquals(temp, my_data, 'The value should have been saved') - # WHEN: I add a component for the second time I am mad. - # THEN and I will get an exception - with self.assertRaises(KeyError) as context: - Registry().set_flag('test1', my_data) - self.assertEqual(context.exception.args[0], 'Duplicate Working Flag exception test1', - 'KeyError exception should have been thrown for duplicate working flag') + # WHEN: I add a component for the second time I am not mad. + # THEN and I will not get an exception + Registry().set_flag('test1', my_data2) + temp = Registry().get_flag('test1') + self.assertEquals(temp, my_data2, 'The value should have been updated') # WHEN I try to get back a non existent Working Flag # THEN I will get an exception From fd4cfd1eaa4819bd67498158e366e7854c792981 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Wed, 25 May 2016 09:04:41 +0200 Subject: [PATCH 21/62] Fix traceback during songshowplus import. Fixes bug 1585489. Fixes: https://launchpad.net/bugs/1585489 --- .../songs/lib/importers/songshowplus.py | 14 +++++-- .../songs/test_songshowplusimport.py | 2 + .../songshowplussongs/cleanse-me.json | 38 ++++++++++++++++++ .../songshowplussongs/cleanse-me.sbsong | Bin 0 -> 1093 bytes 4 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 tests/resources/songshowplussongs/cleanse-me.json create mode 100644 tests/resources/songshowplussongs/cleanse-me.sbsong diff --git a/openlp/plugins/songs/lib/importers/songshowplus.py b/openlp/plugins/songs/lib/importers/songshowplus.py index d9a205e22..23aa5173b 100644 --- a/openlp/plugins/songs/lib/importers/songshowplus.py +++ b/openlp/plugins/songs/lib/importers/songshowplus.py @@ -105,6 +105,7 @@ class SongShowPlusImport(SongImport): song_data = open(file, 'rb') while True: block_key, = struct.unpack("I", song_data.read(4)) + log.debug('block_key: %d' % block_key) # The file ends with 4 NULL's if block_key == 0: break @@ -116,7 +117,13 @@ class SongShowPlusImport(SongImport): null, verse_name_length, = struct.unpack("BB", song_data.read(2)) verse_name = self.decode(song_data.read(verse_name_length)) length_descriptor_size, = struct.unpack("B", song_data.read(1)) - log.debug(length_descriptor_size) + log.debug('length_descriptor_size: %d' % length_descriptor_size) + # In the case of song_numbers the number is in the data from the + # current position to the next block starts + if block_key == SONG_NUMBER: + sn_bytes = song_data.read(length_descriptor_size - 1) + self.song_number = int.from_bytes(sn_bytes, byteorder='little') + continue # Detect if/how long the length descriptor is if length_descriptor_size == 12 or length_descriptor_size == 20: length_descriptor, = struct.unpack("I", song_data.read(4)) @@ -126,8 +133,9 @@ class SongShowPlusImport(SongImport): length_descriptor = 0 else: length_descriptor, = struct.unpack("B", song_data.read(1)) - log.debug(length_descriptor_size) + log.debug('length_descriptor: %d' % length_descriptor) data = song_data.read(length_descriptor) + log.debug(data) if block_key == TITLE: self.title = self.decode(data) elif block_key == AUTHOR: @@ -164,8 +172,6 @@ class SongShowPlusImport(SongImport): self.ssp_verse_order_list.append(verse_tag) elif block_key == SONG_BOOK: self.song_book_name = self.decode(data) - elif block_key == SONG_NUMBER: - self.song_number = ord(data) elif block_key == CUSTOM_VERSE: verse_tag = self.to_openlp_verse_tag(verse_name) self.add_verse(self.decode(data), verse_tag) diff --git a/tests/functional/openlp_plugins/songs/test_songshowplusimport.py b/tests/functional/openlp_plugins/songs/test_songshowplusimport.py index ec86eca07..a96f21a47 100644 --- a/tests/functional/openlp_plugins/songs/test_songshowplusimport.py +++ b/tests/functional/openlp_plugins/songs/test_songshowplusimport.py @@ -52,6 +52,8 @@ class TestSongShowPlusFileImport(SongImportTestHelper): self.load_external_result_data(os.path.join(TEST_PATH, 'Beautiful Garden Of Prayer.json'))) self.file_import([os.path.join(TEST_PATH, 'a mighty fortress is our god.sbsong')], self.load_external_result_data(os.path.join(TEST_PATH, 'a mighty fortress is our god.json'))) + self.file_import([os.path.join(TEST_PATH, 'cleanse-me.sbsong')], + self.load_external_result_data(os.path.join(TEST_PATH, 'cleanse-me.json'))) class TestSongShowPlusImport(TestCase): diff --git a/tests/resources/songshowplussongs/cleanse-me.json b/tests/resources/songshowplussongs/cleanse-me.json new file mode 100644 index 000000000..c88b434f9 --- /dev/null +++ b/tests/resources/songshowplussongs/cleanse-me.json @@ -0,0 +1,38 @@ +{ + "authors": [ + "J. Edwin Orr" + ], + "ccli_number": 56307, + "comments": "", + "copyright": "Public Domain ", + "song_book_name": "", + "song_number": 438, + "title": "Cleanse Me [438]", + "topics": [ + "Cleansing", + "Communion", + "Consecration", + "Holiness", + "Holy Spirit", + "Revival" + ], + "verse_order_list": [], + "verses": [ + [ + "Search me, O God,\r\nAnd know my heart today;\r\nTry me, O Savior,\r\nKnow my thoughts, I pray.\r\nSee if there be\r\nSome wicked way in me;\r\nCleanse me from every sin\r\nAnd set me free.", + "v1" + ], + [ + "I praise Thee, Lord,\r\nFor cleansing me from sin;\r\nFulfill Thy Word,\r\nAnd make me pure within.\r\nFill me with fire\r\nWhere once I burned with shame;\r\nGrant my desire\r\nTo magnify Thy name.", + "v2" + ], + [ + "Lord, take my life,\r\nAnd make it wholly Thine;\r\nFill my poor heart\r\nWith Thy great love divine.\r\nTake all my will,\r\nMy passion, self and pride;\r\nI now surrender, Lord\r\nIn me abide.", + "v3" + ], + [ + "O Holy Ghost,\r\nRevival comes from Thee;\r\nSend a revival,\r\nStart the work in me.\r\nThy Word declares\r\nThou wilt supply our need;\r\nFor blessings now,\r\nO Lord, I humbly plead.", + "v4" + ] + ] +} diff --git a/tests/resources/songshowplussongs/cleanse-me.sbsong b/tests/resources/songshowplussongs/cleanse-me.sbsong new file mode 100644 index 0000000000000000000000000000000000000000..aa9915f8ecb4b40487d288e4e86c8926104cc294 GIT binary patch literal 1093 zcmYjRO>Yx15KUW}wkd&%JJKBZIz&}V3$4Tnl_nIZf=EOUh=a2`$y)K+E8ClBe-j5T zs6t#g@W*(w8&D3b*w1ff-kY)Wq}6J*<-2oqc6`2p)dSfbTo_h1FkLf!IXyZ5x(W2Y zoOFlY_vqarU8YNIw*VaoeD7m9F*>0)E?3&pBVcm2b-S^RpBag1xF_WHB%-Azc7=X)}mO7bp zN=sD{yyc9v|N4W|sdqW?f>9`F+h_?K!NU>rp*Z-n=HPkzXI)Rj%{XJY_~5*l=sQnI z-FIzgO*k?mC+hV}Gu6f*prV_GE}nBWXJHm4^e%PGw1tblFl*g0qp9}raZ@{THer~Z zl-`OT@F`@fHZ<_cLUTnahdN^HkbP$Lw5p3*&}u8c*Q}hhf7IG3);cOOddjPD)Y5dM zW#){L9NJ3b8f_I74sPpFL7WH?XEV<#l5q>BR4)(!Gh<1u#83sr#vuJQ!c_>`*&YQp zQ&MO};dLqnu1LlkO7GdGjJqld0n6Y>O+cz`+^*R;ZGRimTL+bc%!P;wpLn4c%20yw zhi1YuDx@DFD=G2~0n|~fuUm%xJ3ntOh{#?I3jIus@*D(mrC5kiR}`q`N>7$KmA0T8 z6T>iNXF(hw^RT%X7+6;36YvXMj`Z*$lsAv0xrB&VgIu1M7M&63o_M@_;qZ_Xui^^r p2)YZq=x+$Z>k6`8H(*p~ucLr_0`9CD@e~_*$nxjVdbYk1;4gFPC9D7d literal 0 HcmV?d00001 From 3163d335439691499cd2dd4d1c0a0c1800333a35 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Thu, 26 May 2016 15:03:00 +0200 Subject: [PATCH 22/62] Fix of tracback during SongPro import. Fixes bug 1582152. Fixes: https://launchpad.net/bugs/1582152 --- openlp/plugins/songs/lib/importers/songpro.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/plugins/songs/lib/importers/songpro.py b/openlp/plugins/songs/lib/importers/songpro.py index b1c8e7fe8..90fe34492 100644 --- a/openlp/plugins/songs/lib/importers/songpro.py +++ b/openlp/plugins/songs/lib/importers/songpro.py @@ -72,7 +72,7 @@ class SongProImport(SongImport): Receive a single file or a list of files to import. """ self.encoding = None - with open(self.import_source, 'rt') as songs_file: + with open(self.import_source, 'rt', errors='ignore') as songs_file: self.import_wizard.progress_bar.setMaximum(0) tag = '' text = '' From 9fdcd30c65feb0dc347bd91cd5275f4ac2fece64 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Fri, 27 May 2016 01:13:14 -0700 Subject: [PATCH 23/62] Convert strings from python2 to python3 in plugins part 3 --- openlp/plugins/remotes/lib/httprouter.py | 36 ++++---- openlp/plugins/remotes/lib/httpserver.py | 8 +- openlp/plugins/remotes/lib/remotetab.py | 28 +++---- .../songs/forms/duplicatesongremovalform.py | 5 +- openlp/plugins/songs/forms/editsongform.py | 62 +++++++------- openlp/plugins/songs/forms/editverseform.py | 10 +-- openlp/plugins/songs/forms/mediafilesform.py | 2 +- openlp/plugins/songs/forms/songexportform.py | 7 +- openlp/plugins/songs/forms/songimportform.py | 6 +- .../songs/forms/songmaintenanceform.py | 28 ++++--- .../plugins/songs/forms/songselectdialog.py | 3 +- openlp/plugins/songs/forms/songselectform.py | 6 +- openlp/plugins/songs/lib/__init__.py | 4 +- openlp/plugins/songs/lib/db.py | 8 +- openlp/plugins/songs/lib/importer.py | 71 +++++++++------- .../plugins/songs/lib/importers/cclifile.py | 14 ++-- .../plugins/songs/lib/importers/dreambeam.py | 10 ++- .../plugins/songs/lib/importers/easyslides.py | 20 +++-- .../songs/lib/importers/easyworship.py | 27 +++--- .../songs/lib/importers/foilpresenter.py | 3 +- openlp/plugins/songs/lib/importers/lyrix.py | 4 +- .../plugins/songs/lib/importers/mediashout.py | 17 ++-- openlp/plugins/songs/lib/importers/openlp.py | 4 +- .../plugins/songs/lib/importers/openlyrics.py | 8 +- .../plugins/songs/lib/importers/openoffice.py | 2 +- .../plugins/songs/lib/importers/opensong.py | 10 +-- openlp/plugins/songs/lib/importers/opspro.py | 23 ++++-- .../songs/lib/importers/powerpraise.py | 3 +- .../plugins/songs/lib/importers/powersong.py | 23 +++--- .../lib/importers/presentationmanager.py | 3 +- .../songs/lib/importers/propresenter.py | 7 +- .../plugins/songs/lib/importers/songimport.py | 9 +- .../songs/lib/importers/songshowplus.py | 14 ++-- .../plugins/songs/lib/importers/sundayplus.py | 2 +- .../plugins/songs/lib/importers/videopsalm.py | 6 +- .../songs/lib/importers/wordsofworship.py | 8 +- .../songs/lib/importers/worshipassistant.py | 17 ++-- .../songs/lib/importers/worshipcenterpro.py | 6 +- .../plugins/songs/lib/importers/zionworx.py | 13 +-- openlp/plugins/songs/lib/mediaitem.py | 82 ++++++++++--------- openlp/plugins/songs/lib/openlyricsexport.py | 10 ++- openlp/plugins/songs/lib/openlyricsxml.py | 27 +++--- openlp/plugins/songs/lib/songselect.py | 12 +-- openlp/plugins/songs/lib/songstab.py | 4 +- .../openlp_core_lib/test_projectordb.py | 19 +++++ 45 files changed, 400 insertions(+), 291 deletions(-) diff --git a/openlp/plugins/remotes/lib/httprouter.py b/openlp/plugins/remotes/lib/httprouter.py index 5d14a5637..174dc570a 100644 --- a/openlp/plugins/remotes/lib/httprouter.py +++ b/openlp/plugins/remotes/lib/httprouter.py @@ -141,7 +141,8 @@ class HttpRouter(RegistryProperties): """ Initialise the router stack and any other variables. """ - auth_code = "%s:%s" % (Settings().value('remotes/user id'), Settings().value('remotes/password')) + auth_code = "{user}:{password}".format(user=Settings().value('remotes/user id'), + password=Settings().value('remotes/password')) try: self.auth = base64.b64encode(auth_code) except TypeError: @@ -189,7 +190,7 @@ class HttpRouter(RegistryProperties): if self.headers['Authorization'] is None: self.do_authorisation() self.wfile.write(bytes('no auth header received', 'UTF-8')) - elif self.headers['Authorization'] == 'Basic %s' % self.auth: + elif self.headers['Authorization'] == 'Basic {auth}'.format(auth=self.auth): self.do_http_success() self.call_function(function, *args) else: @@ -231,7 +232,7 @@ class HttpRouter(RegistryProperties): for route, func in self.routes: match = re.match(route, url_path_split.path) if match: - log.debug('Route "%s" matched "%s"', route, url_path) + log.debug('Route "{route}" matched "{path}"'.format(route=route, path=url_path)) args = [] for param in match.groups(): args.append(param) @@ -319,9 +320,9 @@ class HttpRouter(RegistryProperties): stage = translate('RemotePlugin.Mobile', 'Stage View') live = translate('RemotePlugin.Mobile', 'Live View') self.template_vars = { - 'app_title': "%s %s" % (UiStrings().OLPV2x, remote), - 'stage_title': "%s %s" % (UiStrings().OLPV2x, stage), - 'live_title': "%s %s" % (UiStrings().OLPV2x, live), + 'app_title': "{main} {remote}".format(main=UiStrings().OLPV2x, remote=remote), + 'stage_title': "{main} {stage}".format(main=UiStrings().OLPV2x, stage=stage), + 'live_title': "{main} {live}".format(main=UiStrings().OLPV2x, live=live), 'service_manager': translate('RemotePlugin.Mobile', 'Service Manager'), 'slide_controller': translate('RemotePlugin.Mobile', 'Slide Controller'), 'alerts': translate('RemotePlugin.Mobile', 'Alerts'), @@ -354,7 +355,7 @@ class HttpRouter(RegistryProperties): :param file_name: file name with path :return: """ - log.debug('serve file request %s' % file_name) + log.debug('serve file request {name}'.format(name=file_name)) parts = file_name.split('/') if len(parts) == 1: file_name = os.path.join(parts[0], 'stage.html') @@ -381,10 +382,10 @@ class HttpRouter(RegistryProperties): content = Template(filename=path, input_encoding='utf-8', output_encoding='utf-8').render(**variables) else: file_handle = open(path, 'rb') - log.debug('Opened %s' % path) + log.debug('Opened {path}'.format(path=path)) content = file_handle.read() except IOError: - log.exception('Failed to open %s' % path) + log.exception('Failed to open {path}'.format(path=path)) return self.do_not_found() finally: if file_handle: @@ -402,7 +403,7 @@ class HttpRouter(RegistryProperties): Ultimately for i18n, this could first look for xx/file.html before falling back to file.html. where xx is the language, e.g. 'en' """ - log.debug('serve file request %s' % file_name) + log.debug('serve file request {name}'.format(name=file_name)) if not file_name: file_name = 'index.html' if '.' not in file_name: @@ -433,7 +434,9 @@ class HttpRouter(RegistryProperties): :param dimensions: image size :param controller_name: controller to be called """ - log.debug('serve thumbnail %s/thumbnails%s/%s' % (controller_name, dimensions, file_name)) + log.debug('serve thumbnail {cname}/thumbnails{dim}/{fname}'.format(cname=controller_name, + dim=dimensions, + fname=file_name)) supported_controllers = ['presentations', 'images'] # -1 means use the default dimension in ImageManager width = -1 @@ -539,7 +542,7 @@ class HttpRouter(RegistryProperties): :param var: variable - not used """ - log.debug("controller_text var = %s" % var) + log.debug("controller_text var = {var}".format(var=var)) current_item = self.live_controller.service_item data = [] if current_item: @@ -594,7 +597,8 @@ class HttpRouter(RegistryProperties): :param display_type: This is the type of slide controller, either ``preview`` or ``live``. :param action: The action to perform. """ - event = getattr(self.live_controller, 'slidecontroller_%s_%s' % (display_type, action)) + event = getattr(self.live_controller, 'slidecontroller_{display}_{action}'.format(display=display_type, + action=action)) if self.request_data: try: data = json.loads(self.request_data)['request']['id'] @@ -623,7 +627,7 @@ class HttpRouter(RegistryProperties): :param action: The action to perform. """ - event = getattr(self.service_manager, 'servicemanager_%s_item' % action) + event = getattr(self.service_manager, 'servicemanager_{action}_item'.format(action=action)) if self.request_data: try: data = int(json.loads(self.request_data)['request']['id']) @@ -680,7 +684,7 @@ class HttpRouter(RegistryProperties): return self.do_http_error() plugin = self.plugin_manager.get_plugin_by_name(plugin_name) if plugin.status == PluginStatus.Active and plugin.media_item: - getattr(plugin.media_item, '%s_go_live' % plugin_name).emit([request_id, True]) + getattr(plugin.media_item, '{name}_go_live'.format(name=plugin_name)).emit([request_id, True]) return self.do_http_success() def add_to_service(self, plugin_name): @@ -696,5 +700,5 @@ class HttpRouter(RegistryProperties): plugin = self.plugin_manager.get_plugin_by_name(plugin_name) if plugin.status == PluginStatus.Active and plugin.media_item: item_id = plugin.media_item.create_item_from_id(request_id) - getattr(plugin.media_item, '%s_add_to_service' % plugin_name).emit([item_id, True]) + getattr(plugin.media_item, '{name}_add_to_service'.format(name=plugin_name)).emit([item_id, True]) self.do_http_success() diff --git a/openlp/plugins/remotes/lib/httpserver.py b/openlp/plugins/remotes/lib/httpserver.py index 88d1097dc..7cc90fc07 100644 --- a/openlp/plugins/remotes/lib/httpserver.py +++ b/openlp/plugins/remotes/lib/httpserver.py @@ -136,11 +136,13 @@ class OpenLPServer(RegistryProperties): while loop < 4: try: self.httpd = server_class((address, port), CustomHandler) - log.debug("Server started for class %s %s %d" % (server_class, address, port)) + log.debug("Server started for class {name} {address} {port:d}".format(name=server_class, + address=address, + port=port)) break except OSError: - log.debug("failed to start http server thread state %d %s" % - (loop, self.http_thread.isRunning())) + log.debug("failed to start http server thread state " + "{loop:d} {running}".format(loop=loop, running=self.http_thread.isRunning())) loop += 1 time.sleep(0.1) except: diff --git a/openlp/plugins/remotes/lib/remotetab.py b/openlp/plugins/remotes/lib/remotetab.py index af64e401f..45a1533af 100644 --- a/openlp/plugins/remotes/lib/remotetab.py +++ b/openlp/plugins/remotes/lib/remotetab.py @@ -192,14 +192,14 @@ class RemoteTab(SettingsTab): 'Show thumbnails of non-text slides in remote and stage view.')) self.android_app_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'Android App')) self.android_qr_description_label.setText( - translate('RemotePlugin.RemoteTab', 'Scan the QR code or click download to install the ' - 'Android app from Google Play.') % - 'https://play.google.com/store/apps/details?id=org.openlp.android2') + translate('RemotePlugin.RemoteTab', + 'Scan the QR code or click download to install the Android app from Google ' + 'Play.').format(qr='https://play.google.com/store/apps/details?id=org.openlp.android2')) self.ios_app_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'iOS App')) self.ios_qr_description_label.setText( - translate('RemotePlugin.RemoteTab', 'Scan the QR code or click download to install the ' - 'iOS app from the App Store.') % - 'https://itunes.apple.com/app/id1096218725') + translate('RemotePlugin.RemoteTab', + 'Scan the QR code or click download to install the iOS app from the App ' + 'Store.').format(qr='https://itunes.apple.com/app/id1096218725')) self.https_settings_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'HTTPS Server')) self.https_error_label.setText( translate('RemotePlugin.RemoteTab', 'Could not find an SSL certificate. The HTTPS server will not be ' @@ -217,18 +217,18 @@ class RemoteTab(SettingsTab): Update the display based on the data input on the screen """ ip_address = self.get_ip_address(self.address_edit.text()) - http_url = 'http://%s:%s/' % (ip_address, self.port_spin_box.value()) - https_url = 'https://%s:%s/' % (ip_address, self.https_port_spin_box.value()) - self.remote_url.setText('%s' % (http_url, http_url)) - self.remote_https_url.setText('%s' % (https_url, https_url)) + http_url = 'http://{url}:{text}/'.format(url=ip_address, text=self.port_spin_box.value()) + https_url = 'https://{url}:{text}/'.format(url=ip_address, text=self.https_port_spin_box.value()) + self.remote_url.setText('{url}'.format(url=http_url)) + self.remote_https_url.setText('{url}'.format(url=https_url)) http_url_temp = http_url + 'stage' https_url_temp = https_url + 'stage' - self.stage_url.setText('%s' % (http_url_temp, http_url_temp)) - self.stage_https_url.setText('%s' % (https_url_temp, https_url_temp)) + self.stage_url.setText('{url}'.format(url=http_url_temp)) + self.stage_https_url.setText('{url}'.format(url=https_url_temp)) http_url_temp = http_url + 'main' https_url_temp = https_url + 'main' - self.live_url.setText('%s' % (http_url_temp, http_url_temp)) - self.live_https_url.setText('%s' % (https_url_temp, https_url_temp)) + self.live_url.setText('{url}'.format(url=http_url_temp)) + self.live_https_url.setText('{url}'.format(url=https_url_temp)) def get_ip_address(self, ip_address): """ diff --git a/openlp/plugins/songs/forms/duplicatesongremovalform.py b/openlp/plugins/songs/forms/duplicatesongremovalform.py index 26de9507f..ee048855f 100644 --- a/openlp/plugins/songs/forms/duplicatesongremovalform.py +++ b/openlp/plugins/songs/forms/duplicatesongremovalform.py @@ -130,6 +130,7 @@ class DuplicateSongRemovalForm(OpenLPWizard, RegistryProperties): Song wizard localisation. """ self.setWindowTitle(translate('Wizard', 'Wizard')) + # TODO: Check format() using template strings self.title_label.setText(WizardStrings.HeaderStyle % translate('OpenLP.Ui', 'Welcome to the Duplicate Song Removal Wizard')) self.information_label.setText( @@ -148,8 +149,8 @@ class DuplicateSongRemovalForm(OpenLPWizard, RegistryProperties): Set the wizard review page header text. """ self.review_page.setTitle( - translate('Wizard', 'Review duplicate songs (%s/%s)') % - (self.review_current_count, self.review_total_count)) + translate('Wizard', 'Review duplicate songs ({current}/{total})').format(current=self.review_current_count, + total=self.review_total_count)) def custom_page_changed(self, page_id): """ diff --git a/openlp/plugins/songs/forms/editsongform.py b/openlp/plugins/songs/forms/editsongform.py index b33788a4c..200e1436f 100644 --- a/openlp/plugins/songs/forms/editsongform.py +++ b/openlp/plugins/songs/forms/editsongform.py @@ -50,7 +50,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties): """ Class to manage the editing of a song """ - log.info('%s EditSongForm loaded', __name__) + log.info('{name} EditSongForm loaded'.format(name=__name__)) def __init__(self, media_item, parent, manager): """ @@ -185,20 +185,23 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties): verse = verse.data(QtCore.Qt.UserRole) if verse not in verse_names: verses.append(verse) - verse_names.append('%s%s' % (VerseType.translated_tag(verse[0]), verse[1:])) + verse_names.append('{verse1}{verse2}'.format(verse1=VerseType.translated_tag(verse[0]), + verse2=verse[1:])) for count, item in enumerate(order): if item not in verses: invalid_verses.append(order_names[count]) if invalid_verses: valid = create_separated_list(verse_names) if len(invalid_verses) > 1: - msg = translate('SongsPlugin.EditSongForm', 'There are no verses corresponding to "%(invalid)s". ' - 'Valid entries are %(valid)s.\nPlease enter the verses separated by spaces.') % \ - {'invalid': ', '.join(invalid_verses), 'valid': valid} + msg = translate('SongsPlugin.EditSongForm', + 'There are no verses corresponding to "{invalid}". Valid entries are {valid}.\n' + 'Please enter the verses separated by spaces.' + ).format(invalid=', '.join(invalid_verses), valid=valid) else: - msg = translate('SongsPlugin.EditSongForm', 'There is no verse corresponding to "%(invalid)s".' - 'Valid entries are %(valid)s.\nPlease enter the verses separated by spaces.') % \ - {'invalid': invalid_verses[0], 'valid': valid} + msg = translate('SongsPlugin.EditSongForm', + 'There is no verse corresponding to "{invalid}". Valid entries are {valid}.\n' + 'Please enter the verses separated by spaces.').format(invalid=invalid_verses[0], + valid=valid) critical_error_message_box(title=translate('SongsPlugin.EditSongForm', 'Invalid Verse Order'), message=msg) return len(invalid_verses) == 0 @@ -242,23 +245,24 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties): field = item.data(QtCore.Qt.UserRole) verse_tags.append(field) if not self._validate_tags(tags): - misplaced_tags.append('%s %s' % (VerseType.translated_name(field[0]), field[1:])) + misplaced_tags.append('{field1} {field2}'.format(field1=VerseType.translated_name(field[0]), + field2=field[1:])) if misplaced_tags: critical_error_message_box( message=translate('SongsPlugin.EditSongForm', - 'There are misplaced formatting tags in the following verses:\n\n%s\n\n' - 'Please correct these tags before continuing.' % ', '.join(misplaced_tags))) + 'There are misplaced formatting tags in the following verses:\n\n{tag}\n\n' + 'Please correct these tags before continuing.').format(tag=', '.join(misplaced_tags))) return False for tag in verse_tags: if verse_tags.count(tag) > 26: # lp#1310523: OpenLyrics allows only a-z variants of one verse: # http://openlyrics.info/dataformat.html#verse-name critical_error_message_box(message=translate( - 'SongsPlugin.EditSongForm', 'You have %(count)s verses named %(name)s %(number)s. ' - 'You can have at most 26 verses with the same name' % - {'count': verse_tags.count(tag), - 'name': VerseType.translated_name(tag[0]), - 'number': tag[1:]})) + 'SongsPlugin.EditSongForm', + 'You have {count} verses named {name} {number}. You can have at most ' + '26 verses with the same name').format(count=verse_tags.count(tag), + name=VerseType.translated_name(tag[0]), + number=tag[1:])) return False return True @@ -313,7 +317,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties): self.song.verse_order = re.sub('([' + verse.upper() + verse.lower() + '])(\W|$)', r'\g<1>1\2', self.song.verse_order) except: - log.exception('Problem processing song Lyrics \n%s', sxml.dump_xml()) + log.exception('Problem processing song Lyrics \n{xml}'.forma(xml=sxml.dump_xml())) raise def keyPressEvent(self, event): @@ -492,7 +496,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties): verse[0]['type'] = VerseType.tags[index] if verse[0]['label'] == '': verse[0]['label'] = '1' - verse_def = '%s%s' % (verse[0]['type'], verse[0]['label']) + verse_def = '{verse}{label}'.format(verse=verse[0]['type'], label=verse[0]['label']) item = QtWidgets.QTableWidgetItem(verse[1]) item.setData(QtCore.Qt.UserRole, verse_def) self.verse_list_widget.setItem(count, 0, item) @@ -501,7 +505,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties): for count, verse in enumerate(verses): self.verse_list_widget.setRowCount(self.verse_list_widget.rowCount() + 1) item = QtWidgets.QTableWidgetItem(verse) - verse_def = '%s%s' % (VerseType.tags[VerseType.Verse], str(count + 1)) + verse_def = '{verse}{count:d}'.format(verse=VerseType.tags[VerseType.Verse], count=(count + 1)) item.setData(QtCore.Qt.UserRole, verse_def) self.verse_list_widget.setItem(count, 0, item) if self.song.verse_order: @@ -514,7 +518,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties): if verse_index is None: verse_index = VerseType.from_tag(verse_def[0]) verse_tag = VerseType.translated_tags[verse_index].upper() - translated.append('%s%s' % (verse_tag, verse_def[1:])) + translated.append('{tag}{verse}'.format(tag=verse_tag, verse=verse_def[1:])) self.verse_order_edit.setText(' '.join(translated)) else: self.verse_order_edit.setText('') @@ -554,7 +558,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties): item = self.verse_list_widget.item(row, 0) verse_def = item.data(QtCore.Qt.UserRole) verse_tag = VerseType.translated_tag(verse_def[0]) - row_def = '%s%s' % (verse_tag, verse_def[1:]) + row_def = '{tag}{verse}'.format(tag=verse_tag, verse=verse_def[1:]) row_label.append(row_def) self.verse_list_widget.setVerticalHeaderLabels(row_label) self.verse_list_widget.resizeRowsToContents() @@ -742,7 +746,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties): self.verse_form.set_verse('', True) if self.verse_form.exec(): after_text, verse_tag, verse_num = self.verse_form.get_verse() - verse_def = '%s%s' % (verse_tag, verse_num) + verse_def = '{tag}{number}'.format(tag=verse_tag, number=verse_num) item = QtWidgets.QTableWidgetItem(after_text) item.setData(QtCore.Qt.UserRole, verse_def) item.setText(after_text) @@ -760,7 +764,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties): self.verse_form.set_verse(temp_text, True, verse_id) if self.verse_form.exec(): after_text, verse_tag, verse_num = self.verse_form.get_verse() - verse_def = '%s%s' % (verse_tag, verse_num) + verse_def = '{tag}{number}'.format(tag=verse_tag, number=verse_num) item.setData(QtCore.Qt.UserRole, verse_def) item.setText(after_text) # number of lines has changed, repaint the list moving the data @@ -793,7 +797,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties): field = item.data(QtCore.Qt.UserRole) verse_tag = VerseType.translated_name(field[0]) verse_num = field[1:] - verse_list += '---[%s:%s]---\n' % (verse_tag, verse_num) + verse_list += '---[{tag}:{number}]---\n'.format(tag=verse_tag, number=verse_num) verse_list += item.text() verse_list += '\n' self.verse_form.set_verse(verse_list) @@ -828,7 +832,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties): verse_num = match.group(1) else: verse_num = '1' - verse_def = '%s%s' % (verse_tag, verse_num) + verse_def = '{tag}{number}'.format(tag=verse_tag, number=verse_num) else: if parts.endswith('\n'): parts = parts.rstrip('\n') @@ -919,7 +923,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties): """ Loads file(s) from the filesystem. """ - filters = '%s (*)' % UiStrings().AllFiles + filters = '{text} (*)'.format(text=UiStrings().AllFiles) file_names = FileDialog.getOpenFileNames(self, translate('SongsPlugin.EditSongForm', 'Open File(s)'), '', filters) for filename in file_names: @@ -1027,7 +1031,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties): for item in order_text.split(): verse_tag = VerseType.tags[VerseType.from_translated_tag(item[0])] verse_num = item[1:].lower() - order.append('%s%s' % (verse_tag, verse_num)) + order.append('{tag}{number}'.format(tag=verse_tag, number=verse_num)) self.song.verse_order = ' '.join(order) self.song.ccli_number = self.ccli_number_edit.text() theme_name = self.theme_combo_box.currentText() @@ -1082,12 +1086,12 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties): try: os.remove(audio) except: - log.exception('Could not remove file: %s', audio) + log.exception('Could not remove file: {audio}'.format(audio=audio)) if not files: try: os.rmdir(save_path) except OSError: - log.exception('Could not remove directory: %s', save_path) + log.exception('Could not remove directory: {path}'.format(path=save_path)) clean_song(self.manager, self.song) self.manager.save_object(self.song) self.media_item.auto_select_id = self.song.id diff --git a/openlp/plugins/songs/forms/editverseform.py b/openlp/plugins/songs/forms/editverseform.py index 9ff9ef54b..454fdb71e 100644 --- a/openlp/plugins/songs/forms/editverseform.py +++ b/openlp/plugins/songs/forms/editverseform.py @@ -59,7 +59,7 @@ class EditVerseForm(QtWidgets.QDialog, Ui_EditVerseDialog): if self.verse_text_edit.textCursor().columnNumber() != 0: self.verse_text_edit.insertPlainText('\n') verse_tag = VerseType.translated_name(verse_tag) - self.verse_text_edit.insertPlainText('---[%s:%s]---\n' % (verse_tag, verse_num)) + self.verse_text_edit.insertPlainText('---[{tag}:{number}]---\n'.format(tag=verse_tag, number=verse_num)) self.verse_text_edit.setFocus() def on_split_button_clicked(self): @@ -107,7 +107,7 @@ class EditVerseForm(QtWidgets.QDialog, Ui_EditVerseDialog): self.verse_type_combo_box.currentIndex()] if not text: return - position = text.rfind('---[%s' % verse_name, 0, position) + position = text.rfind('---[{verse}'.format(verse=verse_name), 0, position) if position == -1: self.verse_number_box.setValue(1) return @@ -124,7 +124,7 @@ class EditVerseForm(QtWidgets.QDialog, Ui_EditVerseDialog): verse_num = 1 self.verse_number_box.setValue(verse_num) - def set_verse(self, text, single=False, tag='%s1' % VerseType.tags[VerseType.Verse]): + def set_verse(self, text, single=False, tag='{verse}1'.format(verse=VerseType.tags[VerseType.Verse])): """ Save the verse @@ -142,7 +142,7 @@ class EditVerseForm(QtWidgets.QDialog, Ui_EditVerseDialog): self.insert_button.setVisible(False) else: if not text: - text = '---[%s:1]---\n' % VerseType.translated_names[VerseType.Verse] + text = '---[{tag}:1]---\n'.format(tag=VerseType.translated_names[VerseType.Verse]) self.verse_type_combo_box.setCurrentIndex(0) self.verse_number_box.setValue(1) self.insert_button.setVisible(True) @@ -167,5 +167,5 @@ class EditVerseForm(QtWidgets.QDialog, Ui_EditVerseDialog): """ text = self.verse_text_edit.toPlainText() if not text.startswith('---['): - text = '---[%s:1]---\n%s' % (VerseType.translated_names[VerseType.Verse], text) + text = '---[{tag}:1]---\n{text}'.format(tag=VerseType.translated_names[VerseType.Verse], text=text) return text diff --git a/openlp/plugins/songs/forms/mediafilesform.py b/openlp/plugins/songs/forms/mediafilesform.py index 8920bc0ef..9593976fd 100644 --- a/openlp/plugins/songs/forms/mediafilesform.py +++ b/openlp/plugins/songs/forms/mediafilesform.py @@ -34,7 +34,7 @@ class MediaFilesForm(QtWidgets.QDialog, Ui_MediaFilesDialog): """ Class to show a list of files from the """ - log.info('%s MediaFilesForm loaded', __name__) + log.info('{name} MediaFilesForm loaded'.format(name=__name__)) def __init__(self, parent): super(MediaFilesForm, self).__init__(parent, QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.WindowTitleHint) diff --git a/openlp/plugins/songs/forms/songexportform.py b/openlp/plugins/songs/forms/songexportform.py index e8a559c44..27f317963 100644 --- a/openlp/plugins/songs/forms/songexportform.py +++ b/openlp/plugins/songs/forms/songexportform.py @@ -143,6 +143,7 @@ class SongExportForm(OpenLPWizard): Song wizard localisation. """ self.setWindowTitle(translate('SongsPlugin.ExportWizardForm', 'Song Export Wizard')) + # TODO: Verify format() with template variables self.title_label.setText(WizardStrings.HeaderStyle % translate('OpenLP.Ui', 'Welcome to the Song Export Wizard')) self.information_label.setText( @@ -151,7 +152,7 @@ class SongExportForm(OpenLPWizard): self.available_songs_page.setTitle(translate('SongsPlugin.ExportWizardForm', 'Select Songs')) self.available_songs_page.setSubTitle(translate('SongsPlugin.ExportWizardForm', 'Check the songs you want to export.')) - self.search_label.setText('%s:' % UiStrings().Search) + self.search_label.setText('{text}:'.format(text=UiStrings().Search)) self.uncheck_button.setText(translate('SongsPlugin.ExportWizardForm', 'Uncheck All')) self.check_button.setText(translate('SongsPlugin.ExportWizardForm', 'Check All')) self.export_song_page.setTitle(translate('SongsPlugin.ExportWizardForm', 'Select Directory')) @@ -223,7 +224,7 @@ class SongExportForm(OpenLPWizard): if song.temporary: continue authors = create_separated_list([author.display_name for author in song.authors]) - title = '%s (%s)' % (str(song.title), authors) + title = '{title} ({author})'.format(title=song.title, author=authors) item = QtWidgets.QListWidgetItem(title) item.setData(QtCore.Qt.UserRole, song) item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled) @@ -257,7 +258,7 @@ class SongExportForm(OpenLPWizard): self.progress_label.setText(translate('SongsPlugin.SongExportForm', 'Your song export failed.')) except OSError as ose: self.progress_label.setText(translate('SongsPlugin.SongExportForm', 'Your song export failed because this ' - 'error occurred: %s') % ose.strerror) + 'error occurred: {error}').format(error=ose.strerror)) def on_search_line_edit_changed(self, text): """ diff --git a/openlp/plugins/songs/forms/songimportform.py b/openlp/plugins/songs/forms/songimportform.py index 7a6af3981..2539973da 100644 --- a/openlp/plugins/songs/forms/songimportform.py +++ b/openlp/plugins/songs/forms/songimportform.py @@ -132,6 +132,7 @@ class SongImportForm(OpenLPWizard, RegistryProperties): Song wizard localisation. """ self.setWindowTitle(translate('SongsPlugin.ImportWizardForm', 'Song Import Wizard')) + # TODO: Verify format() with template variables self.title_label.setText(WizardStrings.HeaderStyle % translate('OpenLP.Ui', 'Welcome to the Song Import Wizard')) self.information_label.setText( @@ -236,7 +237,7 @@ class SongImportForm(OpenLPWizard, RegistryProperties): """ if filters: filters += ';;' - filters += '%s (*)' % UiStrings().AllFiles + filters += '{text} (*)'.format(text=UiStrings().AllFiles) file_names = FileDialog.getOpenFileNames( self, title, Settings().value(self.plugin.settings_section + '/last directory import'), filters) @@ -271,9 +272,11 @@ class SongImportForm(OpenLPWizard, RegistryProperties): select_mode, format_name, ext_filter = SongFormat.get(this_format, 'selectMode', 'name', 'filter') file_path_edit = self.format_widgets[this_format]['file_path_edit'] if select_mode == SongFormatSelect.SingleFile: + # TODO: Verify format() with template variables self.get_file_name( WizardStrings.OpenTypeFile % format_name, file_path_edit, 'last directory import', ext_filter) elif select_mode == SongFormatSelect.SingleFolder: + # TODO: Verify format() with template variables self.get_folder(WizardStrings.OpenTypeFolder % format_name, file_path_edit, 'last directory import') def on_add_button_clicked(self): @@ -283,6 +286,7 @@ class SongImportForm(OpenLPWizard, RegistryProperties): this_format = self.current_format select_mode, format_name, ext_filter, custom_title = \ SongFormat.get(this_format, 'selectMode', 'name', 'filter', 'getFilesTitle') + # TODO: Verify format() with template variables title = custom_title if custom_title else WizardStrings.OpenTypeFile % format_name if select_mode == SongFormatSelect.MultipleFiles: self.get_files(title, self.format_widgets[this_format]['file_list_widget'], ext_filter) diff --git a/openlp/plugins/songs/forms/songmaintenanceform.py b/openlp/plugins/songs/forms/songmaintenanceform.py index 74462e6d0..a9b871c7e 100644 --- a/openlp/plugins/songs/forms/songmaintenanceform.py +++ b/openlp/plugins/songs/forms/songmaintenanceform.py @@ -164,7 +164,8 @@ class SongMaintenanceForm(QtWidgets.QDialog, Ui_SongMaintenanceDialog, RegistryP books = self.manager.get_all_objects(Book) books.sort(key=get_book_key) for book in books: - book_name = QtWidgets.QListWidgetItem('%s (%s)' % (book.name, book.publisher)) + book_name = QtWidgets.QListWidgetItem('{name} ({publisher})'.format(name=book.name, + publisher=book.publisher)) book_name.setData(QtCore.Qt.UserRole, book.id) self.song_books_list_widget.addItem(book_name) @@ -310,11 +311,12 @@ class SongMaintenanceForm(QtWidgets.QDialog, Ui_SongMaintenanceDialog, RegistryP else: critical_error_message_box( message=translate('SongsPlugin.SongMaintenanceForm', 'Could not save your changes.')) - elif critical_error_message_box(message=translate( - 'SongsPlugin.SongMaintenanceForm', 'The author %s already exists. Would you like to make songs with ' - 'author %s use the existing author %s?') % - (author.display_name, temp_display_name, author.display_name), parent=self, question=True) == \ - QtWidgets.QMessageBox.Yes: + elif critical_error_message_box( + message=translate( + 'SongsPlugin.SongMaintenanceForm', + 'The author {original} already exists. Would you like to make songs with author {new} use the ' + 'existing author {original}?').format(original=author.display_name, new=temp_display_name), + parent=self, question=True) == QtWidgets.QMessageBox.Yes: self._merge_objects(author, self.merge_authors, self.reset_authors) else: # We restore the author's old first and last name as well as @@ -346,9 +348,10 @@ class SongMaintenanceForm(QtWidgets.QDialog, Ui_SongMaintenanceDialog, RegistryP critical_error_message_box( message=translate('SongsPlugin.SongMaintenanceForm', 'Could not save your changes.')) elif critical_error_message_box( - message=translate('SongsPlugin.SongMaintenanceForm', - 'The topic %s already exists. Would you like to make songs with topic %s use the ' - 'existing topic %s?') % (topic.name, temp_name, topic.name), + message=translate('SongsPlugin.SongMaintenanceForm', + 'The topic {original} already exists. Would you like to make songs with ' + 'topic {new} use the existing topic {original}?').format(original=topic.name, + new=temp_name), parent=self, question=True) == QtWidgets.QMessageBox.Yes: self._merge_objects(topic, self.merge_topics, self.reset_topics) else: @@ -384,9 +387,10 @@ class SongMaintenanceForm(QtWidgets.QDialog, Ui_SongMaintenanceDialog, RegistryP critical_error_message_box( message=translate('SongsPlugin.SongMaintenanceForm', 'Could not save your changes.')) elif critical_error_message_box( - message=translate('SongsPlugin.SongMaintenanceForm', - 'The book %s already exists. Would you like to make ' - 'songs with book %s use the existing book %s?') % (book.name, temp_name, book.name), + message=translate('SongsPlugin.SongMaintenanceForm', + 'The book {original} already exists. Would you like to make songs with ' + 'book {new} use the existing book {original}?').format(original=book.name, + new=temp_name), parent=self, question=True) == QtWidgets.QMessageBox.Yes: self._merge_objects(book, self.merge_song_books, self.reset_song_books) else: diff --git a/openlp/plugins/songs/forms/songselectdialog.py b/openlp/plugins/songs/forms/songselectdialog.py index 833ee39ec..9ad07d50a 100644 --- a/openlp/plugins/songs/forms/songselectdialog.py +++ b/openlp/plugins/songs/forms/songselectdialog.py @@ -242,7 +242,8 @@ class Ui_SongSelectDialog(object): self.search_label.setText(translate('SongsPlugin.SongSelectForm', 'Search Text:')) self.search_button.setText(translate('SongsPlugin.SongSelectForm', 'Search')) self.stop_button.setText(translate('SongsPlugin.SongSelectForm', 'Stop')) - self.result_count_label.setText(translate('SongsPlugin.SongSelectForm', 'Found %s song(s)') % 0) + self.result_count_label.setText(translate('SongsPlugin.SongSelectForm', + 'Found {count:d} song(s)').format(count=0)) self.logout_button.setText(translate('SongsPlugin.SongSelectForm', 'Logout')) self.view_button.setText(translate('SongsPlugin.SongSelectForm', 'View')) self.title_label.setText(translate('SongsPlugin.SongSelectForm', 'Title:')) diff --git a/openlp/plugins/songs/forms/songselectform.py b/openlp/plugins/songs/forms/songselectform.py index 84ced5383..57bdefdeb 100755 --- a/openlp/plugins/songs/forms/songselectform.py +++ b/openlp/plugins/songs/forms/songselectform.py @@ -305,7 +305,8 @@ class SongSelectForm(QtWidgets.QDialog, Ui_SongSelectDialog): self.search_progress_bar.setValue(0) self.set_progress_visible(True) self.search_results_widget.clear() - self.result_count_label.setText(translate('SongsPlugin.SongSelectForm', 'Found %s song(s)') % self.song_count) + self.result_count_label.setText(translate('SongsPlugin.SongSelectForm', + 'Found {count:d} song(s)').format(count=self.song_count)) self.application.process_events() self.song_count = 0 search_history = self.search_combobox.getItems() @@ -343,7 +344,8 @@ class SongSelectForm(QtWidgets.QDialog, Ui_SongSelectDialog): :param song: """ self.song_count += 1 - self.result_count_label.setText(translate('SongsPlugin.SongSelectForm', 'Found %s song(s)') % self.song_count) + self.result_count_label.setText(translate('SongsPlugin.SongSelectForm', + 'Found {count:d} song(s)').format(count=self.song_count)) item_title = song['title'] + ' (' + ', '.join(song['authors']) + ')' song_item = QtWidgets.QListWidgetItem(item_title, self.search_results_widget) song_item.setData(QtCore.Qt.UserRole, song) diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index 0e03bfe7c..4d8586204 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -534,11 +534,11 @@ def delete_song(song_id, song_plugin): try: os.remove(media_file.file_name) except OSError: - log.exception('Could not remove file: %s', media_file.file_name) + log.exception('Could not remove file: {name}'.format(name=media_file.file_name)) try: save_path = os.path.join(AppLocation.get_section_data_path(song_plugin.name), 'audio', str(song_id)) if os.path.exists(save_path): os.rmdir(save_path) except OSError: - log.exception('Could not remove directory: %s', save_path) + log.exception('Could not remove directory: {path}'.format(path=save_path)) song_plugin.manager.delete_object(Song, song_id) diff --git a/openlp/plugins/songs/lib/db.py b/openlp/plugins/songs/lib/db.py index 3026915e4..24b9fe880 100644 --- a/openlp/plugins/songs/lib/db.py +++ b/openlp/plugins/songs/lib/db.py @@ -39,7 +39,7 @@ class Author(BaseModel): """ def get_display_name(self, author_type=None): if author_type: - return "%s (%s)" % (self.display_name, AuthorType.Types[author_type]) + return "{name} ({author})".format(name=self.display_name, author=AuthorType.Types[author_type]) return self.display_name @@ -105,7 +105,9 @@ class Book(BaseModel): Book model """ def __repr__(self): - return '' % (str(self.id), self.name, self.publisher) + return ''.format(myid=self.id, + name=self.name, + publisher=self.publisher) class MediaFile(BaseModel): @@ -187,7 +189,7 @@ class SongBookEntry(BaseModel): @staticmethod def get_display_name(songbook_name, entry): if entry: - return "%s #%s" % (songbook_name, entry) + return "{name} #{entry}".format(name=songbook_name, entry=entry) return songbook_name diff --git a/openlp/plugins/songs/lib/importer.py b/openlp/plugins/songs/lib/importer.py index 7b9101306..8f7654161 100644 --- a/openlp/plugins/songs/lib/importer.py +++ b/openlp/plugins/songs/lib/importer.py @@ -56,13 +56,13 @@ try: from .importers.songsoffellowship import SongsOfFellowshipImport HAS_SOF = True except ImportError: - log.exception('Error importing %s', 'SongsOfFellowshipImport') + log.exception('Error importing {text}'.format(text='SongsOfFellowshipImport')) HAS_SOF = False try: from .importers.openoffice import OpenOfficeImport HAS_OOO = True except ImportError: - log.exception('Error importing %s', 'OooImport') + log.exception('Error importing {text}'.format(text='OooImport')) HAS_OOO = False HAS_MEDIASHOUT = False if is_win(): @@ -70,21 +70,21 @@ if is_win(): from .importers.mediashout import MediaShoutImport HAS_MEDIASHOUT = True except ImportError: - log.exception('Error importing %s', 'MediaShoutImport') + log.exception('Error importing {text}'.format(text='MediaShoutImport')) HAS_WORSHIPCENTERPRO = False if is_win(): try: from .importers.worshipcenterpro import WorshipCenterProImport HAS_WORSHIPCENTERPRO = True except ImportError: - log.exception('Error importing %s', 'WorshipCenterProImport') + log.exception('Error importing {text}'.format(text='WorshipCenterProImport')) HAS_OPSPRO = False if is_win(): try: from .importers.opspro import OPSProImport HAS_OPSPRO = True except ImportError: - log.exception('Error importing %s', 'OPSProImport') + log.exception('Error importing {text}'.format(text='OPSProImport')) class SongFormatSelect(object): @@ -198,7 +198,7 @@ class SongFormat(object): 'class': OpenLyricsImport, 'name': 'OpenLyrics', 'prefix': 'openLyrics', - 'filter': '%s (*.xml)' % translate('SongsPlugin.ImportWizardForm', 'OpenLyrics Files'), + 'filter': '{text} (*.xml)'.format(text=translate('SongsPlugin.ImportWizardForm', 'OpenLyrics Files')), 'comboBoxText': translate('SongsPlugin.ImportWizardForm', 'OpenLyrics or OpenLP 2 Exported Song') }, OpenLP2: { @@ -206,7 +206,7 @@ class SongFormat(object): 'name': UiStrings().OLPV2, 'prefix': 'openLP2', 'selectMode': SongFormatSelect.SingleFile, - 'filter': '%s (*.sqlite)' % (translate('SongsPlugin.ImportWizardForm', 'OpenLP 2 Databases')) + 'filter': '{text} (*.sqlite)'.format(text=translate('SongsPlugin.ImportWizardForm', 'OpenLP 2 Databases')) }, Generic: { 'name': translate('SongsPlugin.ImportWizardForm', 'Generic Document/Presentation'), @@ -221,46 +221,50 @@ class SongFormat(object): 'class': CCLIFileImport, 'name': 'CCLI/SongSelect', 'prefix': 'ccli', - 'filter': '%s (*.usr *.txt *.bin)' % translate('SongsPlugin.ImportWizardForm', 'CCLI SongSelect Files') + 'filter': '{text} (*.usr *.txt *.bin)'.format(text=translate('SongsPlugin.ImportWizardForm', + 'CCLI SongSelect Files')) }, DreamBeam: { 'class': DreamBeamImport, 'name': 'DreamBeam', 'prefix': 'dreamBeam', - 'filter': '%s (*.xml)' % translate('SongsPlugin.ImportWizardForm', 'DreamBeam Song Files') + 'filter': '{text} (*.xml)'.format(text=translate('SongsPlugin.ImportWizardForm', 'DreamBeam Song Files')) }, EasySlides: { 'class': EasySlidesImport, 'name': 'EasySlides', 'prefix': 'easySlides', 'selectMode': SongFormatSelect.SingleFile, - 'filter': '%s (*.xml)' % translate('SongsPlugin.ImportWizardForm', 'EasySlides XML File') + 'filter': '{text} (*.xml)'.format(text=translate('SongsPlugin.ImportWizardForm', 'EasySlides XML File')) }, EasyWorshipDB: { 'class': EasyWorshipSongImport, 'name': 'EasyWorship Song Database', 'prefix': 'ew', 'selectMode': SongFormatSelect.SingleFile, - 'filter': '%s (*.db)' % translate('SongsPlugin.ImportWizardForm', 'EasyWorship Song Database') + 'filter': '{text} (*.db)'.format(text=translate('SongsPlugin.ImportWizardForm', + 'EasyWorship Song Database')) }, EasyWorshipService: { 'class': EasyWorshipSongImport, 'name': 'EasyWorship Service File', 'prefix': 'ew', 'selectMode': SongFormatSelect.SingleFile, - 'filter': '%s (*.ews)' % translate('SongsPlugin.ImportWizardForm', 'EasyWorship Service File') + 'filter': '{text} (*.ews)'.format(text=translate('SongsPlugin.ImportWizardForm', + 'EasyWorship Service File')) }, FoilPresenter: { 'class': FoilPresenterImport, 'name': 'Foilpresenter', 'prefix': 'foilPresenter', - 'filter': '%s (*.foil)' % translate('SongsPlugin.ImportWizardForm', 'Foilpresenter Song Files') + 'filter': '{text} (*.foil)'.format(text=translate('SongsPlugin.ImportWizardForm', + 'Foilpresenter Song Files')) }, Lyrix: { 'class': LyrixImport, 'name': 'LyriX', 'prefix': 'lyrix', - 'filter': '%s (*.txt)' % translate('SongsPlugin.ImportWizardForm', 'LyriX Files'), + 'filter': '{text} (*.txt)'.format(text=translate('SongsPlugin.ImportWizardForm', 'LyriX Files')), 'comboBoxText': translate('SongsPlugin.ImportWizardForm', 'LyriX (Exported TXT-files)') }, MediaShout: { @@ -268,7 +272,7 @@ class SongFormat(object): 'prefix': 'mediaShout', 'canDisable': True, 'selectMode': SongFormatSelect.SingleFile, - 'filter': '%s (*.mdb)' % translate('SongsPlugin.ImportWizardForm', 'MediaShout Database'), + 'filter': '{text} (*.mdb)'.format(text=translate('SongsPlugin.ImportWizardForm', 'MediaShout Database')), 'disabledLabelText': translate('SongsPlugin.ImportWizardForm', 'The MediaShout importer is only supported on Windows. It has ' 'been disabled due to a missing Python module. If you want to ' @@ -285,7 +289,7 @@ class SongFormat(object): 'prefix': 'OPSPro', 'canDisable': True, 'selectMode': SongFormatSelect.SingleFile, - 'filter': '%s (*.mdb)' % translate('SongsPlugin.ImportWizardForm', 'OPS Pro database'), + 'filter': '{text} (*.mdb)'.format(text=translate('SongsPlugin.ImportWizardForm', 'OPS Pro database')), 'disabledLabelText': translate('SongsPlugin.ImportWizardForm', 'The OPS Pro importer is only supported on Windows. It has been ' 'disabled due to a missing Python module. If you want to use this ' @@ -295,7 +299,7 @@ class SongFormat(object): 'class': PowerPraiseImport, 'name': 'PowerPraise', 'prefix': 'powerPraise', - 'filter': '%s (*.ppl)' % translate('SongsPlugin.ImportWizardForm', 'PowerPraise Song Files') + 'filter': '{text} (*.ppl)'.format(text=translate('SongsPlugin.ImportWizardForm', 'PowerPraise Song Files')) }, PowerSong: { 'class': PowerSongImport, @@ -309,26 +313,29 @@ class SongFormat(object): 'class': PresentationManagerImport, 'name': 'PresentationManager', 'prefix': 'presentationManager', - 'filter': '%s (*.sng)' % translate('SongsPlugin.ImportWizardForm', 'PresentationManager Song Files') + 'filter': '{text} (*.sng)'.format(text=translate('SongsPlugin.ImportWizardForm', + 'PresentationManager Song Files')) }, ProPresenter: { 'class': ProPresenterImport, 'name': 'ProPresenter 4, 5 and 6', 'prefix': 'proPresenter', - 'filter': '%s (*.pro4 *.pro5 *.pro6)' % translate('SongsPlugin.ImportWizardForm', 'ProPresenter Song Files') + 'filter': '{text} (*.pro4 *.pro5 *.pro6)'.format(text=translate('SongsPlugin.ImportWizardForm', + 'ProPresenter Song Files')) }, SongBeamer: { 'class': SongBeamerImport, 'name': 'SongBeamer', 'prefix': 'songBeamer', - 'filter': '%s (*.sng)' % translate('SongsPlugin.ImportWizardForm', 'SongBeamer Files') + 'filter': '{text} (*.sng)'.format(text=translate('SongsPlugin.ImportWizardForm', + 'SongBeamer Files')) }, SongPro: { 'class': SongProImport, 'name': 'SongPro', 'prefix': 'songPro', 'selectMode': SongFormatSelect.SingleFile, - 'filter': '%s (*.txt)' % translate('SongsPlugin.ImportWizardForm', 'SongPro Text Files'), + 'filter': '{text} (*.txt)'.format(text=translate('SongsPlugin.ImportWizardForm', 'SongPro Text Files')), 'comboBoxText': translate('SongsPlugin.ImportWizardForm', 'SongPro (Export File)'), 'descriptionText': translate('SongsPlugin.ImportWizardForm', 'In SongPro, export your songs using the File -> Export menu') @@ -337,13 +344,15 @@ class SongFormat(object): 'class': SongShowPlusImport, 'name': 'SongShow Plus', 'prefix': 'songShowPlus', - 'filter': '%s (*.sbsong)' % translate('SongsPlugin.ImportWizardForm', 'SongShow Plus Song Files') + 'filter': '{text} (*.sbsong)'.format(text=translate('SongsPlugin.ImportWizardForm', + 'SongShow Plus Song Files')) }, SongsOfFellowship: { 'name': 'Songs of Fellowship', 'prefix': 'songsOfFellowship', 'canDisable': True, - 'filter': '%s (*.rtf)' % translate('SongsPlugin.ImportWizardForm', 'Songs Of Fellowship Song Files'), + 'filter': '{text} (*.rtf)'.format(text=translate('SongsPlugin.ImportWizardForm', + 'Songs Of Fellowship Song Files')), 'disabledLabelText': translate('SongsPlugin.ImportWizardForm', 'The Songs of Fellowship importer has been disabled because ' 'OpenLP cannot access OpenOffice or LibreOffice.') @@ -352,30 +361,33 @@ class SongFormat(object): 'class': SundayPlusImport, 'name': 'SundayPlus', 'prefix': 'sundayPlus', - 'filter': '%s (*.ptf)' % translate('SongsPlugin.ImportWizardForm', 'SundayPlus Song Files') + 'filter': '{text} (*.ptf)'.format(text=translate('SongsPlugin.ImportWizardForm', 'SundayPlus Song Files')) }, VideoPsalm: { 'class': VideoPsalmImport, 'name': 'VideoPsalm', 'prefix': 'videopsalm', 'selectMode': SongFormatSelect.SingleFile, - 'filter': '%s (*.json)' % translate('SongsPlugin.ImportWizardForm', 'VideoPsalm Files'), + 'filter': '{text} (*.json)'.format(text=translate('SongsPlugin.ImportWizardForm', 'VideoPsalm Files')), 'comboBoxText': translate('SongsPlugin.ImportWizardForm', 'VideoPsalm'), 'descriptionText': translate('SongsPlugin.ImportWizardForm', 'The VideoPsalm songbooks are normally located' - ' in %s') % 'C:\\Users\\Public\\Documents\\VideoPsalm\\SongBooks\\' + ' in {path}').format(path='C:\\Users\\Public\\Documents\\VideoPsalm' + '\\SongBooks\\') }, WordsOfWorship: { 'class': WordsOfWorshipImport, 'name': 'Words of Worship', 'prefix': 'wordsOfWorship', - 'filter': '%s (*.wsg *.wow-song)' % translate('SongsPlugin.ImportWizardForm', 'Words Of Worship Song Files') + 'filter': '{text} (*.wsg *.wow-song)'.format(text=translate('SongsPlugin.ImportWizardForm', + 'Words Of Worship Song Files')) }, WorshipAssistant: { 'class': WorshipAssistantImport, 'name': 'Worship Assistant 0', 'prefix': 'worshipAssistant', 'selectMode': SongFormatSelect.SingleFile, - 'filter': '%s (*.csv)' % translate('SongsPlugin.ImportWizardForm', 'Worship Assistant Files'), + 'filter': '{text} (*.csv)'.format(text=translate('SongsPlugin.ImportWizardForm', + 'Worship Assistant Files')), 'comboBoxText': translate('SongsPlugin.ImportWizardForm', 'Worship Assistant (CSV)'), 'descriptionText': translate('SongsPlugin.ImportWizardForm', 'In Worship Assistant, export your Database to a CSV file.') @@ -385,7 +397,8 @@ class SongFormat(object): 'prefix': 'worshipCenterPro', 'canDisable': True, 'selectMode': SongFormatSelect.SingleFile, - 'filter': '%s (*.mdb)' % translate('SongsPlugin.ImportWizardForm', 'WorshipCenter Pro Song Files'), + 'filter': '{text} (*.mdb)'.format(text=translate('SongsPlugin.ImportWizardForm', + 'WorshipCenter Pro Song Files')), 'disabledLabelText': translate('SongsPlugin.ImportWizardForm', 'The WorshipCenter Pro importer is only supported on Windows. It has been ' 'disabled due to a missing Python module. If you want to use this ' diff --git a/openlp/plugins/songs/lib/importers/cclifile.py b/openlp/plugins/songs/lib/importers/cclifile.py index 24008cc5d..800509ab2 100644 --- a/openlp/plugins/songs/lib/importers/cclifile.py +++ b/openlp/plugins/songs/lib/importers/cclifile.py @@ -58,7 +58,7 @@ class CCLIFileImport(SongImport): self.import_wizard.progress_bar.setMaximum(len(self.import_source)) for filename in self.import_source: filename = str(filename) - log.debug('Importing CCLI File: %s', filename) + log.debug('Importing CCLI File: {name}'.format(name=filename)) if os.path.isfile(filename): detect_file = open(filename, 'rb') detect_content = detect_file.read(2048) @@ -76,17 +76,17 @@ class CCLIFileImport(SongImport): infile.close() ext = os.path.splitext(filename)[1] if ext.lower() == '.usr' or ext.lower() == '.bin': - log.info('SongSelect USR format file found: %s', filename) + log.info('SongSelect USR format file found: {name}'.format(name=filename)) if not self.do_import_usr_file(lines): self.log_error(filename) elif ext.lower() == '.txt': - log.info('SongSelect TEXT format file found: %s', filename) + log.info('SongSelect TEXT format file found: {name}'.format(name=filename)) if not self.do_import_txt_file(lines): self.log_error(filename) else: self.log_error(filename, translate('SongsPlugin.CCLIFileImport', 'The file does not have a valid ' 'extension.')) - log.info('Extension %s is not valid', filename) + log.info('Extension {name} is not valid'.format(name=filename)) if self.stop_import_flag: return @@ -146,7 +146,7 @@ class CCLIFileImport(SongImport): :param text_list: An array of strings containing the usr file content. """ - log.debug('USR file text: %s', text_list) + log.debug('USR file text: {text}'.format(text=text_list)) song_author = '' song_topics = '' for line in text_list: @@ -193,7 +193,7 @@ class CCLIFileImport(SongImport): if check_first_verse_line: if verse_lines[0].startswith('(PRE-CHORUS'): verse_type = VerseType.tags[VerseType.PreChorus] - log.debug('USR verse PRE-CHORUS: %s', verse_lines[0]) + log.debug('USR verse PRE-CHORUS: {lines}'.format(lines=verse_lines[0])) verse_text = verse_lines[1] elif verse_lines[0].startswith('(BRIDGE'): verse_type = VerseType.tags[VerseType.Bridge] @@ -248,7 +248,7 @@ class CCLIFileImport(SongImport): # e.g. CCLI-Liedlizenznummer: 14 / CCLI License No. 14 """ - log.debug('TXT file text: %s', text_list) + log.debug('TXT file text: {text}'.format(text=text_list)) line_number = 0 check_first_verse_line = False verse_text = '' diff --git a/openlp/plugins/songs/lib/importers/dreambeam.py b/openlp/plugins/songs/lib/importers/dreambeam.py index db785df7d..9371adc56 100644 --- a/openlp/plugins/songs/lib/importers/dreambeam.py +++ b/openlp/plugins/songs/lib/importers/dreambeam.py @@ -90,7 +90,7 @@ class DreamBeamImport(SongImport): try: parsed_file = etree.parse(open(file, 'r'), parser) except etree.XMLSyntaxError: - log.exception('XML syntax error in file %s' % file) + log.exception('XML syntax error in file {name}'.format(name=file)) self.log_error(file, SongStrings.XMLSyntaxError) continue xml = etree.tostring(parsed_file).decode() @@ -115,15 +115,17 @@ class DreamBeamImport(SongImport): verse_type = lyrics_item.get('Type') verse_number = lyrics_item.get('Number') verse_text = str(lyrics_item.text) - self.add_verse(verse_text, ('%s%s' % (verse_type[:1], verse_number))) + self.add_verse(verse_text, + '{verse}{number}'.format(verse=verse_type[:1], number=verse_number)) if hasattr(song_xml, 'Collection'): self.song_book_name = str(song_xml.Collection.text) if hasattr(song_xml, 'Number'): self.song_number = str(song_xml.Number.text) if hasattr(song_xml, 'Sequence'): for lyrics_sequence_item in (song_xml.Sequence.iterchildren()): - self.verse_order_list.append("%s%s" % (lyrics_sequence_item.get('Type')[:1], - lyrics_sequence_item.get('Number'))) + item = lyrics_sequence_item.get('Type')[:1] + self.verse_order_list.append("{item}{number}".format(item=item), + lyrics_sequence_item.get('Number')) if hasattr(song_xml, 'Notes'): self.comments = str(song_xml.Notes.text) else: diff --git a/openlp/plugins/songs/lib/importers/easyslides.py b/openlp/plugins/songs/lib/importers/easyslides.py index 3137e2baa..907a6c90f 100644 --- a/openlp/plugins/songs/lib/importers/easyslides.py +++ b/openlp/plugins/songs/lib/importers/easyslides.py @@ -45,7 +45,7 @@ class EasySlidesImport(SongImport): super(EasySlidesImport, self).__init__(manager, **kwargs) def do_import(self): - log.info('Importing EasySlides XML file %s', self.import_source) + log.info('Importing EasySlides XML file {source}'.format(source=self.import_source)) parser = etree.XMLParser(remove_blank_text=True) parsed_file = etree.parse(self.import_source, parser) xml = etree.tostring(parsed_file).decode() @@ -96,10 +96,10 @@ class EasySlidesImport(SongImport): try: setattr(self, self_attribute, str(import_attribute).strip()) except UnicodeDecodeError: - log.exception('UnicodeDecodeError decoding %s' % import_attribute) + log.exception('UnicodeDecodeError decoding {attribute}'.format(attribute=import_attribute)) self._success = False except AttributeError: - log.exception('No attribute %s' % import_attribute) + log.exception('No attribute {attribute}'.format(attribute=import_attribute)) if mandatory: self._success = False @@ -119,7 +119,7 @@ class EasySlidesImport(SongImport): try: self.add_copyright(str(element).strip()) except UnicodeDecodeError: - log.exception('Unicode error on decoding copyright: %s' % element) + log.exception('Unicode error on decoding copyright: {element}'.format(element=element)) self._success = False except AttributeError: pass @@ -157,9 +157,10 @@ class EasySlidesImport(SongImport): separators = (separator_lines > 0) # the number of different regions in song - 1 if len(region_lines) > 1: - log.info('EasySlidesImport: the file contained a song named "%s"' - 'with more than two regions, but only two regions are tested, encountered regions were: %s', - self.title, ','.join(list(region_lines.keys()))) + log.info('EasySlidesImport: the file contained a song named "{title}"' + 'with more than two regions, but only two regions are tested, ' + 'encountered regions were: {keys}'.format(title=self.title, + keys=','.join(list(region_lines.keys())))) # if the song has regions regions = (len(region_lines) > 0) # if the regions are inside verses @@ -232,7 +233,7 @@ class EasySlidesImport(SongImport): for [reg, vt, vn, inst] in our_verse_order: if self._list_has(verses, [reg, vt, vn, inst]): # this is false, but needs user input - versetag = '%s%s' % (vt, vn) + versetag = '{tag}{number}'.format(tag=vt, number=vn) versetags.append(versetag) lines = '\n'.join(verses[reg][vt][vn][inst]) self.add_verse(lines, versetag) @@ -259,7 +260,8 @@ class EasySlidesImport(SongImport): if tag in versetags: self.verse_order_list.append(tag) else: - log.info('Got order item %s, which is not in versetags, dropping item from presentation order', tag) + log.info('Got order item {tag}, which is not in versetags, dropping item from presentation ' + 'order'.format(tag=tag)) except UnicodeDecodeError: log.exception('Unicode decode error while decoding Sequence') self._success = False diff --git a/openlp/plugins/songs/lib/importers/easyworship.py b/openlp/plugins/songs/lib/importers/easyworship.py index 25bbc37ff..cdffe9292 100644 --- a/openlp/plugins/songs/lib/importers/easyworship.py +++ b/openlp/plugins/songs/lib/importers/easyworship.py @@ -171,15 +171,16 @@ class EasyWorshipSongImport(SongImport): if copyright: self.copyright += ', ' self.copyright += translate('SongsPlugin.EasyWorshipSongImport', - 'Administered by %s') % admin + 'Administered by {admin}').format(admin=admin) # Set the SongImport object members. self.set_song_import_object(authors, inflated_content) if self.stop_import_flag: break if self.entry_error_log: self.log_error(self.import_source, - translate('SongsPlugin.EasyWorshipSongImport', '"%s" could not be imported. %s') - % (self.title, self.entry_error_log)) + translate('SongsPlugin.EasyWorshipSongImport', + '"{title}" could not be imported. {entry}').format(title=self.title, + entry=self.entry_error_log)) self.entry_error_log = '' elif not self.finish(): self.log_error(self.import_source) @@ -306,7 +307,7 @@ class EasyWorshipSongImport(SongImport): if copy: self.copyright += ', ' self.copyright += translate('SongsPlugin.EasyWorshipSongImport', - 'Administered by %s') % admin.decode(self.encoding) + 'Administered by {admin}').format(admin=admin.decode(self.encoding)) if ccli: self.ccli_number = ccli.decode(self.encoding) if authors: @@ -319,15 +320,17 @@ class EasyWorshipSongImport(SongImport): break if self.entry_error_log: self.log_error(self.import_source, - translate('SongsPlugin.EasyWorshipSongImport', '"%s" could not be imported. %s') - % (self.title, self.entry_error_log)) + translate('SongsPlugin.EasyWorshipSongImport', + '"{title}" could not be imported. ' + '{entry}').format(title=self.title, entry=self.entry_error_log)) self.entry_error_log = '' elif not self.finish(): self.log_error(self.import_source) except Exception as e: self.log_error(self.import_source, - translate('SongsPlugin.EasyWorshipSongImport', '"%s" could not be imported. %s') - % (self.title, e)) + translate('SongsPlugin.EasyWorshipSongImport', + '"{title}" could not be imported. {error}').format(title=self.title, + error=e)) db_file.close() self.memo_file.close() @@ -421,7 +424,7 @@ class EasyWorshipSongImport(SongImport): fsl = ['>'] for field_desc in field_descriptions: if field_desc.field_type == FieldType.String: - fsl.append('%ds' % field_desc.size) + fsl.append('{size:d}s'.format(size=field_desc.size)) elif field_desc.field_type == FieldType.Int16: fsl.append('H') elif field_desc.field_type == FieldType.Int32: @@ -429,13 +432,13 @@ class EasyWorshipSongImport(SongImport): elif field_desc.field_type == FieldType.Logical: fsl.append('B') elif field_desc.field_type == FieldType.Memo: - fsl.append('%ds' % field_desc.size) + fsl.append('{size:d}s'.format(size=field_desc.size)) elif field_desc.field_type == FieldType.Blob: - fsl.append('%ds' % field_desc.size) + fsl.append('{size:d}s'.format(size=field_desc.size)) elif field_desc.field_type == FieldType.Timestamp: fsl.append('Q') else: - fsl.append('%ds' % field_desc.size) + fsl.append('{size:d}s'.format(size=field_desc.size)) self.record_structure = struct.Struct(''.join(fsl)) self.field_descriptions = field_descriptions diff --git a/openlp/plugins/songs/lib/importers/foilpresenter.py b/openlp/plugins/songs/lib/importers/foilpresenter.py index 061f50a9f..011dece24 100644 --- a/openlp/plugins/songs/lib/importers/foilpresenter.py +++ b/openlp/plugins/songs/lib/importers/foilpresenter.py @@ -121,6 +121,7 @@ class FoilPresenterImport(SongImport): for file_path in self.import_source: if self.stop_import_flag: return + # TODO: Verify format() with template strings self.import_wizard.increment_progress_bar(WizardStrings.ImportingType % os.path.basename(file_path)) try: parsed_file = etree.parse(file_path, parser) @@ -128,7 +129,7 @@ class FoilPresenterImport(SongImport): self.foil_presenter.xml_to_song(xml) except etree.XMLSyntaxError: self.log_error(file_path, SongStrings.XMLSyntaxError) - log.exception('XML syntax error in file %s' % file_path) + log.exception('XML syntax error in file {path}'.format(path=file_path)) class FoilPresenter(object): diff --git a/openlp/plugins/songs/lib/importers/lyrix.py b/openlp/plugins/songs/lib/importers/lyrix.py index 28904354f..387213f57 100644 --- a/openlp/plugins/songs/lib/importers/lyrix.py +++ b/openlp/plugins/songs/lib/importers/lyrix.py @@ -102,8 +102,8 @@ class LyrixImport(SongImport): else: current_verse += '\n' + line except Exception as e: - self.log_error(translate('SongsPlugin.LyrixImport', 'File %s' % file.name), - translate('SongsPlugin.LyrixImport', 'Error: %s') % e) + self.log_error(translate('SongsPlugin.LyrixImport', 'File {name}').format(name=file.name), + translate('SongsPlugin.LyrixImport', 'Error: {error}').format(error=e)) return self.title = song_title self.parse_author(author) diff --git a/openlp/plugins/songs/lib/importers/mediashout.py b/openlp/plugins/songs/lib/importers/mediashout.py index 323d99acd..cb3a19640 100644 --- a/openlp/plugins/songs/lib/importers/mediashout.py +++ b/openlp/plugins/songs/lib/importers/mediashout.py @@ -23,6 +23,10 @@ The :mod:`mediashout` module provides the functionality for importing a MediaShout database into the OpenLP database. """ + +# WARNING: See https://docs.python.org/2/library/sqlite3.html for value substitution +# in SQL statements + import pyodbc from openlp.core.lib import translate @@ -47,8 +51,8 @@ class MediaShoutImport(SongImport): Receive a single file to import. """ try: - conn = pyodbc.connect('DRIVER={Microsoft Access Driver (*.mdb)};DBQ=%s;PWD=6NOZ4eHK7k' % - self.import_source) + conn = pyodbc.connect('DRIVER={Microsoft Access Driver (*.mdb)};DBQ={source};' + 'PWD=6NOZ4eHK7k'.format(sorce=self.import_source)) except: # Unfortunately no specific exception type self.log_error(self.import_source, translate('SongsPlugin.MediaShoutImport', @@ -61,16 +65,15 @@ class MediaShoutImport(SongImport): for song in songs: if self.stop_import_flag: break - cursor.execute('SELECT Type, Number, Text FROM Verses WHERE Record = %s ORDER BY Type, Number' - % song.Record) + cursor.execute('SELECT Type, Number, Text FROM Verses WHERE Record = ? ORDER BY Type, Number', song.Record) verses = cursor.fetchall() - cursor.execute('SELECT Type, Number, POrder FROM PlayOrder WHERE Record = %s ORDER BY POrder' % song.Record) + cursor.execute('SELECT Type, Number, POrder FROM PlayOrder WHERE Record = ? ORDER BY POrder', song.Record) verse_order = cursor.fetchall() cursor.execute('SELECT Name FROM Themes INNER JOIN SongThemes ON SongThemes.ThemeId = Themes.ThemeId ' - 'WHERE SongThemes.Record = %s' % song.Record) + 'WHERE SongThemes.Record = ?', song.Record) topics = cursor.fetchall() cursor.execute('SELECT Name FROM Groups INNER JOIN SongGroups ON SongGroups.GroupId = Groups.GroupId ' - 'WHERE SongGroups.Record = %s' % song.Record) + 'WHERE SongGroups.Record = ?', song.Record) topics += cursor.fetchall() self.process_song(song, verses, verse_order, topics) diff --git a/openlp/plugins/songs/lib/importers/openlp.py b/openlp/plugins/songs/lib/importers/openlp.py index 20c603e28..0bc1655a9 100644 --- a/openlp/plugins/songs/lib/importers/openlp.py +++ b/openlp/plugins/songs/lib/importers/openlp.py @@ -102,7 +102,7 @@ class OpenLPSongImport(SongImport): self.log_error(self.import_source, translate('SongsPlugin.OpenLPSongImport', 'Not a valid OpenLP 2 song database.')) return - self.import_source = 'sqlite:///%s' % self.import_source + self.import_source = 'sqlite:///{url}'.format(url=self.import_source) # Load the db file and reflect it engine = create_engine(self.import_source) source_meta = MetaData() @@ -239,8 +239,10 @@ class OpenLPSongImport(SongImport): self.manager.save_object(new_song) if progress_dialog: progress_dialog.setValue(progress_dialog.value() + 1) + # TODO: Verify format() with template strings progress_dialog.setLabelText(WizardStrings.ImportingType % new_song.title) else: + # TODO: Verify format() with template strings self.import_wizard.increment_progress_bar(WizardStrings.ImportingType % new_song.title) if self.stop_import_flag: break diff --git a/openlp/plugins/songs/lib/importers/openlyrics.py b/openlp/plugins/songs/lib/importers/openlyrics.py index f60023cdf..84b667ce4 100644 --- a/openlp/plugins/songs/lib/importers/openlyrics.py +++ b/openlp/plugins/songs/lib/importers/openlyrics.py @@ -58,6 +58,7 @@ class OpenLyricsImport(SongImport): for file_path in self.import_source: if self.stop_import_flag: return + # TODO: Verify format() with template strings self.import_wizard.increment_progress_bar(WizardStrings.ImportingType % os.path.basename(file_path)) try: # Pass a file object, because lxml does not cope with some @@ -66,9 +67,10 @@ class OpenLyricsImport(SongImport): xml = etree.tostring(parsed_file).decode() self.open_lyrics.xml_to_song(xml) except etree.XMLSyntaxError: - log.exception('XML syntax error in file %s' % file_path) + log.exception('XML syntax error in file {path}'.format(file_path)) self.log_error(file_path, SongStrings.XMLSyntaxError) except OpenLyricsError as exception: - log.exception('OpenLyricsException %d in file %s: %s' % - (exception.type, file_path, exception.log_message)) + log.exception('OpenLyricsException {error:d} in file {name}: {text}'.format(error=exception.type, + name=file_path, + text=exception.log_message)) self.log_error(file_path, exception.display_message) diff --git a/openlp/plugins/songs/lib/importers/openoffice.py b/openlp/plugins/songs/lib/importers/openoffice.py index b21f3a7d3..c1a949d1e 100644 --- a/openlp/plugins/songs/lib/importers/openoffice.py +++ b/openlp/plugins/songs/lib/importers/openoffice.py @@ -161,7 +161,7 @@ class OpenOfficeImport(SongImport): else: self.import_wizard.increment_progress_bar('Processing file ' + file_path, 0) except AttributeError: - log.exception("open_ooo_file failed: %s", url) + log.exception("open_ooo_file failed: {url}".format(url=url)) return def create_property(self, name, value): diff --git a/openlp/plugins/songs/lib/importers/opensong.py b/openlp/plugins/songs/lib/importers/opensong.py index 3c0644ff6..a1bfacbcb 100644 --- a/openlp/plugins/songs/lib/importers/opensong.py +++ b/openlp/plugins/songs/lib/importers/opensong.py @@ -254,8 +254,8 @@ class OpenSongImport(SongImport): length = 0 while length < len(verse_num) and verse_num[length].isnumeric(): length += 1 - verse_def = '%s%s' % (verse_tag, verse_num[:length]) - verse_joints[verse_def] = '%s\n[---]\n%s' % (verse_joints[verse_def], lines) \ + verse_def = '{tag}{number}'.format(tag=verse_tag, number=verse_num[:length]) + verse_joints[verse_def] = '{verse}\n[---]\n{lines}'.format(verse=verse_joints[verse_def], lines=lines) \ if verse_def in verse_joints else lines # Parsing the dictionary produces the elements in a non-intuitive order. While it "works", it's not a # natural layout should the user come back to edit the song. Instead we sort by the verse type, so that we @@ -287,11 +287,11 @@ class OpenSongImport(SongImport): verse_num = '1' verse_index = VerseType.from_loose_input(verse_tag) verse_tag = VerseType.tags[verse_index] - verse_def = '%s%s' % (verse_tag, verse_num) + verse_def = '{tag}{number}'.format(tag=verse_tag, number=verse_num) if verse_num in verses.get(verse_tag, {}): self.verse_order_list.append(verse_def) else: - log.info('Got order %s but not in verse tags, dropping this item from presentation order', - verse_def) + log.info('Got order {order} but not in verse tags, dropping this item from presentation ' + 'order'.format(order=verse_def)) if not self.finish(): self.log_error(file.name) diff --git a/openlp/plugins/songs/lib/importers/opspro.py b/openlp/plugins/songs/lib/importers/opspro.py index 08bb1bcc9..8f9674deb 100644 --- a/openlp/plugins/songs/lib/importers/opspro.py +++ b/openlp/plugins/songs/lib/importers/opspro.py @@ -23,6 +23,10 @@ The :mod:`opspro` module provides the functionality for importing a OPS Pro database into the OpenLP database. """ + +# WARNING: See https://docs.python.org/2/library/sqlite3.html for value substitution +# in SQL statements + import logging import re import pyodbc @@ -51,10 +55,11 @@ class OPSProImport(SongImport): """ password = self.extract_mdb_password() try: - conn = pyodbc.connect('DRIVER={Microsoft Access Driver (*.mdb)};DBQ=%s;PWD=%s' % (self.import_source, - password)) + conn = pyodbc.connect('DRIVER={Microsoft Access Driver (*.mdb)};DBQ={source};' + 'PWD={password}'.format(source=self.import_source, password=password)) except (pyodbc.DatabaseError, pyodbc.IntegrityError, pyodbc.InternalError, pyodbc.OperationalError) as e: - log.warning('Unable to connect the OPS Pro database %s. %s', self.import_source, str(e)) + log.warning('Unable to connect the OPS Pro database {source}. {error}'.format(source=self.import_source, + error=str(e))) # Unfortunately no specific exception type self.log_error(self.import_source, translate('SongsPlugin.OPSProImport', 'Unable to connect the OPS Pro database.')) @@ -68,19 +73,19 @@ class OPSProImport(SongImport): if self.stop_import_flag: break # Type means: 0=Original, 1=Projection, 2=Own - cursor.execute('SELECT Lyrics, Type, IsDualLanguage FROM Lyrics WHERE SongID = %d AND Type < 2 ' - 'ORDER BY Type DESC' % song.ID) + cursor.execute('SELECT Lyrics, Type, IsDualLanguage FROM Lyrics WHERE SongID = ? AND Type < 2 ' + 'ORDER BY Type DESC', song.ID) lyrics = cursor.fetchone() cursor.execute('SELECT CategoryName FROM Category INNER JOIN SongCategory ' - 'ON Category.ID = SongCategory.CategoryID WHERE SongCategory.SongID = %d ' - 'ORDER BY CategoryName' % song.ID) + 'ON Category.ID = SongCategory.CategoryID WHERE SongCategory.SongID = ? ' + 'ORDER BY CategoryName', song.ID) topics = cursor.fetchall() try: self.process_song(song, lyrics, topics) except Exception as e: self.log_error(self.import_source, - translate('SongsPlugin.OPSProImport', '"%s" could not be imported. %s') - % (song.Title, e)) + translate('SongsPlugin.OPSProImport', + '"{title}" could not be imported. {error}').format(title=song.Title, error=e)) def process_song(self, song, lyrics, topics): """ diff --git a/openlp/plugins/songs/lib/importers/powerpraise.py b/openlp/plugins/songs/lib/importers/powerpraise.py index 93a360542..b11ac0dda 100644 --- a/openlp/plugins/songs/lib/importers/powerpraise.py +++ b/openlp/plugins/songs/lib/importers/powerpraise.py @@ -41,6 +41,7 @@ class PowerPraiseImport(SongImport): for file_path in self.import_source: if self.stop_import_flag: return + # TODO: Verify format() with template strings self.import_wizard.increment_progress_bar(WizardStrings.ImportingType % os.path.basename(file_path)) root = objectify.parse(open(file_path, 'rb')).getroot() self.process_song(root) @@ -66,7 +67,7 @@ class PowerPraiseImport(SongImport): else: verse_def = 'o' verse_count[verse_def] = verse_count.get(verse_def, 0) + 1 - verse_def = '%s%d' % (verse_def, verse_count[verse_def]) + verse_def = '{verse}{count:d}'.format(verse=verse_def, count=verse_count[verse_def]) verse_text = [] for slide in part.slide: if not hasattr(slide, 'line'): diff --git a/openlp/plugins/songs/lib/importers/powersong.py b/openlp/plugins/songs/lib/importers/powersong.py index a6ff674e8..be40bf873 100644 --- a/openlp/plugins/songs/lib/importers/powersong.py +++ b/openlp/plugins/songs/lib/importers/powersong.py @@ -96,7 +96,7 @@ class PowerSongImport(SongImport): self.import_source = '' if not self.import_source or not isinstance(self.import_source, list): self.log_error(translate('SongsPlugin.PowerSongImport', 'No songs to import.'), - translate('SongsPlugin.PowerSongImport', 'No %s files found.') % ps_string) + translate('SongsPlugin.PowerSongImport', 'No {text} files found.').format(text=ps_string)) return self.import_wizard.progress_bar.setMaximum(len(self.import_source)) for file in self.import_source: @@ -113,9 +113,9 @@ class PowerSongImport(SongImport): field = self._read_string(song_data) except ValueError: parse_error = True - self.log_error(os.path.basename(file), str( - translate('SongsPlugin.PowerSongImport', 'Invalid %s file. Unexpected byte value.')) % - ps_string) + self.log_error(os.path.basename(file), + translate('SongsPlugin.PowerSongImport', + 'Invalid {text} file. Unexpected byte value.').format(text=ps_string)) break else: if label == 'TITLE': @@ -131,19 +131,20 @@ class PowerSongImport(SongImport): continue # Check that file had TITLE field if not self.title: - self.log_error(os.path.basename(file), str( - translate('SongsPlugin.PowerSongImport', 'Invalid %s file. Missing "TITLE" header.')) % ps_string) + self.log_error(os.path.basename(file), + translate('SongsPlugin.PowerSongImport', + 'Invalid {text} file. Missing "TITLE" header.').format(text=ps_string)) continue # Check that file had COPYRIGHTLINE label if not found_copyright: - self.log_error(self.title, str( - translate('SongsPlugin.PowerSongImport', 'Invalid %s file. Missing "COPYRIGHTLINE" header.')) % - ps_string) + self.log_error(self.title, + translate('SongsPlugin.PowerSongImport', + 'Invalid {text} file. Missing "COPYRIGHTLINE" header.').format(text=ps_string)) continue # Check that file had at least one verse if not self.verses: - self.log_error(self.title, str( - translate('SongsPlugin.PowerSongImport', 'Verses not found. Missing "PART" header.'))) + self.log_error(self.title, + translate('SongsPlugin.PowerSongImport', 'Verses not found. Missing "PART" header.')) continue if not self.finish(): self.log_error(self.title) diff --git a/openlp/plugins/songs/lib/importers/presentationmanager.py b/openlp/plugins/songs/lib/importers/presentationmanager.py index c26f11312..06ab3f60d 100644 --- a/openlp/plugins/songs/lib/importers/presentationmanager.py +++ b/openlp/plugins/songs/lib/importers/presentationmanager.py @@ -44,6 +44,7 @@ class PresentationManagerImport(SongImport): for file_path in self.import_source: if self.stop_import_flag: return + # TODO: Verify format() with template strings self.import_wizard.increment_progress_bar(WizardStrings.ImportingType % os.path.basename(file_path)) try: tree = etree.parse(file_path, parser=etree.XMLParser(recover=True)) @@ -90,7 +91,7 @@ class PresentationManagerImport(SongImport): verse_def = 'o' if not is_duplicate: # Only increment verse number if no duplicate verse_count[verse_def] = verse_count.get(verse_def, 0) + 1 - verse_def = '%s%d' % (verse_def, verse_count[verse_def]) + verse_def = '{verse}{count:d}'.format(verse=verse_def, count=verse_count[verse_def]) if not is_duplicate: # Only add verse if no duplicate self.add_verse(str(verse).strip(), verse_def) verse_order_list.append(verse_def) diff --git a/openlp/plugins/songs/lib/importers/propresenter.py b/openlp/plugins/songs/lib/importers/propresenter.py index 55e05a08f..02d9fa73b 100644 --- a/openlp/plugins/songs/lib/importers/propresenter.py +++ b/openlp/plugins/songs/lib/importers/propresenter.py @@ -46,6 +46,7 @@ class ProPresenterImport(SongImport): for file_path in self.import_source: if self.stop_import_flag: return + # TODO: Verify format() with template strings self.import_wizard.increment_progress_bar(WizardStrings.ImportingType % os.path.basename(file_path)) root = objectify.parse(open(file_path, 'rb')).getroot() self.process_song(root, file_path) @@ -87,7 +88,7 @@ class ProPresenterImport(SongImport): RTFData = slide.displayElements.RVTextElement.get('RTFData') rtf = base64.standard_b64decode(RTFData) words, encoding = strip_rtf(rtf.decode()) - self.add_verse(words, "v%d" % count) + self.add_verse(words, "v{count}".format(count=count)) # ProPresenter 5 elif(self.version >= 500 and self.version < 600): @@ -103,7 +104,7 @@ class ProPresenterImport(SongImport): RTFData = slide.displayElements.RVTextElement.get('RTFData') rtf = base64.standard_b64decode(RTFData) words, encoding = strip_rtf(rtf.decode()) - self.add_verse(words, "v%d" % count) + self.add_verse(words, "v{count:d}".format(count=count)) # ProPresenter 6 elif(self.version >= 600 and self.version < 700): @@ -127,7 +128,7 @@ class ProPresenterImport(SongImport): words, encoding = strip_rtf(data.decode()) break if words: - self.add_verse(words, "v%d" % count) + self.add_verse(words, "v{count:d}".format(count=count)) if not self.finish(): self.log_error(self.import_source) diff --git a/openlp/plugins/songs/lib/importers/songimport.py b/openlp/plugins/songs/lib/importers/songimport.py index 835386b26..c9ef382a7 100644 --- a/openlp/plugins/songs/lib/importers/songimport.py +++ b/openlp/plugins/songs/lib/importers/songimport.py @@ -117,7 +117,7 @@ class SongImport(QtCore.QObject): self.import_wizard.error_report_text_edit.setVisible(True) self.import_wizard.error_copy_to_button.setVisible(True) self.import_wizard.error_save_to_button.setVisible(True) - self.import_wizard.error_report_text_edit.append('- %s (%s)' % (file_path, reason)) + self.import_wizard.error_report_text_edit.append('- {path} ({error})'.format(path=file_path, error=reason)) def stop_import(self): """ @@ -326,10 +326,11 @@ class SongImport(QtCore.QObject): if not self.check_complete(): self.set_defaults() return False - log.info('committing song %s to database', self.title) + log.info('committing song {title} to database'.format(title=self.title)) song = Song() song.title = self.title if self.import_wizard is not None: + # TODO: Verify format() with template variables self.import_wizard.increment_progress_bar(WizardStrings.ImportingType % song.title) song.alternate_title = self.alternate_title # Values will be set when cleaning the song. @@ -344,11 +345,11 @@ class SongImport(QtCore.QObject): if verse_def[0].lower() in VerseType.tags: verse_tag = verse_def[0].lower() else: - new_verse_def = '%s%d' % (VerseType.tags[VerseType.Other], other_count) + new_verse_def = '{tag}{count:d}'.format(tag=VerseType.tags[VerseType.Other], count=other_count) verses_changed_to_other[verse_def] = new_verse_def other_count += 1 verse_tag = VerseType.tags[VerseType.Other] - log.info('Versetype %s changing to %s', verse_def, new_verse_def) + log.info('Versetype {old} changing to {new}'.format(old=verse_def, new=new_verse_def)) verse_def = new_verse_def sxml.add_verse_to_lyrics(verse_tag, verse_def[1:], verse_text, lang) song.lyrics = str(sxml.extract_xml(), 'utf-8') diff --git a/openlp/plugins/songs/lib/importers/songshowplus.py b/openlp/plugins/songs/lib/importers/songshowplus.py index d9a205e22..02b35fd9e 100644 --- a/openlp/plugins/songs/lib/importers/songshowplus.py +++ b/openlp/plugins/songs/lib/importers/songshowplus.py @@ -101,6 +101,7 @@ class SongShowPlusImport(SongImport): self.other_count = 0 self.other_list = {} file_name = os.path.split(file)[1] + # TODO: Verify format() with template variables self.import_wizard.increment_progress_bar(WizardStrings.ImportingType % file_name, 0) song_data = open(file, 'rb') while True: @@ -145,13 +146,16 @@ class SongShowPlusImport(SongImport): if match: self.ccli_number = int(match.group()) else: - log.warning("Can't parse CCLI Number from string: %s" % self.decode(data)) + log.warning("Can't parse CCLI Number from string: {text}".format(text=self.decode(data))) elif block_key == VERSE: - self.add_verse(self.decode(data), "%s%s" % (VerseType.tags[VerseType.Verse], verse_no)) + self.add_verse(self.decode(data), "{tag}{number}".format(tag=VerseType.tags[VerseType.Verse], + number=verse_no)) elif block_key == CHORUS: - self.add_verse(self.decode(data), "%s%s" % (VerseType.tags[VerseType.Chorus], verse_no)) + self.add_verse(self.decode(data), "{tag}{number}".format(tag=VerseType.tags[VerseType.Chorus], + number=verse_no)) elif block_key == BRIDGE: - self.add_verse(self.decode(data), "%s%s" % (VerseType.tags[VerseType.Bridge], verse_no)) + self.add_verse(self.decode(data), "{tag}{number}".format(tag=VerseType.tags[VerseType.Bridge], + number=verse_no)) elif block_key == TOPIC: self.topics.append(self.decode(data)) elif block_key == COMMENTS: @@ -170,7 +174,7 @@ class SongShowPlusImport(SongImport): verse_tag = self.to_openlp_verse_tag(verse_name) self.add_verse(self.decode(data), verse_tag) else: - log.debug("Unrecognised blockKey: %s, data: %s" % (block_key, data)) + log.debug("Unrecognised blockKey: {key}, data: {data}".format(key=block_key, data=data)) song_data.seek(next_block_starts) self.verse_order_list = self.ssp_verse_order_list song_data.close() diff --git a/openlp/plugins/songs/lib/importers/sundayplus.py b/openlp/plugins/songs/lib/importers/sundayplus.py index 1f10004e7..c79006fff 100644 --- a/openlp/plugins/songs/lib/importers/sundayplus.py +++ b/openlp/plugins/songs/lib/importers/sundayplus.py @@ -141,7 +141,7 @@ class SundayPlusImport(SongImport): if len(value): verse_type = VerseType.tags[VerseType.from_loose_input(value[0])] if len(value) >= 2 and value[-1] in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']: - verse_type = "%s%s" % (verse_type, value[-1]) + verse_type = "{verse}{value}".format(verse=verse_type, value=value[-1]) elif name == 'HOTKEY': value = self.decode(value).strip() # HOTKEY always appears after MARKER_NAME, so it diff --git a/openlp/plugins/songs/lib/importers/videopsalm.py b/openlp/plugins/songs/lib/importers/videopsalm.py index 0bc581239..60c8e27e4 100644 --- a/openlp/plugins/songs/lib/importers/videopsalm.py +++ b/openlp/plugins/songs/lib/importers/videopsalm.py @@ -115,8 +115,8 @@ class VideoPsalmImport(SongImport): for verse in song['Verses']: self.add_verse(verse['Text'], 'v') if not self.finish(): - self.log_error('Could not import %s' % self.title) + self.log_error('Could not import {title}'.format(title=self.title)) except Exception as e: - self.log_error(translate('SongsPlugin.VideoPsalmImport', 'File %s' % file.name), - translate('SongsPlugin.VideoPsalmImport', 'Error: %s') % e) + self.log_error(translate('SongsPlugin.VideoPsalmImport', 'File {name}').format(name=file.name), + translate('SongsPlugin.VideoPsalmImport', 'Error: {error}').format(error=e)) song_file.close() diff --git a/openlp/plugins/songs/lib/importers/wordsofworship.py b/openlp/plugins/songs/lib/importers/wordsofworship.py index 6135ae2b8..43d84179e 100644 --- a/openlp/plugins/songs/lib/importers/wordsofworship.py +++ b/openlp/plugins/songs/lib/importers/wordsofworship.py @@ -108,8 +108,8 @@ class WordsOfWorshipImport(SongImport): if song_data.read(19).decode() != 'WoW File\nSong Words': self.log_error(source, translate('SongsPlugin.WordsofWorshipSongImport', - 'Invalid Words of Worship song file. Missing "%s" header.') - % 'WoW File\\nSong Words') + 'Invalid Words of Worship song file. Missing "{text}" ' + 'header.').format(text='WoW File\\nSong Words')) continue # Seek to byte which stores number of blocks in the song song_data.seek(56) @@ -118,8 +118,8 @@ class WordsOfWorshipImport(SongImport): if song_data.read(16).decode() != 'CSongDoc::CBlock': self.log_error(source, translate('SongsPlugin.WordsofWorshipSongImport', - 'Invalid Words of Worship song file. Missing "%s" string.') - % 'CSongDoc::CBlock') + 'Invalid Words of Worship song file. Missing "{text}" ' + 'string.').format(text='CSongDoc::CBlock')) continue # Seek to the beginning of the first block song_data.seek(82) diff --git a/openlp/plugins/songs/lib/importers/worshipassistant.py b/openlp/plugins/songs/lib/importers/worshipassistant.py index 671b6d9cf..2374131c9 100644 --- a/openlp/plugins/songs/lib/importers/worshipassistant.py +++ b/openlp/plugins/songs/lib/importers/worshipassistant.py @@ -91,11 +91,11 @@ class WorshipAssistantImport(SongImport): records = list(songs_reader) except csv.Error as e: self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Error reading CSV file.'), - translate('SongsPlugin.WorshipAssistantImport', 'Line %d: %s') % - (songs_reader.line_num, e)) + translate('SongsPlugin.WorshipAssistantImport', + 'Line {number:d}: {error}').format(number=songs_reader.line_num, error=e)) return num_records = len(records) - log.info('%s records found in CSV file' % num_records) + log.info('{count} records found in CSV file'.format(count=num_records)) self.import_wizard.progress_bar.setMaximum(num_records) # Create regex to strip html tags re_html_strip = re.compile(r'<[^>]+>') @@ -122,12 +122,14 @@ class WorshipAssistantImport(SongImport): verse_order_list = [x.strip() for x in record['ROADMAP'].split(',')] lyrics = record['LYRICS2'] except UnicodeDecodeError as e: - self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Record %d' % index), - translate('SongsPlugin.WorshipAssistantImport', 'Decoding error: %s') % e) + self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Record {count:d}').format(count=index), + translate('SongsPlugin.WorshipAssistantImport', + 'Decoding error: {error}').format(error=e)) continue except TypeError as e: self.log_error(translate('SongsPlugin.WorshipAssistantImport', - 'File not valid WorshipAssistant CSV format.'), 'TypeError: %s' % e) + 'File not valid WorshipAssistant CSV format.'), + 'TypeError: {error}'.format(error=e)) return verse = '' used_verses = [] @@ -180,6 +182,7 @@ class WorshipAssistantImport(SongImport): cleaned_verse_order_list.append(verse) self.verse_order_list = cleaned_verse_order_list if not self.finish(): - self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Record %d') % index + + self.log_error(translate('SongsPlugin.WorshipAssistantImport', + 'Record {count:d}').format(count=index) + (': "' + self.title + '"' if self.title else '')) songs_file.close() diff --git a/openlp/plugins/songs/lib/importers/worshipcenterpro.py b/openlp/plugins/songs/lib/importers/worshipcenterpro.py index e932b8895..df04823e8 100644 --- a/openlp/plugins/songs/lib/importers/worshipcenterpro.py +++ b/openlp/plugins/songs/lib/importers/worshipcenterpro.py @@ -49,9 +49,11 @@ class WorshipCenterProImport(SongImport): Receive a single file to import. """ try: - conn = pyodbc.connect('DRIVER={Microsoft Access Driver (*.mdb)};DBQ=%s' % self.import_source) + conn = pyodbc.connect('DRIVER={Microsoft Access Driver (*.mdb)};' + 'DBQ={source}'.format(source=self.import_source)) except (pyodbc.DatabaseError, pyodbc.IntegrityError, pyodbc.InternalError, pyodbc.OperationalError) as e: - log.warning('Unable to connect the WorshipCenter Pro database %s. %s', self.import_source, str(e)) + log.warning('Unable to connect the WorshipCenter Pro ' + 'database {source}. {error}'.format(source=self.import_source, error=str(e))) # Unfortunately no specific exception type self.log_error(self.import_source, translate('SongsPlugin.WorshipCenterProImport', 'Unable to connect the WorshipCenter Pro database.')) diff --git a/openlp/plugins/songs/lib/importers/zionworx.py b/openlp/plugins/songs/lib/importers/zionworx.py index 429c8a55a..30ac8c250 100644 --- a/openlp/plugins/songs/lib/importers/zionworx.py +++ b/openlp/plugins/songs/lib/importers/zionworx.py @@ -84,10 +84,11 @@ class ZionWorxImport(SongImport): records = list(songs_reader) except csv.Error as e: self.log_error(translate('SongsPlugin.ZionWorxImport', 'Error reading CSV file.'), - translate('SongsPlugin.ZionWorxImport', 'Line %d: %s') % (songs_reader.line_num, e)) + translate('SongsPlugin.ZionWorxImport', + 'Line {number:d}: {error}').format(number=songs_reader.line_num, error=e)) return num_records = len(records) - log.info('%s records found in CSV file' % num_records) + log.info('{count} records found in CSV file'.format(count=num_records)) self.import_wizard.progress_bar.setMaximum(num_records) for index, record in enumerate(records, 1): if self.stop_import_flag: @@ -101,12 +102,12 @@ class ZionWorxImport(SongImport): self.add_copyright(self._decode(record['Copyright'])) lyrics = self._decode(record['Lyrics']) except UnicodeDecodeError as e: - self.log_error(translate('SongsPlugin.ZionWorxImport', 'Record %d' % index), - translate('SongsPlugin.ZionWorxImport', 'Decoding error: %s') % e) + self.log_error(translate('SongsPlugin.ZionWorxImport', 'Record {index}').format(index=index), + translate('SongsPlugin.ZionWorxImport', 'Decoding error: {error}').format(error=e)) continue except TypeError as e: - self.log_error(translate( - 'SongsPlugin.ZionWorxImport', 'File not valid ZionWorx CSV format.'), 'TypeError: %s' % e) + self.log_error(translate('SongsPlugin.ZionWorxImport', 'File not valid ZionWorx CSV format.'), + 'TypeError: {error}'.format(error=e)) return verse = '' for line in lyrics.splitlines(): diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 11deeb31d..f52abb86f 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -129,7 +129,7 @@ class SongMediaItem(MediaManagerItem): self.display_copyright_symbol = Settings().value(self.settings_section + '/display copyright symbol') def retranslateUi(self): - self.search_text_label.setText('%s:' % UiStrings().Search) + self.search_text_label.setText('{text}:'.format(text=UiStrings().Search)) self.search_text_button.setText(UiStrings().Search) self.maintenance_action.setText(SongStrings.SongMaintenance) self.maintenance_action.setToolTip(translate('SongsPlugin.MediaItem', @@ -166,12 +166,14 @@ class SongMediaItem(MediaManagerItem): translate('SongsPlugin.MediaItem', 'CCLI number'), translate('SongsPlugin.MediaItem', 'Search CCLI number...')) ]) - self.search_text_edit.set_current_search_type(Settings().value('%s/last search type' % self.settings_section)) + self.search_text_edit.set_current_search_type( + Settings().value('{section}/last search type'.format(section=self.settings_section))) self.config_update() def on_search_text_button_clicked(self): # Save the current search type to the configuration. - Settings().setValue('%s/last search type' % self.settings_section, self.search_text_edit.current_search_type()) + Settings().setValue('{section}/last search type'.format(section=self.settings_section), + self.search_text_edit.current_search_type()) # Reload the list considering the new search type. search_keywords = str(self.search_text_edit.displayText()) search_type = self.search_text_edit.current_search_type() @@ -181,31 +183,31 @@ class SongMediaItem(MediaManagerItem): self.display_results_song(search_results) elif search_type == SongSearch.Titles: log.debug('Titles Search') - search_string = '%' + clean_string(search_keywords) + '%' + search_string = '%{text}%'.format(text=clean_string(search_keywords)) search_results = self.plugin.manager.get_all_objects(Song, Song.search_title.like(search_string)) self.display_results_song(search_results) elif search_type == SongSearch.Lyrics: log.debug('Lyrics Search') - search_string = '%' + clean_string(search_keywords) + '%' + search_string = '%{text}%'.format(text=clean_string(search_keywords)) search_results = self.plugin.manager.get_all_objects(Song, Song.search_lyrics.like(search_string)) self.display_results_song(search_results) elif search_type == SongSearch.Authors: log.debug('Authors Search') - search_string = '%' + search_keywords + '%' + search_string = '%{text}%'.format(text=search_keywords) search_results = self.plugin.manager.get_all_objects( Author, Author.display_name.like(search_string)) self.display_results_author(search_results) elif search_type == SongSearch.Topics: log.debug('Topics Search') - search_string = '%' + search_keywords + '%' + search_string = '%{text}%'.format(text=search_keywords) search_results = self.plugin.manager.get_all_objects( Topic, Topic.name.like(search_string)) self.display_results_topic(search_results) elif search_type == SongSearch.Books: log.debug('Songbook Search') search_keywords = search_keywords.rpartition(' ') - search_book = search_keywords[0] + '%' - search_entry = search_keywords[2] + '%' + search_book = '{text}%'.format(text=search_keywords[0]) + search_entry = '{text}%'.format(text=search_keywords[2]) search_results = (self.plugin.manager.session.query(SongBookEntry.entry, Book.name, Song.title, Song.id) .join(Song) .join(Book) @@ -214,26 +216,26 @@ class SongMediaItem(MediaManagerItem): self.display_results_book(search_results) elif search_type == SongSearch.Themes: log.debug('Theme Search') - search_string = '%' + search_keywords + '%' + search_string = '%{text}%'.format(text=search_keywords) search_results = self.plugin.manager.get_all_objects( Song, Song.theme_name.like(search_string)) self.display_results_themes(search_results) elif search_type == SongSearch.Copyright: log.debug('Copyright Search') - search_string = '%' + search_keywords + '%' + search_string = '%{text}%'.format(text=search_keywords) search_results = self.plugin.manager.get_all_objects( Song, and_(Song.copyright.like(search_string), Song.copyright != '')) self.display_results_song(search_results) elif search_type == SongSearch.CCLInumber: log.debug('CCLI number Search') - search_string = '%' + search_keywords + '%' + search_string = '%{text}%'.format(text=search_keywords) search_results = self.plugin.manager.get_all_objects( Song, and_(Song.ccli_number.like(search_string), Song.ccli_number != '')) self.display_results_cclinumber(search_results) self.check_search_result() def search_entire(self, search_keywords): - search_string = '%' + clean_string(search_keywords) + '%' + search_string = '%{text}%'.format(text=clean_string(search_keywords)) return self.plugin.manager.get_all_objects( Song, or_(Song.search_title.like(search_string), Song.search_lyrics.like(search_string), Song.comments.like(search_string))) @@ -272,7 +274,8 @@ class SongMediaItem(MediaManagerItem): if song.temporary: continue author_list = [author.display_name for author in song.authors] - song_detail = '%s (%s)' % (song.title, create_separated_list(author_list)) if author_list else song.title + text = create_separated_list(author_list) if author_list else song.title + song_detail = '{title} ({author})'.format(title=song.title, author=text) song_name = QtWidgets.QListWidgetItem(song_detail) song_name.setData(QtCore.Qt.UserRole, song.id) self.list_view.addItem(song_name) @@ -305,7 +308,7 @@ class SongMediaItem(MediaManagerItem): # Do not display temporary songs if song.temporary: continue - song_detail = '%s (%s)' % (author.display_name, song.title) + song_detail = '{author} ({title})'.format(author=author.display_name, title=song.title) song_name = QtWidgets.QListWidgetItem(song_detail) song_name.setData(QtCore.Qt.UserRole, song.id) self.list_view.addItem(song_name) @@ -325,7 +328,8 @@ class SongMediaItem(MediaManagerItem): self.list_view.clear() search_results.sort(key=get_songbook_key) for result in search_results: - song_detail = '%s #%s: %s' % (result[1], result[0], result[2]) + song_detail = '{result1} #{result0}: {result2}'.format(result1=result[1], result0=result[0], + result2=result[2]) song_name = QtWidgets.QListWidgetItem(song_detail) song_name.setData(QtCore.Qt.UserRole, result[3]) self.list_view.addItem(song_name) @@ -354,7 +358,7 @@ class SongMediaItem(MediaManagerItem): # Do not display temporary songs if song.temporary: continue - song_detail = '%s (%s)' % (topic.name, song.title) + song_detail = '{topic} ({title})'.format(topic=topic.name, title=song.title) song_name = QtWidgets.QListWidgetItem(song_detail) song_name.setData(QtCore.Qt.UserRole, song.id) self.list_view.addItem(song_name) @@ -377,7 +381,7 @@ class SongMediaItem(MediaManagerItem): # Do not display temporary songs if song.temporary: continue - song_detail = '%s (%s)' % (song.theme_name, song.title) + song_detail = '{theme} ({song})'.format(theme=song.theme_name, song=song.title) song_name = QtWidgets.QListWidgetItem(song_detail) song_name.setData(QtCore.Qt.UserRole, song.id) self.list_view.addItem(song_name) @@ -400,7 +404,7 @@ class SongMediaItem(MediaManagerItem): # Do not display temporary songs if song.temporary: continue - song_detail = '%s (%s)' % (song.ccli_number, song.title) + song_detail = '{ccli} ({song})'.format(ccli=song.ccli_number, song=song.title) song_name = QtWidgets.QListWidgetItem(song_detail) song_name.setData(QtCore.Qt.UserRole, song.id) self.list_view.addItem(song_name) @@ -456,7 +460,7 @@ class SongMediaItem(MediaManagerItem): Called by ServiceManager or SlideController by event passing the Song Id in the payload along with an indicator to say which type of display is required. """ - log.debug('on_remote_edit for song %s' % song_id) + log.debug('on_remote_edit for song {song}'.format(song=song_id)) song_id = int(song_id) valid = self.plugin.manager.get_object(Song, song_id) if valid: @@ -499,7 +503,8 @@ class SongMediaItem(MediaManagerItem): if QtWidgets.QMessageBox.question( self, UiStrings().ConfirmDelete, translate('SongsPlugin.MediaItem', - 'Are you sure you want to delete the "%d" selected song(s)?') % len(items), + 'Are you sure you want to delete the "{items:d}" ' + 'selected song(s)?').format(items=len(items)), QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No), QtWidgets.QMessageBox.Yes) == QtWidgets.QMessageBox.No: return @@ -524,8 +529,9 @@ class SongMediaItem(MediaManagerItem): old_song = self.plugin.manager.get_object(Song, item_id) song_xml = self.open_lyrics.song_to_xml(old_song) new_song = self.open_lyrics.xml_to_song(song_xml) - new_song.title = '%s <%s>' % \ - (new_song.title, translate('SongsPlugin.MediaItem', 'copy', 'For song cloning')) + new_song.title = '{title} <{text}>'.format(title=new_song.title, + text=translate('SongsPlugin.MediaItem', + 'copy', 'For song cloning')) # Copy audio files from the old to the new song if len(old_song.media_files) > 0: save_path = os.path.join(AppLocation.get_section_data_path(self.plugin.name), 'audio', str(new_song.id)) @@ -552,7 +558,8 @@ class SongMediaItem(MediaManagerItem): :param remote: Triggered from remote :param context: Why is it being generated """ - log.debug('generate_slide_data: %s, %s, %s' % (service_item, item, self.remote_song)) + log.debug('generate_slide_data: {service}, {item}, {remote}'.format(service=service_item, item=item, + remote=self.remote_song)) item_id = self._get_id_of_item_to_generate(item, self.remote_song) service_item.add_capability(ItemCapabilities.CanEdit) service_item.add_capability(ItemCapabilities.CanPreview) @@ -581,7 +588,7 @@ class SongMediaItem(MediaManagerItem): if verse_index is None: verse_index = VerseType.from_tag(verse_tag) verse_tag = VerseType.translated_tags[verse_index].upper() - verse_def = '%s%s' % (verse_tag, verse[0]['label']) + verse_def = '{tag}{label}'.format(tag=verse_tag, label=verse[0]['label']) service_item.add_from_text(str(verse[1]), verse_def) else: # Loop through the verse list and expand the song accordingly. @@ -596,7 +603,7 @@ class SongMediaItem(MediaManagerItem): else: verse_index = VerseType.from_tag(verse[0]['type']) verse_tag = VerseType.translated_tags[verse_index] - verse_def = '%s%s' % (verse_tag, verse[0]['label']) + verse_def = '{tag}{label}'.format(tzg=verse_tag, text=verse[0]['label']) service_item.add_from_text(verse[1], verse_def) service_item.title = song.title author_list = self.generate_footer(service_item, song) @@ -639,23 +646,24 @@ class SongMediaItem(MediaManagerItem): item.raw_footer = [] item.raw_footer.append(song.title) if authors_none: - item.raw_footer.append("%s: %s" % (translate('OpenLP.Ui', 'Written by'), - create_separated_list(authors_none))) + item.raw_footer.append("{text}: {authors}".format(text=translate('OpenLP.Ui', 'Written by'), + authors=create_separated_list(authors_none))) if authors_words_music: - item.raw_footer.append("%s: %s" % (AuthorType.Types[AuthorType.WordsAndMusic], - create_separated_list(authors_words_music))) + item.raw_footer.append("{text}: {authors}".format(text=AuthorType.Types[AuthorType.WordsAndMusic], + authors=create_separated_list(authors_words_music))) if authors_words: - item.raw_footer.append("%s: %s" % (AuthorType.Types[AuthorType.Words], - create_separated_list(authors_words))) + item.raw_footer.append("{text}: {authors}".format(text=AuthorType.Types[AuthorType.Words], + authors=create_separated_list(authors_words))) if authors_music: - item.raw_footer.append("%s: %s" % (AuthorType.Types[AuthorType.Music], - create_separated_list(authors_music))) + item.raw_footer.append("{text}: {authors}".format(text=AuthorType.Types[AuthorType.Music], + authors=create_separated_list(authors_music))) if authors_translation: - item.raw_footer.append("%s: %s" % (AuthorType.Types[AuthorType.Translation], - create_separated_list(authors_translation))) + item.raw_footer.append("{text}: {authors}".format(text=AuthorType.Types[AuthorType.Translation], + authors=create_separated_list(authors_translation))) if song.copyright: if self.display_copyright_symbol: - item.raw_footer.append("%s %s" % (SongStrings.CopyrightSymbol, song.copyright)) + item.raw_footer.append("{symbol} {song}".format(symbol=SongStrings.CopyrightSymbol, + song=song.copyright)) else: item.raw_footer.append(song.copyright) if self.display_songbook and song.songbook_entries: diff --git a/openlp/plugins/songs/lib/openlyricsexport.py b/openlp/plugins/songs/lib/openlyricsexport.py index d5ca31e18..db1d02265 100644 --- a/openlp/plugins/songs/lib/openlyricsexport.py +++ b/openlp/plugins/songs/lib/openlyricsexport.py @@ -61,18 +61,20 @@ class OpenLyricsExport(RegistryProperties): if self.parent.stop_export_flag: return False self.parent.increment_progress_bar( - translate('SongsPlugin.OpenLyricsExport', 'Exporting "%s"...') % song.title) + translate('SongsPlugin.OpenLyricsExport', 'Exporting "{title}"...').format(title=song.title)) xml = open_lyrics.song_to_xml(song) tree = etree.ElementTree(etree.fromstring(xml.encode())) - filename = '%s (%s)' % (song.title, ', '.join([author.display_name for author in song.authors])) + filename = '{title} ({author})'.format(title=song.title, + author=', '.join([author.display_name for author in song.authors])) filename = clean_filename(filename) # Ensure the filename isn't too long for some filesystems - filename_with_ext = '%s.xml' % filename[0:250 - len(self.save_path)] + filename_with_ext = '{name}.xml'.format(name=filename[0:250 - len(self.save_path)]) # Make sure we're not overwriting an existing file conflicts = 0 while os.path.exists(os.path.join(self.save_path, filename_with_ext)): conflicts += 1 - filename_with_ext = '%s-%d.xml' % (filename[0:247 - len(self.save_path)], conflicts) + filename_with_ext = '{name}-{extra}.xml'.format(name=filename[0:247 - len(self.save_path)], + extra=conflicts) # Pass a file object, because lxml does not cope with some special # characters in the path (see lp:757673 and lp:744337). tree.write(open(os.path.join(self.save_path, filename_with_ext), 'wb'), encoding='utf-8', diff --git a/openlp/plugins/songs/lib/openlyricsxml.py b/openlp/plugins/songs/lib/openlyricsxml.py index 806df438d..51165da32 100644 --- a/openlp/plugins/songs/lib/openlyricsxml.py +++ b/openlp/plugins/songs/lib/openlyricsxml.py @@ -70,6 +70,7 @@ from openlp.plugins.songs.lib.db import Author, AuthorType, Book, Song, Topic log = logging.getLogger(__name__) NAMESPACE = 'http://openlyrics.info/namespace/2009/song' +# TODO: Verify format() with template variable NSMAP = '{' + NAMESPACE + '}' + '%s' @@ -126,7 +127,7 @@ class SongXML(object): try: self.song_xml = objectify.fromstring(xml) except etree.XMLSyntaxError: - log.exception('Invalid xml %s', xml) + log.exception('Invalid xml {text}'.format(text=xml)) xml_iter = self.song_xml.getiterator() for element in xml_iter: if element.tag == 'verse': @@ -422,7 +423,7 @@ class OpenLyrics(object): :param tags_element: Some tag elements """ available_tags = FormattingTags.get_html_tags() - start_tag = '{%s}' % tag_name + start_tag = '{{{name}}}'.format(name=tag_name) for tag in available_tags: if tag['start tag'] == start_tag: # Create new formatting tag in openlyrics xml. @@ -449,18 +450,18 @@ class OpenLyrics(object): xml_tags = tags_element.xpath('tag/attribute::name') # Some formatting tag has only starting part e.g.
. Handle this case. if tag in end_tags: - text = text.replace('{%s}' % tag, '' % tag) + text = text.replace('{{{tag}}}'.format(tag=tag), ''.format(tag=tag)) else: - text = text.replace('{%s}' % tag, '' % tag) + text = text.replace('{{{tag}}}'.format(tag=tag), ''.format(tag=tag)) # Add tag to element if tag not present. if tag not in xml_tags: self._add_tag_to_formatting(tag, tags_element) # Replace end tags. for tag in end_tags: - text = text.replace('{/%s}' % tag, '') + text = text.replace('{/{tag}}'.format(tag=tag), '') # Replace \n with
. text = text.replace('\n', '
') - element = etree.XML('%s' % text) + element = etree.XML('{text}'.format(text=text)) verse_element.append(element) return element @@ -566,9 +567,9 @@ class OpenLyrics(object): name = tag.get('name') if name is None: continue - start_tag = '{%s}' % name[:5] + start_tag = '{{{name}}}'.format(name=name[:5]) # Some tags have only start tag e.g. {br} - end_tag = '{/' + name[:5] + '}' if hasattr(tag, 'close') else '' + end_tag = '{{/{name}}}'.format(name=name[:5]) if hasattr(tag, 'close') else '' openlp_tag = { 'desc': name, 'start tag': start_tag, @@ -604,26 +605,30 @@ class OpenLyrics(object): text = '' use_endtag = True # Skip elements - not yet supported. + # TODO: Verify format() with template variables if element.tag == NSMAP % 'comment': if element.tail: # Append tail text at chord element. text += element.tail return text # Skip element - not yet supported. + # TODO: Verify format() with template variables elif element.tag == NSMAP % 'chord': if element.tail: # Append tail text at chord element. text += element.tail return text # Convert line breaks
to \n. + # TODO: Verify format() with template variables elif newlines and element.tag == NSMAP % 'br': text += '\n' if element.tail: text += element.tail return text # Start formatting tag. + # TODO: Verify format() with template variables if element.tag == NSMAP % 'tag': - text += '{%s}' % element.get('name') + text += '{{{name}}}'.format(name=element.get('name')) # Some formattings may have only start tag. # Handle this case if element has no children and contains no text. if not element and not element.text: @@ -636,8 +641,9 @@ class OpenLyrics(object): # Use recursion since nested formatting tags are allowed. text += self._process_lines_mixed_content(child, newlines) # Append text from tail and add formatting end tag. + # TODO: Verify format() with template variables if element.tag == NSMAP % 'tag' and use_endtag: - text += '{/%s}' % element.get('name') + text += '{/{{name}}}'.format(name=element.get('name')) # Append text from tail. if element.tail: text += element.tail @@ -663,6 +669,7 @@ class OpenLyrics(object): # Loop over the "line" elements removing comments and chords. for line in element: # Skip comment lines. + # TODO: Verify format() with template variables if line.tag == NSMAP % 'comment': continue if text: diff --git a/openlp/plugins/songs/lib/songselect.py b/openlp/plugins/songs/lib/songselect.py index ca417b504..60f4383d2 100644 --- a/openlp/plugins/songs/lib/songselect.py +++ b/openlp/plugins/songs/lib/songselect.py @@ -78,7 +78,7 @@ class SongSelectImport(object): try: login_page = BeautifulSoup(self.opener.open(LOGIN_URL).read(), 'lxml') except (TypeError, URLError) as e: - log.exception('Could not login to SongSelect, %s', e) + log.exception('Could not login to SongSelect, {error}'.format(error=e)) return False if callback: callback() @@ -92,7 +92,7 @@ class SongSelectImport(object): try: posted_page = BeautifulSoup(self.opener.open(LOGIN_URL, data.encode('utf-8')).read(), 'lxml') except (TypeError, URLError) as e: - log.exception('Could not login to SongSelect, %s', e) + log.exception('Could not login to SongSelect, {error}'.format(error=e)) return False if callback: callback() @@ -105,7 +105,7 @@ class SongSelectImport(object): try: self.opener.open(LOGOUT_URL) except (TypeError, URLError) as e: - log.exception('Could not log of SongSelect, %s', e) + log.exception('Could not log of SongSelect, {error}'.format(error=e)) def search(self, search_text, max_results, callback=None): """ @@ -127,7 +127,7 @@ class SongSelectImport(object): results_page = BeautifulSoup(self.opener.open(SEARCH_URL + '?' + urlencode(params)).read(), 'lxml') search_results = results_page.find_all('li', 'result pane') except (TypeError, URLError) as e: - log.exception('Could not search SongSelect, %s', e) + log.exception('Could not search SongSelect, {error}'.format(error=e)) search_results = None if not search_results: break @@ -158,7 +158,7 @@ class SongSelectImport(object): try: song_page = BeautifulSoup(self.opener.open(song['link']).read(), 'lxml') except (TypeError, URLError) as e: - log.exception('Could not get song from SongSelect, %s', e) + log.exception('Could not get song from SongSelect, {error}'.format(error=e)) return None if callback: callback() @@ -203,7 +203,7 @@ class SongSelectImport(object): verse_type = VerseType.from_loose_input(verse_type) verse_number = int(verse_number) song_xml.add_verse_to_lyrics(VerseType.tags[verse_type], verse_number, verse['lyrics']) - verse_order.append('%s%s' % (VerseType.tags[verse_type], verse_number)) + verse_order.append('{tag}{number}'.format(tag=VerseType.tags[verse_type], number=verse_number)) db_song.verse_order = ' '.join(verse_order) db_song.lyrics = song_xml.extract_xml() clean_song(self.db_manager, db_song) diff --git a/openlp/plugins/songs/lib/songstab.py b/openlp/plugins/songs/lib/songstab.py index 5a8c18a50..61739abeb 100644 --- a/openlp/plugins/songs/lib/songstab.py +++ b/openlp/plugins/songs/lib/songstab.py @@ -74,8 +74,8 @@ class SongsTab(SettingsTab): 'Import missing songs from service files')) self.display_songbook_check_box.setText(translate('SongsPlugin.SongsTab', 'Display songbook in footer')) self.display_copyright_check_box.setText(translate('SongsPlugin.SongsTab', - 'Display "%s" symbol before copyright info') % - SongStrings.CopyrightSymbol) + 'Display "{symbol}" symbol before copyright ' + 'info').format(symbol=SongStrings.CopyrightSymbol)) def on_search_as_type_check_box_changed(self, check_state): self.song_search = (check_state == QtCore.Qt.Checked) diff --git a/tests/functional/openlp_core_lib/test_projectordb.py b/tests/functional/openlp_core_lib/test_projectordb.py index 7f3f927aa..7c677177e 100644 --- a/tests/functional/openlp_core_lib/test_projectordb.py +++ b/tests/functional/openlp_core_lib/test_projectordb.py @@ -265,3 +265,22 @@ class TestProjectorDB(TestCase): 'manufacturer="IN YOUR DREAMS", model="OpenLP", other="None", sources="None", ' 'source_list="[]") >', 'Projector.__repr__() should have returned a proper representation string') + + def projectorsource_repr_test(self): + """ + Test ProjectorSource.__repr__() text + """ + # GIVEN: test setup + projector1 = Projector(**TEST1_DATA) + self.projector.add_projector(projector1) + item = self.projector.get_projector_by_id(projector1.id) + item_id = item.id + + # WHEN: A source entry is saved for item + source = ProjectorSource(projector_id=item_id, code='11', text='First RGB source') + self.projector.add_source(source) + + # THEN: __repr__ should return a proper string + self.assertEqual(str(source), + '', + 'ProjectorSource.__repr__)_ should have returned a proper representation string') From 96333b3f082d3d1c6ab4f2b6c0b13397904cd41e Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Fri, 27 May 2016 01:29:31 -0700 Subject: [PATCH 24/62] Oops in foramt - missed escaping brace(s) --- openlp/plugins/songs/lib/openlyricsxml.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openlp/plugins/songs/lib/openlyricsxml.py b/openlp/plugins/songs/lib/openlyricsxml.py index 51165da32..5adffb300 100644 --- a/openlp/plugins/songs/lib/openlyricsxml.py +++ b/openlp/plugins/songs/lib/openlyricsxml.py @@ -458,7 +458,7 @@ class OpenLyrics(object): self._add_tag_to_formatting(tag, tags_element) # Replace end tags. for tag in end_tags: - text = text.replace('{/{tag}}'.format(tag=tag), '
') + text = text.replace('{/{tag}}}'.format(tag=tag), '
') # Replace \n with
. text = text.replace('\n', '
') element = etree.XML('{text}'.format(text=text)) @@ -643,7 +643,7 @@ class OpenLyrics(object): # Append text from tail and add formatting end tag. # TODO: Verify format() with template variables if element.tag == NSMAP % 'tag' and use_endtag: - text += '{/{{name}}}'.format(name=element.get('name')) + text += '{/{name}}}'.format(name=element.get('name')) # Append text from tail. if element.tail: text += element.tail From 546030b64db4162af72d169dbc6b692a27aa69cb Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Fri, 27 May 2016 22:50:31 -0700 Subject: [PATCH 25/62] Convert strings to python3 in plugins part 4 --- openlp/core/lib/projector/pjlink1.py | 4 +- .../songusage/forms/songusagedetailform.py | 21 ++--- .../openlp_core_lib/test_projector_pjlink1.py | 78 +++++++++++++++++-- 3 files changed, 87 insertions(+), 16 deletions(-) diff --git a/openlp/core/lib/projector/pjlink1.py b/openlp/core/lib/projector/pjlink1.py index bbf2ccc64..ce06b3625 100644 --- a/openlp/core/lib/projector/pjlink1.py +++ b/openlp/core/lib/projector/pjlink1.py @@ -58,7 +58,7 @@ SocketSTate = QAbstractSocket.SocketState PJLINK_PREFIX = '%' PJLINK_CLASS = '1' -PJLINK_HEADER = '%s%s' % (PJLINK_PREFIX, PJLINK_CLASS) +PJLINK_HEADER = '{prefix}{linkclass}'.format(prefix=PJLINK_PREFIX, linkclass=PJLINK_CLASS) PJLINK_SUFFIX = CR @@ -160,8 +160,10 @@ class PJLink1(QTcpSocket): self.source = None self.other_info = None if hasattr(self, 'timer'): + log.debug('({ip}): Calling timer.stop()'.format(ip=self.ip)) self.timer.stop() if hasattr(self, 'socket_timer'): + log.debug('({ip}): Calling socket_timer.stop()'.format(ip=self.ip)) self.socket_timer.stop() self.send_queue = [] self.send_busy = False diff --git a/openlp/plugins/songusage/forms/songusagedetailform.py b/openlp/plugins/songusage/forms/songusagedetailform.py index 8edf9775f..541c139c7 100644 --- a/openlp/plugins/songusage/forms/songusagedetailform.py +++ b/openlp/plugins/songusage/forms/songusagedetailform.py @@ -81,9 +81,10 @@ class SongUsageDetailForm(QtWidgets.QDialog, Ui_SongUsageDetailDialog, RegistryP ) return check_directory_exists(path) - file_name = translate('SongUsagePlugin.SongUsageDetailForm', 'usage_detail_%s_%s.txt') % \ - (self.from_date_calendar.selectedDate().toString('ddMMyyyy'), - self.to_date_calendar.selectedDate().toString('ddMMyyyy')) + file_name = translate('SongUsagePlugin.SongUsageDetailForm', + 'usage_detail_{old}_{new}.txt' + ).format(old=self.from_date_calendar.selectedDate().toString('ddMMyyyy'), + new=self.to_date_calendar.selectedDate().toString('ddMMyyyy')) Settings().setValue(self.plugin.settings_section + '/from date', self.from_date_calendar.selectedDate()) Settings().setValue(self.plugin.settings_section + '/to date', self.to_date_calendar.selectedDate()) usage = self.plugin.manager.get_all_objects( @@ -95,21 +96,23 @@ class SongUsageDetailForm(QtWidgets.QDialog, Ui_SongUsageDetailDialog, RegistryP try: file_handle = open(report_file_name, 'wb') for instance in usage: - record = '\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",' \ - '\"%s\",\"%s\"\n' % \ - (instance.usagedate, instance.usagetime, instance.title, instance.copyright, - instance.ccl_number, instance.authors, instance.plugin_name, instance.source) + record = ('\"{date}\",\"{time}\",\"{title}\",\"{copyright}\",\"{ccli}\",\"{authors}\",' + '\"{name}\",\"{source}\"\n').format(date=instance.usagedate, time=instance.usagetime, + title=instance.title, copyright=instance.copyright, + ccli=instance.ccl_number, authors=instance.authors, + name=instance.plugin_name, source=instance.source) file_handle.write(record.encode('utf-8')) self.main_window.information_message( translate('SongUsagePlugin.SongUsageDetailForm', 'Report Creation'), translate('SongUsagePlugin.SongUsageDetailForm', - 'Report \n%s \nhas been successfully created. ') % report_file_name + 'Report \n{name} \nhas been successfully created. ').format(name=report_file_name) ) except OSError as ose: log.exception('Failed to write out song usage records') critical_error_message_box(translate('SongUsagePlugin.SongUsageDetailForm', 'Report Creation Failed'), translate('SongUsagePlugin.SongUsageDetailForm', - 'An error occurred while creating the report: %s') % ose.strerror) + 'An error occurred while creating the report: {error}' + ).format(error=ose.strerror)) finally: if file_handle: file_handle.close() diff --git a/tests/functional/openlp_core_lib/test_projector_pjlink1.py b/tests/functional/openlp_core_lib/test_projector_pjlink1.py index ac1059656..45dbde093 100644 --- a/tests/functional/openlp_core_lib/test_projector_pjlink1.py +++ b/tests/functional/openlp_core_lib/test_projector_pjlink1.py @@ -34,6 +34,18 @@ from tests.resources.projector.data import TEST_PIN, TEST_SALT, TEST_CONNECT_AUT pjlink_test = PJLink1(name='test', ip='127.0.0.1', pin=TEST_PIN, no_poll=True) +class DummyTimer(object): + ''' + Dummy class to fake timers + ''' + def __init__(self, *args, **kwargs): + pass + + def start(self, *args, **kwargs): + pass + + def stop(self, *args, **kwargs): + pass class TestPJLink(TestCase): """ @@ -43,13 +55,10 @@ class TestPJLink(TestCase): @patch.object(pjlink_test, 'send_command') @patch.object(pjlink_test, 'waitForReadyRead') @patch('openlp.core.common.qmd5_hash') - def authenticated_connection_call_test(self, - mock_qmd5_hash, - mock_waitForReadyRead, - mock_send_command, + def authenticated_connection_call_test(self, mock_qmd5_hash, mock_waitForReadyRead, mock_send_command, mock_readyRead): """ - Fix for projector connect with PJLink authentication exception. Ticket 92187. + Ticket 92187: Fix for projector connect with PJLink authentication exception. """ # GIVEN: Test object pjlink = pjlink_test @@ -63,9 +72,23 @@ class TestPJLink(TestCase): self.assertTrue(mock_qmd5_hash.called_with(TEST_PIN, "Connection request should have been called with TEST_PIN")) + def projector_class_test(self): + """ + Test class version from projector + """ + # GIVEN: Test object + pjlink = pjlink_test + + # WHEN: Process class response + pjlink.process_clss('1') + + # THEN: Projector class should be set to 1 + self.assertEquals(pjlink.pjlink_class, '1', + 'Projector should have returned class=1') + def non_standard_class_reply_test(self): """ - bugfix 1550891 - CLSS request returns non-standard 'Class N' reply + Bugfix 1550891: CLSS request returns non-standard 'Class N' reply """ # GIVEN: Test object pjlink = pjlink_test @@ -264,3 +287,46 @@ class TestPJLink(TestCase): # THEN: Input selected should reflect current input self.assertEquals(pjlink.source, '1', 'Input source should be set to "1"') + + def projector_reset_information_test(self): + """ + Test reset_information() resets all information and stops timers + """ + # GIVEN: Test object and test data + pjlink = pjlink_test + pjlink.power = S_ON + pjlink.pjlink_name = 'OPENLPTEST' + pjlink.manufacturer = 'PJLINK' + pjlink.model = '1' + pjlink.shutter = True + pjlink.mute = True + pjlink.lamp = True + pjlink.fan = True + pjlink.source_available = True + pjlink.other_info = 'ANOTHER TEST' + pjlink.send_queue = True + pjlink.send_busy = True + pjlink.timer = DummyTimer() + pjlink.socket_timer = DummyTimer() + + # WHEN: reset_information() is called + with patch.object(pjlink.timer, 'stop') as mock_timer: + with patch.object(pjlink.socket_timer, 'stop') as mock_socket_timer: + pjlink.reset_information() + + # THEN: All information should be reset and timers stopped + self.assertEquals(pjlink.power, S_OFF, 'Projector power should be OFF') + self.assertIsNone(pjlink.pjlink_name, 'Projector pjlink_name should be None') + self.assertIsNone(pjlink.manufacturer, 'Projector manufacturer should be None') + self.assertIsNone(pjlink.model, 'Projector model should be None') + self.assertIsNone(pjlink.shutter, 'Projector shutter should be None') + self.assertIsNone(pjlink.mute, 'Projector shuttter should be None') + self.assertIsNone(pjlink.lamp, 'Projector lamp should be None') + self.assertIsNone(pjlink.fan, 'Projector fan should be None') + self.assertIsNone(pjlink.source_available, 'Projector source_available should be None') + self.assertIsNone(pjlink.source, 'Projector source should be None') + self.assertIsNone(pjlink.other_info, 'Projector other_info should be None') + self.assertEquals(pjlink.send_queue, [], 'Projector send_queue should be an empty list') + self.assertFalse(pjlink.send_busy, 'Projector send_busy should be False') + self.assertTrue(mock_timer.called, 'Projector timer.stop() should have been called') + self.assertTrue(mock_socket_timer.called, 'Projector socket_timer.stop() should have been called') From c27b676c8c762ebb6380123c73faea108caf41f8 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Fri, 27 May 2016 22:55:54 -0700 Subject: [PATCH 26/62] pep8 --- tests/functional/openlp_core_lib/test_projector_pjlink1.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/functional/openlp_core_lib/test_projector_pjlink1.py b/tests/functional/openlp_core_lib/test_projector_pjlink1.py index 45dbde093..7f7f0e9cf 100644 --- a/tests/functional/openlp_core_lib/test_projector_pjlink1.py +++ b/tests/functional/openlp_core_lib/test_projector_pjlink1.py @@ -34,6 +34,7 @@ from tests.resources.projector.data import TEST_PIN, TEST_SALT, TEST_CONNECT_AUT pjlink_test = PJLink1(name='test', ip='127.0.0.1', pin=TEST_PIN, no_poll=True) + class DummyTimer(object): ''' Dummy class to fake timers @@ -47,6 +48,7 @@ class DummyTimer(object): def stop(self, *args, **kwargs): pass + class TestPJLink(TestCase): """ Tests for the PJLink module From 5a6c4f90a10600801c028e30d352f2fb7e64e4f6 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Tue, 31 May 2016 18:10:31 +0200 Subject: [PATCH 27/62] Fix formatting problems --- openlp/core/ui/media/__init__.py | 1 + openlp/plugins/bibles/lib/mediaitem.py | 2 +- .../test_registryproperties.py | 21 ++++++++++++++++++- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/openlp/core/ui/media/__init__.py b/openlp/core/ui/media/__init__.py index 9e2f61ae8..248aca6f2 100644 --- a/openlp/core/ui/media/__init__.py +++ b/openlp/core/ui/media/__init__.py @@ -134,6 +134,7 @@ def format_milliseconds(milliseconds): :param milliseconds: Milliseconds to format :return: Time string in format: hh.mm.ss,ttt """ + milliseconds = int(milliseconds) seconds, millis = divmod(milliseconds, 1000) minutes, seconds = divmod(seconds, 60) hours, minutes = divmod(minutes, 60) diff --git a/openlp/plugins/bibles/lib/mediaitem.py b/openlp/plugins/bibles/lib/mediaitem.py index d6e7eb62e..d5304e867 100644 --- a/openlp/plugins/bibles/lib/mediaitem.py +++ b/openlp/plugins/bibles/lib/mediaitem.py @@ -407,7 +407,7 @@ class BibleMediaItem(MediaManagerItem): self.initialise_chapter_verse(bible, first_book['name'], first_book['book_reference_id']) def initialise_chapter_verse(self, bible, book, book_ref_id): - log.debug('initialise_chapter_verse {bible}, {book), {ref}'.format(bible=bible, book=book, ref=book_ref_id)) + log.debug('initialise_chapter_verse {bible}, {book}, {ref}'.format(bible=bible, book=book, ref=book_ref_id)) book = self.plugin.manager.get_book_by_id(bible, book_ref_id) self.chapter_count = self.plugin.manager.get_chapter_count(bible, book) verse_count = self.plugin.manager.get_verse_count_by_book_ref_id(bible, book_ref_id, 1) diff --git a/tests/functional/openlp_core_common/test_registryproperties.py b/tests/functional/openlp_core_common/test_registryproperties.py index c9cf9c1c0..0f0184876 100644 --- a/tests/functional/openlp_core_common/test_registryproperties.py +++ b/tests/functional/openlp_core_common/test_registryproperties.py @@ -25,7 +25,8 @@ Test the registry properties from unittest import TestCase from openlp.core.common import Registry, RegistryProperties -from tests.functional import MagicMock + +from tests.functional import MagicMock, patch class TestRegistryProperties(TestCase, RegistryProperties): @@ -53,7 +54,25 @@ class TestRegistryProperties(TestCase, RegistryProperties): """ # GIVEN an Empty Registry application = MagicMock() + # WHEN the application is registered Registry().register('application', application) + # THEN the application should be none self.assertEqual(self.application, application, 'The application value should match') + + @patch('openlp.core.common.registryproperties.is_win') + def application_on_windows_test(self, mocked_is_win): + """ + Test property if registry value assigned on Windows + """ + # GIVEN an Empty Registry and we're on Windows + application = MagicMock() + mocked_is_win.return_value = True + + # WHEN the application is registered + Registry().register('application', application) + + # THEN the application should be none + self.assertEqual(self.application, application, 'The application value should match') + From 672b8334fa538cb3493442525761cfdcd0e65e39 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Tue, 31 May 2016 23:40:13 +0200 Subject: [PATCH 28/62] Initial attempt to move to nose2 --- nose2.cfg | 17 +++++ tests/functional/openlp_core/test_init.py | 12 +-- .../openlp_core_common/test_actions.py | 12 +-- .../openlp_core_common/test_applocation.py | 18 ++--- .../openlp_core_common/test_common.py | 18 ++--- .../functional/openlp_core_common/test_db.py | 4 +- .../openlp_core_common/test_init.py | 38 +++++----- .../test_languagemanager.py | 4 +- .../openlp_core_common/test_registry.py | 8 +- .../openlp_core_common/test_registrymixin.py | 4 +- .../test_registryproperties.py | 6 +- .../openlp_core_common/test_settings.py | 12 +-- .../openlp_core_common/test_uistrings.py | 2 +- .../openlp_core_common/test_versionchecker.py | 2 +- tests/functional/openlp_core_lib/test_db.py | 10 +-- .../openlp_core_lib/test_file_dialog.py | 4 +- .../openlp_core_lib/test_formattingtags.py | 4 +- .../openlp_core_lib/test_htmlbuilder.py | 18 ++--- .../openlp_core_lib/test_image_manager.py | 6 +- tests/functional/openlp_core_lib/test_lib.py | 66 ++++++++--------- .../openlp_core_lib/test_mediamanageritem.py | 8 +- .../openlp_core_lib/test_pluginmanager.py | 44 +++++------ .../openlp_core_lib/test_projector_pjlink1.py | 30 ++++---- .../openlp_core_lib/test_projectordb.py | 20 ++--- .../openlp_core_lib/test_renderer.py | 12 +-- .../functional/openlp_core_lib/test_screen.py | 2 +- .../openlp_core_lib/test_serviceitem.py | 18 ++--- .../functional/openlp_core_lib/test_theme.py | 2 +- tests/functional/openlp_core_lib/test_ui.py | 26 +++---- .../openlp_core_lib/test_webpagereader.py | 18 ++--- .../openlp_core_ui/test_first_time.py | 2 +- .../openlp_core_ui/test_firsttimeform.py | 16 ++-- .../test_formattingtagscontroller.py | 8 +- .../openlp_core_ui/test_formattingtagsform.py | 4 +- .../openlp_core_ui/test_maindisplay.py | 20 ++--- .../openlp_core_ui/test_mainwindow.py | 20 ++--- .../openlp_core_ui/test_servicemanager.py | 22 +++--- .../openlp_core_ui/test_settingsform.py | 10 +-- .../openlp_core_ui/test_slidecontroller.py | 72 +++++++++--------- .../openlp_core_ui/test_themeform.py | 4 +- .../openlp_core_ui/test_thememanager.py | 18 ++--- .../openlp_core_ui_lib/test_color_button.py | 16 ++-- .../test_listpreviewwidget.py | 2 +- .../test_mediacontroller.py | 22 +++--- .../openlp_core_ui_media/test_vlcplayer.py | 74 +++++++++---------- .../openlp_core_ui_media/test_webkitplayer.py | 4 +- .../openlp_plugins/alerts/test_manager.py | 6 +- .../openlp_plugins/bibles/test_csvimport.py | 4 +- .../openlp_plugins/bibles/test_http.py | 6 +- .../openlp_plugins/bibles/test_lib.py | 8 +- .../openlp_plugins/bibles/test_mediaitem.py | 6 +- .../bibles/test_opensongimport.py | 6 +- .../openlp_plugins/bibles/test_osisimport.py | 10 +-- .../openlp_plugins/bibles/test_swordimport.py | 10 ++- .../bibles/test_versereferencelist.py | 10 +-- .../bibles/test_zefaniaimport.py | 6 +- .../openlp_plugins/custom/test_mediaitem.py | 6 +- .../openlp_plugins/images/test_imagetab.py | 4 +- .../openlp_plugins/images/test_lib.py | 22 +++--- .../openlp_plugins/media/test_mediaplugin.py | 6 +- .../presentations/test_impresscontroller.py | 10 +-- .../presentations/test_mediaitem.py | 6 +- .../presentations/test_messagelistener.py | 8 +- .../presentations/test_pdfcontroller.py | 14 ++-- .../test_powerpointcontroller.py | 18 ++--- .../presentations/test_pptviewcontroller.py | 14 ++-- .../test_presentationcontroller.py | 20 ++--- .../openlp_plugins/remotes/test_remotetab.py | 8 +- .../openlp_plugins/remotes/test_router.py | 30 ++++---- .../openlp_plugins/songs/test_editsongform.py | 4 +- .../songs/test_editverseform.py | 2 +- .../openlp_plugins/songs/test_ewimport.py | 30 ++++---- .../songs/test_foilpresenterimport.py | 10 +-- .../openlp_plugins/songs/test_lib.py | 60 +++++++-------- .../openlp_plugins/songs/test_mediaitem.py | 32 ++++---- .../songs/test_openlpimporter.py | 4 +- .../songs/test_openlyricsexport.py | 2 +- .../songs/test_openlyricsimport.py | 10 +-- .../openlp_plugins/songs/test_openoffice.py | 4 +- .../songs/test_opensongimport.py | 6 +- .../openlp_plugins/songs/test_opsproimport.py | 24 +++--- .../songs/test_songbeamerimport.py | 8 +- .../openlp_plugins/songs/test_songselect.py | 66 ++++++++--------- .../songs/test_songshowplusimport.py | 10 +-- .../songs/test_worshipcenterproimport.py | 55 +++++++------- .../songs/test_zionworximport.py | 2 +- .../songusage/test_songusage.py | 8 +- tests/functional/test_init.py | 8 +- .../openlp_core_common/test_utils.py | 6 +- .../openlp_core_lib/test_pluginmanager.py | 2 +- .../openlp_core_lib/test_searchedit.py | 8 +- .../openlp_core_ui/test_filerenamedialog.py | 6 +- .../openlp_core_ui/test_mainwindow.py | 6 +- .../openlp_core_ui/test_projectoreditform.py | 4 +- .../openlp_core_ui/test_projectormanager.py | 4 +- .../test_projectorsourceform.py | 6 +- .../openlp_core_ui/test_servicemanager.py | 16 ++-- .../openlp_core_ui/test_servicenotedialog.py | 2 +- .../openlp_core_ui/test_settings_form.py | 8 +- .../openlp_core_ui/test_shortcutlistform.py | 20 ++--- .../openlp_core_ui/test_starttimedialog.py | 4 +- .../openlp_core_ui/test_thememanager.py | 8 +- .../test_historycombobox.py | 2 +- .../test_listpreviewwidget.py | 8 +- .../test_mediainfoWrapper.py | 2 +- .../bibles/forms/test_bibleimportform.py | 4 +- .../openlp_plugins/bibles/test_lib_http.py | 18 ++--- .../openlp_plugins/bibles/test_lib_manager.py | 8 +- .../bibles/test_lib_parse_reference.py | 10 +-- .../custom/forms/test_customform.py | 12 +-- .../custom/forms/test_customslideform.py | 4 +- .../media/forms/test_mediaclipselectorform.py | 8 +- .../songs/forms/test_authorsform.py | 14 ++-- .../songs/forms/test_editsongform.py | 14 ++-- .../songs/forms/test_editverseform.py | 8 +- .../songs/forms/test_topicsform.py | 6 +- tests/utils/test_bzr_tags.py | 2 +- 117 files changed, 793 insertions(+), 769 deletions(-) create mode 100644 nose2.cfg diff --git a/nose2.cfg b/nose2.cfg new file mode 100644 index 000000000..c34cc46e1 --- /dev/null +++ b/nose2.cfg @@ -0,0 +1,17 @@ +[unittest] +verbose = True + +[log-capture] +always-on = True +clear-handlers = True +filter = -nose +log-level = ERROR + +[test-result] +always-on = True +descriptions = True + +[coverage] +always-on = False +coverage = openlp +coverage-report = html diff --git a/tests/functional/openlp_core/test_init.py b/tests/functional/openlp_core/test_init.py index 86f2c1515..53c88d62f 100644 --- a/tests/functional/openlp_core/test_init.py +++ b/tests/functional/openlp_core/test_init.py @@ -29,7 +29,7 @@ from tests.helpers.testmixin import TestMixin class TestInitFunctions(TestMixin, TestCase): - def parse_options_basic_test(self): + def test_parse_options_basic(self): """ Test the parse options process works @@ -46,7 +46,7 @@ class TestInitFunctions(TestMixin, TestCase): self.assertEquals(args.style, None, 'There are no style flags to be processed') self.assertEquals(args.rargs, [], 'The service file should be blank') - def parse_options_debug_test(self): + def test_parse_options_debug(self): """ Test the parse options process works for debug only @@ -63,7 +63,7 @@ class TestInitFunctions(TestMixin, TestCase): self.assertEquals(args.style, None, 'There are no style flags to be processed') self.assertEquals(args.rargs, [], 'The service file should be blank') - def parse_options_debug_and_portable_test(self): + def test_parse_options_debug_and_portable(self): """ Test the parse options process works for debug and portable @@ -80,7 +80,7 @@ class TestInitFunctions(TestMixin, TestCase): self.assertEquals(args.style, None, 'There are no style flags to be processed') self.assertEquals(args.rargs, [], 'The service file should be blank') - def parse_options_all_no_file_test(self): + def test_parse_options_all_no_file(self): """ Test the parse options process works with two options @@ -97,7 +97,7 @@ class TestInitFunctions(TestMixin, TestCase): self.assertEquals(args.style, None, 'There are no style flags to be processed') self.assertEquals(args.rargs, [], 'The service file should be blank') - def parse_options_file_test(self): + def test_parse_options_file(self): """ Test the parse options process works with a file @@ -114,7 +114,7 @@ class TestInitFunctions(TestMixin, TestCase): self.assertEquals(args.style, None, 'There are no style flags to be processed') self.assertEquals(args.rargs, 'dummy_temp', 'The service file should not be blank') - def parse_options_file_and_debug_test(self): + def test_parse_options_file_and_debug(self): """ Test the parse options process works with a file diff --git a/tests/functional/openlp_core_common/test_actions.py b/tests/functional/openlp_core_common/test_actions.py index afdc89c34..cf7d4d9e0 100644 --- a/tests/functional/openlp_core_common/test_actions.py +++ b/tests/functional/openlp_core_common/test_actions.py @@ -49,7 +49,7 @@ class TestCategoryActionList(TestCase): """ del self.list - def contains_test(self): + def test_contains(self): """ Test the __contains__() method """ @@ -61,7 +61,7 @@ class TestCategoryActionList(TestCase): self.assertTrue(self.action1 in self.list) self.assertFalse(self.action2 in self.list) - def len_test(self): + def test_len(self): """ Test the __len__ method """ @@ -77,7 +77,7 @@ class TestCategoryActionList(TestCase): # THEN: Check the length. self.assertEqual(len(self.list), 1, "The length should be 1.") - def append_test(self): + def test_append(self): """ Test the append() method """ @@ -92,7 +92,7 @@ class TestCategoryActionList(TestCase): self.assertEqual(self.list.actions[0], (0, self.action1)) self.assertEqual(self.list.actions[1], (1, self.action2)) - def add_test(self): + def test_add(self): """ Test the add() method """ @@ -111,7 +111,7 @@ class TestCategoryActionList(TestCase): self.assertEqual(self.list.actions[0], (41, self.action2)) self.assertEqual(self.list.actions[1], (42, self.action1)) - def iterator_test(self): + def test_iterator(self): """ Test the __iter__ and __next__ methods """ @@ -126,7 +126,7 @@ class TestCategoryActionList(TestCase): self.assertIs(l[0], self.action1) self.assertIs(l[1], self.action2) - def remove_test(self): + def test_remove(self): """ Test the remove() method """ diff --git a/tests/functional/openlp_core_common/test_applocation.py b/tests/functional/openlp_core_common/test_applocation.py index 0d42867e2..68e94b11e 100644 --- a/tests/functional/openlp_core_common/test_applocation.py +++ b/tests/functional/openlp_core_common/test_applocation.py @@ -36,7 +36,7 @@ class TestAppLocation(TestCase): """ A test suite to test out various methods around the AppLocation class. """ - def get_data_path_test(self): + def test_get_data_path(self): """ Test the AppLocation.get_data_path() method """ @@ -60,7 +60,7 @@ class TestAppLocation(TestCase): mocked_check_directory_exists.assert_called_with(os.path.join('test', 'dir')) self.assertEqual(os.path.join('test', 'dir'), data_path, 'Result should be "test/dir"') - def get_data_path_with_custom_location_test(self): + def test_get_data_path_with_custom_location(self): """ Test the AppLocation.get_data_path() method when a custom location is set in the settings """ @@ -80,7 +80,7 @@ class TestAppLocation(TestCase): mocked_settings.value.assert_called_with('advanced/data path') self.assertEqual('custom/dir', data_path, 'Result should be "custom/dir"') - def get_files_no_section_no_extension_test(self): + def test_get_files_no_section_no_extension(self): """ Test the AppLocation.get_files() method with no parameters passed. """ @@ -96,7 +96,7 @@ class TestAppLocation(TestCase): # Then: check if the file lists are identical. self.assertListEqual(FILE_LIST, result, 'The file lists should be identical.') - def get_files_test(self): + def test_get_files(self): """ Test the AppLocation.get_files() method with all parameters passed. """ @@ -115,7 +115,7 @@ class TestAppLocation(TestCase): # Then: check if the file lists are identical. self.assertListEqual(['file5.mp3', 'file6.mp3'], result, 'The file lists should be identical.') - def get_section_data_path_test(self): + def test_get_section_data_path(self): """ Test the AppLocation.get_section_data_path() method """ @@ -132,7 +132,7 @@ class TestAppLocation(TestCase): mocked_check_directory_exists.assert_called_with(os.path.join('test', 'dir', 'section')) self.assertEqual(os.path.join('test', 'dir', 'section'), data_path, 'Result should be "test/dir/section"') - def get_directory_for_app_dir_test(self): + def test_get_directory_for_app_dir(self): """ Test the AppLocation.get_directory() method for AppLocation.AppDir """ @@ -146,7 +146,7 @@ class TestAppLocation(TestCase): # THEN: check that the correct directory is returned self.assertEqual(os.path.join('app', 'dir'), directory, 'Directory should be "app/dir"') - def get_directory_for_plugins_dir_test(self): + def test_get_directory_for_plugins_dir(self): """ Test the AppLocation.get_directory() method for AppLocation.PluginsDir """ @@ -167,7 +167,7 @@ class TestAppLocation(TestCase): # THEN: The correct directory should be returned self.assertEqual(os.path.join('plugins', 'dir'), directory, 'Directory should be "plugins/dir"') - def get_frozen_path_in_unfrozen_app_test(self): + def test_get_frozen_path_in_unfrozen_app(self): """ Test the _get_frozen_path() function when the application is not frozen (compiled by PyInstaller) """ @@ -181,7 +181,7 @@ class TestAppLocation(TestCase): # THEN: The non-frozen parameter is returned self.assertEqual('not frozen', frozen_path, '_get_frozen_path should return "not frozen"') - def get_frozen_path_in_frozen_app_test(self): + def test_get_frozen_path_in_frozen_app(self): """ Test the get_frozen_path() function when the application is frozen (compiled by PyInstaller) """ diff --git a/tests/functional/openlp_core_common/test_common.py b/tests/functional/openlp_core_common/test_common.py index 0b8632e64..7fb3fb276 100644 --- a/tests/functional/openlp_core_common/test_common.py +++ b/tests/functional/openlp_core_common/test_common.py @@ -34,7 +34,7 @@ class TestCommonFunctions(TestCase): """ A test suite to test out various functions in the openlp.core.common module. """ - def check_directory_exists_test(self): + def test_check_directory_exists(self): """ Test the check_directory_exists() function """ @@ -73,7 +73,7 @@ class TestCommonFunctions(TestCase): mocked_exists.assert_called_with(directory_to_check) self.assertRaises(ValueError, check_directory_exists, directory_to_check) - def de_hump_conversion_test(self): + def test_de_hump_conversion(self): """ Test the de_hump function with a class name """ @@ -86,7 +86,7 @@ class TestCommonFunctions(TestCase): # THEN: the new string should be converted to python format self.assertTrue(new_string == "my_class", 'The class name should have been converted') - def de_hump_static_test(self): + def test_de_hump_static(self): """ Test the de_hump function with a python string """ @@ -99,7 +99,7 @@ class TestCommonFunctions(TestCase): # THEN: the new string should be converted to python format self.assertTrue(new_string == "my_class", 'The class name should have been preserved') - def trace_error_handler_test(self): + def test_trace_error_handler(self): """ Test the trace_error_handler() method """ @@ -115,7 +115,7 @@ class TestCommonFunctions(TestCase): mocked_logger.error.assert_called_with( 'OpenLP Error trace\n File openlp.fake at line 56 \n\t called trace_error_handler_test') - def translate_test(self): + def test_translate(self): """ Test the translate() function """ @@ -132,7 +132,7 @@ class TestCommonFunctions(TestCase): mocked_translate.assert_called_with(context, text, comment) self.assertEqual('Translated string', result, 'The translated string should have been returned') - def is_win_test(self): + def test_is_win(self): """ Test the is_win() function """ @@ -148,7 +148,7 @@ class TestCommonFunctions(TestCase): self.assertFalse(is_macosx(), 'is_macosx() should return False') self.assertFalse(is_linux(), 'is_linux() should return False') - def is_macosx_test(self): + def test_is_macosx(self): """ Test the is_macosx() function """ @@ -164,7 +164,7 @@ class TestCommonFunctions(TestCase): self.assertFalse(is_win(), 'is_win() should return False') self.assertFalse(is_linux(), 'is_linux() should return False') - def is_linux_test(self): + def test_is_linux(self): """ Test the is_linux() function """ @@ -180,7 +180,7 @@ class TestCommonFunctions(TestCase): self.assertFalse(is_win(), 'is_win() should return False') self.assertFalse(is_macosx(), 'is_macosx() should return False') - def clean_button_text_test(self): + def test_clean_button_text(self): """ Test the clean_button_text() function. """ diff --git a/tests/functional/openlp_core_common/test_db.py b/tests/functional/openlp_core_common/test_db.py index 029efadc3..e750a6260 100644 --- a/tests/functional/openlp_core_common/test_db.py +++ b/tests/functional/openlp_core_common/test_db.py @@ -67,7 +67,7 @@ class TestUtilsDBFunctions(TestCase): time.sleep(1) retries += 1 - def delete_column_test(self): + def test_delete_column(self): """ Test deleting a single column in a table """ @@ -85,7 +85,7 @@ class TestUtilsDBFunctions(TestCase): if column.name == 'song_book_id': self.fail("The column 'song_book_id' should have been deleted.") - def delete_columns_test(self): + def test_delete_columns(self): """ Test deleting multiple columns in a table """ diff --git a/tests/functional/openlp_core_common/test_init.py b/tests/functional/openlp_core_common/test_init.py index 2032e883e..0ccaba94c 100644 --- a/tests/functional/openlp_core_common/test_init.py +++ b/tests/functional/openlp_core_common/test_init.py @@ -48,7 +48,7 @@ class TestInit(TestCase, TestMixin): """ self.destroy_settings() - def add_actions_empty_list_test(self): + def test_add_actions_empty_list(self): """ Test that no actions are added when the list is empty """ @@ -63,7 +63,7 @@ class TestInit(TestCase, TestMixin): self.assertEqual(0, mocked_target.addSeparator.call_count, 'addSeparator method should not have been called') self.assertEqual(0, mocked_target.addAction.call_count, 'addAction method should not have been called') - def add_actions_none_action_test(self): + def test_add_actions_none_action(self): """ Test that a separator is added when a None action is in the list """ @@ -78,7 +78,7 @@ class TestInit(TestCase, TestMixin): mocked_target.addSeparator.assert_called_with() self.assertEqual(0, mocked_target.addAction.call_count, 'addAction method should not have been called') - def add_actions_add_action_test(self): + def test_add_actions_add_action(self): """ Test that an action is added when a valid action is in the list """ @@ -93,7 +93,7 @@ class TestInit(TestCase, TestMixin): self.assertEqual(0, mocked_target.addSeparator.call_count, 'addSeparator method should not have been called') mocked_target.addAction.assert_called_with('action') - def add_actions_action_and_none_test(self): + def test_add_actions_action_and_none(self): """ Test that an action and a separator are added when a valid action and None are in the list """ @@ -108,7 +108,7 @@ class TestInit(TestCase, TestMixin): mocked_target.addSeparator.assert_called_with() mocked_target.addAction.assert_called_with('action') - def get_uno_instance_pipe_test(self): + def test_get_uno_instance_pipe(self): """ Test that when the UNO connection type is "pipe" the resolver is given the "pipe" URI """ @@ -121,7 +121,7 @@ class TestInit(TestCase, TestMixin): # THEN: the resolve method is called with the correct argument mock_resolver.resolve.assert_called_with('uno:pipe,name=openlp_pipe;urp;StarOffice.ComponentContext') - def get_uno_instance_socket_test(self): + def test_get_uno_instance_socket(self): """ Test that when the UNO connection type is other than "pipe" the resolver is given the "socket" URI """ @@ -134,7 +134,7 @@ class TestInit(TestCase, TestMixin): # THEN: the resolve method is called with the correct argument mock_resolver.resolve.assert_called_with('uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext') - def get_uno_command_libreoffice_command_exists_test(self): + def test_get_uno_command_libreoffice_command_exists(self): """ Test the ``get_uno_command`` function uses the libreoffice command when available. :return: @@ -151,7 +151,7 @@ class TestInit(TestCase, TestMixin): 'libreoffice --nologo --norestore --minimized --nodefault --nofirststartwizard' ' "--accept=pipe,name=openlp_pipe;urp;"') - def get_uno_command_only_soffice_command_exists_test(self): + def test_get_uno_command_only_soffice_command_exists(self): """ Test the ``get_uno_command`` function uses the soffice command when the libreoffice command is not available. :return: @@ -169,7 +169,7 @@ class TestInit(TestCase, TestMixin): self.assertEquals(result, 'soffice --nologo --norestore --minimized --nodefault --nofirststartwizard' ' "--accept=pipe,name=openlp_pipe;urp;"') - def get_uno_command_when_no_command_exists_test(self): + def test_get_uno_command_when_no_command_exists(self): """ Test the ``get_uno_command`` function raises an FileNotFoundError when neither the libreoffice or soffice commands are available. @@ -183,7 +183,7 @@ class TestInit(TestCase, TestMixin): # THEN: a FileNotFoundError exception should be raised self.assertRaises(FileNotFoundError, get_uno_command) - def get_uno_command_connection_type_test(self): + def test_get_uno_command_connection_type(self): """ Test the ``get_uno_command`` function when the connection type is anything other than pipe. :return: @@ -198,7 +198,7 @@ class TestInit(TestCase, TestMixin): self.assertEqual(result, 'libreoffice --nologo --norestore --minimized --nodefault --nofirststartwizard' ' "--accept=socket,host=localhost,port=2002;urp;"') - def get_filesystem_encoding_sys_function_not_called_test(self): + def test_get_filesystem_encoding_sys_function_not_called(self): """ Test the get_filesystem_encoding() function does not call the sys.getdefaultencoding() function """ @@ -215,7 +215,7 @@ class TestInit(TestCase, TestMixin): self.assertEqual(0, mocked_getdefaultencoding.called, 'getdefaultencoding should not have been called') self.assertEqual('cp1252', result, 'The result should be "cp1252"') - def get_filesystem_encoding_sys_function_is_called_test(self): + def test_get_filesystem_encoding_sys_function_is_called(self): """ Test the get_filesystem_encoding() function calls the sys.getdefaultencoding() function """ @@ -233,7 +233,7 @@ class TestInit(TestCase, TestMixin): mocked_getdefaultencoding.assert_called_with() self.assertEqual('utf-8', result, 'The result should be "utf-8"') - def split_filename_with_file_path_test(self): + def test_split_filename_with_file_path(self): """ Test the split_filename() function with a path to a file """ @@ -253,7 +253,7 @@ class TestInit(TestCase, TestMixin): # THEN: A tuple should be returned. self.assertEqual(wanted_result, result, 'A tuple with the dir and file name should have been returned') - def split_filename_with_dir_path_test(self): + def test_split_filename_with_dir_path(self): """ Test the split_filename() function with a path to a directory """ @@ -274,7 +274,7 @@ class TestInit(TestCase, TestMixin): self.assertEqual(wanted_result, result, 'A two-entry tuple with the directory and file name (empty) should have been returned.') - def clean_filename_test(self): + def test_clean_filename(self): """ Test the clean_filename() function """ @@ -288,7 +288,7 @@ class TestInit(TestCase, TestMixin): # THEN: The file name should be cleaned. self.assertEqual(wanted_name, result, 'The file name should not contain any special characters.') - def delete_file_no_path_test(self): + def test_delete_file_no_path(self): """ Test the delete_file function when called with out a valid path """ @@ -299,7 +299,7 @@ class TestInit(TestCase, TestMixin): # THEN: delete_file should return False self.assertFalse(result, "delete_file should return False when called with ''") - def delete_file_path_success_test(self): + def test_delete_file_path_success(self): """ Test the delete_file function when it successfully deletes a file """ @@ -312,7 +312,7 @@ class TestInit(TestCase, TestMixin): # THEN: delete_file should return True self.assertTrue(result, 'delete_file should return True when it successfully deletes a file') - def delete_file_path_no_file_exists_test(self): + def test_delete_file_path_no_file_exists(self): """ Test the delete_file function when the file to remove does not exist """ @@ -325,7 +325,7 @@ class TestInit(TestCase, TestMixin): # THEN: delete_file should return True self.assertTrue(result, 'delete_file should return True when the file doesnt exist') - def delete_file_path_exception_test(self): + def test_delete_file_path_exception(self): """ Test the delete_file function when os.remove raises an exception """ diff --git a/tests/functional/openlp_core_common/test_languagemanager.py b/tests/functional/openlp_core_common/test_languagemanager.py index 8fe7d543c..53949464a 100644 --- a/tests/functional/openlp_core_common/test_languagemanager.py +++ b/tests/functional/openlp_core_common/test_languagemanager.py @@ -33,7 +33,7 @@ class TestLanguageManager(TestCase): A test suite to test out various methods around the common __init__ class. """ - def get_locale_key_test(self): + def test_get_locale_key(self): """ Test the get_locale_key(string) function """ @@ -50,7 +50,7 @@ class TestLanguageManager(TestCase): self.assertEqual(['Aushang', '\u00C4u\u00DFerung', 'Auszug'], sorted_list, 'Strings should be sorted properly') - def get_natural_key_test(self): + def test_get_natural_key(self): """ Test the get_natural_key(string) function """ diff --git a/tests/functional/openlp_core_common/test_registry.py b/tests/functional/openlp_core_common/test_registry.py index 0642ff93c..faa9b4cbc 100644 --- a/tests/functional/openlp_core_common/test_registry.py +++ b/tests/functional/openlp_core_common/test_registry.py @@ -33,7 +33,7 @@ TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../', '..', class TestRegistry(TestCase): - def registry_service_test(self): + def test_registry_service(self): """ Test the registry creation and its usage """ @@ -65,7 +65,7 @@ class TestRegistry(TestCase): temp = Registry().get('test1') self.assertEqual(temp, None, 'None should have been returned for deleted service') - def registry_function_test(self): + def test_registry_function(self): """ Test the registry function creation and their usages """ @@ -93,7 +93,7 @@ class TestRegistry(TestCase): # THEN: I expect then function to have been called and a return given self.assertEqual(return_value[0], 'function_2', 'A return value is provided and matches') - def registry_working_flags_test(self): + def test_registry_working_flags(self): """ Test the registry working flags creation and its usage """ @@ -130,7 +130,7 @@ class TestRegistry(TestCase): self.assertEqual(context.exception.args[0], 'Working Flag test1 not found in list', 'KeyError exception should have been thrown for duplicate working flag') - def remove_function_test(self): + def test_remove_function(self): """ Test the remove_function() method """ diff --git a/tests/functional/openlp_core_common/test_registrymixin.py b/tests/functional/openlp_core_common/test_registrymixin.py index 31f49a3d3..b8ac13742 100644 --- a/tests/functional/openlp_core_common/test_registrymixin.py +++ b/tests/functional/openlp_core_common/test_registrymixin.py @@ -32,7 +32,7 @@ TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../', '..', class TestRegistryMixin(TestCase): - def registry_mixin_missing_test(self): + def test_registry_mixin_missing(self): """ Test the registry creation and its usage """ @@ -45,7 +45,7 @@ class TestRegistryMixin(TestCase): # THEN: The following methods are missing self.assertEqual(len(Registry().functions_list), 0), 'The function should not be in the dict anymore.' - def registry_mixin_present_test(self): + def test_registry_mixin_present(self): """ Test the registry creation and its usage """ diff --git a/tests/functional/openlp_core_common/test_registryproperties.py b/tests/functional/openlp_core_common/test_registryproperties.py index 0f0184876..98408b323 100644 --- a/tests/functional/openlp_core_common/test_registryproperties.py +++ b/tests/functional/openlp_core_common/test_registryproperties.py @@ -39,7 +39,7 @@ class TestRegistryProperties(TestCase, RegistryProperties): """ Registry.create() - def no_application_test(self): + def test_no_application(self): """ Test property if no registry value assigned """ @@ -48,7 +48,7 @@ class TestRegistryProperties(TestCase, RegistryProperties): # THEN the application should be none self.assertEqual(self.application, None, 'The application value should be None') - def application_test(self): + def test_application(self): """ Test property if registry value assigned """ @@ -62,7 +62,7 @@ class TestRegistryProperties(TestCase, RegistryProperties): self.assertEqual(self.application, application, 'The application value should match') @patch('openlp.core.common.registryproperties.is_win') - def application_on_windows_test(self, mocked_is_win): + def test_application_on_windows(self, mocked_is_win): """ Test property if registry value assigned on Windows """ diff --git a/tests/functional/openlp_core_common/test_settings.py b/tests/functional/openlp_core_common/test_settings.py index 05a1f317c..e2e84997d 100644 --- a/tests/functional/openlp_core_common/test_settings.py +++ b/tests/functional/openlp_core_common/test_settings.py @@ -47,7 +47,7 @@ class TestSettings(TestCase, TestMixin): """ self.destroy_settings() - def recent_files_conv_test(self): + def test_recent_files_conv(self): """ Test that recent_files_conv, converts various possible types of values correctly. """ @@ -66,7 +66,7 @@ class TestSettings(TestCase, TestMixin): # THEN: The actual result should be the same as the expected result self.assertEqual(actual_result, expected_result) - def settings_basic_test(self): + def test_settings_basic(self): """ Test the Settings creation and its default usage """ @@ -84,7 +84,7 @@ class TestSettings(TestCase, TestMixin): # THEN the new value is returned when re-read self.assertTrue(Settings().value('core/has run wizard'), 'The saved value should have been returned') - def settings_override_test(self): + def test_settings_override(self): """ Test the Settings creation and its override usage """ @@ -106,7 +106,7 @@ class TestSettings(TestCase, TestMixin): # THEN the new value is returned when re-read self.assertEqual('very short', Settings().value('test/extend'), 'The saved value should be returned') - def settings_override_with_group_test(self): + def test_settings_override_with_group(self): """ Test the Settings creation and its override usage - with groups """ @@ -130,7 +130,7 @@ class TestSettings(TestCase, TestMixin): # THEN the new value is returned when re-read self.assertEqual('very short', Settings().value('test/extend'), 'The saved value should be returned') - def settings_nonexisting_test(self): + def test_settings_nonexisting(self): """ Test the Settings on query for non-existing value """ @@ -142,7 +142,7 @@ class TestSettings(TestCase, TestMixin): # THEN: An exception with the non-existing key should be thrown self.assertEqual(str(cm.exception), "'core/does not exists'", 'We should get an exception') - def extend_default_settings_test(self): + def test_extend_default_settings(self): """ Test that the extend_default_settings method extends the default settings """ diff --git a/tests/functional/openlp_core_common/test_uistrings.py b/tests/functional/openlp_core_common/test_uistrings.py index 0bb596f7b..0a83e9c92 100644 --- a/tests/functional/openlp_core_common/test_uistrings.py +++ b/tests/functional/openlp_core_common/test_uistrings.py @@ -29,7 +29,7 @@ from openlp.core.common import UiStrings class TestUiStrings(TestCase): - def check_same_instance_test(self): + def test_check_same_instance(self): """ Test the UiStrings class - we always should have only one instance of the UiStrings class. """ diff --git a/tests/functional/openlp_core_common/test_versionchecker.py b/tests/functional/openlp_core_common/test_versionchecker.py index d14bfa679..8654be5d0 100644 --- a/tests/functional/openlp_core_common/test_versionchecker.py +++ b/tests/functional/openlp_core_common/test_versionchecker.py @@ -44,7 +44,7 @@ class TestVersionchecker(TestMixin, TestCase): """ self.destroy_settings() - def version_thread_triggered_test(self): + def test_version_thread_triggered(self): """ Test the version thread call does not trigger UI :return: diff --git a/tests/functional/openlp_core_lib/test_db.py b/tests/functional/openlp_core_lib/test_db.py index 28159e78c..77495466d 100644 --- a/tests/functional/openlp_core_lib/test_db.py +++ b/tests/functional/openlp_core_lib/test_db.py @@ -37,7 +37,7 @@ class TestDB(TestCase): """ A test case for all the tests for the :mod:`~openlp.core.lib.db` module. """ - def init_db_calls_correct_functions_test(self): + def test_init_db_calls_correct_functions(self): """ Test that the init_db function makes the correct function calls """ @@ -67,7 +67,7 @@ class TestDB(TestCase): self.assertIs(session, mocked_scoped_session_object, 'The ``session`` object should be the mock') self.assertIs(metadata, mocked_metadata, 'The ``metadata`` object should be the mock') - def init_db_defaults_test(self): + def test_init_db_defaults(self): """ Test that initialising an in-memory SQLite database via ``init_db`` uses the defaults """ @@ -81,7 +81,7 @@ class TestDB(TestCase): self.assertIsInstance(session, ScopedSession, 'The ``session`` object should be a ``ScopedSession`` instance') self.assertIsInstance(metadata, MetaData, 'The ``metadata`` object should be a ``MetaData`` instance') - def get_upgrade_op_test(self): + def test_get_upgrade_op(self): """ Test that the ``get_upgrade_op`` function creates a MigrationContext and an Operations object """ @@ -105,7 +105,7 @@ class TestDB(TestCase): MockedMigrationContext.configure.assert_called_with(mocked_connection) MockedOperations.assert_called_with(mocked_context) - def delete_database_without_db_file_name_test(self): + def test_delete_database_without_db_file_name(self): """ Test that the ``delete_database`` function removes a database file, without the file name parameter """ @@ -125,7 +125,7 @@ class TestDB(TestCase): mocked_delete_file.assert_called_with(test_location) self.assertTrue(result, 'The result of delete_file should be True (was rigged that way)') - def delete_database_with_db_file_name_test(self): + def test_delete_database_with_db_file_name(self): """ Test that the ``delete_database`` function removes a database file, with the file name supplied """ diff --git a/tests/functional/openlp_core_lib/test_file_dialog.py b/tests/functional/openlp_core_lib/test_file_dialog.py index 4c9268195..252ce3190 100644 --- a/tests/functional/openlp_core_lib/test_file_dialog.py +++ b/tests/functional/openlp_core_lib/test_file_dialog.py @@ -26,7 +26,7 @@ class TestFileDialog(TestCase): self.qt_gui_patcher.stop() self.ui_strings_patcher.stop() - def get_open_file_names_canceled_test(self): + def test_get_open_file_names_canceled(self): """ Test that FileDialog.getOpenFileNames() returns and empty QStringList when QFileDialog is canceled (returns an empty QStringList) @@ -45,7 +45,7 @@ class TestFileDialog(TestCase): 'FileDialog.getOpenFileNames should return and empty list when QFileDialog.getOpenFileNames ' 'is canceled') - def returned_file_list_test(self): + def test_returned_file_list(self): """ Test that FileDialog.getOpenFileNames handles a list of files properly when QFileList.getOpenFileNames returns a good file name, a url encoded file name and a non-existing file diff --git a/tests/functional/openlp_core_lib/test_formattingtags.py b/tests/functional/openlp_core_lib/test_formattingtags.py index 9fa651087..c12fab6f0 100644 --- a/tests/functional/openlp_core_lib/test_formattingtags.py +++ b/tests/functional/openlp_core_lib/test_formattingtags.py @@ -47,7 +47,7 @@ class TestFormattingTags(TestCase): """ FormattingTags.html_expands = [] - def get_html_tags_no_user_tags_test(self): + def test_get_html_tags_no_user_tags(self): """ Test the FormattingTags class' get_html_tags static method. """ @@ -68,7 +68,7 @@ class TestFormattingTags(TestCase): # THEN: Lists should be identical. assert old_tags_list == new_tags_list, 'The formatting tag lists should be identical.' - def get_html_tags_with_user_tags_test(self): + def test_get_html_tags_with_user_tags(self): """ FormattingTags class - test the get_html_tags(), add_html_tags() and remove_html_tag() methods. """ diff --git a/tests/functional/openlp_core_lib/test_htmlbuilder.py b/tests/functional/openlp_core_lib/test_htmlbuilder.py index 58841eb90..48c60b55f 100644 --- a/tests/functional/openlp_core_lib/test_htmlbuilder.py +++ b/tests/functional/openlp_core_lib/test_htmlbuilder.py @@ -216,7 +216,7 @@ class Htmbuilder(TestCase, TestMixin): """ self.destroy_settings() - def build_html_test(self): + def test_build_html(self): """ Test the build_html() function """ @@ -246,7 +246,7 @@ class Htmbuilder(TestCase, TestMixin): # THEN: The returned html should match. self.assertEqual(html, HTML, 'The returned html should match') - def build_background_css_radial_test(self): + def test_build_background_css_radial(self): """ Test the build_background_css() function with a radial background """ @@ -262,7 +262,7 @@ class Htmbuilder(TestCase, TestMixin): # THEN: The returned css should match. self.assertEqual(BACKGROUND_CSS_RADIAL, css, 'The background css should be equal.') - def build_lyrics_css_test(self): + def test_build_lyrics_css(self): """ Test the build_lyrics_css() function """ @@ -283,7 +283,7 @@ class Htmbuilder(TestCase, TestMixin): # THEN: The css should be equal. self.assertEqual(LYRICS_CSS, css, 'The lyrics css should be equal.') - def build_lyrics_outline_css_test(self): + def test_build_lyrics_outline_css(self): """ Test the build_lyrics_outline_css() function """ @@ -300,7 +300,7 @@ class Htmbuilder(TestCase, TestMixin): # THEN: The css should be equal. self.assertEqual(LYRICS_OUTLINE_CSS, css, 'The outline css should be equal.') - def build_lyrics_format_css_test(self): + def test_build_lyrics_format_css(self): """ Test the build_lyrics_format_css() function """ @@ -323,7 +323,7 @@ class Htmbuilder(TestCase, TestMixin): # THEN: They should be equal. self.assertEqual(LYRICS_FORMAT_CSS, css, 'The lyrics format css should be equal.') - def build_footer_css_test(self): + def test_build_footer_css(self): """ Test the build_footer_css() function """ @@ -341,7 +341,7 @@ class Htmbuilder(TestCase, TestMixin): # THEN: THE css should be the same. self.assertEqual(FOOTER_CSS, css, 'The footer strings should be equal.') - def build_footer_css_wrap_test(self): + def test_build_footer_css_wrap(self): """ Test the build_footer_css() function """ @@ -360,7 +360,7 @@ class Htmbuilder(TestCase, TestMixin): # THEN: Footer should wrap self.assertEqual(FOOTER_CSS_WRAP, css, 'The footer strings should be equal.') - def build_footer_invalid_test(self): + def test_build_footer_invalid(self): """ Test the build_footer_css() function """ @@ -381,7 +381,7 @@ class Htmbuilder(TestCase, TestMixin): self.assertEqual(FOOTER_CSS_INVALID, css[0], 'The footer strings should be blank.') self.assertEqual(FOOTER_CSS_INVALID, css[1], 'The footer strings should be blank.') - def webkit_version_test(self): + def test_webkit_version(self): """ Test the webkit_version() function """ diff --git a/tests/functional/openlp_core_lib/test_image_manager.py b/tests/functional/openlp_core_lib/test_image_manager.py index 7adec97bb..7fc639508 100644 --- a/tests/functional/openlp_core_lib/test_image_manager.py +++ b/tests/functional/openlp_core_lib/test_image_manager.py @@ -57,7 +57,7 @@ class TestImageManager(TestCase, TestMixin): """ del self.app - def basic_image_manager_test(self): + def test_basic_image_manager(self): """ Test the Image Manager setup basic functionality """ @@ -83,7 +83,7 @@ class TestImageManager(TestCase, TestMixin): self.image_manager.get_image(TEST_PATH, 'church1.jpg') self.assertNotEquals(context.exception, '', 'KeyError exception should have been thrown for missing image') - def different_dimension_image_test(self): + def test_different_dimension_image(self): """ Test the Image Manager with dimensions """ @@ -115,7 +115,7 @@ class TestImageManager(TestCase, TestMixin): self.image_manager.get_image(full_path, 'church.jpg', 120, 120) self.assertNotEquals(context.exception, '', 'KeyError exception should have been thrown for missing dimension') - def process_cache_test(self): + def test_process_cache(self): """ Test the process_cache method """ diff --git a/tests/functional/openlp_core_lib/test_lib.py b/tests/functional/openlp_core_lib/test_lib.py index d519837bf..145be21f4 100644 --- a/tests/functional/openlp_core_lib/test_lib.py +++ b/tests/functional/openlp_core_lib/test_lib.py @@ -38,7 +38,7 @@ TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', class TestLib(TestCase): - def str_to_bool_with_bool_true_test(self): + def test_str_to_bool_with_bool_true(self): """ Test the str_to_bool function with boolean input of True """ @@ -52,7 +52,7 @@ class TestLib(TestCase): self.assertIsInstance(true_result, bool, 'The result should be a boolean') self.assertTrue(true_result, 'The result should be True') - def str_to_bool_with_bool_false_test(self): + def test_str_to_bool_with_bool_false(self): """ Test the str_to_bool function with boolean input of False """ @@ -66,7 +66,7 @@ class TestLib(TestCase): self.assertIsInstance(false_result, bool, 'The result should be a boolean') self.assertFalse(false_result, 'The result should be True') - def str_to_bool_with_integer_test(self): + def test_str_to_bool_with_integer(self): """ Test the str_to_bool function with an integer input """ @@ -79,7 +79,7 @@ class TestLib(TestCase): # THEN: we should get back a false self.assertFalse(int_result, 'The result should be False') - def str_to_bool_with_invalid_string_test(self): + def test_str_to_bool_with_invalid_string(self): """ Test the str_to_bool function with an invalid string """ @@ -92,7 +92,7 @@ class TestLib(TestCase): # THEN: we should get back a false self.assertFalse(str_result, 'The result should be False') - def str_to_bool_with_string_false_test(self): + def test_str_to_bool_with_string_false(self): """ Test the str_to_bool function with a string saying "false" """ @@ -105,7 +105,7 @@ class TestLib(TestCase): # THEN: we should get back a false self.assertFalse(false_result, 'The result should be False') - def str_to_bool_with_string_no_test(self): + def test_str_to_bool_with_string_no(self): """ Test the str_to_bool function with a string saying "NO" """ @@ -118,7 +118,7 @@ class TestLib(TestCase): # THEN: we should get back a false self.assertFalse(str_result, 'The result should be False') - def str_to_bool_with_true_string_value_test(self): + def test_str_to_bool_with_true_string_value(self): """ Test the str_to_bool function with a string set to "True" """ @@ -131,7 +131,7 @@ class TestLib(TestCase): # THEN: we should get back a true self.assertTrue(true_result, 'The result should be True') - def str_to_bool_with_yes_string_value_test(self): + def test_str_to_bool_with_yes_string_value(self): """ Test the str_to_bool function with a string set to "yes" """ @@ -144,7 +144,7 @@ class TestLib(TestCase): # THEN: we should get back a true self.assertTrue(str_result, 'The result should be True') - def get_text_file_string_no_file_test(self): + def test_get_text_file_string_no_file(self): """ Test the get_text_file_string() function when a file does not exist """ @@ -160,7 +160,7 @@ class TestLib(TestCase): mocked_isfile.assert_called_with(filename) self.assertFalse(result, 'False should be returned if no file exists') - def get_text_file_string_read_error_test(self): + def test_get_text_file_string_read_error(self): """ Test the get_text_file_string() method when a read error happens """ @@ -179,13 +179,13 @@ class TestLib(TestCase): mocked_open.assert_called_with(filename, 'r', encoding='utf-8') self.assertIsNone(result, 'None should be returned if the file cannot be opened') - def get_text_file_string_decode_error_test(self): + def test_get_text_file_string_decode_error(self): """ Test the get_text_file_string() method when the contents cannot be decoded """ self.skipTest('Impossible to test due to conflicts when mocking out the "open" function') - def build_icon_with_qicon_test(self): + def test_build_icon_with_qicon(self): """ Test the build_icon() function with a QIcon instance """ @@ -200,7 +200,7 @@ class TestLib(TestCase): # THEN: The result should be our mocked QIcon self.assertIs(mocked_icon, result, 'The result should be the mocked QIcon') - def build_icon_with_resource_test(self): + def test_build_icon_with_resource(self): """ Test the build_icon() function with a resource URI """ @@ -222,7 +222,7 @@ class TestLib(TestCase): # best we can do is to assert that we get back a MagicMock object. self.assertIsInstance(result, MagicMock, 'The result should be a MagicMock, because we mocked it out') - def image_to_byte_test(self): + def test_image_to_byte(self): """ Test the image_to_byte() function """ @@ -248,7 +248,7 @@ class TestLib(TestCase): self.assertEqual('base64mock', result, 'The result should be the return value of the mocked out ' 'base64 method') - def create_thumb_with_size_test(self): + def test_create_thumb_with_size(self): """ Test the create_thumb() function with a given size. """ @@ -282,7 +282,7 @@ class TestLib(TestCase): except: pass - def create_thumb_no_size_test(self): + def test_create_thumb_no_size(self): """ Test the create_thumb() function with no size specified. """ @@ -316,7 +316,7 @@ class TestLib(TestCase): except: pass - def create_thumb_invalid_size_test(self): + def test_create_thumb_invalid_size(self): """ Test the create_thumb() function with invalid size specified. """ @@ -351,7 +351,7 @@ class TestLib(TestCase): except: pass - def create_thumb_width_only_test(self): + def test_create_thumb_width_only(self): """ Test the create_thumb() function with a size of only width specified. """ @@ -386,7 +386,7 @@ class TestLib(TestCase): except: pass - def create_thumb_height_only_test(self): + def test_create_thumb_height_only(self): """ Test the create_thumb() function with a size of only height specified. """ @@ -421,7 +421,7 @@ class TestLib(TestCase): except: pass - def create_thumb_empty_img_test(self): + def test_create_thumb_empty_img(self): """ Test the create_thumb() function with a size of only height specified. """ @@ -469,7 +469,7 @@ class TestLib(TestCase): except: pass - def check_item_selected_true_test(self): + def test_check_item_selected_true(self): """ Test that the check_item_selected() function returns True when there are selected indexes """ @@ -486,7 +486,7 @@ class TestLib(TestCase): mocked_list_widget.selectedIndexes.assert_called_with() self.assertTrue(result, 'The result should be True') - def check_item_selected_false_test(self): + def test_check_item_selected_false(self): """ Test that the check_item_selected() function returns False when there are no selected indexes. """ @@ -507,7 +507,7 @@ class TestLib(TestCase): MockedQtWidgets.QMessageBox.information.assert_called_with('parent', 'mocked translate', 'message') self.assertFalse(result, 'The result should be False') - def clean_tags_test(self): + def test_clean_tags(self): """ Test clean_tags() method. """ @@ -529,7 +529,7 @@ class TestLib(TestCase): # THEN: The strings should be identical. self.assertEqual(wanted_string, result_string, 'The strings should be identical') - def expand_tags_test(self): + def test_expand_tags(self): """ Test the expand_tags() method. """ @@ -568,7 +568,7 @@ class TestLib(TestCase): # THEN: The strings should be identical. self.assertEqual(wanted_string, result_string, 'The strings should be identical.') - def validate_thumb_file_does_not_exist_test(self): + def test_validate_thumb_file_does_not_exist(self): """ Test the validate_thumb() function when the thumbnail does not exist """ @@ -585,7 +585,7 @@ class TestLib(TestCase): mocked_os.path.exists.assert_called_with(thumb_path) assert result is False, 'The result should be False' - def validate_thumb_file_exists_and_newer_test(self): + def test_validate_thumb_file_exists_and_newer(self): """ Test the validate_thumb() function when the thumbnail exists and has a newer timestamp than the file """ @@ -605,7 +605,7 @@ class TestLib(TestCase): # THEN: we should have called a few functions, and the result should be True # mocked_os.path.exists.assert_called_with(thumb_path) - def validate_thumb_file_exists_and_older_test(self): + def test_validate_thumb_file_exists_and_older(self): """ Test the validate_thumb() function when the thumbnail exists but is older than the file """ @@ -629,7 +629,7 @@ class TestLib(TestCase): mocked_os.stat.assert_any_call(thumb_path) assert result is False, 'The result should be False' - def resize_thumb_test(self): + def test_resize_thumb(self): """ Test the resize_thumb() function """ @@ -650,7 +650,7 @@ class TestLib(TestCase): self.assertEqual(wanted_width, result_size.width(), 'The image should have the requested width.') self.assertEqual(image.pixel(0, 0), wanted_background_rgb, 'The background should be white.') - def create_separated_list_qlocate_test(self): + def test_create_separated_list_qlocate(self): """ Test the create_separated_list function using the Qt provided method """ @@ -669,7 +669,7 @@ class TestLib(TestCase): assert string_result == 'Author 1, Author 2, and Author 3', 'The string should be u\'Author 1, ' \ 'Author 2, and Author 3\'.' - def create_separated_list_empty_list_test(self): + def test_create_separated_list_empty_list(self): """ Test the create_separated_list function with an empty list """ @@ -685,7 +685,7 @@ class TestLib(TestCase): # THEN: We shoud have an emptry string. assert string_result == '', 'The string sould be empty.' - def create_separated_list_with_one_item_test(self): + def test_create_separated_list_with_one_item(self): """ Test the create_separated_list function with a list consisting of only one entry """ @@ -701,7 +701,7 @@ class TestLib(TestCase): # THEN: We should have "Author 1" assert string_result == 'Author 1', 'The string should be u\'Author 1\'.' - def create_separated_list_with_two_items_test(self): + def test_create_separated_list_with_two_items(self): """ Test the create_separated_list function with a list of two entries """ @@ -718,7 +718,7 @@ class TestLib(TestCase): # THEN: We should have "Author 1 and Author 2" assert string_result == 'Author 1 and Author 2', 'The string should be u\'Author 1 and Author 2\'.' - def create_separated_list_with_three_items_test(self): + def test_create_separated_list_with_three_items(self): """ Test the create_separated_list function with a list of three items """ diff --git a/tests/functional/openlp_core_lib/test_mediamanageritem.py b/tests/functional/openlp_core_lib/test_mediamanageritem.py index 892b67f2d..b943d9a7d 100644 --- a/tests/functional/openlp_core_lib/test_mediamanageritem.py +++ b/tests/functional/openlp_core_lib/test_mediamanageritem.py @@ -44,7 +44,7 @@ class TestMediaManagerItem(TestCase, TestMixin): @patch(u'openlp.core.lib.mediamanageritem.Settings') @patch(u'openlp.core.lib.mediamanageritem.MediaManagerItem.on_preview_click') - def on_double_clicked_test(self, mocked_on_preview_click, MockedSettings): + def test_on_double_clicked(self, mocked_on_preview_click, MockedSettings): """ Test that when an item is double-clicked then the item is previewed """ @@ -60,7 +60,7 @@ class TestMediaManagerItem(TestCase, TestMixin): # THEN: on_preview_click() should have been called mocked_on_preview_click.assert_called_with() - def required_icons_test(self): + def test_required_icons(self): """ Test the default icons for plugins """ @@ -77,7 +77,7 @@ class TestMediaManagerItem(TestCase, TestMixin): @patch(u'openlp.core.lib.mediamanageritem.Settings') @patch(u'openlp.core.lib.mediamanageritem.MediaManagerItem.on_live_click') - def on_double_clicked_go_live_test(self, mocked_on_live_click, MockedSettings): + def test_on_double_clicked_go_live(self, mocked_on_live_click, MockedSettings): """ Test that when "Double-click to go live" is enabled that the item goes live """ @@ -96,7 +96,7 @@ class TestMediaManagerItem(TestCase, TestMixin): @patch(u'openlp.core.lib.mediamanageritem.Settings') @patch(u'openlp.core.lib.mediamanageritem.MediaManagerItem.on_live_click') @patch(u'openlp.core.lib.mediamanageritem.MediaManagerItem.on_preview_click') - def on_double_clicked_single_click_preview_test(self, mocked_on_preview_click, mocked_on_live_click, + def test_on_double_clicked_single_click_preview(self, mocked_on_preview_click, mocked_on_live_click, MockedSettings): """ Test that when "Single-click preview" is enabled then nothing happens on double-click diff --git a/tests/functional/openlp_core_lib/test_pluginmanager.py b/tests/functional/openlp_core_lib/test_pluginmanager.py index 09c39a81b..1fd8b7a68 100644 --- a/tests/functional/openlp_core_lib/test_pluginmanager.py +++ b/tests/functional/openlp_core_lib/test_pluginmanager.py @@ -49,7 +49,7 @@ class TestPluginManager(TestCase): Registry().register('main_window', self.mocked_main_window) Registry().register('settings_form', self.mocked_settings_form) - def hook_media_manager_with_disabled_plugin_test(self): + def test_hook_media_manager_with_disabled_plugin(self): """ Test running the hook_media_manager() method with a disabled plugin """ @@ -66,7 +66,7 @@ class TestPluginManager(TestCase): self.assertEqual(0, mocked_plugin.create_media_manager_item.call_count, 'The create_media_manager_item() method should not have been called.') - def hook_media_manager_with_active_plugin_test(self): + def test_hook_media_manager_with_active_plugin(self): """ Test running the hook_media_manager() method with an active plugin """ @@ -82,7 +82,7 @@ class TestPluginManager(TestCase): # THEN: The create_media_manager_item() method should have been called mocked_plugin.create_media_manager_item.assert_called_with() - def hook_settings_tabs_with_disabled_plugin_and_no_form_test(self): + def test_hook_settings_tabs_with_disabled_plugin_and_no_form(self): """ Test running the hook_settings_tabs() method with a disabled plugin and no form """ @@ -99,7 +99,7 @@ class TestPluginManager(TestCase): self.assertEqual(0, mocked_plugin.create_media_manager_item.call_count, 'The create_media_manager_item() method should not have been called.') - def hook_settings_tabs_with_disabled_plugin_and_mocked_form_test(self): + def test_hook_settings_tabs_with_disabled_plugin_and_mocked_form(self): """ Test running the hook_settings_tabs() method with a disabled plugin and a mocked form """ @@ -121,7 +121,7 @@ class TestPluginManager(TestCase): self.assertEqual(mocked_settings_form.plugin_manager.plugins, plugin_manager.plugins, 'The plugins on the settings form should be the same as the plugins in the plugin manager') - def hook_settings_tabs_with_active_plugin_and_mocked_form_test(self): + def test_hook_settings_tabs_with_active_plugin_and_mocked_form(self): """ Test running the hook_settings_tabs() method with an active plugin and a mocked settings form """ @@ -143,7 +143,7 @@ class TestPluginManager(TestCase): self.assertEqual(plugin_manager.plugins, mocked_settings_form.plugin_manager.plugins, 'The plugins on the settings form should be the same as the plugins in the plugin manager') - def hook_settings_tabs_with_active_plugin_and_no_form_test(self): + def test_hook_settings_tabs_with_active_plugin_and_no_form(self): """ Test running the hook_settings_tabs() method with an active plugin and no settings form """ @@ -159,7 +159,7 @@ class TestPluginManager(TestCase): # THEN: The create_settings_tab() method should have been called mocked_plugin.create_settings_tab.assert_called_with(self.mocked_settings_form) - def hook_import_menu_with_disabled_plugin_test(self): + def test_hook_import_menu_with_disabled_plugin(self): """ Test running the hook_import_menu() method with a disabled plugin """ @@ -176,7 +176,7 @@ class TestPluginManager(TestCase): self.assertEqual(0, mocked_plugin.add_import_menu_item.call_count, 'The add_import_menu_item() method should not have been called.') - def hook_import_menu_with_active_plugin_test(self): + def test_hook_import_menu_with_active_plugin(self): """ Test running the hook_import_menu() method with an active plugin """ @@ -192,7 +192,7 @@ class TestPluginManager(TestCase): # THEN: The add_import_menu_item() method should have been called mocked_plugin.add_import_menu_item.assert_called_with(self.mocked_main_window.file_import_menu) - def hook_export_menu_with_disabled_plugin_test(self): + def test_hook_export_menu_with_disabled_plugin(self): """ Test running the hook_export_menu() method with a disabled plugin """ @@ -209,7 +209,7 @@ class TestPluginManager(TestCase): self.assertEqual(0, mocked_plugin.add_export_menu_item.call_count, 'The add_export_menu_item() method should not have been called.') - def hook_export_menu_with_active_plugin_test(self): + def test_hook_export_menu_with_active_plugin(self): """ Test running the hook_export_menu() method with an active plugin """ @@ -225,7 +225,7 @@ class TestPluginManager(TestCase): # THEN: The add_export_menu_item() method should have been called mocked_plugin.add_export_menu_item.assert_called_with(self.mocked_main_window.file_export_menu) - def hook_upgrade_plugin_settings_with_disabled_plugin_test(self): + def test_hook_upgrade_plugin_settings_with_disabled_plugin(self): """ Test running the hook_upgrade_plugin_settings() method with a disabled plugin """ @@ -243,7 +243,7 @@ class TestPluginManager(TestCase): self.assertEqual(0, mocked_plugin.upgrade_settings.call_count, 'The upgrade_settings() method should not have been called.') - def hook_upgrade_plugin_settings_with_active_plugin_test(self): + def test_hook_upgrade_plugin_settings_with_active_plugin(self): """ Test running the hook_upgrade_plugin_settings() method with an active plugin """ @@ -260,7 +260,7 @@ class TestPluginManager(TestCase): # THEN: The add_export_menu_item() method should have been called mocked_plugin.upgrade_settings.assert_called_with(settings) - def hook_tools_menu_with_disabled_plugin_test(self): + def test_hook_tools_menu_with_disabled_plugin(self): """ Test running the hook_tools_menu() method with a disabled plugin """ @@ -277,7 +277,7 @@ class TestPluginManager(TestCase): self.assertEqual(0, mocked_plugin.add_tools_menu_item.call_count, 'The add_tools_menu_item() method should not have been called.') - def hook_tools_menu_with_active_plugin_test(self): + def test_hook_tools_menu_with_active_plugin(self): """ Test running the hook_tools_menu() method with an active plugin """ @@ -293,7 +293,7 @@ class TestPluginManager(TestCase): # THEN: The add_tools_menu_item() method should have been called mocked_plugin.add_tools_menu_item.assert_called_with(self.mocked_main_window.tools_menu) - def initialise_plugins_with_disabled_plugin_test(self): + def test_initialise_plugins_with_disabled_plugin(self): """ Test running the initialise_plugins() method with a disabled plugin """ @@ -311,7 +311,7 @@ class TestPluginManager(TestCase): mocked_plugin.is_active.assert_called_with() self.assertEqual(0, mocked_plugin.initialise.call_count, 'The initialise() method should not have been called.') - def initialise_plugins_with_active_plugin_test(self): + def test_initialise_plugins_with_active_plugin(self): """ Test running the initialise_plugins() method with an active plugin """ @@ -329,7 +329,7 @@ class TestPluginManager(TestCase): mocked_plugin.is_active.assert_called_with() mocked_plugin.initialise.assert_called_with() - def finalise_plugins_with_disabled_plugin_test(self): + def test_finalise_plugins_with_disabled_plugin(self): """ Test running the finalise_plugins() method with a disabled plugin """ @@ -347,7 +347,7 @@ class TestPluginManager(TestCase): mocked_plugin.is_active.assert_called_with() self.assertEqual(0, mocked_plugin.finalise.call_count, 'The finalise() method should not have been called.') - def finalise_plugins_with_active_plugin_test(self): + def test_finalise_plugins_with_active_plugin(self): """ Test running the finalise_plugins() method with an active plugin """ @@ -365,7 +365,7 @@ class TestPluginManager(TestCase): mocked_plugin.is_active.assert_called_with() mocked_plugin.finalise.assert_called_with() - def get_plugin_by_name_does_not_exist_test(self): + def test_get_plugin_by_name_does_not_exist(self): """ Test running the get_plugin_by_name() method to find a plugin that does not exist """ @@ -381,7 +381,7 @@ class TestPluginManager(TestCase): # THEN: The is_active() and finalise() methods should have been called self.assertIsNone(result, 'The result for get_plugin_by_name should be None') - def get_plugin_by_name_exists_test(self): + def test_get_plugin_by_name_exists(self): """ Test running the get_plugin_by_name() method to find a plugin that exists """ @@ -397,7 +397,7 @@ class TestPluginManager(TestCase): # THEN: The is_active() and finalise() methods should have been called self.assertEqual(result, mocked_plugin, 'The result for get_plugin_by_name should be the mocked plugin') - def new_service_created_with_disabled_plugin_test(self): + def test_new_service_created_with_disabled_plugin(self): """ Test running the new_service_created() method with a disabled plugin """ @@ -416,7 +416,7 @@ class TestPluginManager(TestCase): self.assertEqual(0, mocked_plugin.new_service_created.call_count, 'The new_service_created() method should not have been called.') - def new_service_created_with_active_plugin_test(self): + def test_new_service_created_with_active_plugin(self): """ Test running the new_service_created() method with an active plugin """ diff --git a/tests/functional/openlp_core_lib/test_projector_pjlink1.py b/tests/functional/openlp_core_lib/test_projector_pjlink1.py index 7f7f0e9cf..4928e5d0c 100644 --- a/tests/functional/openlp_core_lib/test_projector_pjlink1.py +++ b/tests/functional/openlp_core_lib/test_projector_pjlink1.py @@ -57,7 +57,7 @@ class TestPJLink(TestCase): @patch.object(pjlink_test, 'send_command') @patch.object(pjlink_test, 'waitForReadyRead') @patch('openlp.core.common.qmd5_hash') - def authenticated_connection_call_test(self, mock_qmd5_hash, mock_waitForReadyRead, mock_send_command, + def test_authenticated_connection_call(self, mock_qmd5_hash, mock_waitForReadyRead, mock_send_command, mock_readyRead): """ Ticket 92187: Fix for projector connect with PJLink authentication exception. @@ -74,7 +74,7 @@ class TestPJLink(TestCase): self.assertTrue(mock_qmd5_hash.called_with(TEST_PIN, "Connection request should have been called with TEST_PIN")) - def projector_class_test(self): + def test_projector_class(self): """ Test class version from projector """ @@ -88,7 +88,7 @@ class TestPJLink(TestCase): self.assertEquals(pjlink.pjlink_class, '1', 'Projector should have returned class=1') - def non_standard_class_reply_test(self): + def test_non_standard_class_reply(self): """ Bugfix 1550891: CLSS request returns non-standard 'Class N' reply """ @@ -103,7 +103,7 @@ class TestPJLink(TestCase): 'Non-standard class reply should have set proper class') @patch.object(pjlink_test, 'change_status') - def status_change_test(self, mock_change_status): + def test_status_change(self, mock_change_status): """ Test process_command call with ERR2 (Parameter) status """ @@ -120,7 +120,7 @@ class TestPJLink(TestCase): ERROR_STRING[E_PARAMETER])) @patch.object(pjlink_test, 'process_inpt') - def projector_return_ok_test(self, mock_process_inpt): + def test_projector_return_ok(self, mock_process_inpt): """ Test projector calls process_inpt command when process_command is called with INPT option """ @@ -135,7 +135,7 @@ class TestPJLink(TestCase): "process_inpt should have been called with 31") @patch.object(pjlink_test, 'projectorReceivedData') - def projector_process_lamp_test(self, mock_projectorReceivedData): + def test_projector_process_lamp(self, mock_projectorReceivedData): """ Test status lamp on/off and hours """ @@ -152,7 +152,7 @@ class TestPJLink(TestCase): 'Lamp hours should have been set to 22222') @patch.object(pjlink_test, 'projectorReceivedData') - def projector_process_multiple_lamp_test(self, mock_projectorReceivedData): + def test_projector_process_multiple_lamp(self, mock_projectorReceivedData): """ Test status multiple lamp on/off and hours """ @@ -179,7 +179,7 @@ class TestPJLink(TestCase): 'Lamp 3 hours should have been set to 33333') @patch.object(pjlink_test, 'projectorReceivedData') - def projector_process_power_on_test(self, mock_projectorReceivedData): + def test_projector_process_power_on(self, mock_projectorReceivedData): """ Test status power to ON """ @@ -194,7 +194,7 @@ class TestPJLink(TestCase): self.assertEquals(pjlink.power, S_ON, 'Power should have been set to ON') @patch.object(pjlink_test, 'projectorReceivedData') - def projector_process_power_off_test(self, mock_projectorReceivedData): + def test_projector_process_power_off(self, mock_projectorReceivedData): """ Test status power to STANDBY """ @@ -209,7 +209,7 @@ class TestPJLink(TestCase): self.assertEquals(pjlink.power, S_STANDBY, 'Power should have been set to STANDBY') @patch.object(pjlink_test, 'projectorUpdateIcons') - def projector_process_avmt_closed_unmuted_test(self, mock_projectorReceivedData): + def test_projector_process_avmt_closed_unmuted(self, mock_projectorReceivedData): """ Test avmt status shutter closed and audio muted """ @@ -226,7 +226,7 @@ class TestPJLink(TestCase): self.assertFalse(pjlink.mute, 'Audio should be off') @patch.object(pjlink_test, 'projectorUpdateIcons') - def projector_process_avmt_open_muted_test(self, mock_projectorReceivedData): + def test_projector_process_avmt_open_muted(self, mock_projectorReceivedData): """ Test avmt status shutter open and mute on """ @@ -243,7 +243,7 @@ class TestPJLink(TestCase): self.assertTrue(pjlink.mute, 'Audio should be off') @patch.object(pjlink_test, 'projectorUpdateIcons') - def projector_process_avmt_open_unmuted_test(self, mock_projectorReceivedData): + def test_projector_process_avmt_open_unmuted(self, mock_projectorReceivedData): """ Test avmt status shutter open and mute off off """ @@ -260,7 +260,7 @@ class TestPJLink(TestCase): self.assertFalse(pjlink.mute, 'Audio should be on') @patch.object(pjlink_test, 'projectorUpdateIcons') - def projector_process_avmt_closed_muted_test(self, mock_projectorReceivedData): + def test_projector_process_avmt_closed_muted(self, mock_projectorReceivedData): """ Test avmt status shutter closed and mute off """ @@ -276,7 +276,7 @@ class TestPJLink(TestCase): self.assertTrue(pjlink.shutter, 'Shutter should have been set to closed') self.assertTrue(pjlink.mute, 'Audio should be on') - def projector_process_input_test(self): + def test_projector_process_input(self): """ Test input source status shows current input """ @@ -290,7 +290,7 @@ class TestPJLink(TestCase): # THEN: Input selected should reflect current input self.assertEquals(pjlink.source, '1', 'Input source should be set to "1"') - def projector_reset_information_test(self): + def test_projector_reset_information(self): """ Test reset_information() resets all information and stops timers """ diff --git a/tests/functional/openlp_core_lib/test_projectordb.py b/tests/functional/openlp_core_lib/test_projectordb.py index 7c677177e..61263042f 100644 --- a/tests/functional/openlp_core_lib/test_projectordb.py +++ b/tests/functional/openlp_core_lib/test_projectordb.py @@ -107,7 +107,7 @@ class TestProjectorDB(TestCase): time.sleep(1) retries += 1 - def find_record_by_ip_test(self): + def test_find_record_by_ip(self): """ Test find record by IP """ @@ -121,7 +121,7 @@ class TestProjectorDB(TestCase): self.assertTrue(compare_data(Projector(**TEST2_DATA), record), 'Record found should have been test_2 data') - def find_record_by_name_test(self): + def test_find_record_by_name(self): """ Test find record by name """ @@ -135,7 +135,7 @@ class TestProjectorDB(TestCase): self.assertTrue(compare_data(Projector(**TEST2_DATA), record), 'Record found should have been test_2 data') - def record_delete_test(self): + def test_record_delete(self): """ Test record can be deleted """ @@ -150,7 +150,7 @@ class TestProjectorDB(TestCase): found = self.projector.get_projector_by_ip(TEST3_DATA['ip']) self.assertFalse(found, 'test_3 record should have been deleted') - def record_edit_test(self): + def test_record_edit(self): """ Test edited record returns the same record ID with different data """ @@ -176,7 +176,7 @@ class TestProjectorDB(TestCase): self.assertEqual(record_id, record.id, 'Edited record should have the same ID') self.assertTrue(compare_data(Projector(**TEST3_DATA), record), 'Edited record should have new data') - def source_add_test(self): + def test_source_add(self): """ Test source entry for projector item """ @@ -194,7 +194,7 @@ class TestProjectorDB(TestCase): item = self.projector.get_projector_by_id(item_id) self.assertTrue(compare_source(item.source_list[0], source)) - def manufacturer_repr_test(self): + def test_manufacturer_repr(self): """ Test Manufacturer.__repr__ text """ @@ -208,7 +208,7 @@ class TestProjectorDB(TestCase): self.assertEqual(str(manufacturer), '', 'Manufacturer.__repr__() should have returned a proper representation string') - def model_repr_test(self): + def test_model_repr(self): """ Test Model.__repr__ text """ @@ -222,7 +222,7 @@ class TestProjectorDB(TestCase): self.assertEqual(str(model), '', 'Model.__repr__() should have returned a proper representation string') - def source_repr_test(self): + def test_source_repr(self): """ Test Source.__repr__ text """ @@ -238,7 +238,7 @@ class TestProjectorDB(TestCase): self.assertEqual(str(source), '', 'Source.__repr__() should have returned a proper representation string') - def projector_repr_test(self): + def test_projector_repr(self): """ Test Projector.__repr__() text """ @@ -266,7 +266,7 @@ class TestProjectorDB(TestCase): 'source_list="[]") >', 'Projector.__repr__() should have returned a proper representation string') - def projectorsource_repr_test(self): + def test_projectorsource_repr(self): """ Test ProjectorSource.__repr__() text """ diff --git a/tests/functional/openlp_core_lib/test_renderer.py b/tests/functional/openlp_core_lib/test_renderer.py index 697c8ae85..a08fc8674 100644 --- a/tests/functional/openlp_core_lib/test_renderer.py +++ b/tests/functional/openlp_core_lib/test_renderer.py @@ -59,7 +59,7 @@ class TestRenderer(TestCase): """ del self.screens - def default_screen_layout_test(self): + def test_default_screen_layout(self): """ Test the default layout calculations """ @@ -73,7 +73,7 @@ class TestRenderer(TestCase): self.assertEqual(renderer.footer_start, 691, 'The base renderer should be a live controller') @patch('openlp.core.lib.renderer.FormattingTags.get_html_tags') - def get_start_tags_test(self, mocked_get_html_tags): + def test_get_start_tags(self, mocked_get_html_tags): """ Test the get_start_tags() method """ @@ -95,7 +95,7 @@ class TestRenderer(TestCase): self.assertEqual(result, expected_tuple), 'A tuple should be returned containing the text with correct ' \ 'tags, the opening tags, and the opening html tags.' - def word_split_test(self): + def test_word_split(self): """ Test the word_split() method """ @@ -109,7 +109,7 @@ class TestRenderer(TestCase): # THEN: The word lists should be the same. self.assertListEqual(result_words, expected_words) - def format_slide_logical_split_test(self): + def test_format_slide_logical_split(self): """ Test that a line with text and a logic break does not break the renderer just returns the input """ @@ -126,7 +126,7 @@ class TestRenderer(TestCase): # THEN: The word lists should be the same. self.assertListEqual(result_words, expected_words) - def format_slide_blank_before_split_test(self): + def test_format_slide_blank_before_split(self): """ Test that a line with blanks before the logical split at handled """ @@ -143,7 +143,7 @@ class TestRenderer(TestCase): # THEN: The blanks have been removed. self.assertListEqual(result_words, expected_words) - def format_slide_blank_after_split_test(self): + def test_format_slide_blank_after_split(self): """ Test that a line with blanks before the logical split at handled """ diff --git a/tests/functional/openlp_core_lib/test_screen.py b/tests/functional/openlp_core_lib/test_screen.py index ea6d70b42..763662c13 100644 --- a/tests/functional/openlp_core_lib/test_screen.py +++ b/tests/functional/openlp_core_lib/test_screen.py @@ -62,7 +62,7 @@ class TestScreenList(TestCase): del self.screens del self.application - def add_desktop_test(self): + def test_add_desktop(self): """ Test the ScreenList.screen_count_changed method to check if new monitors are detected by OpenLP. """ diff --git a/tests/functional/openlp_core_lib/test_serviceitem.py b/tests/functional/openlp_core_lib/test_serviceitem.py index cda7ad91b..e1c73b3ca 100644 --- a/tests/functional/openlp_core_lib/test_serviceitem.py +++ b/tests/functional/openlp_core_lib/test_serviceitem.py @@ -54,7 +54,7 @@ class TestServiceItem(TestCase): Registry().register('renderer', mocked_renderer) Registry().register('image_manager', MagicMock()) - def service_item_basic_test(self): + def test_service_item_basic(self): """ Test the Service Item - basic test """ @@ -67,7 +67,7 @@ class TestServiceItem(TestCase): self.assertTrue(service_item.is_valid, 'The new service item should be valid') self.assertTrue(service_item.missing_frames(), 'There should not be any frames in the service item') - def service_item_load_custom_from_service_test(self): + def test_service_item_load_custom_from_service(self): """ Test the Service Item - adding a custom slide from a saved service """ @@ -97,7 +97,7 @@ class TestServiceItem(TestCase): self.assertEqual('Slide 2', service_item.get_frame_title(1), '"Slide 2" has been returned as the title') self.assertEqual('', service_item.get_frame_title(2), 'Blank has been returned as the title of slide 3') - def service_item_load_image_from_service_test(self): + def test_service_item_load_image_from_service(self): """ Test the Service Item - adding an image from a saved service """ @@ -141,7 +141,7 @@ class TestServiceItem(TestCase): self.assertTrue(service_item.is_capable(ItemCapabilities.CanAppend), 'This service item should be able to have new items added to it') - def service_item_load_image_from_local_service_test(self): + def test_service_item_load_image_from_local_service(self): """ Test the Service Item - adding an image from a saved local service """ @@ -206,7 +206,7 @@ class TestServiceItem(TestCase): self.assertTrue(service_item.is_capable(ItemCapabilities.CanAppend), 'This service item should be able to have new items added to it') - def add_from_command_for_a_presentation_test(self): + def test_add_from_command_for_a_presentation(self): """ Test the Service Item - adding a presentation """ @@ -226,7 +226,7 @@ class TestServiceItem(TestCase): self.assertEqual(service_item.service_item_type, ServiceItemType.Command, 'It should be a Command') self.assertEqual(service_item.get_frames()[0], frame, 'Frames should match') - def add_from_comamnd_without_display_title_and_notes_test(self): + def test_add_from_comamnd_without_display_title_and_notes(self): """ Test the Service Item - add from command, but not presentation """ @@ -246,7 +246,7 @@ class TestServiceItem(TestCase): @patch(u'openlp.core.lib.serviceitem.ServiceItem.image_manager') @patch('openlp.core.lib.serviceitem.AppLocation.get_section_data_path') - def add_from_command_for_a_presentation_thumb_test(self, mocked_get_section_data_path, mocked_image_manager): + def test_add_from_command_for_a_presentation_thumb(self, mocked_get_section_data_path, mocked_image_manager): """ Test the Service Item - adding a presentation, updating the thumb path & adding the thumb to image_manager """ @@ -274,7 +274,7 @@ class TestServiceItem(TestCase): self.assertEqual(service_item.get_frames()[0], frame, 'Frames should match') self.assertEqual(1, mocked_image_manager.add_image.call_count, 'image_manager should be used') - def service_item_load_optical_media_from_service_test(self): + def test_service_item_load_optical_media_from_service(self): """ Test the Service Item - load an optical media item """ @@ -295,7 +295,7 @@ class TestServiceItem(TestCase): self.assertEqual(service_item.end_time, 672.069, 'End time should be 672.069') self.assertEqual(service_item.media_length, 17.694, 'Media length should be 17.694') - def service_item_load_song_and_audio_from_service_test(self): + def test_service_item_load_song_and_audio_from_service(self): """ Test the Service Item - adding a song slide from a saved service """ diff --git a/tests/functional/openlp_core_lib/test_theme.py b/tests/functional/openlp_core_lib/test_theme.py index 59f522793..c006abb78 100644 --- a/tests/functional/openlp_core_lib/test_theme.py +++ b/tests/functional/openlp_core_lib/test_theme.py @@ -44,7 +44,7 @@ class TestTheme(TestCase): """ pass - def new_theme_test(self): + def test_new_theme(self): """ Test the theme creation - basic test """ diff --git a/tests/functional/openlp_core_lib/test_ui.py b/tests/functional/openlp_core_lib/test_ui.py index c6fef4010..dfd74233b 100644 --- a/tests/functional/openlp_core_lib/test_ui.py +++ b/tests/functional/openlp_core_lib/test_ui.py @@ -37,7 +37,7 @@ class TestUi(TestCase): Test the functions in the ui module """ - def add_welcome_page_test(self): + def test_add_welcome_page(self): """ Test appending a welcome page to a wizard """ @@ -51,7 +51,7 @@ class TestUi(TestCase): self.assertEqual(1, len(wizard.pageIds()), 'The wizard should have one page.') self.assertIsInstance(wizard.page(0).pixmap(QtWidgets.QWizard.WatermarkPixmap), QtGui.QPixmap) - def create_button_box_test(self): + def test_create_button_box(self): """ Test creating a button box for a dialog """ @@ -79,7 +79,7 @@ class TestUi(TestCase): self.assertEqual(1, len(btnbox.buttons())) self.assertEqual(QtWidgets.QDialogButtonBox.HelpRole, btnbox.buttonRole(btnbox.buttons()[0])) - def create_horizontal_adjusting_combo_box_test(self): + def test_create_horizontal_adjusting_combo_box(self): """ Test creating a horizontal adjusting combo box """ @@ -94,7 +94,7 @@ class TestUi(TestCase): self.assertEqual('combo1', combo.objectName()) self.assertEqual(QtWidgets.QComboBox.AdjustToMinimumContentsLength, combo.sizeAdjustPolicy()) - def create_button_test(self): + def test_create_button(self): """ Test creating a button """ @@ -126,7 +126,7 @@ class TestUi(TestCase): self.assertEqual('my_btn', btn.objectName()) self.assertTrue(btn.isEnabled()) - def create_action_test(self): + def test_create_action(self): """ Test creating an action """ @@ -151,7 +151,7 @@ class TestUi(TestCase): self.assertEqual('my tooltip', action.toolTip()) self.assertEqual('my statustip', action.statusTip()) - def create_action_on_mac_osx_test(self): + def test_create_action_on_mac_osx(self): """ Test creating an action on OS X calls the correct method """ @@ -169,7 +169,7 @@ class TestUi(TestCase): # THEN: setIconVisibleInMenu should be called mocked_action.setIconVisibleInMenu.assert_called_with(False) - def create_action_not_on_mac_osx_test(self): + def test_create_action_not_on_mac_osx(self): """ Test creating an action on something other than OS X doesn't call the method """ @@ -188,7 +188,7 @@ class TestUi(TestCase): self.assertEqual(0, mocked_action.setIconVisibleInMenu.call_count, 'setIconVisibleInMenu should not have been called') - def create_checked_disabled_invisible_action_test(self): + def test_create_checked_disabled_invisible_action(self): """ Test that an invisible, disabled, checked action is created correctly """ @@ -203,7 +203,7 @@ class TestUi(TestCase): self.assertFalse(action.isEnabled(), 'The action should be disabled') self.assertFalse(action.isVisible(), 'The action should be invisble') - def create_action_separator_test(self): + def test_create_action_separator(self): """ Test creating an action as separator """ @@ -216,7 +216,7 @@ class TestUi(TestCase): # THEN: The action should be a separator self.assertTrue(action.isSeparator(), 'The action should be a separator') - def create_valign_selection_widgets_test(self): + def test_create_valign_selection_widgets(self): """ Test creating a combo box for valign selection """ @@ -233,7 +233,7 @@ class TestUi(TestCase): for text in [UiStrings().Top, UiStrings().Middle, UiStrings().Bottom]: self.assertTrue(combo.findText(text) >= 0) - def find_and_set_in_combo_box_test(self): + def test_find_and_set_in_combo_box(self): """ Test finding a string in a combo box and setting it as the selected item if present """ @@ -260,7 +260,7 @@ class TestUi(TestCase): # THEN: The index should have changed self.assertEqual(2, combo.currentIndex()) - def create_widget_action_test(self): + def test_create_widget_action(self): """ Test creating an action for a widget """ @@ -274,7 +274,7 @@ class TestUi(TestCase): self.assertIsInstance(action, QtWidgets.QAction) self.assertEqual(action.objectName(), 'some action') - def set_case_insensitive_completer_test(self): + def test_set_case_insensitive_completer(self): """ Test setting a case insensitive completer on a widget """ diff --git a/tests/functional/openlp_core_lib/test_webpagereader.py b/tests/functional/openlp_core_lib/test_webpagereader.py index 80b2c1f9a..6e33fca51 100644 --- a/tests/functional/openlp_core_lib/test_webpagereader.py +++ b/tests/functional/openlp_core_lib/test_webpagereader.py @@ -33,7 +33,7 @@ class TestUtils(TestCase): """ A test suite to test out various methods around the AppLocation class. """ - def get_user_agent_linux_test(self): + def test_get_user_agent_linux(self): """ Test that getting a user agent on Linux returns a user agent suitable for Linux """ @@ -49,7 +49,7 @@ class TestUtils(TestCase): result = 'Linux' in user_agent or 'CrOS' in user_agent self.assertTrue(result, 'The user agent should be a valid Linux user agent') - def get_user_agent_windows_test(self): + def test_get_user_agent_windows(self): """ Test that getting a user agent on Windows returns a user agent suitable for Windows """ @@ -64,7 +64,7 @@ class TestUtils(TestCase): # THEN: The user agent is a Linux (or ChromeOS) user agent self.assertIn('Windows', user_agent, 'The user agent should be a valid Windows user agent') - def get_user_agent_macos_test(self): + def test_get_user_agent_macos(self): """ Test that getting a user agent on OS X returns a user agent suitable for OS X """ @@ -79,7 +79,7 @@ class TestUtils(TestCase): # THEN: The user agent is a Linux (or ChromeOS) user agent self.assertIn('Mac OS X', user_agent, 'The user agent should be a valid OS X user agent') - def get_user_agent_default_test(self): + def test_get_user_agent_default(self): """ Test that getting a user agent on a non-Linux/Windows/OS X platform returns the default user agent """ @@ -94,7 +94,7 @@ class TestUtils(TestCase): # THEN: The user agent is a Linux (or ChromeOS) user agent self.assertIn('NetBSD', user_agent, 'The user agent should be the default user agent') - def get_web_page_no_url_test(self): + def test_get_web_page_no_url(self): """ Test that sending a URL of None to the get_web_page method returns None """ @@ -107,7 +107,7 @@ class TestUtils(TestCase): # THEN: None should be returned self.assertIsNone(result, 'The return value of get_web_page should be None') - def get_web_page_test(self): + def test_get_web_page(self): """ Test that the get_web_page method works correctly """ @@ -137,7 +137,7 @@ class TestUtils(TestCase): self.assertEqual(0, MockRegistry.call_count, 'The Registry() object should have never been called') self.assertEqual(mocked_page_object, returned_page, 'The returned page should be the mock object') - def get_web_page_with_header_test(self): + def test_get_web_page_with_header(self): """ Test that adding a header to the call to get_web_page() adds the header to the request """ @@ -166,7 +166,7 @@ class TestUtils(TestCase): mocked_page_object.geturl.assert_called_with() self.assertEqual(mocked_page_object, returned_page, 'The returned page should be the mock object') - def get_web_page_with_user_agent_in_headers_test(self): + def test_get_web_page_with_user_agent_in_headers(self): """ Test that adding a user agent in the header when calling get_web_page() adds that user agent to the request """ @@ -194,7 +194,7 @@ class TestUtils(TestCase): mocked_page_object.geturl.assert_called_with() self.assertEqual(mocked_page_object, returned_page, 'The returned page should be the mock object') - def get_web_page_update_openlp_test(self): + def test_get_web_page_update_openlp(self): """ Test that passing "update_openlp" as true to get_web_page calls Registry().get('app').process_events() """ diff --git a/tests/functional/openlp_core_ui/test_first_time.py b/tests/functional/openlp_core_ui/test_first_time.py index 43c8c0bc1..d8067dfbe 100644 --- a/tests/functional/openlp_core_ui/test_first_time.py +++ b/tests/functional/openlp_core_ui/test_first_time.py @@ -38,7 +38,7 @@ class TestFirstTimeWizard(TestMixin, TestCase): """ Test First Time Wizard import functions """ - def webpage_connection_retry_test(self): + def test_webpage_connection_retry(self): """ Test get_web_page will attempt CONNECTION_RETRIES+1 connections - bug 1409031 """ diff --git a/tests/functional/openlp_core_ui/test_firsttimeform.py b/tests/functional/openlp_core_ui/test_firsttimeform.py index 8b9a0f8b5..5dd1430cd 100644 --- a/tests/functional/openlp_core_ui/test_firsttimeform.py +++ b/tests/functional/openlp_core_ui/test_firsttimeform.py @@ -78,7 +78,7 @@ class TestFirstTimeForm(TestCase, TestMixin): if os.path.isfile(self.tempfile): os.remove(self.tempfile) - def initialise_test(self): + def test_initialise(self): """ Test if we can intialise the FirstTimeForm """ @@ -97,7 +97,7 @@ class TestFirstTimeForm(TestCase, TestMixin): self.assertListEqual([], frw.theme_screenshot_workers, 'The list of workers should be empty') self.assertFalse(frw.has_run_wizard, 'has_run_wizard should be False') - def set_defaults_test(self): + def test_set_defaults(self): """ Test that the default values are set when set_defaults() is run """ @@ -134,7 +134,7 @@ class TestFirstTimeForm(TestCase, TestMixin): mocked_gettempdir.assert_called_with() mocked_check_directory_exists.assert_called_with(expected_temp_path) - def update_screen_list_combo_test(self): + def test_update_screen_list_combo(self): """ Test that the update_screen_list_combo() method works correctly """ @@ -157,7 +157,7 @@ class TestFirstTimeForm(TestCase, TestMixin): mocked_display_combo_box.count.assert_called_with() mocked_display_combo_box.setCurrentIndex.assert_called_with(1) - def on_cancel_button_clicked_test(self): + def test_on_cancel_button_clicked(self): """ Test that the cancel button click slot shuts down the threads correctly """ @@ -184,7 +184,7 @@ class TestFirstTimeForm(TestCase, TestMixin): self.assertEqual(1, mocked_time.sleep.call_count, 'sleep() should have only been called once') mocked_set_normal_cursor.assert_called_with() - def broken_config_test(self): + def test_broken_config(self): """ Test if we can handle an config file with missing data """ @@ -200,7 +200,7 @@ class TestFirstTimeForm(TestCase, TestMixin): # THEN: The First Time Form should not have web access self.assertFalse(first_time_form.web_access, 'There should not be web access with a broken config file') - def invalid_config_test(self): + def test_invalid_config(self): """ Test if we can handle an config file in invalid format """ @@ -218,7 +218,7 @@ class TestFirstTimeForm(TestCase, TestMixin): @patch('openlp.core.ui.firsttimeform.get_web_page') @patch('openlp.core.ui.firsttimeform.QtWidgets.QMessageBox') - def network_error_test(self, mocked_message_box, mocked_get_web_page): + def test_network_error(self, mocked_message_box, mocked_get_web_page): """ Test we catch a network error in First Time Wizard - bug 1409627 """ @@ -238,7 +238,7 @@ class TestFirstTimeForm(TestCase, TestMixin): 'first_time_form should have caught Network Error') @patch('openlp.core.ui.firsttimeform.urllib.request.urlopen') - def socket_timeout_test(self, mocked_urlopen): + def test_socket_timeout(self, mocked_urlopen): """ Test socket timeout gets caught """ diff --git a/tests/functional/openlp_core_ui/test_formattingtagscontroller.py b/tests/functional/openlp_core_ui/test_formattingtagscontroller.py index d9e56d205..b869f5e80 100644 --- a/tests/functional/openlp_core_ui/test_formattingtagscontroller.py +++ b/tests/functional/openlp_core_ui/test_formattingtagscontroller.py @@ -32,7 +32,7 @@ class TestFormattingTagController(TestCase): def setUp(self): self.services = FormattingTagController() - def strip_test(self): + def test_strip(self): """ Test that the _strip strips the correct chars """ @@ -45,7 +45,7 @@ class TestFormattingTagController(TestCase): # THEN: The tag should be returned with the wrappers removed. self.assertEqual(result, 'tag', 'FormattingTagForm._strip should return u\'tag\' when called with u\'{tag}\'') - def end_tag_changed_processes_correctly_test(self): + def test_end_tag_changed_processes_correctly(self): """ Test that the end html tags are generated correctly """ @@ -70,7 +70,7 @@ class TestFormattingTagController(TestCase): self.assertTrue(error == test['valid'], 'Function should not generate unexpected error messages : %s ' % error) - def start_tag_changed_processes_correctly_test(self): + def test_start_tag_changed_processes_correctly(self): """ Test that the end html tags are generated correctly """ @@ -93,7 +93,7 @@ class TestFormattingTagController(TestCase): self.assertTrue(error == test['valid'], 'Function should not generate unexpected error messages : %s ' % error) - def start_html_to_end_html_test(self): + def test_start_html_to_end_html(self): """ Test that the end html tags are generated correctly """ diff --git a/tests/functional/openlp_core_ui/test_formattingtagsform.py b/tests/functional/openlp_core_ui/test_formattingtagsform.py index d4b27985e..3dbd52f66 100644 --- a/tests/functional/openlp_core_ui/test_formattingtagsform.py +++ b/tests/functional/openlp_core_ui/test_formattingtagsform.py @@ -50,7 +50,7 @@ class TestFormattingTagForm(TestCase): """ self.setup_patcher.stop() - def on_row_selected_test(self): + def test_on_row_selected(self): """ Test that the appropriate actions are preformed when on_row_selected is called """ @@ -64,7 +64,7 @@ class TestFormattingTagForm(TestCase): # THEN: setEnabled and should have been called on delete_button form.delete_button.setEnabled.assert_called_with(True) - def on_new_clicked_test(self): + def test_on_new_clicked(self): """ Test that clicking the Add a new tag button does the right thing """ diff --git a/tests/functional/openlp_core_ui/test_maindisplay.py b/tests/functional/openlp_core_ui/test_maindisplay.py index 1eb92e93e..5aa0f42a4 100644 --- a/tests/functional/openlp_core_ui/test_maindisplay.py +++ b/tests/functional/openlp_core_ui/test_maindisplay.py @@ -70,7 +70,7 @@ class TestMainDisplay(TestCase, TestMixin): self.mocked_audio_player.stop() del self.screens - def initial_main_display_test(self): + def test_initial_main_display(self): """ Test the initial Main Display state """ @@ -84,7 +84,7 @@ class TestMainDisplay(TestCase, TestMixin): # THEN: The controller should be a live controller. self.assertEqual(main_display.is_live, True, 'The main display should be a live controller') - def set_transparency_enabled_test(self): + def test_set_transparency_enabled(self): """ Test setting the display to be transparent """ @@ -103,7 +103,7 @@ class TestMainDisplay(TestCase, TestMixin): self.assertTrue(main_display.testAttribute(QtCore.Qt.WA_TranslucentBackground), 'The MainDisplay should have a translucent background') - def set_transparency_disabled_test(self): + def test_set_transparency_disabled(self): """ Test setting the display to be opaque """ @@ -120,7 +120,7 @@ class TestMainDisplay(TestCase, TestMixin): self.assertFalse(main_display.testAttribute(QtCore.Qt.WA_TranslucentBackground), 'The MainDisplay should not have a translucent background') - def css_changed_test(self): + def test_css_changed(self): """ Test that when the CSS changes, the plugins are looped over and given an opportunity to update the CSS """ @@ -143,7 +143,7 @@ class TestMainDisplay(TestCase, TestMixin): mocked_bibles_plugin.refresh_css.assert_called_with(main_display.frame) @skipUnless(is_macosx(), 'Can only run test on Mac OS X due to pyobjc dependency.') - def macosx_display_window_flags_state_test(self): + def test_macosx_display_window_flags_state(self): """ Test that on Mac OS X we set the proper window flags """ @@ -160,7 +160,7 @@ class TestMainDisplay(TestCase, TestMixin): 'The window flags should be Qt.Window, and Qt.FramelessWindowHint.') @skipUnless(is_macosx(), 'Can only run test on Mac OS X due to pyobjc dependency.') - def macosx_display_test(self): + def test_macosx_display(self): """ Test display on Mac OS X """ @@ -186,7 +186,7 @@ class TestMainDisplay(TestCase, TestMixin): 'Window collection behavior should be NSWindowCollectionBehaviorManaged') @patch(u'openlp.core.ui.maindisplay.Settings') - def show_display_startup_logo_test(self, MockedSettings): + def test_show_display_startup_logo(self, MockedSettings): # GIVEN: Mocked show_display, setting for logo visibility display = MagicMock() main_display = MainDisplay(display) @@ -206,7 +206,7 @@ class TestMainDisplay(TestCase, TestMixin): main_display.setVisible.assert_called_once_with(True) @patch(u'openlp.core.ui.maindisplay.Settings') - def show_display_hide_startup_logo_test(self, MockedSettings): + def test_show_display_hide_startup_logo(self, MockedSettings): # GIVEN: Mocked show_display, setting for logo visibility display = MagicMock() main_display = MainDisplay(display) @@ -227,7 +227,7 @@ class TestMainDisplay(TestCase, TestMixin): @patch(u'openlp.core.ui.maindisplay.Settings') @patch(u'openlp.core.ui.maindisplay.build_html') - def build_html_no_video_test(self, MockedSettings, Mocked_build_html): + def test_build_html_no_video(self, MockedSettings, Mocked_build_html): # GIVEN: Mocked display display = MagicMock() mocked_media_controller = MagicMock() @@ -255,7 +255,7 @@ class TestMainDisplay(TestCase, TestMixin): @patch(u'openlp.core.ui.maindisplay.Settings') @patch(u'openlp.core.ui.maindisplay.build_html') - def build_html_video_test(self, MockedSettings, Mocked_build_html): + def test_build_html_video(self, MockedSettings, Mocked_build_html): # GIVEN: Mocked display display = MagicMock() mocked_media_controller = MagicMock() diff --git a/tests/functional/openlp_core_ui/test_mainwindow.py b/tests/functional/openlp_core_ui/test_mainwindow.py index 8a8b2516c..3fa1f3769 100644 --- a/tests/functional/openlp_core_ui/test_mainwindow.py +++ b/tests/functional/openlp_core_ui/test_mainwindow.py @@ -72,7 +72,7 @@ class TestMainWindow(TestCase, TestMixin): def tearDown(self): del self.main_window - def cmd_line_file_test(self): + def test_cmd_line_file(self): """ Test that passing a service file from the command line loads the service. """ @@ -87,7 +87,7 @@ class TestMainWindow(TestCase, TestMixin): # THEN the service from the arguments is loaded mocked_load_path.assert_called_with(service), 'load_path should have been called with the service\'s path' - def cmd_line_arg_test(self): + def test_cmd_line_arg(self): """ Test that passing a non service file does nothing. """ @@ -102,7 +102,7 @@ class TestMainWindow(TestCase, TestMixin): # THEN the file should not be opened assert not mocked_load_path.called, 'load_path should not have been called' - def main_window_title_test(self): + def test_main_window_title(self): """ Test that running a new instance of OpenLP set the window title correctly """ @@ -114,7 +114,7 @@ class TestMainWindow(TestCase, TestMixin): self.assertEqual(self.main_window.windowTitle(), UiStrings().OLPV2x, 'The main window\'s title should be the same as the OLPV2x string in UiStrings class') - def set_service_modifed_test(self): + def test_set_service_modifed(self): """ Test that when setting the service's title the main window's title is set correctly """ @@ -127,7 +127,7 @@ class TestMainWindow(TestCase, TestMixin): self.assertEqual(self.main_window.windowTitle(), '%s - %s*' % (UiStrings().OLPV2x, 'test.osz'), 'The main window\'s title should be set to " - test.osz*"') - def set_service_unmodified_test(self): + def test_set_service_unmodified(self): """ Test that when setting the service's title the main window's title is set correctly """ @@ -140,7 +140,7 @@ class TestMainWindow(TestCase, TestMixin): self.assertEqual(self.main_window.windowTitle(), '%s - %s' % (UiStrings().OLPV2x, 'test.osz'), 'The main window\'s title should be set to " - test.osz"') - def mainwindow_configuration_test(self): + def test_mainwindow_configuration(self): """ Check that the Main Window initialises the Registry Correctly """ @@ -158,7 +158,7 @@ class TestMainWindow(TestCase, TestMixin): self.assertTrue('plugin_manager' in self.registry.service_list, 'The plugin_manager should have been registered.') - def on_search_shortcut_triggered_shows_media_manager_test(self): + def test_on_search_shortcut_triggered_shows_media_manager(self): """ Test that the media manager is made visible when the search shortcut is triggered """ @@ -174,7 +174,7 @@ class TestMainWindow(TestCase, TestMixin): # THEN: The media manager dock is made visible mocked_media_manager_dock.setVisible.assert_called_with(True) - def on_search_shortcut_triggered_focuses_widget_test(self): + def test_on_search_shortcut_triggered_focuses_widget(self): """ Test that the focus is set on the widget when the search shortcut is triggered """ @@ -198,7 +198,7 @@ class TestMainWindow(TestCase, TestMixin): @patch('openlp.core.ui.mainwindow.FirstTimeForm') @patch('openlp.core.ui.mainwindow.QtWidgets.QMessageBox.warning') @patch('openlp.core.ui.mainwindow.Settings') - def on_first_time_wizard_clicked_show_projectors_after_test(self, mocked_Settings, mocked_warning, + def test_on_first_time_wizard_clicked_show_projectors_after(self, mocked_Settings, mocked_warning, mocked_FirstTimeForm, mocked_application, mocked_first_time, mocked_plugin_manager): @@ -225,7 +225,7 @@ class TestMainWindow(TestCase, TestMixin): @patch('openlp.core.ui.mainwindow.FirstTimeForm') @patch('openlp.core.ui.mainwindow.QtWidgets.QMessageBox.warning') @patch('openlp.core.ui.mainwindow.Settings') - def on_first_time_wizard_clicked_hide_projectors_after_test(self, mocked_Settings, mocked_warning, + def test_on_first_time_wizard_clicked_hide_projectors_after(self, mocked_Settings, mocked_warning, mocked_FirstTimeForm, mocked_application, mocked_first_time, mocked_plugin_manager): diff --git a/tests/functional/openlp_core_ui/test_servicemanager.py b/tests/functional/openlp_core_ui/test_servicemanager.py index 822703443..3c6c20ab5 100644 --- a/tests/functional/openlp_core_ui/test_servicemanager.py +++ b/tests/functional/openlp_core_ui/test_servicemanager.py @@ -40,7 +40,7 @@ class TestServiceManager(TestCase): """ Registry.create() - def initial_service_manager_test(self): + def test_initial_service_manager(self): """ Test the initial of service manager. """ @@ -50,7 +50,7 @@ class TestServiceManager(TestCase): # THEN: The the controller should be registered in the registry. self.assertNotEqual(Registry().get('service_manager'), None, 'The base service manager should be registered') - def create_basic_service_test(self): + def test_create_basic_service(self): """ Test the create basic service array """ @@ -65,7 +65,7 @@ class TestServiceManager(TestCase): self.assertEqual(service['openlp_core']['service-theme'], 'test_theme', 'The test theme should be saved') self.assertEqual(service['openlp_core']['lite-service'], False, 'The lite service should be saved') - def supported_suffixes_test(self): + def test_supported_suffixes(self): """ Test the create basic service array """ @@ -79,7 +79,7 @@ class TestServiceManager(TestCase): self.assertEqual('ppt' in service_manager.suffixes, True, 'The suffix ppt should be in the list') self.assertEqual('pptx' in service_manager.suffixes, True, 'The suffix pptx should be in the list') - def build_context_menu_test(self): + def test_build_context_menu(self): """ Test the creation of a context menu from a null service item. """ @@ -123,7 +123,7 @@ class TestServiceManager(TestCase): self.assertEquals(service_manager.theme_menu.menuAction().setVisible.call_count, 1, 'Should have been called once') - def build_song_context_menu_test(self): + def test_build_song_context_menu(self): """ Test the creation of a context menu from service item of type text from Songs. """ @@ -189,7 +189,7 @@ class TestServiceManager(TestCase): self.assertEquals(service_manager.auto_play_slides_loop.setChecked.call_count, 1, 'Should have be called once') self.assertEquals(service_manager.timed_slide_interval.setChecked.call_count, 1, 'Should have be called once') - def build_bible_context_menu_test(self): + def test_build_bible_context_menu(self): """ Test the creation of a context menu from service item of type text from Bibles. """ @@ -254,7 +254,7 @@ class TestServiceManager(TestCase): self.assertEquals(service_manager.auto_play_slides_loop.setChecked.call_count, 1, 'Should have be called once') self.assertEquals(service_manager.timed_slide_interval.setChecked.call_count, 1, 'Should have be called once') - def build_custom_context_menu_test(self): + def test_build_custom_context_menu(self): """ Test the creation of a context menu from service item of type text from Custom. """ @@ -319,7 +319,7 @@ class TestServiceManager(TestCase): self.assertEquals(service_manager.auto_play_slides_loop.setChecked.call_count, 1, 'Should have be called once') self.assertEquals(service_manager.timed_slide_interval.setChecked.call_count, 1, 'Should have be called once') - def build_image_context_menu_test(self): + def test_build_image_context_menu(self): """ Test the creation of a context menu from service item of type Image from Image. """ @@ -382,7 +382,7 @@ class TestServiceManager(TestCase): self.assertEquals(service_manager.auto_play_slides_loop.setChecked.call_count, 1, 'Should have be called once') self.assertEquals(service_manager.timed_slide_interval.setChecked.call_count, 1, 'Should have be called once') - def build_media_context_menu_test(self): + def test_build_media_context_menu(self): """ Test the creation of a context menu from service item of type Command from Media. """ @@ -439,7 +439,7 @@ class TestServiceManager(TestCase): # THEN the following additional calls should have occurred. self.assertEquals(service_manager.time_action.setVisible.call_count, 3, 'Should have be called three times') - def build_presentation_pdf_context_menu_test(self): + def test_build_presentation_pdf_context_menu(self): """ Test the creation of a context menu from service item of type Command with PDF from Presentation. """ @@ -492,7 +492,7 @@ class TestServiceManager(TestCase): self.assertEquals(service_manager.theme_menu.menuAction().setVisible.call_count, 1, 'Should have be called once') - def build_presentation_non_pdf_context_menu_test(self): + def test_build_presentation_non_pdf_context_menu(self): """ Test the creation of a context menu from service item of type Command with Impress from Presentation. """ diff --git a/tests/functional/openlp_core_ui/test_settingsform.py b/tests/functional/openlp_core_ui/test_settingsform.py index 25dae3fc9..051bc7af1 100644 --- a/tests/functional/openlp_core_ui/test_settingsform.py +++ b/tests/functional/openlp_core_ui/test_settingsform.py @@ -39,7 +39,7 @@ class TestSettingsForm(TestCase): """ Registry.create() - def insert_tab_visible_test(self): + def test_insert_tab_visible(self): """ Test that the insert_tab() method works correctly when a visible tab is inserted """ @@ -59,7 +59,7 @@ class TestSettingsForm(TestCase): mocked_add_widget.assert_called_with(general_tab) self.assertEqual(1, mocked_add_item.call_count, 'addItem should have been called') - def insert_tab_not_visible_test(self): + def test_insert_tab_not_visible(self): """ Test that the insert_tab() method works correctly when a tab that should not be visible is inserted """ @@ -77,7 +77,7 @@ class TestSettingsForm(TestCase): mocked_add_widget.assert_called_with(general_tab) self.assertEqual(0, mocked_add_item.call_count, 'addItem should not have been called') - def accept_with_inactive_plugins_test(self): + def test_accept_with_inactive_plugins(self): """ Test that the accept() method works correctly when some of the plugins are inactive """ @@ -105,7 +105,7 @@ class TestSettingsForm(TestCase): mocked_general_save.assert_called_with() self.assertEqual(0, mocked_theme_save.call_count, 'The Themes tab\'s save() should not have been called') - def list_item_changed_invalid_item_test(self): + def test_list_item_changed_invalid_item(self): """ Test that the list_item_changed() slot handles a non-existent item """ @@ -124,7 +124,7 @@ class TestSettingsForm(TestCase): # THEN: The rest of the method should not have been called self.assertEqual(0, mocked_count.call_count, 'The count method of the stacked layout should not be called') - def reject_with_inactive_items_test(self): + def test_reject_with_inactive_items(self): """ Test that the reject() method works correctly when some of the plugins are inactive """ diff --git a/tests/functional/openlp_core_ui/test_slidecontroller.py b/tests/functional/openlp_core_ui/test_slidecontroller.py index f47601bbd..3777d5f82 100644 --- a/tests/functional/openlp_core_ui/test_slidecontroller.py +++ b/tests/functional/openlp_core_ui/test_slidecontroller.py @@ -35,7 +35,7 @@ from tests.functional import MagicMock, patch class TestSlideController(TestCase): - def initial_slide_controller_test(self): + def test_initial_slide_controller(self): """ Test the initial slide controller state . """ @@ -46,7 +46,7 @@ class TestSlideController(TestCase): # THEN: The controller should not be a live controller. self.assertEqual(slide_controller.is_live, False, 'The base slide controller should not be a live controller') - def text_service_item_blank_test(self): + def test_text_service_item_blank(self): """ Test that loading a text-based service item into the slide controller sets the correct blank menu """ @@ -65,7 +65,7 @@ class TestSlideController(TestCase): # THEN: the call to set the visible items on the toolbar should be correct toolbar.set_widget_visible.assert_called_with(WIDE_MENU, True) - def non_text_service_item_blank_test(self): + def test_non_text_service_item_blank(self): """ Test that loading a non-text service item into the slide controller sets the correct blank menu """ @@ -85,7 +85,7 @@ class TestSlideController(TestCase): toolbar.set_widget_visible.assert_called_with(NON_TEXT_MENU, True) @patch('openlp.core.ui.slidecontroller.Settings') - def receive_spin_delay_test(self, MockedSettings): + def test_receive_spin_delay(self, MockedSettings): """ Test that the spin box is updated accordingly after a call to receive_spin_delay() """ @@ -103,7 +103,7 @@ class TestSlideController(TestCase): mocked_value.assert_called_with('core/loop delay') mocked_delay_spin_box.setValue.assert_called_with(1) - def toggle_display_blank_test(self): + def test_toggle_display_blank(self): """ Check that the toggle_display('blank') method calls the on_blank_display() method """ @@ -124,7 +124,7 @@ class TestSlideController(TestCase): self.assertEqual(0, mocked_on_theme_display.call_count, 'on_theme_display should not have been called') self.assertEqual(0, mocked_on_hide_display.call_count, 'on_hide_display should not have been called') - def toggle_display_hide_test(self): + def test_toggle_display_hide(self): """ Check that the toggle_display('hide') method calls the on_blank_display() method """ @@ -145,7 +145,7 @@ class TestSlideController(TestCase): self.assertEqual(0, mocked_on_theme_display.call_count, 'on_theme_display should not have been called') self.assertEqual(0, mocked_on_hide_display.call_count, 'on_hide_display should not have been called') - def toggle_display_theme_test(self): + def test_toggle_display_theme(self): """ Check that the toggle_display('theme') method calls the on_theme_display() method """ @@ -166,7 +166,7 @@ class TestSlideController(TestCase): self.assertEqual(0, mocked_on_blank_display.call_count, 'on_blank_display should not have been called') self.assertEqual(0, mocked_on_hide_display.call_count, 'on_hide_display should not have been called') - def toggle_display_desktop_test(self): + def test_toggle_display_desktop(self): """ Check that the toggle_display('desktop') method calls the on_hide_display() method """ @@ -187,7 +187,7 @@ class TestSlideController(TestCase): self.assertEqual(0, mocked_on_blank_display.call_count, 'on_blank_display should not have been called') self.assertEqual(0, mocked_on_theme_display.call_count, 'on_theme_display should not have been called') - def toggle_display_show_test(self): + def test_toggle_display_show(self): """ Check that the toggle_display('show') method calls all the on_X_display() methods """ @@ -208,7 +208,7 @@ class TestSlideController(TestCase): mocked_on_theme_display.assert_called_once_with(False) mocked_on_hide_display.assert_called_once_with(False) - def live_escape_test(self): + def test_live_escape(self): """ Test that when the live_escape() method is called, the display is set to invisible and any media is stopped """ @@ -231,7 +231,7 @@ class TestSlideController(TestCase): mocked_display.setVisible.assert_called_once_with(False) mocked_media_controller.media_stop.assert_called_once_with(slide_controller) - def on_go_live_live_controller_test(self): + def test_on_go_live_live_controller(self): """ Test that when the on_go_live() method is called the message is sent to the live controller and focus is set correctly. @@ -259,7 +259,7 @@ class TestSlideController(TestCase): mocked_live_controller.add_service_manager_item.assert_called_once_with(mocked_service_item, 1) mocked_live_controller.preview_widget.setFocus.assert_called_once_with() - def on_go_live_service_manager_test(self): + def test_on_go_live_service_manager(self): """ Test that when the on_go_live() method is called the message is sent to the live controller and focus is set correctly. @@ -290,7 +290,7 @@ class TestSlideController(TestCase): mocked_service_manager.preview_live.assert_called_once_with(42, 1) mocked_live_controller.preview_widget.setFocus.assert_called_once_with() - def service_previous_test(self): + def test_service_previous(self): """ Check that calling the service_previous() method adds the previous key to the queue and processes the queue """ @@ -308,7 +308,7 @@ class TestSlideController(TestCase): mocked_keypress_queue.append.assert_called_once_with(ServiceItemAction.Previous) mocked_process_queue.assert_called_once_with() - def service_next_test(self): + def test_service_next(self): """ Check that calling the service_next() method adds the next key to the queue and processes the queue """ @@ -327,7 +327,7 @@ class TestSlideController(TestCase): mocked_process_queue.assert_called_once_with() @patch('openlp.core.ui.slidecontroller.Settings') - def update_slide_limits_test(self, MockedSettings): + def test_update_slide_limits(self, MockedSettings): """ Test that calling the update_slide_limits() method updates the slide limits """ @@ -346,7 +346,7 @@ class TestSlideController(TestCase): mocked_value.assert_called_once_with('advanced/slide limits') self.assertEqual(10, slide_controller.slide_limits, 'Slide limits should have been updated to 10') - def enable_tool_bar_live_test(self): + def test_enable_tool_bar_live(self): """ Check that when enable_tool_bar on a live slide controller is called, enable_live_tool_bar is called """ @@ -366,7 +366,7 @@ class TestSlideController(TestCase): mocked_enable_live_tool_bar.assert_called_once_with(mocked_service_item) self.assertEqual(0, mocked_enable_preview_tool_bar.call_count, 'The preview method should not have been called') - def enable_tool_bar_preview_test(self): + def test_enable_tool_bar_preview(self): """ Check that when enable_tool_bar on a preview slide controller is called, enable_preview_tool_bar is called """ @@ -386,7 +386,7 @@ class TestSlideController(TestCase): mocked_enable_preview_tool_bar.assert_called_once_with(mocked_service_item) self.assertEqual(0, mocked_enable_live_tool_bar.call_count, 'The live method should not have been called') - def refresh_service_item_text_test(self): + def test_refresh_service_item_text(self): """ Test that the refresh_service_item() method refreshes a text service item """ @@ -409,7 +409,7 @@ class TestSlideController(TestCase): mocked_service_item.render.assert_called_once_with() mocked_process_item.assert_called_once_with(mocked_service_item, 5) - def refresh_service_item_image_test(self): + def test_refresh_service_item_image(self): """ Test that the refresh_service_item() method refreshes a image service item """ @@ -432,7 +432,7 @@ class TestSlideController(TestCase): mocked_service_item.render.assert_called_once_with() mocked_process_item.assert_called_once_with(mocked_service_item, 5) - def refresh_service_item_not_image_or_text_test(self): + def test_refresh_service_item_not_image_or_text(self): """ Test that the refresh_service_item() method does not refresh a service item if it's neither text or an image """ @@ -456,7 +456,7 @@ class TestSlideController(TestCase): self.assertEqual(0, mocked_process_item.call_count, 'The mocked_process_item() method should not have been called') - def add_service_item_with_song_edit_test(self): + def test_add_service_item_with_song_edit(self): """ Test the add_service_item() method when song_edit is True """ @@ -476,7 +476,7 @@ class TestSlideController(TestCase): self.assertFalse(slide_controller.song_edit, 'song_edit should be False') mocked_process_item.assert_called_once_with(mocked_item, 2) - def add_service_item_without_song_edit_test(self): + def test_add_service_item_without_song_edit(self): """ Test the add_service_item() method when song_edit is False """ @@ -496,7 +496,7 @@ class TestSlideController(TestCase): self.assertFalse(slide_controller.song_edit, 'song_edit should be False') mocked_process_item.assert_called_once_with(mocked_item, 0) - def replace_service_manager_item_different_items_test(self): + def test_replace_service_manager_item_different_items(self): """ Test that when the service items are not the same, nothing happens """ @@ -517,7 +517,7 @@ class TestSlideController(TestCase): self.assertEqual(0, mocked_preview_widget.current_slide_number.call_count, 'The preview_widgetcurrent_slide_number.() method should not have been called') - def replace_service_manager_item_same_item_test(self): + def test_replace_service_manager_item_same_item(self): """ Test that when the service item is the same, the service item is reprocessed """ @@ -538,7 +538,7 @@ class TestSlideController(TestCase): mocked_preview_widget.current_slide_number.assert_called_with() mocked_process_item.assert_called_once_with(mocked_item, 7) - def on_slide_blank_test(self): + def test_on_slide_blank(self): """ Test on_slide_blank """ @@ -552,7 +552,7 @@ class TestSlideController(TestCase): # THEN: on_blank_display should have been called with True slide_controller.on_blank_display.assert_called_once_with(True) - def on_slide_unblank_test(self): + def test_on_slide_unblank(self): """ Test on_slide_unblank """ @@ -566,7 +566,7 @@ class TestSlideController(TestCase): # THEN: on_blank_display should have been called with False slide_controller.on_blank_display.assert_called_once_with(False) - def on_slide_selected_index_no_service_item_test(self): + def test_on_slide_selected_index_no_service_item(self): """ Test that when there is no service item, the on_slide_selected_index() method returns immediately """ @@ -582,7 +582,7 @@ class TestSlideController(TestCase): self.assertEqual(0, mocked_item.is_command.call_count, 'The service item should have not been called') @patch.object(Registry, 'execute') - def on_slide_selected_index_service_item_command_test(self, mocked_execute): + def test_on_slide_selected_index_service_item_command(self, mocked_execute): """ Test that when there is a command service item, the command is executed """ @@ -612,7 +612,7 @@ class TestSlideController(TestCase): self.assertEqual(0, mocked_slide_selected.call_count, 'slide_selected should not have been called') @patch.object(Registry, 'execute') - def on_slide_selected_index_service_item_not_command_test(self, mocked_execute): + def test_on_slide_selected_index_service_item_not_command(self, mocked_execute): """ Test that when there is a service item but it's not a command, the preview widget is updated """ @@ -641,7 +641,7 @@ class TestSlideController(TestCase): mocked_slide_selected.assert_called_once_with() @patch.object(Registry, 'execute') - def process_item_test(self, mocked_execute): + def test_process_item(self, mocked_execute): """ Test that presentation service-items is closed when followed by a media service-item """ @@ -685,7 +685,7 @@ class TestSlideController(TestCase): self.assertEqual('mocked_presentation_item_stop', mocked_execute.call_args_list[1][0][0], 'The presentation should have been stopped.') - def live_stolen_focus_shortcuts_test(self): + def test_live_stolen_focus_shortcuts(self): """ Test that all the needed shortcuts are available in scenarios where Live has stolen focus. These are found under def __add_actions_to_widget(self, widget): in slidecontroller.py @@ -885,7 +885,7 @@ class TestSlideController(TestCase): class TestInfoLabel(TestCase): - def paint_event_text_fits_test(self): + def test_paint_event_text_fits(self): """ Test the paintEvent method when text fits the label """ @@ -913,7 +913,7 @@ class TestInfoLabel(TestCase): # THEN: The text should be drawn centered with the complete test_string mocked_qpainter().drawText.assert_called_once_with(mocked_rect(), QtCore.Qt.AlignCenter, test_string) - def paint_event_text_doesnt_fit_test(self): + def test_paint_event_text_doesnt_fit(self): """ Test the paintEvent method when text fits the label """ @@ -944,7 +944,7 @@ class TestInfoLabel(TestCase): mocked_qpainter().drawText.assert_called_once_with(mocked_rect(), QtCore.Qt.AlignLeft, elided_test_string) @patch('builtins.super') - def set_text_test(self, mocked_super): + def test_set_text(self, mocked_super): """ Test the reimplemented setText method """ @@ -963,7 +963,7 @@ class TestInfoLabel(TestCase): class TestLiveController(TestCase): - def initial_live_controller_test(self): + def test_initial_live_controller(self): """ Test the initial live slide controller state . """ @@ -978,7 +978,7 @@ class TestLiveController(TestCase): class TestPreviewLiveController(TestCase): - def initial_preview_controller_test(self): + def test_initial_preview_controller(self): """ Test the initial preview slide controller state. """ diff --git a/tests/functional/openlp_core_ui/test_themeform.py b/tests/functional/openlp_core_ui/test_themeform.py index 9f3cb96e7..d4189d879 100644 --- a/tests/functional/openlp_core_ui/test_themeform.py +++ b/tests/functional/openlp_core_ui/test_themeform.py @@ -34,7 +34,7 @@ class TestThemeManager(TestCase): """ Test the functions in the ThemeManager Class """ - def select_image_file_dialog_cancelled_test(self): + def test_select_image_file_dialog_cancelled(self): """ Test the select image file dialog when the user presses cancel """ @@ -62,7 +62,7 @@ class TestThemeManager(TestCase): 'All Files (*.*)') mocked_set_background_page_values.assert_called_once_with() - def select_image_file_dialog_new_file_test(self): + def test_select_image_file_dialog_new_file(self): """ Test the select image file dialog when the user presses ok """ diff --git a/tests/functional/openlp_core_ui/test_thememanager.py b/tests/functional/openlp_core_ui/test_thememanager.py index 7f4f004da..e6bca75a1 100644 --- a/tests/functional/openlp_core_ui/test_thememanager.py +++ b/tests/functional/openlp_core_ui/test_thememanager.py @@ -53,7 +53,7 @@ class TestThemeManager(TestCase): """ shutil.rmtree(self.temp_folder) - def export_theme_test(self): + def test_export_theme(self): """ Test exporting a theme . """ @@ -73,7 +73,7 @@ class TestThemeManager(TestCase): 'Default', 'Default.xml'), os.path.join('Default', 'Default.xml')) - def initial_theme_manager_test(self): + def test_initial_theme_manager(self): """ Test the instantiation of theme manager. """ @@ -84,7 +84,7 @@ class TestThemeManager(TestCase): # THEN: The the controller should be registered in the registry. self.assertIsNotNone(Registry().get('theme_manager'), 'The base theme manager should be registered') - def write_theme_same_image_test(self): + def test_write_theme_same_image(self): """ Test that we don't try to overwrite a theme background image with itself """ @@ -112,7 +112,7 @@ class TestThemeManager(TestCase): # THEN: The mocked_copyfile should not have been called self.assertFalse(mocked_copyfile.called, 'shutil.copyfile should not be called') - def write_theme_diff_images_test(self): + def test_write_theme_diff_images(self): """ Test that we do overwrite a theme background image when a new is submitted """ @@ -139,7 +139,7 @@ class TestThemeManager(TestCase): # THEN: The mocked_copyfile should not have been called self.assertTrue(mocked_copyfile.called, 'shutil.copyfile should be called') - def write_theme_special_char_name_test(self): + def test_write_theme_special_char_name(self): """ Test that we can save themes with special characters in the name """ @@ -160,7 +160,7 @@ class TestThemeManager(TestCase): self.assertTrue(os.path.exists(os.path.join(self.temp_folder, 'theme 愛 name', 'theme 愛 name.xml')), 'Theme with special characters should have been created!') - def over_write_message_box_yes_test(self): + def test_over_write_message_box_yes(self): """ Test that theme_manager.over_write_message_box returns True when the user clicks yes. """ @@ -180,7 +180,7 @@ class TestThemeManager(TestCase): theme_manager, 'Theme Already Exists', 'Theme Theme Name already exists. Do you want to replace it?', ANY, ANY) - def over_write_message_box_no_test(self): + def test_over_write_message_box_no(self): """ Test that theme_manager.over_write_message_box returns False when the user clicks no. """ @@ -200,7 +200,7 @@ class TestThemeManager(TestCase): theme_manager, 'Theme Already Exists', 'Theme Theme Name already exists. Do you want to replace it?', ANY, ANY) - def unzip_theme_test(self): + def test_unzip_theme(self): """ Test that unzipping of themes works """ @@ -222,7 +222,7 @@ class TestThemeManager(TestCase): self.assertEqual(mocked_critical_error_message_box.call_count, 0, 'No errors should have happened') shutil.rmtree(folder) - def unzip_theme_invalid_version_test(self): + def test_unzip_theme_invalid_version(self): """ Test that themes with invalid (< 2.0) or with no version attributes are rejected """ diff --git a/tests/functional/openlp_core_ui_lib/test_color_button.py b/tests/functional/openlp_core_ui_lib/test_color_button.py index b65b81448..b8743a6c2 100644 --- a/tests/functional/openlp_core_ui_lib/test_color_button.py +++ b/tests/functional/openlp_core_ui_lib/test_color_button.py @@ -49,7 +49,7 @@ class TestColorDialog(TestCase): self.mocked_qt_widgets = self.qt_gui_patcher.start() self.mocked_translate = self.translate_patcher.start() - def constructor_test(self): + def test_constructor(self): """ Test that constructing a ColorButton object works correctly """ @@ -67,7 +67,7 @@ class TestColorDialog(TestCase): mocked_set_tool_tip.assert_called_once_with('Tool Tip Text') self.mocked_clicked.connect.assert_called_once_with(widget.on_clicked) - def change_color_test(self): + def test_change_color(self): """ Test that change_color sets the new color and the stylesheet """ @@ -87,7 +87,7 @@ class TestColorDialog(TestCase): self.mocked_change_color = self.change_color_patcher.start() - def color_test(self): + def test_color(self): """ Test that the color property method returns the set color """ @@ -102,7 +102,7 @@ class TestColorDialog(TestCase): # THEN: The value set in _color should be returned self.assertEqual(value, '#000000', 'The value returned should be equal to the one we set') - def color_test(self): + def test_color(self): """ Test that the color property method returns the set color """ @@ -117,7 +117,7 @@ class TestColorDialog(TestCase): # THEN: The value set in _color should be returned self.assertEqual(value, '#000000', 'The value returned should be equal to the one we set') - def color_setter_test(self): + def test_color_setter(self): """ Test that the color property setter method sets the color """ @@ -132,7 +132,7 @@ class TestColorDialog(TestCase): # THEN: Then change_color should have been called with the value we set self.mocked_change_color.assert_called_once_with('#000000') - def on_clicked_invalid_color_test(self): + def test_on_clicked_invalid_color(self): """ Test the on_click method when an invalid color has been supplied """ @@ -154,7 +154,7 @@ class TestColorDialog(TestCase): self.mocked_color_changed.emit.call_count, 0, 'colorChange signal should not have been emitted with an invalid color') - def on_clicked_same_color_test(self): + def test_on_clicked_same_color(self): """ Test the on_click method when a new color has not been chosen """ @@ -178,7 +178,7 @@ class TestColorDialog(TestCase): self.mocked_color_changed.emit.call_count, 0, 'colorChange signal should not have been emitted when the color has not changed') - def on_clicked_new_color_test(self): + def test_on_clicked_new_color(self): """ Test the on_click method when a new color has been chosen and is valid """ diff --git a/tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py b/tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py index 704acc544..9ccd56a32 100644 --- a/tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py +++ b/tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py @@ -61,7 +61,7 @@ class TestListPreviewWidget(TestCase): self.mocked_viewport.return_value = self.mocked_viewport_obj self.addCleanup(self.viewport_patcher.stop) - def new_list_preview_widget_test(self): + def test_new_list_preview_widget(self): """ Test that creating an instance of ListPreviewWidget works """ diff --git a/tests/functional/openlp_core_ui_media/test_mediacontroller.py b/tests/functional/openlp_core_ui_media/test_mediacontroller.py index a37961b7a..749dd0c2c 100644 --- a/tests/functional/openlp_core_ui_media/test_mediacontroller.py +++ b/tests/functional/openlp_core_ui_media/test_mediacontroller.py @@ -38,7 +38,7 @@ class TestMediaController(TestCase, TestMixin): Registry.create() Registry().register('service_manager', MagicMock()) - def generate_extensions_lists_test(self): + def test_generate_extensions_lists(self): """ Test that the extensions are create correctly """ @@ -59,7 +59,7 @@ class TestMediaController(TestCase, TestMixin): self.assertListEqual(media_player.audio_extensions_list, media_controller.audio_extensions_list, 'Audio extensions should be the same') - def resize_test(self): + def test_resize(self): """ Test that the resize method is called correctly """ @@ -74,7 +74,7 @@ class TestMediaController(TestCase, TestMixin): # THEN: The player's resize method should be called correctly mocked_player.resize.assert_called_with(mocked_display) - def check_file_type_no_players_test(self): + def test_check_file_type_no_players(self): """ Test that we don't try to play media when no players available """ @@ -100,7 +100,7 @@ class TestMediaController(TestCase, TestMixin): @patch('openlp.core.ui.media.mediacontroller.MediaController._get_used_players') @patch('openlp.core.ui.media.mediacontroller.UiStrings') - def check_file_type_no_processor_test(self, mocked_uistrings, mocked_get_used_players): + def test_check_file_type_no_processor(self, mocked_uistrings, mocked_get_used_players): """ Test that we don't try to play media when the processor for the service item is None """ @@ -123,7 +123,7 @@ class TestMediaController(TestCase, TestMixin): @patch('openlp.core.ui.media.mediacontroller.MediaController._get_used_players') @patch('openlp.core.ui.media.mediacontroller.UiStrings') - def check_file_type_automatic_processor_test(self, mocked_uistrings, mocked_get_used_players): + def test_check_file_type_automatic_processor(self, mocked_uistrings, mocked_get_used_players): """ Test that we can play media when players are available and we have a automatic processor from the service item """ @@ -153,7 +153,7 @@ class TestMediaController(TestCase, TestMixin): @patch('openlp.core.ui.media.mediacontroller.MediaController._get_used_players') @patch('openlp.core.ui.media.mediacontroller.UiStrings') - def check_file_type_processor_different_from_available_test(self, mocked_uistrings, mocked_get_used_players): + def test_check_file_type_processor_different_from_available(self, mocked_uistrings, mocked_get_used_players): """ Test that we can play media when players available are different from the processor from the service item """ @@ -181,7 +181,7 @@ class TestMediaController(TestCase, TestMixin): self.assertTrue(ret, '_check_file_type should return True when the players available are different' 'from the processor from the service item.') - def media_play_msg_test(self): + def test_media_play_msg(self): """ Test that the media controller responds to the request to play a loaded video """ @@ -196,7 +196,7 @@ class TestMediaController(TestCase, TestMixin): # THEN: The underlying method is called mocked_media_play.assert_called_with(1, False) - def media_pause_msg_test(self): + def test_media_pause_msg(self): """ Test that the media controller responds to the request to pause a loaded video """ @@ -211,7 +211,7 @@ class TestMediaController(TestCase, TestMixin): # THEN: The underlying method is called mocked_media_pause.assert_called_with(1) - def media_stop_msg_test(self): + def test_media_stop_msg(self): """ Test that the media controller responds to the request to stop a loaded video """ @@ -226,7 +226,7 @@ class TestMediaController(TestCase, TestMixin): # THEN: The underlying method is called mocked_media_stop.assert_called_with(1) - def media_volume_msg_test(self): + def test_media_volume_msg(self): """ Test that the media controller responds to the request to change the volume """ @@ -241,7 +241,7 @@ class TestMediaController(TestCase, TestMixin): # THEN: The underlying method is called mocked_media_volume.assert_called_with(1, 50) - def media_seek_msg_test(self): + def test_media_seek_msg(self): """ Test that the media controller responds to the request to seek to a particular position """ diff --git a/tests/functional/openlp_core_ui_media/test_vlcplayer.py b/tests/functional/openlp_core_ui_media/test_vlcplayer.py index 8e49fe4d9..285418c7d 100644 --- a/tests/functional/openlp_core_ui_media/test_vlcplayer.py +++ b/tests/functional/openlp_core_ui_media/test_vlcplayer.py @@ -52,7 +52,7 @@ class TestVLCPlayer(TestCase, TestMixin): @skip('No way to test this') @patch('openlp.core.ui.media.vlcplayer.vlc') - def get_vlc_fails_and_removes_module_test(self, mocked_vlc): + def test_get_vlc_fails_and_removes_module(self, mocked_vlc): """ Test that when the VLC import fails, it removes the module from sys.modules """ @@ -67,7 +67,7 @@ class TestVLCPlayer(TestCase, TestMixin): self.assertNotIn('openlp.core.ui.media.vendor.vlc', sys.modules) @patch('openlp.core.ui.media.vlcplayer.is_macosx') - def fix_vlc_22_plugin_path_test(self, mocked_is_macosx): + def test_fix_vlc_22_plugin_path(self, mocked_is_macosx): """ Test that on OS X we set the VLC plugin path to fix a bug in the VLC module """ @@ -84,7 +84,7 @@ class TestVLCPlayer(TestCase, TestMixin): @patch.dict(os.environ) @patch('openlp.core.ui.media.vlcplayer.is_macosx') - def not_osx_fix_vlc_22_plugin_path_test(self, mocked_is_macosx): + def test_not_osx_fix_vlc_22_plugin_path(self, mocked_is_macosx): """ Test that on Linux or some other non-OS X we do not set the VLC plugin path """ @@ -98,7 +98,7 @@ class TestVLCPlayer(TestCase, TestMixin): self.assertNotIn('VLC_PLUGIN_PATH', os.environ, 'The plugin path should NOT be in the environment variables') - def init_test(self): + def test_init(self): """ Test that the VLC player class initialises correctly """ @@ -121,7 +121,7 @@ class TestVLCPlayer(TestCase, TestMixin): @patch('openlp.core.ui.media.vlcplayer.get_vlc') @patch('openlp.core.ui.media.vlcplayer.QtWidgets') @patch('openlp.core.ui.media.vlcplayer.Settings') - def setup_test(self, MockedSettings, MockedQtWidgets, mocked_get_vlc, mocked_is_macosx, mocked_is_win): + def test_setup(self, MockedSettings, MockedQtWidgets, mocked_get_vlc, mocked_is_macosx, mocked_is_win): """ Test the setup method """ @@ -171,7 +171,7 @@ class TestVLCPlayer(TestCase, TestMixin): @patch('openlp.core.ui.media.vlcplayer.get_vlc') @patch('openlp.core.ui.media.vlcplayer.QtWidgets') @patch('openlp.core.ui.media.vlcplayer.Settings') - def setup_has_audio_test(self, MockedSettings, MockedQtWidgets, mocked_get_vlc, mocked_is_macosx, mocked_is_win): + def test_setup_has_audio(self, MockedSettings, MockedQtWidgets, mocked_get_vlc, mocked_is_macosx, mocked_is_win): """ Test the setup method when has_audio is True """ @@ -208,7 +208,7 @@ class TestVLCPlayer(TestCase, TestMixin): @patch('openlp.core.ui.media.vlcplayer.get_vlc') @patch('openlp.core.ui.media.vlcplayer.QtWidgets') @patch('openlp.core.ui.media.vlcplayer.Settings') - def setup_visible_mouse_test(self, MockedSettings, MockedQtWidgets, mocked_get_vlc, mocked_is_macosx, + def test_setup_visible_mouse(self, MockedSettings, MockedQtWidgets, mocked_get_vlc, mocked_is_macosx, mocked_is_win): """ Test the setup method when Settings().value("hide mouse") is False @@ -246,7 +246,7 @@ class TestVLCPlayer(TestCase, TestMixin): @patch('openlp.core.ui.media.vlcplayer.get_vlc') @patch('openlp.core.ui.media.vlcplayer.QtWidgets') @patch('openlp.core.ui.media.vlcplayer.Settings') - def setup_windows_test(self, MockedSettings, MockedQtWidgets, mocked_get_vlc, mocked_is_macosx, mocked_is_win): + def test_setup_windows(self, MockedSettings, MockedQtWidgets, mocked_get_vlc, mocked_is_macosx, mocked_is_win): """ Test the setup method when running on Windows """ @@ -283,7 +283,7 @@ class TestVLCPlayer(TestCase, TestMixin): @patch('openlp.core.ui.media.vlcplayer.get_vlc') @patch('openlp.core.ui.media.vlcplayer.QtWidgets') @patch('openlp.core.ui.media.vlcplayer.Settings') - def setup_osx_test(self, MockedSettings, MockedQtWidgets, mocked_get_vlc, mocked_is_macosx, mocked_is_win): + def test_setup_osx(self, MockedSettings, MockedQtWidgets, mocked_get_vlc, mocked_is_macosx, mocked_is_win): """ Test the setup method when running on OS X """ @@ -316,7 +316,7 @@ class TestVLCPlayer(TestCase, TestMixin): mocked_media_player_new.set_nsobject.assert_called_with(2) @patch('openlp.core.ui.media.vlcplayer.get_vlc') - def check_available_test(self, mocked_get_vlc): + def test_check_available(self, mocked_get_vlc): """ Check that when the "vlc" module is available, then VLC is set as available """ @@ -331,7 +331,7 @@ class TestVLCPlayer(TestCase, TestMixin): self.assertTrue(is_available) @patch('openlp.core.ui.media.vlcplayer.get_vlc') - def check_not_available_test(self, mocked_get_vlc): + def test_check_not_available(self, mocked_get_vlc): """ Check that when the "vlc" module is not available, then VLC is set as unavailable """ @@ -347,7 +347,7 @@ class TestVLCPlayer(TestCase, TestMixin): @patch('openlp.core.ui.media.vlcplayer.get_vlc') @patch('openlp.core.ui.media.vlcplayer.os.path.normcase') - def load_test(self, mocked_normcase, mocked_get_vlc): + def test_load(self, mocked_normcase, mocked_get_vlc): """ Test loading a video into VLC """ @@ -385,7 +385,7 @@ class TestVLCPlayer(TestCase, TestMixin): @patch('openlp.core.ui.media.vlcplayer.is_win') @patch('openlp.core.ui.media.vlcplayer.get_vlc') @patch('openlp.core.ui.media.vlcplayer.os.path.normcase') - def load_audio_cd_test(self, mocked_normcase, mocked_get_vlc, mocked_is_win): + def test_load_audio_cd(self, mocked_normcase, mocked_get_vlc, mocked_is_win): """ Test loading an audio CD into VLC """ @@ -430,7 +430,7 @@ class TestVLCPlayer(TestCase, TestMixin): @patch('openlp.core.ui.media.vlcplayer.is_win') @patch('openlp.core.ui.media.vlcplayer.get_vlc') @patch('openlp.core.ui.media.vlcplayer.os.path.normcase') - def load_audio_cd_on_windows_test(self, mocked_normcase, mocked_get_vlc, mocked_is_win): + def test_load_audio_cd_on_windows(self, mocked_normcase, mocked_get_vlc, mocked_is_win): """ Test loading an audio CD into VLC on Windows """ @@ -475,7 +475,7 @@ class TestVLCPlayer(TestCase, TestMixin): @patch('openlp.core.ui.media.vlcplayer.is_win') @patch('openlp.core.ui.media.vlcplayer.get_vlc') @patch('openlp.core.ui.media.vlcplayer.os.path.normcase') - def load_audio_cd_no_tracks_test(self, mocked_normcase, mocked_get_vlc, mocked_is_win): + def test_load_audio_cd_no_tracks(self, mocked_normcase, mocked_get_vlc, mocked_is_win): """ Test loading an audio CD that has no tracks into VLC """ @@ -519,7 +519,7 @@ class TestVLCPlayer(TestCase, TestMixin): @patch('openlp.core.ui.media.vlcplayer.get_vlc') @patch('openlp.core.ui.media.vlcplayer.datetime', MockDateTime) - def media_state_wait_test(self, mocked_get_vlc): + def test_media_state_wait(self, mocked_get_vlc): """ Check that waiting for a state change works """ @@ -542,7 +542,7 @@ class TestVLCPlayer(TestCase, TestMixin): @patch('openlp.core.ui.media.vlcplayer.get_vlc') @patch('openlp.core.ui.media.vlcplayer.datetime', MockDateTime) - def media_state_wait_error_test(self, mocked_get_vlc): + def test_media_state_wait_error(self, mocked_get_vlc): """ Check that getting an error when waiting for a state change returns False """ @@ -565,7 +565,7 @@ class TestVLCPlayer(TestCase, TestMixin): @patch('openlp.core.ui.media.vlcplayer.get_vlc') @patch('openlp.core.ui.media.vlcplayer.datetime', MockDateTime) - def media_state_wait_times_out_test(self, mocked_get_vlc): + def test_media_state_wait_times_out(self, mocked_get_vlc): """ Check that waiting for a state returns False when it times out after 60 seconds """ @@ -588,7 +588,7 @@ class TestVLCPlayer(TestCase, TestMixin): # THEN: The results should be True self.assertFalse(result) - def resize_test(self): + def test_resize(self): """ Test resizing the player """ @@ -606,7 +606,7 @@ class TestVLCPlayer(TestCase, TestMixin): @patch('openlp.core.ui.media.vlcplayer.threading') @patch('openlp.core.ui.media.vlcplayer.get_vlc') - def play_test(self, mocked_get_vlc, mocked_threading): + def test_play(self, mocked_get_vlc, mocked_threading): """ Test the play() method """ @@ -642,7 +642,7 @@ class TestVLCPlayer(TestCase, TestMixin): @patch('openlp.core.ui.media.vlcplayer.threading') @patch('openlp.core.ui.media.vlcplayer.get_vlc') - def play_media_wait_state_not_playing_test(self, mocked_get_vlc, mocked_threading): + def test_play_media_wait_state_not_playing(self, mocked_get_vlc, mocked_threading): """ Test the play() method when media_wait_state() returns False """ @@ -670,7 +670,7 @@ class TestVLCPlayer(TestCase, TestMixin): @patch('openlp.core.ui.media.vlcplayer.threading') @patch('openlp.core.ui.media.vlcplayer.get_vlc') - def play_dvd_test(self, mocked_get_vlc, mocked_threading): + def test_play_dvd(self, mocked_get_vlc, mocked_threading): """ Test the play() method with a DVD """ @@ -710,7 +710,7 @@ class TestVLCPlayer(TestCase, TestMixin): self.assertTrue(result, 'The value returned from play() should be True') @patch('openlp.core.ui.media.vlcplayer.get_vlc') - def pause_test(self, mocked_get_vlc): + def test_pause(self, mocked_get_vlc): """ Test that the pause method works correctly """ @@ -735,7 +735,7 @@ class TestVLCPlayer(TestCase, TestMixin): self.assertEqual(MediaState.Paused, vlc_player.get_live_state()) @patch('openlp.core.ui.media.vlcplayer.get_vlc') - def pause_not_playing_test(self, mocked_get_vlc): + def test_pause_not_playing(self, mocked_get_vlc): """ Test the pause method when the player is not playing """ @@ -755,7 +755,7 @@ class TestVLCPlayer(TestCase, TestMixin): self.assertEqual(0, mocked_display.vlc_media_player.pause.call_count) @patch('openlp.core.ui.media.vlcplayer.get_vlc') - def pause_fail_test(self, mocked_get_vlc): + def test_pause_fail(self, mocked_get_vlc): """ Test the pause method when the player fails to pause the media """ @@ -780,7 +780,7 @@ class TestVLCPlayer(TestCase, TestMixin): self.assertNotEqual(MediaState.Paused, vlc_player.state) @patch('openlp.core.ui.media.vlcplayer.threading') - def stop_test(self, mocked_threading): + def test_stop(self, mocked_threading): """ Test stopping the current item """ @@ -800,7 +800,7 @@ class TestVLCPlayer(TestCase, TestMixin): mocked_thread.start.assert_called_with() self.assertEqual(MediaState.Stopped, vlc_player.get_live_state()) - def volume_test(self): + def test_volume(self): """ Test setting the volume """ @@ -815,7 +815,7 @@ class TestVLCPlayer(TestCase, TestMixin): # THEN: The volume should have been set mocked_display.vlc_media_player.audio_set_volume.assert_called_with(10) - def volume_no_audio_test(self): + def test_volume_no_audio(self): """ Test setting the volume when there's no audio """ @@ -830,7 +830,7 @@ class TestVLCPlayer(TestCase, TestMixin): # THEN: The volume should NOT have been set self.assertEqual(0, mocked_display.vlc_media_player.audio_set_volume.call_count) - def seek_unseekable_media_test(self): + def test_seek_unseekable_media(self): """ Test seeking something that can't be seeked """ @@ -847,7 +847,7 @@ class TestVLCPlayer(TestCase, TestMixin): mocked_display.vlc_media_player.is_seekable.assert_called_with() self.assertEqual(0, mocked_display.vlc_media_player.set_time.call_count) - def seek_seekable_media_test(self): + def test_seek_seekable_media(self): """ Test seeking something that is seekable, but not a DVD """ @@ -864,7 +864,7 @@ class TestVLCPlayer(TestCase, TestMixin): mocked_display.vlc_media_player.is_seekable.assert_called_with() mocked_display.vlc_media_player.set_time.assert_called_with(100) - def seek_dvd_test(self): + def test_seek_dvd(self): """ Test seeking a DVD """ @@ -882,7 +882,7 @@ class TestVLCPlayer(TestCase, TestMixin): mocked_display.vlc_media_player.is_seekable.assert_called_with() mocked_display.vlc_media_player.set_time.assert_called_with(5000) - def reset_test(self): + def test_reset(self): """ Test the reset() method """ @@ -898,7 +898,7 @@ class TestVLCPlayer(TestCase, TestMixin): mocked_display.vlc_widget.setVisible.assert_called_with(False) self.assertEqual(MediaState.Off, vlc_player.get_live_state()) - def set_visible_has_own_widget_test(self): + def test_set_visible_has_own_widget(self): """ Test the set_visible() method when the player has its own widget """ @@ -913,7 +913,7 @@ class TestVLCPlayer(TestCase, TestMixin): # THEN: The media should be stopped and invsibile mocked_display.vlc_widget.setVisible.assert_called_with(True) - def set_visible_no_widget_test(self): + def test_set_visible_no_widget(self): """ Test the set_visible() method when the player doesn't have a widget """ @@ -929,7 +929,7 @@ class TestVLCPlayer(TestCase, TestMixin): self.assertEqual(0, mocked_display.vlc_widget.setVisible.call_count) @patch('openlp.core.ui.media.vlcplayer.get_vlc') - def update_ui_test(self, mocked_get_vlc): + def test_update_ui(self, mocked_get_vlc): """ Test updating the UI """ @@ -961,7 +961,7 @@ class TestVLCPlayer(TestCase, TestMixin): self.assertEqual(expected_calls, mocked_controller.seek_slider.blockSignals.call_args_list) @patch('openlp.core.ui.media.vlcplayer.get_vlc') - def update_ui_dvd_test(self, mocked_get_vlc): + def test_update_ui_dvd(self, mocked_get_vlc): """ Test updating the UI for a CD or DVD """ @@ -995,7 +995,7 @@ class TestVLCPlayer(TestCase, TestMixin): self.assertEqual(expected_calls, mocked_controller.seek_slider.blockSignals.call_args_list) @patch('openlp.core.ui.media.vlcplayer.translate') - def get_info_test(self, mocked_translate): + def test_get_info(self, mocked_translate): """ Test that get_info() returns some information about the VLC player """ diff --git a/tests/functional/openlp_core_ui_media/test_webkitplayer.py b/tests/functional/openlp_core_ui_media/test_webkitplayer.py index cea19f1fe..f74460d3c 100644 --- a/tests/functional/openlp_core_ui_media/test_webkitplayer.py +++ b/tests/functional/openlp_core_ui_media/test_webkitplayer.py @@ -33,7 +33,7 @@ class TestWebkitPlayer(TestCase): Test the functions in the :mod:`webkitplayer` module. """ - def check_available_video_disabled_test(self): + def test_check_available_video_disabled(self): """ Test of webkit video unavailability """ @@ -50,7 +50,7 @@ class TestWebkitPlayer(TestCase): self.assertEqual(False, available, 'The WebkitPlayer should not be available when video feature detection fails') - def check_available_video_enabled_test(self): + def test_check_available_video_enabled(self): """ Test of webkit video availability """ diff --git a/tests/functional/openlp_plugins/alerts/test_manager.py b/tests/functional/openlp_plugins/alerts/test_manager.py index c1873c62b..5cca7a0ba 100644 --- a/tests/functional/openlp_plugins/alerts/test_manager.py +++ b/tests/functional/openlp_plugins/alerts/test_manager.py @@ -40,7 +40,7 @@ class TestAlertManager(TestCase): """ Registry.create() - def remove_message_text_test(self): + def test_remove_message_text(self): """ Test that Alerts are not triggered with empty strings """ @@ -54,7 +54,7 @@ class TestAlertManager(TestCase): # THEN: the display should not have been triggered self.assertFalse(alert_manager.display_alert.called, 'The Alert should not have been called') - def trigger_message_text_test(self): + def test_trigger_message_text(self): """ Test that Alerts are triggered with a text string """ @@ -68,7 +68,7 @@ class TestAlertManager(TestCase): # THEN: the display should have been triggered self.assertTrue(alert_manager.display_alert.called, 'The Alert should have been called') - def line_break_message_text_test(self): + def test_line_break_message_text(self): """ Test that Alerts are triggered with a text string but line breaks are removed """ diff --git a/tests/functional/openlp_plugins/bibles/test_csvimport.py b/tests/functional/openlp_plugins/bibles/test_csvimport.py index df7939aab..f093f925e 100644 --- a/tests/functional/openlp_plugins/bibles/test_csvimport.py +++ b/tests/functional/openlp_plugins/bibles/test_csvimport.py @@ -50,7 +50,7 @@ class TestCSVImport(TestCase): self.registry_patcher.stop() self.manager_patcher.stop() - def create_importer_test(self): + def test_create_importer(self): """ Test creating an instance of the CSV file importer """ @@ -63,7 +63,7 @@ class TestCSVImport(TestCase): # THEN: The importer should be an instance of BibleDB self.assertIsInstance(importer, BibleDB) - def file_import_test(self): + def test_file_import(self): """ Test the actual import of CSV Bible file """ diff --git a/tests/functional/openlp_plugins/bibles/test_http.py b/tests/functional/openlp_plugins/bibles/test_http.py index 56df57c3d..4074f2708 100644 --- a/tests/functional/openlp_plugins/bibles/test_http.py +++ b/tests/functional/openlp_plugins/bibles/test_http.py @@ -88,7 +88,7 @@ class TestBSExtract(TestCase): self.socket_patcher.stop() self.urllib_patcher.stop() - def get_books_from_http_no_soup_test(self): + def test_get_books_from_http_no_soup(self): """ Test the get_books_from_http method when get_soup_for_bible_ref returns a falsey value """ @@ -112,7 +112,7 @@ class TestBSExtract(TestCase): 'BSExtract.get_books_from_http should return None when get_soup_for_bible_ref returns a ' 'false value') - def get_books_from_http_no_content_test(self): + def test_get_books_from_http_no_content(self): """ Test the get_books_from_http method when the specified element cannot be found in the tag object returned from get_soup_for_bible_ref @@ -143,7 +143,7 @@ class TestBSExtract(TestCase): 'BSExtract.get_books_from_http should return None when get_soup_for_bible_ref returns a ' 'false value') - def get_books_from_http_content_test(self): + def test_get_books_from_http_content(self): """ Test the get_books_from_http method with sample HTML Also a regression test for bug #1184869. (The anchor tag in the second list item is empty) diff --git a/tests/functional/openlp_plugins/bibles/test_lib.py b/tests/functional/openlp_plugins/bibles/test_lib.py index 4a9a106f9..6726da6a9 100644 --- a/tests/functional/openlp_plugins/bibles/test_lib.py +++ b/tests/functional/openlp_plugins/bibles/test_lib.py @@ -33,7 +33,7 @@ class TestLib(TestCase): """ Test the functions in the :mod:`lib` module. """ - def get_reference_separator_test(self): + def test_get_reference_separator(self): """ Test the get_reference_separator method """ @@ -56,7 +56,7 @@ class TestLib(TestCase): self.assertEqual(separators[key], value) mocked_update_reference_separators.assert_called_once_with() - def search_results_creation_test(self): + def test_search_results_creation(self): """ Test the creation and construction of the SearchResults class """ @@ -78,7 +78,7 @@ class TestLib(TestCase): self.assertEqual(search_results.chapter, chapter, 'The chapter should be 1') self.assertDictEqual(search_results.verse_list, verse_list, 'The verse lists should be identical') - def search_results_has_verse_list_test(self): + def test_search_results_has_verse_list(self): """ Test that a SearchResults object with a valid verse list returns True when checking ``has_verse_list()`` """ @@ -91,7 +91,7 @@ class TestLib(TestCase): # THEN: It should be True self.assertTrue(has_verse_list, 'The SearchResults object should have a verse list') - def search_results_has_no_verse_list_test(self): + def test_search_results_has_no_verse_list(self): """ Test that a SearchResults object with an empty verse list returns False when checking ``has_verse_list()`` """ diff --git a/tests/functional/openlp_plugins/bibles/test_mediaitem.py b/tests/functional/openlp_plugins/bibles/test_mediaitem.py index a3ce92f4d..f820c7a64 100644 --- a/tests/functional/openlp_plugins/bibles/test_mediaitem.py +++ b/tests/functional/openlp_plugins/bibles/test_mediaitem.py @@ -42,7 +42,7 @@ class TestMediaItem(TestCase, TestMixin): self.media_item = BibleMediaItem(None, MagicMock()) self.setup_application() - def display_results_no_results_test(self): + def test_display_results_no_results(self): """ Test the display_results method when called with a single bible, returning no results """ @@ -64,7 +64,7 @@ class TestMediaItem(TestCase, TestMixin): self.assertEqual(self.media_item.search_results, {}) self.assertEqual(self.media_item.second_search_results, {}) - def display_results_two_bibles_no_results_test(self): + def test_display_results_two_bibles_no_results(self): """ Test the display_results method when called with two bibles, returning no results """ @@ -87,7 +87,7 @@ class TestMediaItem(TestCase, TestMixin): self.assertEqual(self.media_item.search_results, {}) self.assertEqual(self.media_item.second_search_results, {}) - def display_results_returns_lots_of_results_test_test(self): + def test_display_results_returns_lots_of_results(self): """ Test the display_results method a large number of results (> 100) are returned """ diff --git a/tests/functional/openlp_plugins/bibles/test_opensongimport.py b/tests/functional/openlp_plugins/bibles/test_opensongimport.py index ecddd9a2e..8a53e341a 100644 --- a/tests/functional/openlp_plugins/bibles/test_opensongimport.py +++ b/tests/functional/openlp_plugins/bibles/test_opensongimport.py @@ -50,7 +50,7 @@ class TestOpenSongImport(TestCase): self.registry_patcher.stop() self.manager_patcher.stop() - def create_importer_test(self): + def test_create_importer(self): """ Test creating an instance of the OpenSong file importer """ @@ -63,7 +63,7 @@ class TestOpenSongImport(TestCase): # THEN: The importer should be an instance of BibleDB self.assertIsInstance(importer, BibleDB) - def file_import_test(self): + def test_file_import(self): """ Test the actual import of OpenSong Bible file """ @@ -93,7 +93,7 @@ class TestOpenSongImport(TestCase): 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) - def zefania_import_error_test(self): + def test_zefania_import_error(self): """ Test that we give an error message if trying to import a zefania bible """ diff --git a/tests/functional/openlp_plugins/bibles/test_osisimport.py b/tests/functional/openlp_plugins/bibles/test_osisimport.py index 0ce397b29..c6c767397 100644 --- a/tests/functional/openlp_plugins/bibles/test_osisimport.py +++ b/tests/functional/openlp_plugins/bibles/test_osisimport.py @@ -50,7 +50,7 @@ class TestOsisImport(TestCase): self.registry_patcher.stop() self.manager_patcher.stop() - def create_importer_test(self): + def test_create_importer(self): """ Test creating an instance of the OSIS file importer """ @@ -63,7 +63,7 @@ class TestOsisImport(TestCase): # THEN: The importer should be an instance of BibleDB self.assertIsInstance(importer, BibleDB) - def file_import_nested_tags_test(self): + def test_file_import_nested_tags(self): """ Test the actual import of OSIS Bible file, with nested chapter and verse tags """ @@ -93,7 +93,7 @@ class TestOsisImport(TestCase): for verse_tag, verse_text in test_data['verses']: importer.create_verse.assert_any_call(importer.create_book().id, '1', verse_tag, verse_text) - def file_import_mixed_tags_test(self): + def test_file_import_mixed_tags(self): """ Test the actual import of OSIS Bible file, with chapter tags containing milestone verse tags. """ @@ -123,7 +123,7 @@ class TestOsisImport(TestCase): for verse_tag, verse_text in test_data['verses']: importer.create_verse.assert_any_call(importer.create_book().id, '1', verse_tag, verse_text) - def file_import_milestone_tags_test(self): + def test_file_import_milestone_tags(self): """ Test the actual import of OSIS Bible file, with milestone chapter and verse tags. """ @@ -153,7 +153,7 @@ class TestOsisImport(TestCase): for verse_tag, verse_text in test_data['verses']: importer.create_verse.assert_any_call(importer.create_book().id, '1', verse_tag, verse_text) - def file_import_empty_verse_tags_test(self): + def test_file_import_empty_verse_tags(self): """ Test the actual import of OSIS Bible file, with an empty verse tags. """ diff --git a/tests/functional/openlp_plugins/bibles/test_swordimport.py b/tests/functional/openlp_plugins/bibles/test_swordimport.py index ae4d9cdf9..ca3c03691 100644 --- a/tests/functional/openlp_plugins/bibles/test_swordimport.py +++ b/tests/functional/openlp_plugins/bibles/test_swordimport.py @@ -25,19 +25,21 @@ This module contains tests for the SWORD Bible importer. import os import json -from unittest import TestCase, SkipTest +from unittest import TestCase, skipUnless from tests.functional import MagicMock, patch try: from openlp.plugins.bibles.lib.sword import SwordBible + HAS_PYSWORD = True except ImportError: - raise SkipTest('PySword is not installed, skipping SWORD test.') + HAS_PYSWORD = False from openlp.plugins.bibles.lib.db import BibleDB TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'bibles')) +@skipUnless(HAS_PYSWORD, 'pysword not installed') class TestSwordImport(TestCase): """ Test the functions in the :mod:`swordimport` module. @@ -53,7 +55,7 @@ class TestSwordImport(TestCase): self.registry_patcher.stop() self.manager_patcher.stop() - def create_importer_test(self): + def test_create_importer(self): """ Test creating an instance of the Sword file importer """ @@ -69,7 +71,7 @@ class TestSwordImport(TestCase): @patch('openlp.plugins.bibles.lib.sword.SwordBible.application') @patch('openlp.plugins.bibles.lib.sword.modules') @patch('openlp.plugins.bibles.lib.db.BiblesResourcesDB') - def simple_import_test(self, mocked_bible_res_db, mocked_pysword_modules, mocked_application): + def test_simple_import(self, mocked_bible_res_db, mocked_pysword_modules, mocked_application): """ Test that a simple SWORD import works """ diff --git a/tests/functional/openlp_plugins/bibles/test_versereferencelist.py b/tests/functional/openlp_plugins/bibles/test_versereferencelist.py index ea083dc88..3b3642590 100644 --- a/tests/functional/openlp_plugins/bibles/test_versereferencelist.py +++ b/tests/functional/openlp_plugins/bibles/test_versereferencelist.py @@ -31,7 +31,7 @@ class TestVerseReferenceList(TestCase): """ Test the VerseReferenceList class """ - def add_first_verse_test(self): + def test_add_first_verse(self): """ Test the addition of a verse to the empty list """ @@ -57,7 +57,7 @@ class TestVerseReferenceList(TestCase): version) self.assertEqual(reference_list.verse_list[0]['end'], verse, 'The end in first entry should be %u' % verse) - def add_next_verse_test(self): + def test_add_next_verse(self): """ Test the addition of the following verse """ @@ -80,7 +80,7 @@ class TestVerseReferenceList(TestCase): self.assertEqual(reference_list.verse_list[0]['end'], next_verse, 'The end in first entry should be %u' % next_verse) - def add_another_verse_test(self): + def test_add_another_verse(self): """ Test the addition of a verse in another book """ @@ -103,7 +103,7 @@ class TestVerseReferenceList(TestCase): # THEN: the current index should be 1 self.assertEqual(reference_list.current_index, 1, 'The current index should be 1') - def add_version_test(self): + def test_add_version(self): """ Test the addition of a version to the list """ @@ -122,7 +122,7 @@ class TestVerseReferenceList(TestCase): {'version': version, 'copyright': copyright_, 'permission': permission}, 'The version data should be appended') - def add_existing_version_test(self): + def test_add_existing_version(self): """ Test the addition of an existing version to the list """ diff --git a/tests/functional/openlp_plugins/bibles/test_zefaniaimport.py b/tests/functional/openlp_plugins/bibles/test_zefaniaimport.py index ce3f1bdf5..34ecf2c58 100644 --- a/tests/functional/openlp_plugins/bibles/test_zefaniaimport.py +++ b/tests/functional/openlp_plugins/bibles/test_zefaniaimport.py @@ -50,7 +50,7 @@ class TestZefaniaImport(TestCase): self.registry_patcher.stop() self.manager_patcher.stop() - def create_importer_test(self): + def test_create_importer(self): """ Test creating an instance of the Zefania file importer """ @@ -63,7 +63,7 @@ class TestZefaniaImport(TestCase): # THEN: The importer should be an instance of BibleDB self.assertIsInstance(importer, BibleDB) - def file_import_test(self): + def test_file_import(self): """ Test the actual import of Zefania Bible file """ @@ -93,7 +93,7 @@ class TestZefaniaImport(TestCase): importer.create_verse.assert_any_call(importer.create_book().id, '1', verse_tag, verse_text) importer.create_book.assert_any_call('Genesis', 1, 1) - def file_import_no_book_name_test(self): + def test_file_import_no_book_name(self): """ Test the import of Zefania Bible file without book names """ diff --git a/tests/functional/openlp_plugins/custom/test_mediaitem.py b/tests/functional/openlp_plugins/custom/test_mediaitem.py index 4f3eae321..6a70f3173 100644 --- a/tests/functional/openlp_plugins/custom/test_mediaitem.py +++ b/tests/functional/openlp_plugins/custom/test_mediaitem.py @@ -41,7 +41,7 @@ class TestMediaItem(TestCase, TestMixin): """ self.destroy_settings() - def service_load_inactive_test(self): + def test_service_load_inactive(self): """ Test the service load in custom with a default service item """ @@ -54,7 +54,7 @@ class TestMediaItem(TestCase, TestMixin): # THEN: the processing should be ignored self.assertEqual(item, None, 'The Service item is inactive so processing should be bypassed') - def service_load_basic_custom_false_test(self): + def test_service_load_basic_custom_false(self): """ Test the service load in custom with a default service item and no requirement to add to the database """ @@ -77,7 +77,7 @@ class TestMediaItem(TestCase, TestMixin): self.assertEqual(self.media_item.create_from_service_item.call_count, 0, 'The item should not have been added to the database') - def service_load_basic_custom_true_test(self): + def test_service_load_basic_custom_true(self): """ Test the service load in custom with a default service item and a requirement to add to the database """ diff --git a/tests/functional/openlp_plugins/images/test_imagetab.py b/tests/functional/openlp_plugins/images/test_imagetab.py index 3f1a798e3..c17519a15 100644 --- a/tests/functional/openlp_plugins/images/test_imagetab.py +++ b/tests/functional/openlp_plugins/images/test_imagetab.py @@ -66,7 +66,7 @@ class TestImageMediaItem(TestCase, TestMixin): del self.form self.destroy_settings() - def save_tab_nochange_test_test(self): + def test_save_tab_nochange(self): """ Test no changes does not trigger post processing """ @@ -78,7 +78,7 @@ class TestImageMediaItem(TestCase, TestMixin): self.assertEqual(0, self.form.settings_form.register_post_process.call_count, 'Image Post processing should not have been requested') - def save_tab_change_test_test(self): + def test_save_tab_change(self): """ Test a color change is applied and triggers post processing. """ diff --git a/tests/functional/openlp_plugins/images/test_lib.py b/tests/functional/openlp_plugins/images/test_lib.py index 5bf3e9730..f010a9db9 100644 --- a/tests/functional/openlp_plugins/images/test_lib.py +++ b/tests/functional/openlp_plugins/images/test_lib.py @@ -52,7 +52,7 @@ class TestImageMediaItem(TestCase): @patch('openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_list') @patch('openlp.plugins.images.lib.mediaitem.Settings') - def validate_and_load_test(self, mocked_settings, mocked_load_list): + def test_validate_and_load(self, mocked_settings, mocked_load_list): """ Test that the validate_and_load_test() method when called without a group """ @@ -69,7 +69,7 @@ class TestImageMediaItem(TestCase): @patch('openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_list') @patch('openlp.plugins.images.lib.mediaitem.Settings') - def validate_and_load_group_test(self, mocked_settings, mocked_load_list): + def test_validate_and_load_group(self, mocked_settings, mocked_load_list): """ Test that the validate_and_load_test() method when called with a group """ @@ -85,7 +85,7 @@ class TestImageMediaItem(TestCase): mocked_settings().setValue.assert_called_once_with(ANY, '/path1') @patch('openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_full_list') - def save_new_images_list_empty_list_test(self, mocked_load_full_list): + def test_save_new_images_list_empty_list(self, mocked_load_full_list): """ Test that the save_new_images_list() method handles empty lists gracefully """ @@ -101,7 +101,7 @@ class TestImageMediaItem(TestCase): 'The save_object() method should not have been called') @patch('openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_full_list') - def save_new_images_list_single_image_with_reload_test(self, mocked_load_full_list): + def test_save_new_images_list_single_image_with_reload(self, mocked_load_full_list): """ Test that the save_new_images_list() calls load_full_list() when reload_list is set to True """ @@ -120,7 +120,7 @@ class TestImageMediaItem(TestCase): delattr(ImageFilenames, 'filename') @patch('openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_full_list') - def save_new_images_list_single_image_without_reload_test(self, mocked_load_full_list): + def test_save_new_images_list_single_image_without_reload(self, mocked_load_full_list): """ Test that the save_new_images_list() doesn't call load_full_list() when reload_list is set to False """ @@ -135,7 +135,7 @@ class TestImageMediaItem(TestCase): self.assertEquals(mocked_load_full_list.call_count, 0, 'load_full_list() should not have been called') @patch('openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_full_list') - def save_new_images_list_multiple_images_test(self, mocked_load_full_list): + def test_save_new_images_list_multiple_images(self, mocked_load_full_list): """ Test that the save_new_images_list() saves all images in the list """ @@ -151,7 +151,7 @@ class TestImageMediaItem(TestCase): 'load_full_list() should have been called three times') @patch('openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_full_list') - def save_new_images_list_other_objects_in_list_test(self, mocked_load_full_list): + def test_save_new_images_list_other_objects_in_list(self, mocked_load_full_list): """ Test that the save_new_images_list() ignores everything in the provided list except strings """ @@ -166,7 +166,7 @@ class TestImageMediaItem(TestCase): self.assertEquals(self.media_item.manager.save_object.call_count, 2, 'load_full_list() should have been called only once') - def on_reset_click_test(self): + def test_on_reset_click(self): """ Test that on_reset_click() actually resets the background """ @@ -181,7 +181,7 @@ class TestImageMediaItem(TestCase): self.media_item.live_controller.display.reset_image.assert_called_with() @patch('openlp.plugins.images.lib.mediaitem.delete_file') - def recursively_delete_group_test(self, mocked_delete_file): + def test_recursively_delete_group(self, mocked_delete_file): """ Test that recursively_delete_group() works """ @@ -233,7 +233,7 @@ class TestImageMediaItem(TestCase): @patch('openlp.plugins.images.lib.mediaitem.delete_file') @patch('openlp.plugins.images.lib.mediaitem.check_item_selected') - def on_delete_click_test(self, mocked_check_item_selected, mocked_delete_file): + def test_on_delete_click(self, mocked_check_item_selected, mocked_delete_file): """ Test that on_delete_click() works """ @@ -257,7 +257,7 @@ class TestImageMediaItem(TestCase): # THEN: delete_file should have been called twice self.assertEquals(mocked_delete_file.call_count, 2, 'delete_file() should have been called twice') - def create_item_from_id_test(self): + def test_create_item_from_id(self): """ Test that the create_item_from_id() method returns a valid QTreeWidgetItem with a pre-created ImageFilenames """ diff --git a/tests/functional/openlp_plugins/media/test_mediaplugin.py b/tests/functional/openlp_plugins/media/test_mediaplugin.py index c49cdbaa4..2d747b295 100644 --- a/tests/functional/openlp_plugins/media/test_mediaplugin.py +++ b/tests/functional/openlp_plugins/media/test_mediaplugin.py @@ -40,7 +40,7 @@ class MediaPluginTest(TestCase, TestMixin): @patch(u'openlp.plugins.media.mediaplugin.Plugin.initialise') @patch(u'openlp.plugins.media.mediaplugin.Settings') - def initialise_test(self, _mocked_settings, mocked_initialise): + def test_initialise(self, _mocked_settings, mocked_initialise): """ Test that the initialise() method overwrites the built-in one, but still calls it """ @@ -65,7 +65,7 @@ class MediaPluginTest(TestCase, TestMixin): self.assertNotEquals(len(MediaPlugin.about()), 0) @patch('openlp.plugins.media.mediaplugin.check_binary_exists') - def process_check_binary_pass_test(self, mocked_checked_binary_exists): + def test_process_check_binary_pass(self, mocked_checked_binary_exists): """ Test that the Process check returns true if found """ @@ -78,7 +78,7 @@ class MediaPluginTest(TestCase, TestMixin): self.assertTrue(result, 'Mediainfo should have been found') @patch('openlp.plugins.media.mediaplugin.check_binary_exists') - def process_check_binary_fail_test(self, mocked_checked_binary_exists): + def test_process_check_binary_fail(self, mocked_checked_binary_exists): """ Test that the Process check returns false if not found """ diff --git a/tests/functional/openlp_plugins/presentations/test_impresscontroller.py b/tests/functional/openlp_plugins/presentations/test_impresscontroller.py index 56fd0b585..ecb84edce 100644 --- a/tests/functional/openlp_plugins/presentations/test_impresscontroller.py +++ b/tests/functional/openlp_plugins/presentations/test_impresscontroller.py @@ -59,7 +59,7 @@ class TestImpressController(TestCase, TestMixin): self.destroy_settings() shutil.rmtree(self.temp_folder) - def constructor_test(self): + def test_constructor(self): """ Test the Constructor from the ImpressController """ @@ -86,7 +86,7 @@ class TestImpressDocument(TestCase): self.ppc = ImpressController(mocked_plugin) self.doc = ImpressDocument(self.ppc, self.file_name) - def create_titles_and_notes_test(self): + def test_create_titles_and_notes(self): """ Test ImpressDocument.create_titles_and_notes """ @@ -114,7 +114,7 @@ class TestImpressDocument(TestCase): # two arrays of two elements self.doc.save_titles_and_notes.assert_called_once_with(['\n', '\n'], [' ', ' ']) - def get_text_from_page_out_of_bound_test(self): + def test_get_text_from_page_out_of_bound(self): """ Test ImpressDocument.__get_text_from_page with out-of-bounds index """ @@ -143,7 +143,7 @@ class TestImpressDocument(TestCase): self.assertEqual(self.doc.document.getDrawPages().getByIndex.call_count, 0, 'There should be no call to getByIndex') - def get_text_from_page_wrong_type_test(self): + def test_get_text_from_page_wrong_type(self): """ Test ImpressDocument.__get_text_from_page with wrong TextType """ @@ -159,7 +159,7 @@ class TestImpressDocument(TestCase): self.assertEqual(self.doc.document.getDrawPages().getByIndex.call_count, 0, 'There should be no call to getByIndex') - def get_text_from_page_valid_params_test(self): + def test_get_text_from_page_valid_params(self): """ Test ImpressDocument.__get_text_from_page with valid parameters """ diff --git a/tests/functional/openlp_plugins/presentations/test_mediaitem.py b/tests/functional/openlp_plugins/presentations/test_mediaitem.py index a689966ec..aad7ce4d7 100644 --- a/tests/functional/openlp_plugins/presentations/test_mediaitem.py +++ b/tests/functional/openlp_plugins/presentations/test_mediaitem.py @@ -46,7 +46,7 @@ class TestMediaItem(TestCase, TestMixin): self.media_item = PresentationMediaItem(None, MagicMock, MagicMock()) self.setup_application() - def build_file_mask_string_test(self): + def test_build_file_mask_string(self): """ Test the build_file_mask_string() method """ @@ -85,7 +85,7 @@ class TestMediaItem(TestCase, TestMixin): self.assertIn('*.xps', self.media_item.on_new_file_masks, 'The file mask should contain the xps extension') self.assertIn('*.oxps', self.media_item.on_new_file_masks, 'The file mask should contain the oxps extension') - def clean_up_thumbnails_test(self): + def test_clean_up_thumbnails(self): """ Test that the clean_up_thumbnails method works as expected when files exists. """ @@ -110,7 +110,7 @@ class TestMediaItem(TestCase, TestMixin): # the presentation_file's mtime. mocked_doc.assert_has_calls([call.get_thumbnail_path(1, True), call.presentation_deleted()], True) - def clean_up_thumbnails_missing_file_test(self): + def test_clean_up_thumbnails_missing_file(self): """ Test that the clean_up_thumbnails method works as expected when file is missing. """ diff --git a/tests/functional/openlp_plugins/presentations/test_messagelistener.py b/tests/functional/openlp_plugins/presentations/test_messagelistener.py index 14bc06bf2..d3dd1537f 100644 --- a/tests/functional/openlp_plugins/presentations/test_messagelistener.py +++ b/tests/functional/openlp_plugins/presentations/test_messagelistener.py @@ -47,7 +47,7 @@ class TestMessageListener(TestCase, TestMixin): self.media_item = PresentationMediaItem(None, MagicMock, MagicMock()) @patch('openlp.plugins.presentations.lib.mediaitem.MessageListener._setup') - def start_presentation_test(self, media_mock): + def test_start_presentation(self, media_mock): """ Find and chose a controller to play a presentations. """ @@ -75,7 +75,7 @@ class TestMessageListener(TestCase, TestMixin): self.assertTrue(len(controllers), 'We have loaded a controller') @patch('openlp.plugins.presentations.lib.mediaitem.MessageListener._setup') - def start_presentation_with_no_player_test(self, media_mock): + def test_start_presentation_with_no_player(self, media_mock): """ Find and chose a controller to play a presentations when the player is not available. """ @@ -107,7 +107,7 @@ class TestMessageListener(TestCase, TestMixin): self.assertTrue(len(controllers), 'We have loaded a controller') @patch('openlp.plugins.presentations.lib.mediaitem.MessageListener._setup') - def start_pdf_presentation_test(self, media_mock): + def test_start_pdf_presentation(self, media_mock): """ Test the startup of pdf presentation succeed. """ @@ -132,7 +132,7 @@ class TestController(TestCase, TestMixin): Test the Presentation Controller. """ - def add_handler_failure_test(self): + def test_add_handler_failure(self): """ Test that add_handler does set doc.slidenumber to 0 in case filed loading """ diff --git a/tests/functional/openlp_plugins/presentations/test_pdfcontroller.py b/tests/functional/openlp_plugins/presentations/test_pdfcontroller.py index f73655dc7..e7bbcc6bc 100644 --- a/tests/functional/openlp_plugins/presentations/test_pdfcontroller.py +++ b/tests/functional/openlp_plugins/presentations/test_pdfcontroller.py @@ -78,7 +78,7 @@ class TestPdfController(TestCase, TestMixin): shutil.rmtree(self.thumbnail_folder) shutil.rmtree(self.temp_folder) - def constructor_test(self): + def test_constructor(self): """ Test the Constructor from the PdfController """ @@ -91,7 +91,7 @@ class TestPdfController(TestCase, TestMixin): # THEN: The name of the presentation controller should be correct self.assertEqual('Pdf', controller.name, 'The name of the presentation controller should be correct') - def load_pdf_test(self): + def test_load_pdf(self): """ Test loading of a Pdf using the PdfController """ @@ -111,7 +111,7 @@ class TestPdfController(TestCase, TestMixin): self.assertTrue(loaded, 'The loading of the PDF should succeed.') self.assertEqual(3, document.get_slide_count(), 'The pagecount of the PDF should be 3.') - def load_pdf_pictures_test(self): + def test_load_pdf_pictures(self): """ Test loading of a Pdf and check size of generate pictures """ @@ -139,7 +139,7 @@ class TestPdfController(TestCase, TestMixin): self.assertEqual(543, image.width(), 'The width should be 543') @patch('openlp.plugins.presentations.lib.pdfcontroller.check_binary_exists') - def process_check_binary_mudraw_test(self, mocked_check_binary_exists): + def test_process_check_binary_mudraw(self, mocked_check_binary_exists): """ Test that the correct output from mudraw is detected """ @@ -157,7 +157,7 @@ class TestPdfController(TestCase, TestMixin): self.assertEqual('mudraw', ret, 'mudraw should have been detected') @patch('openlp.plugins.presentations.lib.pdfcontroller.check_binary_exists') - def process_check_binary_new_motool_test(self, mocked_check_binary_exists): + def test_process_check_binary_new_motool(self, mocked_check_binary_exists): """ Test that the correct output from the new mutool is detected """ @@ -177,7 +177,7 @@ class TestPdfController(TestCase, TestMixin): self.assertEqual('mutool', ret, 'mutool should have been detected') @patch('openlp.plugins.presentations.lib.pdfcontroller.check_binary_exists') - def process_check_binary_old_motool_test(self, mocked_check_binary_exists): + def test_process_check_binary_old_motool(self, mocked_check_binary_exists): """ Test that the output from the old mutool is not accepted """ @@ -194,7 +194,7 @@ class TestPdfController(TestCase, TestMixin): self.assertIsNone(ret, 'old mutool should not be accepted!') @patch('openlp.plugins.presentations.lib.pdfcontroller.check_binary_exists') - def process_check_binary_gs_test(self, mocked_check_binary_exists): + def test_process_check_binary_gs(self, mocked_check_binary_exists): """ Test that the correct output from gs is detected """ diff --git a/tests/functional/openlp_plugins/presentations/test_powerpointcontroller.py b/tests/functional/openlp_plugins/presentations/test_powerpointcontroller.py index c6ddb8238..3666eac40 100644 --- a/tests/functional/openlp_plugins/presentations/test_powerpointcontroller.py +++ b/tests/functional/openlp_plugins/presentations/test_powerpointcontroller.py @@ -65,7 +65,7 @@ class TestPowerpointController(TestCase, TestMixin): self.destroy_settings() shutil.rmtree(self.temp_folder) - def constructor_test(self): + def test_constructor(self): """ Test the Constructor from the PowerpointController """ @@ -120,7 +120,7 @@ class TestPowerpointDocument(TestCase, TestMixin): self.destroy_settings() shutil.rmtree(self.temp_folder) - def show_error_msg_test(self): + def test_show_error_msg(self): """ Test the PowerpointDocument.show_error_msg() method gets called on com exception """ @@ -160,7 +160,7 @@ class TestPowerpointDocument(TestCase, TestMixin): else: self.skipTest('Powerpoint not available, skipping test.') - def create_titles_and_notes_test(self): + def test_create_titles_and_notes(self): """ Test creating the titles from PowerPoint """ @@ -183,7 +183,7 @@ class TestPowerpointDocument(TestCase, TestMixin): # THEN the save should have been called exactly once with 2 titles and 2 notes self.doc.save_titles_and_notes.assert_called_once_with(['SlideText\n', 'SlideText\n'], [' ', ' ']) - def create_titles_and_notes_with_no_slides_test(self): + def test_create_titles_and_notes_with_no_slides(self): """ Test creating the titles from PowerPoint when it returns no slides """ @@ -201,7 +201,7 @@ class TestPowerpointDocument(TestCase, TestMixin): # THEN the save should have been called exactly once with empty titles and notes doc.save_titles_and_notes.assert_called_once_with([], []) - def get_text_from_shapes_test(self): + def test_get_text_from_shapes(self): """ Test getting text from powerpoint shapes """ @@ -218,7 +218,7 @@ class TestPowerpointDocument(TestCase, TestMixin): # THEN: it should return the text self.assertEqual(result, 'slideText\nslideText\n', 'result should match \'slideText\nslideText\n\'') - def get_text_from_shapes_with_no_shapes_test(self): + def test_get_text_from_shapes_with_no_shapes(self): """ Test getting text from powerpoint shapes with no shapes """ @@ -231,7 +231,7 @@ class TestPowerpointDocument(TestCase, TestMixin): # THEN: it should not fail but return empty string self.assertEqual(result, '', 'result should be empty') - def goto_slide_test(self): + def test_goto_slide(self): """ Test that goto_slide goes to next effect if the slide is already displayed """ @@ -251,7 +251,7 @@ class TestPowerpointDocument(TestCase, TestMixin): # THEN: next_step() should be call to try to advance to the next effect. self.assertTrue(doc.next_step.called, 'next_step() should have been called!') - def blank_screen_test(self): + def test_blank_screen(self): """ Test that blank_screen works as expected """ @@ -271,7 +271,7 @@ class TestPowerpointDocument(TestCase, TestMixin): self.assertEquals(doc.blank_slide, 2, 'doc.blank_slide should be 2 because of the PowerPoint version') self.assertEquals(doc.blank_click, 3, 'doc.blank_click should be 3 because of the PowerPoint version') - def unblank_screen_test(self): + def test_unblank_screen(self): """ Test that unblank_screen works as expected """ diff --git a/tests/functional/openlp_plugins/presentations/test_pptviewcontroller.py b/tests/functional/openlp_plugins/presentations/test_pptviewcontroller.py index 104c0e1fa..3127b2954 100644 --- a/tests/functional/openlp_plugins/presentations/test_pptviewcontroller.py +++ b/tests/functional/openlp_plugins/presentations/test_pptviewcontroller.py @@ -65,7 +65,7 @@ class TestPptviewController(TestCase, TestMixin): self.destroy_settings() shutil.rmtree(self.temp_folder) - def constructor_test(self): + def test_constructor(self): """ Test the Constructor from the PptViewController """ @@ -79,7 +79,7 @@ class TestPptviewController(TestCase, TestMixin): self.assertEqual('Powerpoint Viewer', controller.name, 'The name of the presentation controller should be correct') - def check_available_test(self): + def test_check_available(self): """ Test check_available / check_installed """ @@ -162,7 +162,7 @@ class TestPptviewDocument(TestCase): self.screen_list_patcher.stop() shutil.rmtree(self.temp_folder) - def load_presentation_succesfull_test(self): + def test_load_presentation_succesfull(self): """ Test the PptviewDocument.load_presentation() method when the PPT is successfully opened """ @@ -181,7 +181,7 @@ class TestPptviewDocument(TestCase): # THEN: PptviewDocument.load_presentation should return True self.assertTrue(result) - def load_presentation_un_succesfull_test(self): + def test_load_presentation_un_succesfull(self): """ Test the PptviewDocument.load_presentation() method when the temporary directory does not exist and the PPT is not successfully opened @@ -202,7 +202,7 @@ class TestPptviewDocument(TestCase): mock_makedirs.assert_called_once_with(self.temp_folder) self.assertFalse(result) - def create_titles_and_notes_test(self): + def test_create_titles_and_notes(self): """ Test PowerpointController.create_titles_and_notes """ @@ -219,7 +219,7 @@ class TestPptviewDocument(TestCase): ['Notes for slide 1', 'Inserted', 'Notes for slide 2', 'Notes \nfor slide 4', 'Notes for slide 3']) - def create_titles_and_notes_nonexistent_file_test(self): + def test_create_titles_and_notes_nonexistent_file(self): """ Test PowerpointController.create_titles_and_notes with nonexistent file """ @@ -242,7 +242,7 @@ class TestPptviewDocument(TestCase): mocked_exists.assert_any_call('Idontexist.pptx') self.assertEqual(mocked_open.call_count, 0, 'There should be no calls to open a file.') - def create_titles_and_notes_invalid_file_test(self): + def test_create_titles_and_notes_invalid_file(self): """ Test PowerpointController.create_titles_and_notes with invalid file """ diff --git a/tests/functional/openlp_plugins/presentations/test_presentationcontroller.py b/tests/functional/openlp_plugins/presentations/test_presentationcontroller.py index fe26a819b..0c2d84086 100644 --- a/tests/functional/openlp_plugins/presentations/test_presentationcontroller.py +++ b/tests/functional/openlp_plugins/presentations/test_presentationcontroller.py @@ -60,7 +60,7 @@ class TestPresentationController(TestCase): def tearDown(self): self.get_thumbnail_folder_patcher.stop() - def constructor_test(self): + def test_constructor(self): """ Test the Constructor """ @@ -72,7 +72,7 @@ class TestPresentationController(TestCase): self.assertEqual('PresentationController', self.presentation.name, 'The name of the presentation controller should be correct') - def save_titles_and_notes_test(self): + def test_save_titles_and_notes(self): """ Test PresentationDocument.save_titles_and_notes method with two valid lists """ @@ -95,7 +95,7 @@ class TestPresentationController(TestCase): mocked_open().write.assert_any_call('one') mocked_open().write.assert_any_call('two') - def save_titles_and_notes_with_None_test(self): + def test_save_titles_and_notes_with_None(self): """ Test PresentationDocument.save_titles_and_notes method with no data """ @@ -111,7 +111,7 @@ class TestPresentationController(TestCase): # THEN: No file should have been created self.assertEqual(mocked_open.call_count, 0, 'No file should be created') - def get_titles_and_notes_test(self): + def test_get_titles_and_notes(self): """ Test PresentationDocument.get_titles_and_notes method """ @@ -137,7 +137,7 @@ class TestPresentationController(TestCase): mocked_open.assert_any_call(os.path.join('test', 'slideNotes2.txt'), encoding='utf-8') self.assertEqual(mocked_exists.call_count, 3, 'Three files should have been checked') - def get_titles_and_notes_with_file_not_found_test(self): + def test_get_titles_and_notes_with_file_not_found(self): """ Test PresentationDocument.get_titles_and_notes method with file not found """ @@ -159,7 +159,7 @@ class TestPresentationController(TestCase): self.assertEqual(mocked_open.call_count, 0, 'No calls to open files') self.assertEqual(mocked_exists.call_count, 1, 'There should be one call to file exists') - def get_titles_and_notes_with_file_error_test(self): + def test_get_titles_and_notes_with_file_error(self): """ Test PresentationDocument.get_titles_and_notes method with file errors """ @@ -238,7 +238,7 @@ class TestPresentationDocument(TestCase): self.os_patcher.stop() self._setup_patcher.stop() - def initialise_presentation_document_test(self): + def test_initialise_presentation_document(self): """ Test the PresentationDocument __init__ method when initialising the PresentationDocument Class """ @@ -251,7 +251,7 @@ class TestPresentationDocument(TestCase): # THEN: PresentationDocument._setup should have been called with the argument 'Name' self.mock_setup.assert_called_once_with('Name') - def presentation_document_setup_test(self): + def test_presentation_document_setup(self): """ Test the PresentationDocument _setup method when initialising the PresentationDocument Class """ @@ -267,7 +267,7 @@ class TestPresentationDocument(TestCase): self._setup_patcher.start() - def load_presentation_test(self): + def test_load_presentation(self): """ Test the PresentationDocument.load_presentation method. """ @@ -281,7 +281,7 @@ class TestPresentationDocument(TestCase): # THEN: load_presentation should return false self.assertFalse(result, "PresentationDocument.load_presentation should return false.") - def get_file_name_test(self): + def test_get_file_name(self): """ Test the PresentationDocument.get_file_name method. """ diff --git a/tests/functional/openlp_plugins/remotes/test_remotetab.py b/tests/functional/openlp_plugins/remotes/test_remotetab.py index 24375740f..dfd86bd66 100644 --- a/tests/functional/openlp_plugins/remotes/test_remotetab.py +++ b/tests/functional/openlp_plugins/remotes/test_remotetab.py @@ -71,7 +71,7 @@ class TestRemoteTab(TestCase, TestMixin): del self.form self.destroy_settings() - def get_ip_address_default_test(self): + def test_get_ip_address_default(self): """ Test the get_ip_address function with ZERO_URL """ @@ -81,7 +81,7 @@ class TestRemoteTab(TestCase, TestMixin): self.assertTrue(re.match('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}', ip_address), 'The return value should be a valid ip address') - def get_ip_address_with_ip_test(self): + def test_get_ip_address_with_ip(self): """ Test the get_ip_address function with given ip address """ @@ -93,7 +93,7 @@ class TestRemoteTab(TestCase, TestMixin): # THEN: the default ip address will be returned self.assertEqual(ip_address, given_ip, 'The return value should be %s' % given_ip) - def set_basic_urls_test(self): + def test_set_basic_urls(self): """ Test the set_urls function with standard defaults """ @@ -121,7 +121,7 @@ class TestRemoteTab(TestCase, TestMixin): self.assertEqual(self.form.user_login_group_box.isChecked(), False, 'The authentication box should not be enabled') - def set_certificate_urls_test(self): + def test_set_certificate_urls(self): """ Test the set_urls function with certificate available """ diff --git a/tests/functional/openlp_plugins/remotes/test_router.py b/tests/functional/openlp_plugins/remotes/test_router.py index d1715ab8d..e43401f42 100644 --- a/tests/functional/openlp_plugins/remotes/test_router.py +++ b/tests/functional/openlp_plugins/remotes/test_router.py @@ -67,7 +67,7 @@ class TestRouter(TestCase, TestMixin): """ self.destroy_settings() - def password_encrypter_test(self): + def test_password_encrypter(self): """ Test hash userid and password function """ @@ -84,7 +84,7 @@ class TestRouter(TestCase, TestMixin): self.assertEqual(router.auth, test_value, 'The result for make_sha_hash should return the correct encrypted password') - def process_http_request_test(self): + def test_process_http_request(self): """ Test the router control functionality """ @@ -103,7 +103,7 @@ class TestRouter(TestCase, TestMixin): self.assertEqual(mocked_function, function['function'], 'The mocked function should match defined value.') self.assertFalse(function['secure'], 'The mocked function should not require any security.') - def process_secure_http_request_test(self): + def test_process_secure_http_request(self): """ Test the router control functionality """ @@ -131,7 +131,7 @@ class TestRouter(TestCase, TestMixin): self.router.send_response.assert_called_once_with(401) self.assertEqual(self.router.send_header.call_count, 5, 'The header should have been called five times.') - def get_content_type_test(self): + def test_get_content_type(self): """ Test the get_content_type logic """ @@ -151,7 +151,7 @@ class TestRouter(TestCase, TestMixin): # THEN: all types should match self.assertEqual(content_type, header[1], 'Mismatch of content type') - def main_poll_test(self): + def test_main_poll(self): """ Test the main poll logic """ @@ -171,7 +171,7 @@ class TestRouter(TestCase, TestMixin): self.assertEqual(results.decode('utf-8'), '{"results": {"slide_count": 2}}', 'The resulting json strings should match') - def serve_file_without_params_test(self): + def test_serve_file_without_params(self): """ Test the serve_file method without params """ @@ -190,7 +190,7 @@ class TestRouter(TestCase, TestMixin): self.router.send_response.assert_called_once_with(404) self.assertEqual(self.router.end_headers.call_count, 1, 'end_headers called once') - def serve_file_with_valid_params_test(self): + def test_serve_file_with_valid_params(self): """ Test the serve_file method with an existing file """ @@ -213,7 +213,7 @@ class TestRouter(TestCase, TestMixin): self.router.send_header.assert_called_once_with('Content-type', 'text/html') self.assertEqual(self.router.end_headers.call_count, 1, 'end_headers called once') - def serve_file_with_partial_params_test(self): + def test_serve_file_with_partial_params(self): """ Test the serve_file method with an existing file """ @@ -236,7 +236,7 @@ class TestRouter(TestCase, TestMixin): self.router.send_header.assert_called_once_with('Content-type', 'text/html') self.assertEqual(self.router.end_headers.call_count, 1, 'end_headers called once') - def serve_thumbnail_without_params_test(self): + def test_serve_thumbnail_without_params(self): """ Test the serve_thumbnail routine without params """ @@ -254,7 +254,7 @@ class TestRouter(TestCase, TestMixin): self.assertEqual(self.router.send_response.call_count, 1, 'Send response should be called once') self.assertEqual(self.router.end_headers.call_count, 1, 'end_headers should be called once') - def serve_thumbnail_with_invalid_params_test(self): + def test_serve_thumbnail_with_invalid_params(self): """ Test the serve_thumbnail routine with invalid params """ @@ -287,7 +287,7 @@ class TestRouter(TestCase, TestMixin): # THEN: return a 404 self.router.send_response.assert_called_once_with(404) - def serve_thumbnail_with_valid_params_test(self): + def test_serve_thumbnail_with_valid_params(self): """ Test the serve_thumbnail routine with valid params """ @@ -326,7 +326,7 @@ class TestRouter(TestCase, TestMixin): 'slide1.png')), 'slide1.png', width, height) - def remote_next_test(self): + def test_remote_next(self): """ Test service manager receives remote next click properly (bug 1407445) """ @@ -347,7 +347,7 @@ class TestRouter(TestCase, TestMixin): # THEN: service_manager.next_item() should have been called self.assertTrue(mocked_next_item.called, 'next_item() should have been called in service_manager') - def remote_previous_test(self): + def test_remote_previous(self): """ Test service manager receives remote previous click properly (bug 1407445) """ @@ -368,7 +368,7 @@ class TestRouter(TestCase, TestMixin): # THEN: service_manager.next_item() should have been called self.assertTrue(mocked_previous_item.called, 'previous_item() should have been called in service_manager') - def remote_stage_personal_html_test(self): + def test_remote_stage_personal_html(self): """ Test the stage url with a parameter after loaded a url/stage.html file """ @@ -386,7 +386,7 @@ class TestRouter(TestCase, TestMixin): # THEN: we should use the specific stage file instance self.router._process_file.assert_called_with(os.path.join('trb', 'stage.html')) - def remote_stage_personal_css_test(self): + def test_remote_stage_personal_css(self): """ Test the html with reference stages/trb/trb.css then loaded a stages/trb/trb.css file """ diff --git a/tests/functional/openlp_plugins/songs/test_editsongform.py b/tests/functional/openlp_plugins/songs/test_editsongform.py index db19d000c..184c59717 100644 --- a/tests/functional/openlp_plugins/songs/test_editsongform.py +++ b/tests/functional/openlp_plugins/songs/test_editsongform.py @@ -57,7 +57,7 @@ class TestEditSongForm(TestCase, TestMixin): """ self.destroy_settings() - def validate_matching_tags_test(self): + def test_validate_matching_tags(self): # Given a set of tags tags = ['{r}', '{/r}', '{bl}', '{/bl}', '{su}', '{/su}'] @@ -67,7 +67,7 @@ class TestEditSongForm(TestCase, TestMixin): # THEN they should be valid self.assertTrue(valid, "The tags list should be valid") - def validate_nonmatching_tags_test(self): + def test_validate_nonmatching_tags(self): # Given a set of tags tags = ['{r}', '{/r}', '{bl}', '{/bl}', '{br}', '{su}', '{/su}'] diff --git a/tests/functional/openlp_plugins/songs/test_editverseform.py b/tests/functional/openlp_plugins/songs/test_editverseform.py index 443dd697c..18a43ab7a 100644 --- a/tests/functional/openlp_plugins/songs/test_editverseform.py +++ b/tests/functional/openlp_plugins/songs/test_editverseform.py @@ -53,7 +53,7 @@ class TestEditVerseForm(TestCase, TestMixin): """ self.destroy_settings() - def update_suggested_verse_number_test(self): + def test_update_suggested_verse_number(self): """ Test that update_suggested_verse_number() has no effect when editing a single verse """ diff --git a/tests/functional/openlp_plugins/songs/test_ewimport.py b/tests/functional/openlp_plugins/songs/test_ewimport.py index 1321aabee..f3f278cb4 100644 --- a/tests/functional/openlp_plugins/songs/test_ewimport.py +++ b/tests/functional/openlp_plugins/songs/test_ewimport.py @@ -153,7 +153,7 @@ class TestEasyWorshipSongImport(TestCase): """ Registry.create() - def create_field_desc_entry_test(self): + def test_create_field_desc_entry(self): """ Test creating an instance of the :class`FieldDescEntry` class. """ @@ -172,7 +172,7 @@ class TestEasyWorshipSongImport(TestCase): 'FieldDescEntry.type should be the same as the type argument') self.assertEqual(field_desc_entry.size, size, 'FieldDescEntry.size should be the same as the size argument') - def create_importer_test(self): + def test_create_importer(self): """ Test creating an instance of the EasyWorship file importer """ @@ -186,7 +186,7 @@ class TestEasyWorshipSongImport(TestCase): # THEN: The importer object should not be None self.assertIsNotNone(importer, 'Import should not be none') - def find_field_exists_test(self): + def test_find_field_exists(self): """ Test finding an existing field in a given list using the :mod:`find_field` """ @@ -204,7 +204,7 @@ class TestEasyWorshipSongImport(TestCase): # THEN: The item corresponding the index returned should have the same name attribute self.assertEqual(importer.field_descriptions[importer.find_field(field_name)].name, field_name) - def find_non_existing_field_test(self): + def test_find_non_existing_field(self): """ Test finding an non-existing field in a given list using the :mod:`find_field` """ @@ -221,7 +221,7 @@ class TestEasyWorshipSongImport(TestCase): # THEN: The importer object should not be None self.assertRaises(IndexError, importer.find_field, field_name) - def set_record_struct_test(self): + def test_set_record_struct(self): """ Test the :mod:`set_record_struct` module """ @@ -240,7 +240,7 @@ class TestEasyWorshipSongImport(TestCase): self.assertIsNone(return_value, 'set_record_struct should return None') mocked_struct.Struct.assert_called_with('>50sHIB250s250s10sQ') - def get_field_test(self): + def test_get_field(self): """ Test the :mod:`get_field` module """ @@ -262,7 +262,7 @@ class TestEasyWorshipSongImport(TestCase): 'get_field should return "%s" when called with "%s"' % (result, TEST_FIELDS[field_index])) - def get_memo_field_test(self): + def test_get_memo_field(self): """ Test the :mod:`get_field` module """ @@ -294,7 +294,7 @@ class TestEasyWorshipSongImport(TestCase): else: mocked_memo_file.seek.assert_any_call(call[0], call[1]) - def do_import_source_test(self): + def test_do_import_source(self): """ Test the :mod:`do_import` module opens the correct files """ @@ -313,7 +313,7 @@ class TestEasyWorshipSongImport(TestCase): mocked_os_path.isfile.assert_any_call('Songs.DB') mocked_os_path.isfile.assert_any_call('Songs.MB') - def do_import_source_invalid_test(self): + def test_do_import_source_invalid(self): """ Test the :mod:`do_import` module produces an error when Songs.MB not found. """ @@ -333,7 +333,7 @@ class TestEasyWorshipSongImport(TestCase): importer.log_error.assert_any_call(importer.import_source, 'Could not find the "Songs.MB" file. It must be ' 'in the same folder as the "Songs.DB" file.') - def do_import_database_validity_test(self): + def test_do_import_database_validity(self): """ Test the :mod:`do_import` module handles invalid database files correctly """ @@ -352,7 +352,7 @@ class TestEasyWorshipSongImport(TestCase): self.assertIsNone(importer.do_import(), 'do_import should return None when db_size is less than 0x800') mocked_os_path.getsize.assert_any_call('Songs.DB') - def do_import_memo_validty_test(self): + def test_do_import_memo_validty(self): """ Test the :mod:`do_import` module handles invalid memo files correctly """ @@ -379,7 +379,7 @@ class TestEasyWorshipSongImport(TestCase): mocked_open().close.reset_mock() self.assertIs(mocked_open().seek.called, False, 'db_file.seek should not have been called.') - def code_page_to_encoding_test(self): + def test_code_page_to_encoding(self): """ Test the :mod:`do_import` converts the code page to the encoding correctly """ @@ -405,7 +405,7 @@ class TestEasyWorshipSongImport(TestCase): self.assertIsNone(importer.do_import(), 'do_import should return None when db_size is less than 0x800') mocked_retrieve_windows_encoding.assert_any_call(encoding) - def db_file_import_test(self): + def test_db_file_import(self): """ Test the actual import of real song database files and check that the imported data is correct. """ @@ -461,7 +461,7 @@ class TestEasyWorshipSongImport(TestCase): 'verse_order_list for %s should be %s' % (title, verse_order_list)) mocked_finish.assert_called_with() - def ews_file_import_test(self): + def test_ews_file_import(self): """ Test the actual import of song from ews file and check that the imported data is correct. """ @@ -502,7 +502,7 @@ class TestEasyWorshipSongImport(TestCase): mocked_add_verse.assert_any_call(verse_text, verse_tag) mocked_finish.assert_called_with() - def import_rtf_unescaped_unicode_test(self): + def test_import_rtf_unescaped_unicode(self): """ Test import of rtf without the expected escaping of unicode """ diff --git a/tests/functional/openlp_plugins/songs/test_foilpresenterimport.py b/tests/functional/openlp_plugins/songs/test_foilpresenterimport.py index 36dd0904d..279c0e71b 100644 --- a/tests/functional/openlp_plugins/songs/test_foilpresenterimport.py +++ b/tests/functional/openlp_plugins/songs/test_foilpresenterimport.py @@ -107,7 +107,7 @@ class TestFoilPresenter(TestCase): self.song_xml_patcher.stop() self.translate_patcher.stop() - def create_foil_presenter_test(self): + def test_create_foil_presenter(self): """ Test creating an instance of the foil_presenter class """ @@ -121,7 +121,7 @@ class TestFoilPresenter(TestCase): # THEN: The instance should not be None self.assertIsNotNone(foil_presenter_instance, 'foil_presenter instance should not be none') - def no_xml_test(self): + def test_no_xml(self): """ Test calling xml_to_song with out the xml argument """ @@ -137,7 +137,7 @@ class TestFoilPresenter(TestCase): # Then: xml_to_song should return False self.assertEqual(result, None, 'xml_to_song should return None when called with %s' % arg) - def encoding_declaration_removal_test(self): + def test_encoding_declaration_removal(self): """ Test that the encoding declaration is removed """ @@ -151,7 +151,7 @@ class TestFoilPresenter(TestCase): # THEN: the xml encoding declaration should have been stripped self.mocked_re.compile.sub.called_with('\n') - def no_encoding_declaration_test(self): + def test_no_encoding_declaration(self): """ Check that the xml sting is left intact when no encoding declaration is made """ @@ -165,7 +165,7 @@ class TestFoilPresenter(TestCase): # THEN: the string should have been left intact self.mocked_re.compile.sub.called_with('') - def process_lyrics_no_verses_test(self): + def test_process_lyrics_no_verses(self): """ Test that _process_lyrics handles song files that have no verses. """ diff --git a/tests/functional/openlp_plugins/songs/test_lib.py b/tests/functional/openlp_plugins/songs/test_lib.py index 77da4f543..6141d4e8c 100644 --- a/tests/functional/openlp_plugins/songs/test_lib.py +++ b/tests/functional/openlp_plugins/songs/test_lib.py @@ -52,7 +52,7 @@ class TestLib(TestCase): old rugged cross till my trophies at last i lay down i will cling to the old rugged cross and exchange it some day for a crown''' - def clean_string_test(self): + def test_clean_string(self): """ Test the clean_string() function """ @@ -65,7 +65,7 @@ class TestLib(TestCase): # THEN: The string should be cleaned up and lower-cased self.assertEqual(result, 'aint gonna find you there ', 'The string should be cleaned up properly') - def clean_title_test(self): + def test_clean_title(self): """ Test the clean_title() function """ @@ -78,7 +78,7 @@ class TestLib(TestCase): # THEN: The string should be cleaned up self.assertEqual(result, 'This is a dirty string', 'The title should be cleaned up properly: "%s"' % result) - def songs_probably_equal_same_song_test(self): + def test_songs_probably_equal_same_song(self): """ Test the songs_probably_equal function with twice the same song. """ @@ -92,7 +92,7 @@ class TestLib(TestCase): # THEN: The result should be a tuple.. assert result == (2, 4), 'The result should be the tuble of song positions' - def songs_probably_equal_short_song_test(self): + def test_songs_probably_equal_short_song(self): """ Test the songs_probably_equal function with a song and a shorter version of the same song. """ @@ -106,7 +106,7 @@ class TestLib(TestCase): # THEN: The result should be a tuple.. assert result == (1, 3), 'The result should be the tuble of song positions' - def songs_probably_equal_error_song_test(self): + def test_songs_probably_equal_error_song(self): """ Test the songs_probably_equal function with a song and a very erroneous version of the same song. """ @@ -120,7 +120,7 @@ class TestLib(TestCase): # THEN: The result should be a tuple of song positions. assert result == (4, 7), 'The result should be the tuble of song positions' - def songs_probably_equal_different_song_test(self): + def test_songs_probably_equal_different_song(self): """ Test the songs_probably_equal function with two different songs. """ @@ -134,7 +134,7 @@ class TestLib(TestCase): # THEN: The result should be None. assert result is None, 'The result should be None' - def remove_typos_beginning_test(self): + def test_remove_typos_beginning(self): """ Test the _remove_typos function with a typo at the beginning. """ @@ -148,7 +148,7 @@ class TestLib(TestCase): assert len(result) == 1, 'The result should contain only one element.' assert result[0][0] == 'equal', 'The result should contain an equal element.' - def remove_typos_beginning_negated_test(self): + def test_remove_typos_beginning_negated(self): """ Test the _remove_typos function with a large difference at the beginning. """ @@ -161,7 +161,7 @@ class TestLib(TestCase): # THEN: There diff should not have changed. assert result == diff - def remove_typos_end_test(self): + def test_remove_typos_end(self): """ Test the _remove_typos function with a typo at the end. """ @@ -175,7 +175,7 @@ class TestLib(TestCase): assert len(result) == 1, 'The result should contain only one element.' assert result[0][0] == 'equal', 'The result should contain an equal element.' - def remove_typos_end_negated_test(self): + def test_remove_typos_end_negated(self): """ Test the _remove_typos function with a large difference at the end. """ @@ -188,7 +188,7 @@ class TestLib(TestCase): # THEN: There diff should not have changed. assert result == diff - def remove_typos_middle_test(self): + def test_remove_typos_middle(self): """ Test the _remove_typos function with a typo in the middle. """ @@ -206,7 +206,7 @@ class TestLib(TestCase): assert result[0][3] == 0, 'The start indices should be kept.' assert result[0][4] == 21, 'The stop indices should be kept.' - def remove_typos_beginning_negated_test(self): + def test_remove_typos_beginning_negated(self): """ Test the _remove_typos function with a large difference in the middle. """ @@ -219,7 +219,7 @@ class TestLib(TestCase): # THEN: There diff should not have changed. assert result == diff - def op_length_test(self): + def test_op_length(self): """ Test the _op_length function. """ @@ -232,7 +232,7 @@ class TestLib(TestCase): # THEN: The maximum length should be returned. assert result == 10, 'The length should be 10.' - def strip_rtf_charsets_test(self): + def test_strip_rtf_charsets(self): """ Test that the strip_rtf() method properly decodes the supported charsets. """ @@ -270,7 +270,7 @@ class TestVerseType(TestCase): This is a test case to test various methods in the VerseType enumeration class. """ - def translated_tag_test(self): + def test_translated_tag(self): """ Test that the translated_tag() method returns the correct tags """ @@ -290,7 +290,7 @@ class TestVerseType(TestCase): # THEN: The result should be "C" self.assertEqual(result, 'C', 'The result should be "C"') - def translated_invalid_tag_test(self): + def test_translated_invalid_tag(self): """ Test that the translated_tag() method returns the default tag when passed an invalid tag """ @@ -304,7 +304,7 @@ class TestVerseType(TestCase): # THEN: The result should be "O" self.assertEqual(result, 'O', 'The result should be "O", but was "%s"' % result) - def translated_invalid_tag_with_specified_default_test(self): + def test_translated_invalid_tag_with_specified_default(self): """ Test that the translated_tag() method returns the specified default tag when passed an invalid tag """ @@ -318,7 +318,7 @@ class TestVerseType(TestCase): # THEN: The result should be "B" self.assertEqual(result, 'B', 'The result should be "B", but was "%s"' % result) - def translated_invalid_tag_with_invalid_default_test(self): + def test_translated_invalid_tag_with_invalid_default(self): """ Test that the translated_tag() method returns a sane default tag when passed an invalid default """ @@ -332,7 +332,7 @@ class TestVerseType(TestCase): # THEN: The result should be "O" self.assertEqual(result, 'O', 'The result should be "O", but was "%s"' % result) - def translated_name_test(self): + def test_translated_name(self): """ Test that the translated_name() method returns the correct name """ @@ -352,7 +352,7 @@ class TestVerseType(TestCase): # THEN: The result should be "Chorus" self.assertEqual(result, 'Chorus', 'The result should be "Chorus"') - def translated_invalid_name_test(self): + def test_translated_invalid_name(self): """ Test that the translated_name() method returns the default name when passed an invalid tag """ @@ -366,7 +366,7 @@ class TestVerseType(TestCase): # THEN: The result should be "Other" self.assertEqual(result, 'Other', 'The result should be "Other", but was "%s"' % result) - def translated_invalid_name_with_specified_default_test(self): + def test_translated_invalid_name_with_specified_default(self): """ Test that the translated_name() method returns the specified default name when passed an invalid tag """ @@ -380,7 +380,7 @@ class TestVerseType(TestCase): # THEN: The result should be "Bridge" self.assertEqual(result, 'Bridge', 'The result should be "Bridge", but was "%s"' % result) - def translated_invalid_name_with_invalid_default_test(self): + def test_translated_invalid_name_with_invalid_default(self): """ Test that the translated_name() method returns the specified default tag when passed an invalid tag """ @@ -394,7 +394,7 @@ class TestVerseType(TestCase): # THEN: The result should be "Other" self.assertEqual(result, 'Other', 'The result should be "Other", but was "%s"' % result) - def from_tag_test(self): + def test_from_tag(self): """ Test that the from_tag() method returns the correct VerseType. """ @@ -408,7 +408,7 @@ class TestVerseType(TestCase): # THEN: The result should be VerseType.Verse self.assertEqual(result, VerseType.Verse, 'The result should be VerseType.Verse, but was "%s"' % result) - def from_tag_with_invalid_tag_test(self): + def test_from_tag_with_invalid_tag(self): """ Test that the from_tag() method returns the default VerseType when it is passed an invalid tag. """ @@ -422,7 +422,7 @@ class TestVerseType(TestCase): # THEN: The result should be VerseType.Other self.assertEqual(result, VerseType.Other, 'The result should be VerseType.Other, but was "%s"' % result) - def from_tag_with_specified_default_test(self): + def test_from_tag_with_specified_default(self): """ Test that the from_tag() method returns the specified default when passed an invalid tag. """ @@ -436,7 +436,7 @@ class TestVerseType(TestCase): # THEN: The result should be VerseType.Chorus self.assertEqual(result, VerseType.Chorus, 'The result should be VerseType.Chorus, but was "%s"' % result) - def from_tag_with_invalid_intdefault_test(self): + def test_from_tag_with_invalid_intdefault(self): """ Test that the from_tag() method returns a sane default when passed an invalid tag and an invalid int default. """ @@ -450,7 +450,7 @@ class TestVerseType(TestCase): # THEN: The result should be VerseType.Other self.assertEqual(result, VerseType.Other, 'The result should be VerseType.Other, but was "%s"' % result) - def from_tag_with_invalid_default_test(self): + def test_from_tag_with_invalid_default(self): """ Test that the from_tag() method returns a sane default when passed an invalid tag and an invalid default. """ @@ -464,7 +464,7 @@ class TestVerseType(TestCase): # THEN: The result should be VerseType.Other self.assertEqual(result, VerseType.Other, 'The result should be VerseType.Other, but was "%s"' % result) - def from_tag_with_none_default_test(self): + def test_from_tag_with_none_default(self): """ Test that the from_tag() method returns a sane default when passed an invalid tag and None as default. """ @@ -479,7 +479,7 @@ class TestVerseType(TestCase): self.assertIsNone(result, 'The result should be None, but was "%s"' % result) @patch('openlp.plugins.songs.lib.VerseType.translated_tags', new_callable=PropertyMock, return_value=['x']) - def from_loose_input_with_invalid_input_test(self, mocked_translated_tags): + def test_from_loose_input_with_invalid_input(self, mocked_translated_tags): """ Test that the from_loose_input() method returns a sane default when passed an invalid tag and None as default. """ @@ -491,7 +491,7 @@ class TestVerseType(TestCase): self.assertIsNone(result, 'The result should be None, but was "%s"' % result) @patch('openlp.plugins.songs.lib.VerseType.translated_tags', new_callable=PropertyMock, return_value=['x']) - def from_loose_input_with_valid_input_test(self, mocked_translated_tags): + def test_from_loose_input_with_valid_input(self, mocked_translated_tags): """ Test that the from_loose_input() method returns valid output on valid input. """ diff --git a/tests/functional/openlp_plugins/songs/test_mediaitem.py b/tests/functional/openlp_plugins/songs/test_mediaitem.py index 12447368b..969c27ba1 100644 --- a/tests/functional/openlp_plugins/songs/test_mediaitem.py +++ b/tests/functional/openlp_plugins/songs/test_mediaitem.py @@ -68,7 +68,7 @@ class TestMediaItem(TestCase, TestMixin): """ self.destroy_settings() - def display_results_song_test(self): + def test_display_results_song(self): """ Test displaying song search results with basic song """ @@ -109,7 +109,7 @@ class TestMediaItem(TestCase, TestMixin): self.media_item.list_view.addItem.assert_called_once_with(mock_qlist_widget) self.media_item.list_view.setCurrentItem.assert_called_with(mock_qlist_widget) - def display_results_author_test(self): + def test_display_results_author(self): """ Test displaying song search results grouped by author with basic song """ @@ -145,7 +145,7 @@ class TestMediaItem(TestCase, TestMixin): mock_qlist_widget.setData.assert_called_once_with(MockedUserRole, mock_song.id) self.media_item.list_view.addItem.assert_called_once_with(mock_qlist_widget) - def display_results_book_test(self): + def test_display_results_book(self): """ Test displaying song search results grouped by book and entry with basic song """ @@ -165,7 +165,7 @@ class TestMediaItem(TestCase, TestMixin): mock_qlist_widget.setData.assert_called_once_with(MockedUserRole, 1) self.media_item.list_view.addItem.assert_called_once_with(mock_qlist_widget) - def songbook_natural_sorting_test(self): + def test_songbook_natural_sorting(self): """ Test that songbooks are sorted naturally """ @@ -191,7 +191,7 @@ class TestMediaItem(TestCase, TestMixin): call('Thy Book #2: Thy Song'), call().setData(QtCore.Qt.UserRole, 50)] MockedQListWidgetItem.assert_has_calls(calls) - def display_results_topic_test(self): + def test_display_results_topic(self): """ Test displaying song search results grouped by topic with basic song """ @@ -227,7 +227,7 @@ class TestMediaItem(TestCase, TestMixin): mock_qlist_widget.setData.assert_called_once_with(MockedUserRole, mock_song.id) self.media_item.list_view.addItem.assert_called_once_with(mock_qlist_widget) - def display_results_themes_test(self): + def test_display_results_themes(self): """ Test displaying song search results sorted by theme with basic song """ @@ -261,7 +261,7 @@ class TestMediaItem(TestCase, TestMixin): mock_qlist_widget.setData.assert_called_once_with(MockedUserRole, mock_song.id) self.media_item.list_view.addItem.assert_called_once_with(mock_qlist_widget) - def display_results_cclinumber_test(self): + def test_display_results_cclinumber(self): """ Test displaying song search results sorted by CCLI number with basic song """ @@ -295,7 +295,7 @@ class TestMediaItem(TestCase, TestMixin): mock_qlist_widget.setData.assert_called_once_with(MockedUserRole, mock_song.id) self.media_item.list_view.addItem.assert_called_once_with(mock_qlist_widget) - def build_song_footer_one_author_test(self): + def test_build_song_footer_one_author(self): """ Test build songs footer with basic song and one author """ @@ -320,7 +320,7 @@ class TestMediaItem(TestCase, TestMixin): self.assertEqual(author_list, ['my author'], 'The author list should be returned correctly with one author') - def build_song_footer_two_authors_test(self): + def test_build_song_footer_two_authors(self): """ Test build songs footer with basic song and two authors """ @@ -359,7 +359,7 @@ class TestMediaItem(TestCase, TestMixin): self.assertEqual(author_list, ['another author', 'my author', 'translator'], 'The author list should be returned correctly with two authors') - def build_song_footer_base_ccli_test(self): + def test_build_song_footer_base_ccli(self): """ Test build songs footer with basic song and a CCLI number """ @@ -385,7 +385,7 @@ class TestMediaItem(TestCase, TestMixin): self.assertEqual(service_item.raw_footer, ['My Song', 'My copyright', 'CCLI License: 4321'], 'The array should be returned correctly with a song, an author, copyright and amended ccli') - def build_song_footer_base_songbook_test(self): + def test_build_song_footer_base_songbook(self): """ Test build songs footer with basic song and multiple songbooks """ @@ -418,7 +418,7 @@ class TestMediaItem(TestCase, TestMixin): # THEN: The songbook should be in the footer self.assertEqual(service_item.raw_footer, ['My Song', 'My copyright', 'My songbook #12, Thy songbook #502A']) - def build_song_footer_copyright_enabled_test(self): + def test_build_song_footer_copyright_enabled(self): """ Test building song footer with displaying the copyright symbol """ @@ -435,7 +435,7 @@ class TestMediaItem(TestCase, TestMixin): # THEN: The copyright symbol should be in the footer self.assertEqual(service_item.raw_footer, ['My Song', '© My copyright']) - def build_song_footer_copyright_disabled_test(self): + def test_build_song_footer_copyright_disabled(self): """ Test building song footer without displaying the copyright symbol """ @@ -451,7 +451,7 @@ class TestMediaItem(TestCase, TestMixin): # THEN: The copyright symbol should not be in the footer self.assertEqual(service_item.raw_footer, ['My Song', 'My copyright']) - def authors_match_test(self): + def test_authors_match(self): """ Test the author matching when importing a song from a service """ @@ -477,7 +477,7 @@ class TestMediaItem(TestCase, TestMixin): # THEN: They should match self.assertTrue(result, "Authors should match") - def authors_dont_match_test(self): + def test_authors_dont_match(self): # GIVEN: A song and a string with authors song = MagicMock() song.authors = [] @@ -500,7 +500,7 @@ class TestMediaItem(TestCase, TestMixin): # THEN: They should not match self.assertFalse(result, "Authors should not match") - def build_remote_search_test(self): + def test_build_remote_search(self): """ Test results for the remote search api """ diff --git a/tests/functional/openlp_plugins/songs/test_openlpimporter.py b/tests/functional/openlp_plugins/songs/test_openlpimporter.py index b78d5c43b..07d0f9f4a 100644 --- a/tests/functional/openlp_plugins/songs/test_openlpimporter.py +++ b/tests/functional/openlp_plugins/songs/test_openlpimporter.py @@ -39,7 +39,7 @@ class TestOpenLPImport(TestCase): """ Registry.create() - def create_importer_test(self): + def test_create_importer(self): """ Test creating an instance of the OpenLP database importer """ @@ -53,7 +53,7 @@ class TestOpenLPImport(TestCase): # THEN: The importer object should not be None self.assertIsNotNone(importer, 'Import should not be none') - def invalid_import_source_test(self): + def test_invalid_import_source(self): """ Test OpenLPSongImport.do_import handles different invalid import_source values """ diff --git a/tests/functional/openlp_plugins/songs/test_openlyricsexport.py b/tests/functional/openlp_plugins/songs/test_openlyricsexport.py index 55e7e7bb9..15921d4e1 100644 --- a/tests/functional/openlp_plugins/songs/test_openlyricsexport.py +++ b/tests/functional/openlp_plugins/songs/test_openlyricsexport.py @@ -51,7 +51,7 @@ class TestOpenLyricsExport(TestCase, TestMixin): """ shutil.rmtree(self.temp_folder) - def export_same_filename_test(self): + def test_export_same_filename(self): """ Test that files is not overwritten if songs has same title and author """ diff --git a/tests/functional/openlp_plugins/songs/test_openlyricsimport.py b/tests/functional/openlp_plugins/songs/test_openlyricsimport.py index 71d3a2ba5..654aeee51 100644 --- a/tests/functional/openlp_plugins/songs/test_openlyricsimport.py +++ b/tests/functional/openlp_plugins/songs/test_openlyricsimport.py @@ -100,7 +100,7 @@ class TestOpenLyricsImport(TestCase, TestMixin): """ self.destroy_settings() - def create_importer_test(self): + def test_create_importer(self): """ Test creating an instance of the OpenLyrics file importer """ @@ -114,7 +114,7 @@ class TestOpenLyricsImport(TestCase, TestMixin): # THEN: The importer should be an instance of SongImport self.assertIsInstance(importer, SongImport) - def file_import_test(self): + def test_file_import(self): """ Test the actual import of real song files """ @@ -134,7 +134,7 @@ class TestOpenLyricsImport(TestCase, TestMixin): # THEN: The xml_to_song() method should have been called self.assertTrue(importer.open_lyrics.xml_to_song.called) - def process_formatting_tags_test(self): + def test_process_formatting_tags(self): """ Test that _process_formatting_tags works """ @@ -155,7 +155,7 @@ class TestOpenLyricsImport(TestCase, TestMixin): json.loads(str(Settings().value('formattingTags/html_tags'))), 'The formatting tags should contain both the old and the new') - def process_author_test(self): + def test_process_author(self): """ Test that _process_authors works """ @@ -174,7 +174,7 @@ class TestOpenLyricsImport(TestCase, TestMixin): self.assertEquals(mocked_song.method_calls[0][1][1], 'words+music') self.assertEquals(mocked_song.method_calls[1][1][1], 'words') - def process_songbooks_test(self): + def test_process_songbooks(self): """ Test that _process_songbooks works """ diff --git a/tests/functional/openlp_plugins/songs/test_openoffice.py b/tests/functional/openlp_plugins/songs/test_openoffice.py index acb56939f..5f4aef247 100644 --- a/tests/functional/openlp_plugins/songs/test_openoffice.py +++ b/tests/functional/openlp_plugins/songs/test_openoffice.py @@ -46,7 +46,7 @@ class TestOpenOfficeImport(TestCase, TestMixin): Registry.create() @patch('openlp.plugins.songs.lib.importers.openoffice.SongImport') - def create_importer_test(self, mocked_songimport): + def test_create_importer(self, mocked_songimport): """ Test creating an instance of the OpenOfficeImport file importer """ @@ -60,7 +60,7 @@ class TestOpenOfficeImport(TestCase, TestMixin): self.assertIsNotNone(importer, 'Import should not be none') @patch('openlp.plugins.songs.lib.importers.openoffice.SongImport') - def close_ooo_file_test(self, mocked_songimport): + def test_close_ooo_file(self, mocked_songimport): """ Test that close_ooo_file catches raised exceptions """ diff --git a/tests/functional/openlp_plugins/songs/test_opensongimport.py b/tests/functional/openlp_plugins/songs/test_opensongimport.py index b6514532c..7d51527b8 100644 --- a/tests/functional/openlp_plugins/songs/test_opensongimport.py +++ b/tests/functional/openlp_plugins/songs/test_opensongimport.py @@ -66,7 +66,7 @@ class TestOpenSongImport(TestCase): """ Registry.create() - def create_importer_test(self): + def test_create_importer(self): """ Test creating an instance of the OpenSong file importer """ @@ -80,7 +80,7 @@ class TestOpenSongImport(TestCase): # THEN: The importer object should not be None self.assertIsNotNone(importer, 'Import should not be none') - def invalid_import_source_test(self): + def test_invalid_import_source(self): """ Test OpenSongImport.do_import handles different invalid import_source values """ @@ -101,7 +101,7 @@ class TestOpenSongImport(TestCase): self.assertEqual(mocked_import_wizard.progress_bar.setMaximum.called, False, 'setMaximum on import_wizard.progress_bar should not have been called') - def valid_import_source_test(self): + def test_valid_import_source(self): """ Test OpenSongImport.do_import handles different invalid import_source values """ diff --git a/tests/functional/openlp_plugins/songs/test_opsproimport.py b/tests/functional/openlp_plugins/songs/test_opsproimport.py index cee21f66e..ad4afee0e 100644 --- a/tests/functional/openlp_plugins/songs/test_opsproimport.py +++ b/tests/functional/openlp_plugins/songs/test_opsproimport.py @@ -24,19 +24,21 @@ This module contains tests for the WorshipCenter Pro song importer. """ import os import json -from unittest import TestCase, SkipTest +from unittest import TestCase, skipUnless -if os.name != 'nt': - raise SkipTest('Not Windows, skipping test') +try: + from openlp.core.common import Registry + from openlp.plugins.songs.lib.importers.opspro import OPSProImport + CAN_RUN_TESTS = True +except ImportError: + CAN_RUN_TESTS = False from tests.functional import patch, MagicMock -from openlp.core.common import Registry -from openlp.plugins.songs.lib.importers.opspro import OPSProImport - TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'opsprosongs')) +@skipUnless(CAN_RUN_TESTS, 'Not Windows, skipping test') class TestOpsProSongImport(TestCase): """ Test the functions in the :mod:`opsproimport` module. @@ -48,7 +50,7 @@ class TestOpsProSongImport(TestCase): Registry.create() @patch('openlp.plugins.songs.lib.importers.opspro.SongImport') - def create_importer_test(self, mocked_songimport): + def test_create_importer(self, mocked_songimport): """ Test creating an instance of the OPS Pro file importer """ @@ -62,7 +64,7 @@ class TestOpsProSongImport(TestCase): self.assertIsNotNone(importer, 'Import should not be none') @patch('openlp.plugins.songs.lib.importers.opspro.SongImport') - def detect_chorus_test(self, mocked_songimport): + def test_detect_chorus(self, mocked_songimport): """ Test importing lyrics with a chorus in OPS Pro """ @@ -82,7 +84,7 @@ class TestOpsProSongImport(TestCase): self.assertListEqual(importer.verse_order_list_generated, self._get_data(result_data, 'verse_order_list')) @patch('openlp.plugins.songs.lib.importers.opspro.SongImport') - def join_and_split_test(self, mocked_songimport): + def test_join_and_split(self, mocked_songimport): """ Test importing lyrics with a split and join tags works in OPS Pro """ @@ -102,7 +104,7 @@ class TestOpsProSongImport(TestCase): self.assertListEqual(importer.verse_order_list_generated, self._get_data(result_data, 'verse_order_list')) @patch('openlp.plugins.songs.lib.importers.opspro.SongImport') - def trans_off_tag_test(self, mocked_songimport): + def test_trans_off_tag(self, mocked_songimport): """ Test importing lyrics with a split and join and translations tags works in OPS Pro """ @@ -122,7 +124,7 @@ class TestOpsProSongImport(TestCase): self.assertListEqual(importer.verse_order_list_generated, self._get_data(result_data, 'verse_order_list')) @patch('openlp.plugins.songs.lib.importers.opspro.SongImport') - def trans_tag_test(self, mocked_songimport): + def test_trans_tag(self, mocked_songimport): """ Test importing lyrics with various translations tags works in OPS Pro """ diff --git a/tests/functional/openlp_plugins/songs/test_songbeamerimport.py b/tests/functional/openlp_plugins/songs/test_songbeamerimport.py index 9f20e6a08..40730e80a 100644 --- a/tests/functional/openlp_plugins/songs/test_songbeamerimport.py +++ b/tests/functional/openlp_plugins/songs/test_songbeamerimport.py @@ -60,7 +60,7 @@ class TestSongBeamerImport(TestCase): """ Registry.create() - def create_importer_test(self): + def test_create_importer(self): """ Test creating an instance of the SongBeamer file importer """ @@ -74,7 +74,7 @@ class TestSongBeamerImport(TestCase): # THEN: The importer object should not be None self.assertIsNotNone(importer, 'Import should not be none') - def invalid_import_source_test(self): + def test_invalid_import_source(self): """ Test SongBeamerImport.do_import handles different invalid import_source values """ @@ -95,7 +95,7 @@ class TestSongBeamerImport(TestCase): self.assertEqual(mocked_import_wizard.progress_bar.setMaximum.called, False, 'setMaxium on import_wizard.progress_bar should not have been called') - def valid_import_source_test(self): + def test_valid_import_source(self): """ Test SongBeamerImport.do_import handles different invalid import_source values """ @@ -116,7 +116,7 @@ class TestSongBeamerImport(TestCase): 'do_import should return None when import_source is a list and stop_import_flag is True') mocked_import_wizard.progress_bar.setMaximum.assert_called_with(len(importer.import_source)) - def check_verse_marks_test(self): + def test_check_verse_marks(self): """ Tests different lines to see if a verse mark is detected or not """ diff --git a/tests/functional/openlp_plugins/songs/test_songselect.py b/tests/functional/openlp_plugins/songs/test_songselect.py index 18ada0338..1c61ddc43 100644 --- a/tests/functional/openlp_plugins/songs/test_songselect.py +++ b/tests/functional/openlp_plugins/songs/test_songselect.py @@ -47,7 +47,7 @@ class TestSongSelectImport(TestCase, TestMixin): Test the :class:`~openlp.plugins.songs.lib.songselect.SongSelectImport` class """ @patch('openlp.plugins.songs.lib.songselect.build_opener') - def constructor_test(self, mocked_build_opener): + def test_constructor(self, mocked_build_opener): """ Test that constructing a basic SongSelectImport object works correctly """ @@ -63,7 +63,7 @@ class TestSongSelectImport(TestCase, TestMixin): @patch('openlp.plugins.songs.lib.songselect.build_opener') @patch('openlp.plugins.songs.lib.songselect.BeautifulSoup') - def login_fails_test(self, MockedBeautifulSoup, mocked_build_opener): + def test_login_fails(self, MockedBeautifulSoup, mocked_build_opener): """ Test that when logging in to SongSelect fails, the login method returns False """ @@ -86,7 +86,7 @@ class TestSongSelectImport(TestCase, TestMixin): self.assertFalse(result, 'The login method should have returned False') @patch('openlp.plugins.songs.lib.songselect.build_opener') - def login_except_test(self, mocked_build_opener): + def test_login_except(self, mocked_build_opener): """ Test that when logging in to SongSelect fails, the login method raises URLError """ @@ -104,7 +104,7 @@ class TestSongSelectImport(TestCase, TestMixin): @patch('openlp.plugins.songs.lib.songselect.build_opener') @patch('openlp.plugins.songs.lib.songselect.BeautifulSoup') - def login_succeeds_test(self, MockedBeautifulSoup, mocked_build_opener): + def test_login_succeeds(self, MockedBeautifulSoup, mocked_build_opener): """ Test that when logging in to SongSelect succeeds, the login method returns True """ @@ -127,7 +127,7 @@ class TestSongSelectImport(TestCase, TestMixin): self.assertTrue(result, 'The login method should have returned True') @patch('openlp.plugins.songs.lib.songselect.build_opener') - def logout_test(self, mocked_build_opener): + def test_logout(self, mocked_build_opener): """ Test that when the logout method is called, it logs the user out of SongSelect """ @@ -145,7 +145,7 @@ class TestSongSelectImport(TestCase, TestMixin): @patch('openlp.plugins.songs.lib.songselect.build_opener') @patch('openlp.plugins.songs.lib.songselect.BeautifulSoup') - def search_returns_no_results_test(self, MockedBeautifulSoup, mocked_build_opener): + def test_search_returns_no_results(self, MockedBeautifulSoup, mocked_build_opener): """ Test that when the search finds no results, it simply returns an empty list """ @@ -170,7 +170,7 @@ class TestSongSelectImport(TestCase, TestMixin): @patch('openlp.plugins.songs.lib.songselect.build_opener') @patch('openlp.plugins.songs.lib.songselect.BeautifulSoup') - def search_returns_two_results_test(self, MockedBeautifulSoup, mocked_build_opener): + def test_search_returns_two_results(self, MockedBeautifulSoup, mocked_build_opener): """ Test that when the search finds 2 results, it simply returns a list with 2 results """ @@ -208,7 +208,7 @@ class TestSongSelectImport(TestCase, TestMixin): @patch('openlp.plugins.songs.lib.songselect.build_opener') @patch('openlp.plugins.songs.lib.songselect.BeautifulSoup') - def search_reaches_max_results_test(self, MockedBeautifulSoup, mocked_build_opener): + def test_search_reaches_max_results(self, MockedBeautifulSoup, mocked_build_opener): """ Test that when the search finds MAX (2) results, it simply returns a list with those (2) """ @@ -248,7 +248,7 @@ class TestSongSelectImport(TestCase, TestMixin): @patch('openlp.plugins.songs.lib.songselect.build_opener') @patch('openlp.plugins.songs.lib.songselect.BeautifulSoup') - def stop_called_test(self, MockedBeautifulSoup, mocked_build_opener): + def test_stop_called(self, MockedBeautifulSoup, mocked_build_opener): """ Test that the search is stopped with stop() is called """ @@ -263,7 +263,7 @@ class TestSongSelectImport(TestCase, TestMixin): self.assertFalse(importer.run_search, 'Searching should have been stopped') @patch('openlp.plugins.songs.lib.songselect.build_opener') - def get_song_page_raises_exception_test(self, mocked_build_opener): + def test_get_song_page_raises_exception(self, mocked_build_opener): """ Test that when BeautifulSoup gets a bad song page the get_song() method returns None """ @@ -283,7 +283,7 @@ class TestSongSelectImport(TestCase, TestMixin): @patch('openlp.plugins.songs.lib.songselect.build_opener') @patch('openlp.plugins.songs.lib.songselect.BeautifulSoup') - def get_song_lyrics_raise_exception_test(self, MockedBeautifulSoup, mocked_build_opener): + def test_get_song_lyrics_raise_exception(self, MockedBeautifulSoup, mocked_build_opener): """ Test that when BeautifulSoup gets a bad lyrics page the get_song() method returns None """ @@ -301,7 +301,7 @@ class TestSongSelectImport(TestCase, TestMixin): @patch('openlp.plugins.songs.lib.songselect.build_opener') @patch('openlp.plugins.songs.lib.songselect.BeautifulSoup') - def get_song_test(self, MockedBeautifulSoup, mocked_build_opener): + def test_get_song(self, MockedBeautifulSoup, mocked_build_opener): """ Test that the get_song() method returns the correct song details """ @@ -349,7 +349,7 @@ class TestSongSelectImport(TestCase, TestMixin): @patch('openlp.plugins.songs.lib.songselect.clean_song') @patch('openlp.plugins.songs.lib.songselect.Author') - def save_song_new_author_test(self, MockedAuthor, mocked_clean_song): + def test_save_song_new_author(self, MockedAuthor, mocked_clean_song): """ Test that saving a song with a new author performs the correct actions """ @@ -385,7 +385,7 @@ class TestSongSelectImport(TestCase, TestMixin): @patch('openlp.plugins.songs.lib.songselect.clean_song') @patch('openlp.plugins.songs.lib.songselect.Author') - def save_song_existing_author_test(self, MockedAuthor, mocked_clean_song): + def test_save_song_existing_author(self, MockedAuthor, mocked_clean_song): """ Test that saving a song with an existing author performs the correct actions """ @@ -420,7 +420,7 @@ class TestSongSelectImport(TestCase, TestMixin): @patch('openlp.plugins.songs.lib.songselect.clean_song') @patch('openlp.plugins.songs.lib.songselect.Author') - def save_song_unknown_author_test(self, MockedAuthor, mocked_clean_song): + def test_save_song_unknown_author(self, MockedAuthor, mocked_clean_song): """ Test that saving a song with an author name of only one word performs the correct actions """ @@ -469,7 +469,7 @@ class TestSongSelectForm(TestCase, TestMixin): Registry.create() Registry().register('application', self.app) - def create_form_test(self): + def test_create_form(self): """ Test that we can create the SongSelect form """ @@ -487,7 +487,7 @@ class TestSongSelectForm(TestCase, TestMixin): @patch('openlp.plugins.songs.forms.songselectform.SongSelectImport') @patch('openlp.plugins.songs.forms.songselectform.QtWidgets.QMessageBox.critical') @patch('openlp.plugins.songs.forms.songselectform.translate') - def login_fails_test(self, mocked_translate, mocked_critical, MockedSongSelectImport): + def test_login_fails(self, mocked_translate, mocked_critical, MockedSongSelectImport): """ Test that when the login fails, the form returns to the correct state """ @@ -540,7 +540,7 @@ class TestSongSelectForm(TestCase, TestMixin): @patch('openlp.plugins.songs.forms.songselectform.QtWidgets.QMessageBox.question') @patch('openlp.plugins.songs.forms.songselectform.translate') - def on_import_yes_clicked_test(self, mocked_translate, mocked_question): + def test_on_import_yes_clicked(self, mocked_translate, mocked_question): """ Test that when a song is imported and the user clicks the "yes" button, the UI goes back to the previous page """ @@ -567,7 +567,7 @@ class TestSongSelectForm(TestCase, TestMixin): @patch('openlp.plugins.songs.forms.songselectform.QtWidgets.QMessageBox.question') @patch('openlp.plugins.songs.forms.songselectform.translate') - def on_import_no_clicked_test(self, mocked_translate, mocked_question): + def test_on_import_no_clicked(self, mocked_translate, mocked_question): """ Test that when a song is imported and the user clicks the "no" button, the UI exits """ @@ -592,7 +592,7 @@ class TestSongSelectForm(TestCase, TestMixin): mocked_done.assert_called_with(QtWidgets.QDialog.Accepted) self.assertIsNone(ssform.song) - def on_back_button_clicked_test(self): + def test_on_back_button_clicked(self): """ Test that when the back button is clicked, the stacked widget is set back one page """ @@ -609,7 +609,7 @@ class TestSongSelectForm(TestCase, TestMixin): mocked_search_combobox.setFocus.assert_called_with() @patch('openlp.plugins.songs.forms.songselectform.QtWidgets.QMessageBox.information') - def on_search_show_info_test(self, mocked_information): + def test_on_search_show_info(self, mocked_information): """ Test that when the search_show_info signal is emitted, the on_search_show_info() method shows a dialog """ @@ -624,7 +624,7 @@ class TestSongSelectForm(TestCase, TestMixin): # THEN: An information dialog should be shown mocked_information.assert_called_with(ssform, expected_title, expected_text) - def update_login_progress_test(self): + def test_update_login_progress(self): """ Test the _update_login_progress() method """ @@ -639,7 +639,7 @@ class TestSongSelectForm(TestCase, TestMixin): # THEN: The login progress bar should be updated mocked_login_progress_bar.setValue.assert_called_with(4) - def update_song_progress_test(self): + def test_update_song_progress(self): """ Test the _update_song_progress() method """ @@ -654,7 +654,7 @@ class TestSongSelectForm(TestCase, TestMixin): # THEN: The song progress bar should be updated mocked_song_progress_bar.setValue.assert_called_with(3) - def on_search_results_widget_double_clicked_test(self): + def test_on_search_results_widget_double_clicked(self): """ Test that a song is retrieved when a song in the results list is double-clicked """ @@ -669,7 +669,7 @@ class TestSongSelectForm(TestCase, TestMixin): # THEN: The song is fetched and shown to the user mocked_view_song.assert_called_with(expected_song) - def on_view_button_clicked_test(self): + def test_on_view_button_clicked(self): """ Test that a song is retrieved when the view button is clicked """ @@ -686,7 +686,7 @@ class TestSongSelectForm(TestCase, TestMixin): # THEN: The song is fetched and shown to the user mocked_view_song.assert_called_with(expected_song) - def on_search_results_widget_selection_changed_test(self): + def test_on_search_results_widget_selection_changed(self): """ Test that the view button is updated when the search results list is changed """ @@ -703,7 +703,7 @@ class TestSongSelectForm(TestCase, TestMixin): mocked_view_button.setEnabled.assert_called_with(True) @patch('openlp.plugins.songs.forms.songselectform.SongSelectImport') - def on_stop_button_clicked_test(self, MockedSongSelectImport): + def test_on_stop_button_clicked(self, MockedSongSelectImport): """ Test that the search is stopped when the stop button is clicked """ @@ -724,7 +724,7 @@ class TestSongSelectForm(TestCase, TestMixin): @patch('openlp.plugins.songs.forms.songselectform.Settings') @patch('openlp.plugins.songs.forms.songselectform.QtCore.QThread') @patch('openlp.plugins.songs.forms.songselectform.SearchWorker') - def on_search_button_clicked_test(self, MockedSearchWorker, MockedQtThread, MockedSettings): + def test_on_search_button_clicked(self, MockedSearchWorker, MockedQtThread, MockedSettings): """ Test that search fields are disabled when search button is clicked. """ @@ -739,7 +739,7 @@ class TestSongSelectForm(TestCase, TestMixin): self.assertFalse(ssform.search_button.isEnabled()) self.assertFalse(ssform.search_combobox.isEnabled()) - def on_search_finished_test(self): + def test_on_search_finished(self): """ Test that search fields are enabled when search is finished. """ @@ -776,7 +776,7 @@ class TestSearchWorker(TestCase, TestMixin): """ Test the SearchWorker class """ - def constructor_test(self): + def test_constructor(self): """ Test the SearchWorker constructor """ @@ -791,7 +791,7 @@ class TestSearchWorker(TestCase, TestMixin): self.assertIs(importer, worker.importer, 'The importer should be the right object') self.assertEqual(search_text, worker.search_text, 'The search text should be correct') - def start_test(self): + def test_start(self): """ Test the start() method of the SearchWorker class """ @@ -811,7 +811,7 @@ class TestSearchWorker(TestCase, TestMixin): mocked_quit.emit.assert_called_with() @patch('openlp.plugins.songs.forms.songselectform.translate') - def start_over_1000_songs_test(self, mocked_translate): + def test_start_over_1000_songs(self, mocked_translate): """ Test the start() method of the SearchWorker class when it finds over 1000 songs """ @@ -836,7 +836,7 @@ class TestSearchWorker(TestCase, TestMixin): mocked_finished.emit.assert_called_with() mocked_quit.emit.assert_called_with() - def found_song_callback_test(self): + def test_found_song_callback(self): """ Test that when the _found_song_callback() function is called, the "found_song" signal is emitted """ diff --git a/tests/functional/openlp_plugins/songs/test_songshowplusimport.py b/tests/functional/openlp_plugins/songs/test_songshowplusimport.py index ec86eca07..2dc28d541 100644 --- a/tests/functional/openlp_plugins/songs/test_songshowplusimport.py +++ b/tests/functional/openlp_plugins/songs/test_songshowplusimport.py @@ -58,7 +58,7 @@ class TestSongShowPlusImport(TestCase): """ Test the functions in the :mod:`songshowplusimport` module. """ - def create_importer_test(self): + def test_create_importer(self): """ Test creating an instance of the SongShow Plus file importer """ @@ -72,7 +72,7 @@ class TestSongShowPlusImport(TestCase): # THEN: The importer object should not be None self.assertIsNotNone(importer, 'Import should not be none') - def invalid_import_source_test(self): + def test_invalid_import_source(self): """ Test SongShowPlusImport.do_import handles different invalid import_source values """ @@ -93,7 +93,7 @@ class TestSongShowPlusImport(TestCase): self.assertEqual(mocked_import_wizard.progress_bar.setMaximum.called, False, 'setMaximum on import_wizard.progress_bar should not have been called') - def valid_import_source_test(self): + def test_valid_import_source(self): """ Test SongShowPlusImport.do_import handles different invalid import_source values """ @@ -114,7 +114,7 @@ class TestSongShowPlusImport(TestCase): 'and stop_import_flag is True') mocked_import_wizard.progress_bar.setMaximum.assert_called_with(len(importer.import_source)) - def to_openlp_verse_tag_test(self): + def test_to_openlp_verse_tag(self): """ Test to_openlp_verse_tag method by simulating adding a verse """ @@ -142,7 +142,7 @@ class TestSongShowPlusImport(TestCase): 'SongShowPlusImport.to_openlp_verse_tag should return "%s" when called with "%s"' % (openlp_tag, original_tag)) - def to_openlp_verse_tag_verse_order_test(self): + def test_to_openlp_verse_tag_verse_order(self): """ Test to_openlp_verse_tag method by simulating adding a verse to the verse order """ diff --git a/tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py b/tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py index 72e3c64d3..2cc1f3ce7 100644 --- a/tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py +++ b/tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py @@ -22,48 +22,50 @@ """ This module contains tests for the WorshipCenter Pro song importer. """ -import os -from unittest import TestCase, SkipTest +from unittest import TestCase, skipUnless + +try: + import pyodbc + from openlp.core.common import Registry + from openlp.plugins.songs.lib.importers.worshipcenterpro import WorshipCenterProImport + CAN_RUN_TESTS = True +except ImportError: + CAN_RUN_TESTS = False -if os.name != 'nt': - raise SkipTest('Not Windows, skipping test') -import pyodbc from tests.functional import patch, MagicMock -from openlp.core.common import Registry -from openlp.plugins.songs.lib.importers.worshipcenterpro import WorshipCenterProImport - class TestRecord(object): """ Microsoft Access Driver is not available on non Microsoft Systems for this reason the :class:`TestRecord` is used to simulate a recordset that would be returned by pyobdc. """ - def __init__(self, id, field, value): + def __init__(self, id_, field, value): # The case of the following instance variables is important as it needs to be the same as the ones in use in the # WorshipCenter Pro database. - self.ID = id + self.ID = id_ self.Field = field self.Value = value -class WorshipCenterProImportLogger(WorshipCenterProImport): - """ - This class logs changes in the title instance variable - """ - _title_assignment_list = [] +if CAN_RUN_TESTS: + class WorshipCenterProImportLogger(WorshipCenterProImport): + """ + This class logs changes in the title instance variable + """ + _title_assignment_list = [] - def __init__(self, manager): - WorshipCenterProImport.__init__(self, manager, filenames=[]) + def __init__(self, manager): + WorshipCenterProImport.__init__(self, manager, filenames=[]) - @property - def title(self): - return self._title_assignment_list[-1] + @property + def title(self): + return self._title_assignment_list[-1] - @title.setter - def title(self, title): - self._title_assignment_list.append(title) + @title.setter + def title(self, title): + self._title_assignment_list.append(title) RECORDSET_TEST_DATA = [TestRecord(1, 'TITLE', 'Amazing Grace'), @@ -133,6 +135,7 @@ SONG_TEST_DATA = [{'title': 'Amazing Grace', 'Just to bow and\nreceive a new blessing\nIn the beautiful\ngarden of prayer.')]}] +@skipUnless(CAN_RUN_TESTS, 'Not Windows, skipping test') class TestWorshipCenterProSongImport(TestCase): """ Test the functions in the :mod:`worshipcenterproimport` module. @@ -143,7 +146,7 @@ class TestWorshipCenterProSongImport(TestCase): """ Registry.create() - def create_importer_test(self): + def test_create_importer(self): """ Test creating an instance of the WorshipCenter Pro file importer """ @@ -157,7 +160,7 @@ class TestWorshipCenterProSongImport(TestCase): # THEN: The importer object should not be None self.assertIsNotNone(importer, 'Import should not be none') - def pyodbc_exception_test(self): + def test_pyodbc_exception(self): """ Test that exceptions raised by pyodbc are handled """ @@ -186,7 +189,7 @@ class TestWorshipCenterProSongImport(TestCase): 'Unable to connect the WorshipCenter Pro database.') mocked_log_error.assert_called_with('import_source', 'Translated Text') - def song_import_test(self): + def test_song_import(self): """ Test that a simulated WorshipCenter Pro recordset is imported correctly """ diff --git a/tests/functional/openlp_plugins/songs/test_zionworximport.py b/tests/functional/openlp_plugins/songs/test_zionworximport.py index 8f0caf693..c2e594212 100644 --- a/tests/functional/openlp_plugins/songs/test_zionworximport.py +++ b/tests/functional/openlp_plugins/songs/test_zionworximport.py @@ -46,7 +46,7 @@ class TestZionWorxImport(TestCase): """ Registry.create() - def create_importer_test(self): + def test_create_importer(self): """ Test creating an instance of the ZionWorx file importer """ diff --git a/tests/functional/openlp_plugins/songusage/test_songusage.py b/tests/functional/openlp_plugins/songusage/test_songusage.py index 61d8a22bb..53f9ce60c 100644 --- a/tests/functional/openlp_plugins/songusage/test_songusage.py +++ b/tests/functional/openlp_plugins/songusage/test_songusage.py @@ -36,7 +36,7 @@ class TestSongUsage(TestCase): def setUp(self): Registry.create() - def about_text_test(self): + def test_about_text(self): """ Test the about text of the song usage plugin """ @@ -49,7 +49,7 @@ class TestSongUsage(TestCase): self.assertNotEquals(len(SongUsagePlugin.about()), 0) @patch('openlp.plugins.songusage.songusageplugin.Manager') - def song_usage_init_test(self, MockedManager): + def test_song_usage_init(self, MockedManager): """ Test the initialisation of the SongUsagePlugin class """ @@ -66,7 +66,7 @@ class TestSongUsage(TestCase): self.assertFalse(song_usage.song_usage_active) @patch('openlp.plugins.songusage.songusageplugin.Manager') - def check_pre_conditions_test(self, MockedManager): + def test_check_pre_conditions(self, MockedManager): """ Test that check_pre_condition returns true for valid manager session """ @@ -83,7 +83,7 @@ class TestSongUsage(TestCase): self.assertTrue(ret) @patch('openlp.plugins.songusage.songusageplugin.Manager') - def toggle_song_usage_state_test(self, MockedManager): + def test_toggle_song_usage_state(self, MockedManager): """ Test that toggle_song_usage_state does toggle song_usage_state """ diff --git a/tests/functional/test_init.py b/tests/functional/test_init.py index fcd275d33..825de57f3 100644 --- a/tests/functional/test_init.py +++ b/tests/functional/test_init.py @@ -47,7 +47,7 @@ class TestInit(TestCase, TestMixin): self.destroy_settings() del self.openlp - def event_test(self): + def test_event(self): """ Test the reimplemented event method """ @@ -66,7 +66,7 @@ class TestInit(TestCase, TestMixin): self.assertEqual(self.openlp.args[0], file_path, "The path should be in args.") @patch('openlp.core.is_macosx') - def application_activate_event_test(self, mocked_is_macosx): + def test_application_activate_event(self, mocked_is_macosx): """ Test that clicking on the dock icon on Mac OS X restores the main window if it is minimized """ @@ -84,7 +84,7 @@ class TestInit(TestCase, TestMixin): self.assertTrue(result, "The method should have returned True.") # self.assertFalse(self.openlp.main_window.isMinimized()) - def backup_on_upgrade_first_install_test(self): + def test_backup_on_upgrade_first_install(self): """ Test that we don't try to backup on a new install """ @@ -108,7 +108,7 @@ class TestInit(TestCase, TestMixin): self.assertEqual(Settings().value('core/application version'), '2.2.0', 'Version should be the same!') self.assertEqual(mocked_question.call_count, 0, 'No question should have been asked!') - def backup_on_upgrade_test(self): + def test_backup_on_upgrade(self): """ Test that we try to backup on a new install """ diff --git a/tests/interfaces/openlp_core_common/test_utils.py b/tests/interfaces/openlp_core_common/test_utils.py index 2c0d9a572..2d6e6c587 100644 --- a/tests/interfaces/openlp_core_common/test_utils.py +++ b/tests/interfaces/openlp_core_common/test_utils.py @@ -41,7 +41,7 @@ class TestUtils(TestCase, TestMixin): """ self.setup_application() - def is_not_image_empty_test(self): + def test_is_not_image_empty(self): """ Test the method handles an empty string """ @@ -54,7 +54,7 @@ class TestUtils(TestCase, TestMixin): # THEN the result is false assert result is True, 'The missing file test should return True' - def is_not_image_with_image_file_test(self): + def test_is_not_image_with_image_file(self): """ Test the method handles an image file """ @@ -67,7 +67,7 @@ class TestUtils(TestCase, TestMixin): # THEN the result is false assert result is False, 'The file is present so the test should return False' - def is_not_image_with_none_image_file_test(self): + def test_is_not_image_with_none_image_file(self): """ Test the method handles a non image file """ diff --git a/tests/interfaces/openlp_core_lib/test_pluginmanager.py b/tests/interfaces/openlp_core_lib/test_pluginmanager.py index 5efb1e3c7..df35d1566 100644 --- a/tests/interfaces/openlp_core_lib/test_pluginmanager.py +++ b/tests/interfaces/openlp_core_lib/test_pluginmanager.py @@ -69,7 +69,7 @@ class TestPluginManager(TestCase, TestMixin): @patch('openlp.plugins.custom.lib.db.init_schema') @patch('openlp.plugins.alerts.lib.db.init_schema') @patch('openlp.plugins.bibles.lib.db.init_schema') - def find_plugins_test(self, mocked_is1, mocked_is2, mocked_is3, mocked_is4, mocked_is5, mocked_is6): + def test_find_plugins(self, mocked_is1, mocked_is2, mocked_is3, mocked_is4, mocked_is5, mocked_is6): """ Test the find_plugins() method to ensure it imports the correct plugins """ diff --git a/tests/interfaces/openlp_core_lib/test_searchedit.py b/tests/interfaces/openlp_core_lib/test_searchedit.py index 4f470b6b1..a4c4472f5 100644 --- a/tests/interfaces/openlp_core_lib/test_searchedit.py +++ b/tests/interfaces/openlp_core_lib/test_searchedit.py @@ -69,7 +69,7 @@ class TestSearchEdit(TestCase, TestMixin): del self.search_edit del self.main_window - def set_search_types_test(self): + def test_set_search_types(self): """ Test setting the search types of the search edit. """ @@ -81,7 +81,7 @@ class TestSearchEdit(TestCase, TestMixin): # THEN: The first search type should be the first one in the list. assert self.search_edit.current_search_type() == SearchTypes.First, "The first search type should be selected." - def set_current_search_type_test(self): + def test_set_current_search_type(self): """ Test if changing the search type works. """ @@ -96,7 +96,7 @@ class TestSearchEdit(TestCase, TestMixin): assert self.search_edit.placeholderText() == SECOND_PLACEHOLDER_TEXT,\ "The correct placeholder text should be 'Second Placeholder Text'." - def clear_button_visibility_test(self): + def test_clear_button_visibility(self): """ Test if the clear button is hidden/shown correctly. """ @@ -110,7 +110,7 @@ class TestSearchEdit(TestCase, TestMixin): # THEN: The clear button should not be hidden any more. assert not self.search_edit.clear_button.isHidden(), "The clear button should be visible." - def press_clear_button_test(self): + def test_press_clear_button(self): """ Check if the search edit behaves correctly when pressing the clear button. """ diff --git a/tests/interfaces/openlp_core_ui/test_filerenamedialog.py b/tests/interfaces/openlp_core_ui/test_filerenamedialog.py index cb40cd127..f34875527 100644 --- a/tests/interfaces/openlp_core_ui/test_filerenamedialog.py +++ b/tests/interfaces/openlp_core_ui/test_filerenamedialog.py @@ -51,7 +51,7 @@ class TestStartFileRenameForm(TestCase, TestMixin): del self.form del self.main_window - def window_title_test(self): + def test_window_title(self): """ Test the windowTitle of the FileRenameDialog """ @@ -76,7 +76,7 @@ class TestStartFileRenameForm(TestCase, TestMixin): # THEN: the window title is set correctly self.assertEqual(self.form.windowTitle(), 'File Copy', 'The window title should be "File Copy"') - def line_edit_focus_test(self): + def test_line_edit_focus(self): """ Regression test for bug1067251 Test that the file_name_edit setFocus has called with True when executed @@ -92,7 +92,7 @@ class TestStartFileRenameForm(TestCase, TestMixin): # THEN: the setFocus method of the file_name_edit has been called with True mocked_set_focus.assert_called_with() - def file_name_validation_test(self): + def test_file_name_validation(self): """ Test the file_name_edit validation """ diff --git a/tests/interfaces/openlp_core_ui/test_mainwindow.py b/tests/interfaces/openlp_core_ui/test_mainwindow.py index 984923c70..fbe6c7318 100644 --- a/tests/interfaces/openlp_core_ui/test_mainwindow.py +++ b/tests/interfaces/openlp_core_ui/test_mainwindow.py @@ -65,7 +65,7 @@ class TestMainWindow(TestCase, TestMixin): """ del self.main_window - def restore_current_media_manager_item_test(self): + def test_restore_current_media_manager_item(self): """ Regression test for bug #1152509. """ @@ -80,7 +80,7 @@ class TestMainWindow(TestCase, TestMixin): # THEN: The current widget should have been set. self.main_window.media_tool_box.setCurrentIndex.assert_called_with(2) - def projector_manager_dock_locked_test(self): + def test_projector_manager_dock_locked(self): """ Projector Manager enable UI options - bug #1390702 """ @@ -93,7 +93,7 @@ class TestMainWindow(TestCase, TestMixin): # THEN: Projector manager dock should have been called with disable UI features projector_dock.setFeatures.assert_called_with(0) - def projector_manager_dock_unlocked_test(self): + def test_projector_manager_dock_unlocked(self): """ Projector Manager disable UI options - bug #1390702 """ diff --git a/tests/interfaces/openlp_core_ui/test_projectoreditform.py b/tests/interfaces/openlp_core_ui/test_projectoreditform.py index 7518f139e..77685ca2e 100644 --- a/tests/interfaces/openlp_core_ui/test_projectoreditform.py +++ b/tests/interfaces/openlp_core_ui/test_projectoreditform.py @@ -66,7 +66,7 @@ class TestProjectorEditForm(TestCase, TestMixin): del(self.projector_form) self.destroy_settings() - def edit_form_add_projector_test(self): + def test_edit_form_add_projector(self): """ Test projector edit form with no parameters creates a new entry. @@ -85,7 +85,7 @@ class TestProjectorEditForm(TestCase, TestMixin): self.assertTrue((item.ip is None and item.name is None), 'Projector edit form should have a new Projector() instance to edit') - def edit_form_edit_projector_test(self): + def test_edit_form_edit_projector(self): """ Test projector edit form with existing projector entry diff --git a/tests/interfaces/openlp_core_ui/test_projectormanager.py b/tests/interfaces/openlp_core_ui/test_projectormanager.py index 695a25586..a98dcb0f0 100644 --- a/tests/interfaces/openlp_core_ui/test_projectormanager.py +++ b/tests/interfaces/openlp_core_ui/test_projectormanager.py @@ -63,7 +63,7 @@ class TestProjectorManager(TestCase, TestMixin): self.destroy_settings() del self.projector_manager - def bootstrap_initialise_test(self): + def test_bootstrap_initialise(self): """ Test initialize calls correct startup functions """ @@ -73,7 +73,7 @@ class TestProjectorManager(TestCase, TestMixin): self.assertEqual(type(self.projector_manager.projectordb), ProjectorDB, 'Initialization should have created a ProjectorDB() instance') - def bootstrap_post_set_up_test(self): + def test_bootstrap_post_set_up(self): """ Test post-initialize calls proper setups """ diff --git a/tests/interfaces/openlp_core_ui/test_projectorsourceform.py b/tests/interfaces/openlp_core_ui/test_projectorsourceform.py index 3405a2346..2b081d642 100644 --- a/tests/interfaces/openlp_core_ui/test_projectorsourceform.py +++ b/tests/interfaces/openlp_core_ui/test_projectorsourceform.py @@ -100,7 +100,7 @@ class ProjectorSourceFormTest(TestCase, TestMixin): retries += 1 self.destroy_settings() - def source_dict_test(self): + def test_source_dict(self): """ Test that source list dict returned from sourceselectform module is a valid dict with proper entries """ @@ -118,7 +118,7 @@ class ProjectorSourceFormTest(TestCase, TestMixin): "Source group dictionary should match test dictionary") @patch.object(QDialog, 'exec') - def source_select_edit_button_test(self, mocked_qdialog): + def test_source_select_edit_button(self, mocked_qdialog): """ Test source select form edit has Ok, Cancel, Reset, and Revert buttons """ @@ -138,7 +138,7 @@ class ProjectorSourceFormTest(TestCase, TestMixin): '"Rest", and "Revert" buttons available') @patch.object(QDialog, 'exec') - def source_select_noedit_button_test(self, mocked_qdialog): + def test_source_select_noedit_button(self, mocked_qdialog): """ Test source select form view has OK and Cancel buttons only """ diff --git a/tests/interfaces/openlp_core_ui/test_servicemanager.py b/tests/interfaces/openlp_core_ui/test_servicemanager.py index e3d91ec9e..ca0ea24d7 100644 --- a/tests/interfaces/openlp_core_ui/test_servicemanager.py +++ b/tests/interfaces/openlp_core_ui/test_servicemanager.py @@ -62,7 +62,7 @@ class TestServiceManager(TestCase, TestMixin): """ del self.main_window - def basic_service_manager_test(self): + def test_basic_service_manager(self): """ Test the Service Manager UI Functionality """ @@ -74,7 +74,7 @@ class TestServiceManager(TestCase, TestMixin): self.assertEqual(self.service_manager.service_manager_list.topLevelItemCount(), 0, 'The service manager list should be empty ') - def default_context_menu_test(self): + def test_default_context_menu(self): """ Test the context_menu() method with a default service item """ @@ -116,7 +116,7 @@ class TestServiceManager(TestCase, TestMixin): self.service_manager.auto_start_action.setVisible.assert_called_once_with(False), \ 'The action should be set invisible.' - def edit_context_menu_test(self): + def test_edit_context_menu(self): """ Test the context_menu() method with a edit service item """ @@ -160,7 +160,7 @@ class TestServiceManager(TestCase, TestMixin): self.service_manager.auto_start_action.setVisible.assert_called_once_with(False), \ 'The action should be set invisible.' - def maintain_context_menu_test(self): + def test_maintain_context_menu(self): """ Test the context_menu() method with a maintain """ @@ -203,7 +203,7 @@ class TestServiceManager(TestCase, TestMixin): self.service_manager.auto_start_action.setVisible.assert_called_once_with(False), \ 'The action should be set invisible.' - def loopy_context_menu_test(self): + def test_loopy_context_menu(self): """ Test the context_menu() method with a loop """ @@ -248,7 +248,7 @@ class TestServiceManager(TestCase, TestMixin): self.service_manager.auto_start_action.setVisible.assert_called_once_with(False), \ 'The action should be set invisible.' - def start_time_context_menu_test(self): + def test_start_time_context_menu(self): """ Test the context_menu() method with a start time """ @@ -291,7 +291,7 @@ class TestServiceManager(TestCase, TestMixin): self.service_manager.auto_start_action.setVisible.assert_called_once_with(False), \ 'The action should be set invisible.' - def auto_start_context_menu_test(self): + def test_auto_start_context_menu(self): """ Test the context_menu() method with can auto start """ @@ -337,7 +337,7 @@ class TestServiceManager(TestCase, TestMixin): self.service_manager.rename_action.setVisible.assert_called_once_with(False), \ 'The action should be set invisible.' - def click_on_new_service_test(self): + def test_click_on_new_service(self): """ Test the on_new_service event handler is called by the UI """ diff --git a/tests/interfaces/openlp_core_ui/test_servicenotedialog.py b/tests/interfaces/openlp_core_ui/test_servicenotedialog.py index 16df7e1ba..2141025a7 100644 --- a/tests/interfaces/openlp_core_ui/test_servicenotedialog.py +++ b/tests/interfaces/openlp_core_ui/test_servicenotedialog.py @@ -51,7 +51,7 @@ class TestStartNoteDialog(TestCase, TestMixin): del self.form del self.main_window - def basic_display_test(self): + def test_basic_display(self): """ Test Service Note form functionality """ diff --git a/tests/interfaces/openlp_core_ui/test_settings_form.py b/tests/interfaces/openlp_core_ui/test_settings_form.py index 119deab8a..9c95ac6f6 100644 --- a/tests/interfaces/openlp_core_ui/test_settings_form.py +++ b/tests/interfaces/openlp_core_ui/test_settings_form.py @@ -66,7 +66,7 @@ class TestSettingsForm(TestCase, TestMixin): """ del self.form - def basic_cancel_test(self): + def test_basic_cancel(self): """ Test running the settings form and pressing Cancel """ @@ -80,7 +80,7 @@ class TestSettingsForm(TestCase, TestMixin): # THEN the dialog reject should have been called assert mocked_reject.call_count == 1, 'The QDialog.reject should have been called' - def basic_accept_test(self): + def test_basic_accept(self): """ Test running the settings form and pressing Ok """ @@ -94,7 +94,7 @@ class TestSettingsForm(TestCase, TestMixin): # THEN the dialog reject should have been called assert mocked_accept.call_count == 1, 'The QDialog.accept should have been called' - def basic_register_test(self): + def test_basic_register(self): """ Test running the settings form and adding a single function """ @@ -109,7 +109,7 @@ class TestSettingsForm(TestCase, TestMixin): # THEN the processing stack should be empty assert len(self.form.processes) == 0, 'The one requested process should have been removed from the stack' - def register_multiple_functions_test(self): + def test_register_multiple_functions(self): """ Test running the settings form and adding multiple functions """ diff --git a/tests/interfaces/openlp_core_ui/test_shortcutlistform.py b/tests/interfaces/openlp_core_ui/test_shortcutlistform.py index 095e2caad..86453757c 100644 --- a/tests/interfaces/openlp_core_ui/test_shortcutlistform.py +++ b/tests/interfaces/openlp_core_ui/test_shortcutlistform.py @@ -52,7 +52,7 @@ class TestShortcutform(TestCase, TestMixin): del self.form del self.main_window - def adjust_button_test(self): + def test_adjust_button(self): """ Test the _adjust_button() method """ @@ -71,7 +71,7 @@ class TestShortcutform(TestCase, TestMixin): mocked_check_method.assert_called_once_with(True) self.assertEqual(button.isEnabled(), enabled, 'The button should be disabled.') - def space_key_press_event_test(self): + def test_space_key_press_event(self): """ Test the keyPressEvent when the spacebar was pressed """ @@ -87,7 +87,7 @@ class TestShortcutform(TestCase, TestMixin): mocked_key_release_event.assert_called_with(mocked_event) self.assertEqual(0, mocked_event.accept.call_count) - def primary_push_button_checked_key_press_event_test(self): + def test_primary_push_button_checked_key_press_event(self): """ Test the keyPressEvent when the primary push button is checked """ @@ -104,7 +104,7 @@ class TestShortcutform(TestCase, TestMixin): mocked_key_release_event.assert_called_with(mocked_event) self.assertEqual(0, mocked_event.accept.call_count) - def alternate_push_button_checked_key_press_event_test(self): + def test_alternate_push_button_checked_key_press_event(self): """ Test the keyPressEvent when the alternate push button is checked """ @@ -121,7 +121,7 @@ class TestShortcutform(TestCase, TestMixin): mocked_key_release_event.assert_called_with(mocked_event) self.assertEqual(0, mocked_event.accept.call_count) - def escape_key_press_event_test(self): + def test_escape_key_press_event(self): """ Test the keyPressEvent when the escape key was pressed """ @@ -137,7 +137,7 @@ class TestShortcutform(TestCase, TestMixin): mocked_event.accept.assert_called_with() mocked_close.assert_called_with() - def on_default_radio_button_not_toggled_test(self): + def test_on_default_radio_button_not_toggled(self): """ Test that the default radio button method exits early when the button is not toggled """ @@ -150,7 +150,7 @@ class TestShortcutform(TestCase, TestMixin): # THEN: The method should exit early (i.e. the rest of the methods are not called) self.assertEqual(0, mocked_current_item_action.call_count) - def on_default_radio_button_clicked_no_action_test(self): + def test_on_default_radio_button_clicked_no_action(self): """ Test that nothing happens when an action hasn't been selected and you click the default radio button """ @@ -166,7 +166,7 @@ class TestShortcutform(TestCase, TestMixin): mocked_current_item_action.assert_called_with() self.assertEqual(0, mocked_action_shortcuts.call_count) - def on_default_radio_button_clicked_test(self): + def test_on_default_radio_button_clicked(self): """ Test that the values are copied across correctly when the default radio button is selected """ @@ -191,7 +191,7 @@ class TestShortcutform(TestCase, TestMixin): mocked_refresh_shortcut_list.assert_called_with() mocked_set_text.assert_called_with('Esc') - def on_custom_radio_button_not_toggled_test(self): + def test_on_custom_radio_button_not_toggled(self): """ Test that the custom radio button method exits early when the button is not toggled """ @@ -204,7 +204,7 @@ class TestShortcutform(TestCase, TestMixin): # THEN: The method should exit early (i.e. the rest of the methods are not called) self.assertEqual(0, mocked_current_item_action.call_count) - def on_custom_radio_button_clicked_test(self): + def test_on_custom_radio_button_clicked(self): """ Test that the values are copied across correctly when the custom radio button is selected """ diff --git a/tests/interfaces/openlp_core_ui/test_starttimedialog.py b/tests/interfaces/openlp_core_ui/test_starttimedialog.py index 17504d7d6..4e4a44240 100644 --- a/tests/interfaces/openlp_core_ui/test_starttimedialog.py +++ b/tests/interfaces/openlp_core_ui/test_starttimedialog.py @@ -51,7 +51,7 @@ class TestStartTimeDialog(TestCase, TestMixin): del self.form del self.main_window - def ui_defaults_test(self): + def test_ui_defaults(self): """ Test StartTimeDialog are defaults correct """ @@ -78,7 +78,7 @@ class TestStartTimeDialog(TestCase, TestMixin): self.assertEqual(self.form.second_finish_spin_box.maximum(), 59, 'The maximum finish second should stay the same as the dialog') - def time_display_test(self): + def test_time_display(self): """ Test StartTimeDialog display functionality """ diff --git a/tests/interfaces/openlp_core_ui/test_thememanager.py b/tests/interfaces/openlp_core_ui/test_thememanager.py index 3efa3ec97..489263024 100644 --- a/tests/interfaces/openlp_core_ui/test_thememanager.py +++ b/tests/interfaces/openlp_core_ui/test_thememanager.py @@ -50,7 +50,7 @@ class TestThemeManager(TestCase, TestMixin): self.destroy_settings() del self.theme_manager - def initialise_test(self): + def test_initialise(self): """ Test the thememanager initialise - basic test """ @@ -70,7 +70,7 @@ class TestThemeManager(TestCase, TestMixin): self.assertEqual(self.theme_manager.global_theme, 'my_theme', 'The global theme should have been set to my_theme') - def build_theme_path_test(self): + def test_build_theme_path(self): """ Test the thememanager build_theme_path - basic test """ @@ -90,7 +90,7 @@ class TestThemeManager(TestCase, TestMixin): assert self.theme_manager.thumb_path.startswith(self.theme_manager.path) is True, \ 'The thumb path and the main path should start with the same value' - def click_on_new_theme_test(self): + def test_click_on_new_theme(self): """ Test the on_add_theme event handler is called by the UI """ @@ -108,7 +108,7 @@ class TestThemeManager(TestCase, TestMixin): @patch('openlp.core.ui.themeform.ThemeForm._setup') @patch('openlp.core.ui.filerenameform.FileRenameForm._setup') - def bootstrap_post_test(self, mocked_theme_form, mocked_rename_form): + def test_bootstrap_post(self, mocked_theme_form, mocked_rename_form): """ Test the functions of bootstrap_post_setup are called. """ diff --git a/tests/interfaces/openlp_core_ui_lib/test_historycombobox.py b/tests/interfaces/openlp_core_ui_lib/test_historycombobox.py index 7aa460c8f..1429944fc 100644 --- a/tests/interfaces/openlp_core_ui_lib/test_historycombobox.py +++ b/tests/interfaces/openlp_core_ui_lib/test_historycombobox.py @@ -50,7 +50,7 @@ class TestHistoryComboBox(TestCase, TestMixin): del self.combo del self.main_window - def get_items_test(self): + def test_get_items(self): """ Test the getItems() method """ diff --git a/tests/interfaces/openlp_core_ui_lib/test_listpreviewwidget.py b/tests/interfaces/openlp_core_ui_lib/test_listpreviewwidget.py index 3e0e48e8b..7c1bfda2e 100644 --- a/tests/interfaces/openlp_core_ui_lib/test_listpreviewwidget.py +++ b/tests/interfaces/openlp_core_ui_lib/test_listpreviewwidget.py @@ -57,7 +57,7 @@ class TestListPreviewWidget(TestCase, TestMixin): del self.preview_widget del self.main_window - def initial_slide_count_test(self): + def test_initial_slide_count(self): """ Test the initial slide count . """ @@ -66,7 +66,7 @@ class TestListPreviewWidget(TestCase, TestMixin): # THEN: The count of items should be zero. self.assertEqual(self.preview_widget.slide_count(), 0, 'The slide list should be empty.') - def initial_slide_number_test(self): + def test_initial_slide_number(self): """ Test the initial current slide number. """ @@ -75,7 +75,7 @@ class TestListPreviewWidget(TestCase, TestMixin): # THEN: The number of the current item should be -1. self.assertEqual(self.preview_widget.current_slide_number(), -1, 'The slide number should be -1.') - def replace_service_item_test(self): + def test_replace_service_item(self): """ Test item counts and current number with a service item. """ @@ -90,7 +90,7 @@ class TestListPreviewWidget(TestCase, TestMixin): self.assertEqual(self.preview_widget.slide_count(), 2, 'The slide count should be 2.') self.assertEqual(self.preview_widget.current_slide_number(), 1, 'The current slide number should be 1.') - def change_slide_test(self): + def test_change_slide(self): """ Test the change_slide method. """ diff --git a/tests/interfaces/openlp_core_ul_media_vendor/test_mediainfoWrapper.py b/tests/interfaces/openlp_core_ul_media_vendor/test_mediainfoWrapper.py index acf17f581..fb7270676 100644 --- a/tests/interfaces/openlp_core_ul_media_vendor/test_mediainfoWrapper.py +++ b/tests/interfaces/openlp_core_ul_media_vendor/test_mediainfoWrapper.py @@ -35,7 +35,7 @@ TEST_MEDIA = [['avi_file.avi', 61495], ['mp3_file.mp3', 134426], ['mpg_file.mpg' class TestMediainfoWrapper(TestCase): - def media_length_test(self): + def test_media_length(self): """ Test the Media Info basic functionality """ diff --git a/tests/interfaces/openlp_plugins/bibles/forms/test_bibleimportform.py b/tests/interfaces/openlp_plugins/bibles/forms/test_bibleimportform.py index 25dcb9d45..2df715836 100644 --- a/tests/interfaces/openlp_plugins/bibles/forms/test_bibleimportform.py +++ b/tests/interfaces/openlp_plugins/bibles/forms/test_bibleimportform.py @@ -59,7 +59,7 @@ class TestBibleImportForm(TestCase, TestMixin): @patch('openlp.plugins.bibles.forms.bibleimportform.CWExtract.get_bibles_from_http') @patch('openlp.plugins.bibles.forms.bibleimportform.BGExtract.get_bibles_from_http') @patch('openlp.plugins.bibles.forms.bibleimportform.BSExtract.get_bibles_from_http') - def on_web_update_button_clicked_test(self, mocked_bsextract, mocked_bgextract, mocked_cwextract): + def test_on_web_update_button_clicked(self, mocked_bsextract, mocked_bgextract, mocked_cwextract): """ Test that on_web_update_button_clicked handles problems correctly """ @@ -78,7 +78,7 @@ class TestBibleImportForm(TestCase, TestMixin): # THEN: The webbible list should still be empty self.assertEqual(self.form.web_bible_list, {}, 'The webbible list should be empty') - def custom_init_test(self): + def test_custom_init(self): """ Test that custom_init works as expected if pysword is unavailable """ diff --git a/tests/interfaces/openlp_plugins/bibles/test_lib_http.py b/tests/interfaces/openlp_plugins/bibles/test_lib_http.py index 5d73d01e8..4a7fb4af3 100644 --- a/tests/interfaces/openlp_plugins/bibles/test_lib_http.py +++ b/tests/interfaces/openlp_plugins/bibles/test_lib_http.py @@ -39,7 +39,7 @@ class TestBibleHTTP(TestCase): Registry().register('service_list', MagicMock()) Registry().register('application', MagicMock()) - def bible_gateway_extract_books_test(self): + def test_bible_gateway_extract_books(self): """ Test the Bible Gateway retrieval of book list for NIV bible """ @@ -52,7 +52,7 @@ class TestBibleHTTP(TestCase): # THEN: We should get back a valid service item assert len(books) == 66, 'The bible should not have had any books added or removed' - def bible_gateway_extract_books_support_redirect_test(self): + def test_bible_gateway_extract_books_support_redirect(self): """ Test the Bible Gateway retrieval of book list for DN1933 bible with redirect (bug 1251437) """ @@ -65,7 +65,7 @@ class TestBibleHTTP(TestCase): # THEN: We should get back a valid service item assert len(books) == 66, 'This bible should have 66 books' - def bible_gateway_extract_verse_test(self): + def test_bible_gateway_extract_verse(self): """ Test the Bible Gateway retrieval of verse list for NIV bible John 3 """ @@ -78,7 +78,7 @@ class TestBibleHTTP(TestCase): # THEN: We should get back a valid service item assert len(results.verse_list) == 36, 'The book of John should not have had any verses added or removed' - def bible_gateway_extract_verse_nkjv_test(self): + def test_bible_gateway_extract_verse_nkjv(self): """ Test the Bible Gateway retrieval of verse list for NKJV bible John 3 """ @@ -91,7 +91,7 @@ class TestBibleHTTP(TestCase): # THEN: We should get back a valid service item assert len(results.verse_list) == 36, 'The book of John should not have had any verses added or removed' - def crosswalk_extract_books_test(self): + def test_crosswalk_extract_books(self): """ Test Crosswalk retrieval of book list for NIV bible """ @@ -104,7 +104,7 @@ class TestBibleHTTP(TestCase): # THEN: We should get back a valid service item assert len(books) == 66, 'The bible should not have had any books added or removed' - def crosswalk_extract_verse_test(self): + def test_crosswalk_extract_verse(self): """ Test Crosswalk retrieval of verse list for NIV bible John 3 """ @@ -117,7 +117,7 @@ class TestBibleHTTP(TestCase): # THEN: We should get back a valid service item assert len(results.verse_list) == 36, 'The book of John should not have had any verses added or removed' - def bibleserver_get_bibles_test(self): + def test_bibleserver_get_bibles(self): """ Test getting list of bibles from BibleServer.com """ @@ -132,7 +132,7 @@ class TestBibleHTTP(TestCase): self.assertIn(('New Int. Readers Version', 'NIRV', 'en'), bibles) self.assertIn(('Священное Писание, Восточный перевод', 'CARS', 'ru'), bibles) - def biblegateway_get_bibles_test(self): + def test_biblegateway_get_bibles(self): """ Test getting list of bibles from BibleGateway.com """ @@ -147,7 +147,7 @@ class TestBibleHTTP(TestCase): self.assertIn(('Holman Christian Standard Bible', 'HCSB', 'en'), bibles) @skip("Waiting for Crosswalk to fix their server") - def crosswalk_get_bibles_test(self): + def test_crosswalk_get_bibles(self): """ Test getting list of bibles from Crosswalk.com """ diff --git a/tests/interfaces/openlp_plugins/bibles/test_lib_manager.py b/tests/interfaces/openlp_plugins/bibles/test_lib_manager.py index 38f0a3518..44efbe7fc 100644 --- a/tests/interfaces/openlp_plugins/bibles/test_lib_manager.py +++ b/tests/interfaces/openlp_plugins/bibles/test_lib_manager.py @@ -69,7 +69,7 @@ class TestBibleManager(TestCase, TestMixin): del self.manager self.destroy_settings() - def get_books_test(self): + def test_get_books(self): """ Test the get_books method """ @@ -79,7 +79,7 @@ class TestBibleManager(TestCase, TestMixin): # THEN a list of books should be returned self.assertEqual(66, len(books), 'There should be 66 books in the bible') - def get_book_by_id_test(self): + def test_get_book_by_id(self): """ Test the get_book_by_id method """ @@ -89,7 +89,7 @@ class TestBibleManager(TestCase, TestMixin): # THEN a book should be returned self.assertEqual('1 Timothy', book.name, '1 Timothy should have been returned from the bible') - def get_chapter_count_test(self): + def test_get_chapter_count(self): """ Test the get_chapter_count method """ @@ -100,7 +100,7 @@ class TestBibleManager(TestCase, TestMixin): # THEN the chapter count should be returned self.assertEqual(6, chapter, '1 Timothy should have 6 chapters returned from the bible') - def get_verse_count_by_book_ref_id_test(self): + def test_get_verse_count_by_book_ref_id(self): """ Test the get_verse_count_by_book_ref_id method """ diff --git a/tests/interfaces/openlp_plugins/bibles/test_lib_parse_reference.py b/tests/interfaces/openlp_plugins/bibles/test_lib_parse_reference.py index 08458847e..f1e26c000 100644 --- a/tests/interfaces/openlp_plugins/bibles/test_lib_parse_reference.py +++ b/tests/interfaces/openlp_plugins/bibles/test_lib_parse_reference.py @@ -69,7 +69,7 @@ class TestBibleManager(TestCase, TestMixin): del self.manager self.destroy_settings() - def parse_reference_one_test(self): + def test_parse_reference_one(self): """ Test the parse_reference method with 1 Timothy 1 """ @@ -79,7 +79,7 @@ class TestBibleManager(TestCase, TestMixin): # THEN a verse array should be returned self.assertEqual([(54, 1, 1, -1)], results, "The bible verses should matches the expected results") - def parse_reference_two_test(self): + def test_parse_reference_two(self): """ Test the parse_reference method with 1 Timothy 1:1-2 """ @@ -89,7 +89,7 @@ class TestBibleManager(TestCase, TestMixin): # THEN a verse array should be returned self.assertEqual([(54, 1, 1, 2)], results, "The bible verses should matches the expected results") - def parse_reference_three_test(self): + def test_parse_reference_three(self): """ Test the parse_reference method with 1 Timothy 1:1-2 """ @@ -100,7 +100,7 @@ class TestBibleManager(TestCase, TestMixin): self.assertEqual([(54, 1, 1, -1), (54, 2, 1, 1)], results, "The bible verses should match the expected results") - def parse_reference_four_test(self): + def test_parse_reference_four(self): """ Test the parse_reference method with non existence book """ @@ -110,7 +110,7 @@ class TestBibleManager(TestCase, TestMixin): # THEN a verse array should be returned self.assertEqual(False, results, "The bible Search should return False") - def parse_reference_five_test(self): + def test_parse_reference_five(self): """ Test the parse_reference method with 1 Timothy 1:3-end """ diff --git a/tests/interfaces/openlp_plugins/custom/forms/test_customform.py b/tests/interfaces/openlp_plugins/custom/forms/test_customform.py index 333f03896..fc551c1ce 100644 --- a/tests/interfaces/openlp_plugins/custom/forms/test_customform.py +++ b/tests/interfaces/openlp_plugins/custom/forms/test_customform.py @@ -57,7 +57,7 @@ class TestEditCustomForm(TestCase, TestMixin): del self.form del self.main_window - def load_themes_test(self): + def test_load_themes(self): """ Test the load_themes() method. """ @@ -70,7 +70,7 @@ class TestEditCustomForm(TestCase, TestMixin): # THEN: There should be three items in the combo box. assert self.form.theme_combo_box.count() == 3, 'There should be three items (themes) in the combo box.' - def load_custom_test(self): + def test_load_custom(self): """ Test the load_custom() method. """ @@ -81,7 +81,7 @@ class TestEditCustomForm(TestCase, TestMixin): self.assertEqual(self.form.title_edit.text(), '', 'The title edit should be empty') self.assertEqual(self.form.credit_edit.text(), '', 'The credit edit should be empty') - def on_add_button_clicked_test(self): + def test_on_add_button_clicked(self): """ Test the on_add_button_clicked_test method / add_button button. """ @@ -93,7 +93,7 @@ class TestEditCustomForm(TestCase, TestMixin): # THEN: One slide should be added. assert self.form.slide_list_view.count() == 1, 'There should be one slide added.' - def validate_not_valid_part1_test(self): + def test_validate_not_valid_part1(self): """ Test the _validate() method. """ @@ -112,7 +112,7 @@ class TestEditCustomForm(TestCase, TestMixin): mocked_setFocus.assert_called_with() mocked_critical_error_message_box.assert_called_with(message='You need to type in a title.') - def validate_not_valid_part2_test(self): + def test_validate_not_valid_part2(self): """ Test the _validate() method. """ @@ -129,7 +129,7 @@ class TestEditCustomForm(TestCase, TestMixin): assert not result, 'The _validate() method should have retured False' mocked_critical_error_message_box.assert_called_with(message='You need to add at least one slide.') - def update_slide_list_test(self): + def test_update_slide_list(self): """ Test the update_slide_list() method """ diff --git a/tests/interfaces/openlp_plugins/custom/forms/test_customslideform.py b/tests/interfaces/openlp_plugins/custom/forms/test_customslideform.py index 2a497a912..978e33d0b 100644 --- a/tests/interfaces/openlp_plugins/custom/forms/test_customslideform.py +++ b/tests/interfaces/openlp_plugins/custom/forms/test_customslideform.py @@ -53,7 +53,7 @@ class TestEditCustomSlideForm(TestCase, TestMixin): del self.form del self.main_window - def basic_test(self): + def test_basic(self): """ Test if the dialog is correctly set up. """ @@ -65,7 +65,7 @@ class TestEditCustomSlideForm(TestCase, TestMixin): # THEN: The dialog should be empty. assert self.form.slide_text_edit.toPlainText() == '', 'There should not be any text in the text editor.' - def set_text_test(self): + def test_set_text(self): """ Test the set_text() method. """ diff --git a/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py b/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py index 36c1324de..34ef4c7da 100644 --- a/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py +++ b/tests/interfaces/openlp_plugins/media/forms/test_mediaclipselectorform.py @@ -73,7 +73,7 @@ class TestMediaClipSelectorForm(TestCase, TestMixin): self.vlc_patcher.stop() del self.main_window - def basic_test(self): + def test_basic(self): """ Test if the dialog is correctly set up. """ @@ -85,7 +85,7 @@ class TestMediaClipSelectorForm(TestCase, TestMixin): # THEN: The media path should be empty. assert self.form.media_path_combobox.currentText() == '', 'There should not be any text in the media path.' - def click_load_button_test(self): + def test_click_load_button(self): """ Test that the correct function is called when load is clicked, and that it behaves as expected. """ @@ -126,7 +126,7 @@ class TestMediaClipSelectorForm(TestCase, TestMixin): 'The media path should be the given one.' mocked_critical_error_message_box.assert_called_with(message='VLC player failed playing the media') - def title_combobox_test(self): + def test_title_combobox(self): """ Test the behavior when the title combobox is updated """ @@ -153,7 +153,7 @@ class TestMediaClipSelectorForm(TestCase, TestMixin): self.form.audio_tracks_combobox.itemData.assert_any_call(1) self.form.subtitle_tracks_combobox.itemData.assert_any_call(0) - def click_save_button_test(self): + def test_click_save_button(self): """ Test that the correct function is called when save is clicked, and that it behaves as expected. """ diff --git a/tests/interfaces/openlp_plugins/songs/forms/test_authorsform.py b/tests/interfaces/openlp_plugins/songs/forms/test_authorsform.py index 433e259ee..15365e8aa 100644 --- a/tests/interfaces/openlp_plugins/songs/forms/test_authorsform.py +++ b/tests/interfaces/openlp_plugins/songs/forms/test_authorsform.py @@ -53,7 +53,7 @@ class TestAuthorsForm(TestCase, TestMixin): del self.form del self.main_window - def ui_defaults_test(self): + def test_ui_defaults(self): """ Test the AuthorForm defaults are correct """ @@ -61,7 +61,7 @@ class TestAuthorsForm(TestCase, TestMixin): self.assertEqual(self.form.last_name_edit.text(), '', 'The last name edit should be empty') self.assertEqual(self.form.display_edit.text(), '', 'The display name edit should be empty') - def get_first_name_property_test(self): + def test_get_first_name_property(self): """ Test that getting the first name property on the AuthorForm works correctly """ @@ -74,7 +74,7 @@ class TestAuthorsForm(TestCase, TestMixin): # THEN: The first_name property should have the correct value self.assertEqual(self.form.first_name, first_name, 'The first name property should be correct') - def set_first_name_property_test(self): + def test_set_first_name_property(self): """ Test that setting the first name property on the AuthorForm works correctly """ @@ -87,7 +87,7 @@ class TestAuthorsForm(TestCase, TestMixin): # THEN: The first_name_edit should have the correct value self.assertEqual(self.form.first_name_edit.text(), first_name, 'The first name should be set correctly') - def get_last_name_property_test(self): + def test_get_last_name_property(self): """ Test that getting the last name property on the AuthorForm works correctly """ @@ -100,7 +100,7 @@ class TestAuthorsForm(TestCase, TestMixin): # THEN: The last_name property should have the correct value self.assertEqual(self.form.last_name, last_name, 'The last name property should be correct') - def set_last_name_property_test(self): + def test_set_last_name_property(self): """ Test that setting the last name property on the AuthorForm works correctly """ @@ -113,7 +113,7 @@ class TestAuthorsForm(TestCase, TestMixin): # THEN: The last_name_edit should have the correct value self.assertEqual(self.form.last_name_edit.text(), last_name, 'The last name should be set correctly') - def get_display_name_property_test(self): + def test_get_display_name_property(self): """ Test that getting the display name property on the AuthorForm works correctly """ @@ -126,7 +126,7 @@ class TestAuthorsForm(TestCase, TestMixin): # THEN: The display_name property should have the correct value self.assertEqual(self.form.display_name, display_name, 'The display name property should be correct') - def set_display_name_property_test(self): + def test_set_display_name_property(self): """ Test that setting the display name property on the AuthorForm works correctly """ diff --git a/tests/interfaces/openlp_plugins/songs/forms/test_editsongform.py b/tests/interfaces/openlp_plugins/songs/forms/test_editsongform.py index bb26533ee..3ea957a5e 100644 --- a/tests/interfaces/openlp_plugins/songs/forms/test_editsongform.py +++ b/tests/interfaces/openlp_plugins/songs/forms/test_editsongform.py @@ -56,7 +56,7 @@ class TestEditSongForm(TestCase, TestMixin): del self.form del self.main_window - def ui_defaults_test(self): + def test_ui_defaults(self): """ Test that the EditSongForm defaults are correct """ @@ -65,10 +65,10 @@ class TestEditSongForm(TestCase, TestMixin): self.assertFalse(self.form.author_remove_button.isEnabled(), 'The author remove button should not be enabled') self.assertFalse(self.form.topic_remove_button.isEnabled(), 'The topic remove button should not be enabled') - def is_verse_edit_form_executed_test(self): + def test_is_verse_edit_form_executed(self): pass - def verse_order_no_warning_test(self): + def test_verse_order_no_warning(self): """ Test if the verse order warning is not shown """ @@ -89,7 +89,7 @@ class TestEditSongForm(TestCase, TestMixin): # THEN: No text should be shown. assert self.form.warning_label.text() == '', 'There should be no warning.' - def verse_order_incomplete_warning_test(self): + def test_verse_order_incomplete_warning(self): """ Test if the verse-order-incomple warning is shown """ @@ -111,7 +111,7 @@ class TestEditSongForm(TestCase, TestMixin): assert self.form.warning_label.text() == self.form.not_all_verses_used_warning, \ 'The verse-order-incomplete warning should be shown.' - def bug_1170435_test(self): + def test_bug_1170435(self): """ Regression test for bug 1170435 (test if "no verse order" message is shown) """ @@ -131,7 +131,7 @@ class TestEditSongForm(TestCase, TestMixin): assert self.form.warning_label.text() == self.form.no_verse_order_entered_warning, \ 'The no-verse-order message should be shown.' - def bug_1404967_test(self): + def test_bug_1404967(self): """ Test for CCLI label showing correct text """ @@ -143,7 +143,7 @@ class TestEditSongForm(TestCase, TestMixin): self.assertEquals(form.ccli_label.text(), UiStrings().CCLISongNumberLabel, 'CCLI label text should be "{}"'.format(UiStrings().CCLISongNumberLabel)) - def verse_order_lowercase_test(self): + def test_verse_order_lowercase(self): """ Test that entering a verse order in lowercase automatically converts to uppercase """ diff --git a/tests/interfaces/openlp_plugins/songs/forms/test_editverseform.py b/tests/interfaces/openlp_plugins/songs/forms/test_editverseform.py index bcdc794b2..c4855993f 100644 --- a/tests/interfaces/openlp_plugins/songs/forms/test_editverseform.py +++ b/tests/interfaces/openlp_plugins/songs/forms/test_editverseform.py @@ -53,7 +53,7 @@ class TestEditVerseForm(TestCase, TestMixin): del self.form del self.main_window - def ui_defaults_test(self): + def test_ui_defaults(self): """ Test the EditVerseForm defaults are correct """ @@ -76,7 +76,7 @@ class TestEditVerseForm(TestCase, TestMixin): self.assertEqual(text, self.form.verse_text_edit.toPlainText(), 'The verse text edit should have the typed out verse') - def insert_verse_test(self): + def test_insert_verse(self): """ Test that clicking the insert button inserts the correct verse marker """ @@ -88,7 +88,7 @@ class TestEditVerseForm(TestCase, TestMixin): self.assertIn('---[Verse:1]---', self.form.verse_text_edit.toPlainText(), 'The verse text edit should have a verse marker') - def insert_verse_2_test(self): + def test_insert_verse_2(self): """ Test that clicking the up button on the spin box and then clicking the insert button inserts the correct marker """ @@ -101,7 +101,7 @@ class TestEditVerseForm(TestCase, TestMixin): self.assertIn('---[Verse:2]---', self.form.verse_text_edit.toPlainText(), 'The verse text edit should have a "Verse 2" marker') - def insert_chorus_test(self): + def test_insert_chorus(self): """ Test that clicking the verse type combo box and then clicking the insert button inserts the correct marker """ diff --git a/tests/interfaces/openlp_plugins/songs/forms/test_topicsform.py b/tests/interfaces/openlp_plugins/songs/forms/test_topicsform.py index 7c6f23d67..00ca9e72d 100644 --- a/tests/interfaces/openlp_plugins/songs/forms/test_topicsform.py +++ b/tests/interfaces/openlp_plugins/songs/forms/test_topicsform.py @@ -53,13 +53,13 @@ class TestTopicsForm(TestCase, TestMixin): del self.form del self.main_window - def ui_defaults_test(self): + def test_ui_defaults(self): """ Test the TopicsForm defaults are correct """ self.assertEqual(self.form.name_edit.text(), '', 'The first name edit should be empty') - def get_name_property_test(self): + def test_get_name_property(self): """ Test that getting the name property on the TopicsForm works correctly """ @@ -72,7 +72,7 @@ class TestTopicsForm(TestCase, TestMixin): # THEN: The name property should have the correct value self.assertEqual(self.form.name, topic_name, 'The name property should be correct') - def set_name_property_test(self): + def test_set_name_property(self): """ Test that setting the name property on the TopicsForm works correctly """ diff --git a/tests/utils/test_bzr_tags.py b/tests/utils/test_bzr_tags.py index 95d2d8575..af6f8090a 100644 --- a/tests/utils/test_bzr_tags.py +++ b/tests/utils/test_bzr_tags.py @@ -34,7 +34,7 @@ TAGS1 = {'1.9.0', '1.9.1', '1.9.2', '1.9.3', '1.9.4', '1.9.5', '1.9.6', '1.9.7', class TestBzrTags(TestCase): - def bzr_tags_test(self): + def test_bzr_tags(self): """ Test for proper bzr tags """ From 3627976132811a105f4add030d6cb2c850816d77 Mon Sep 17 00:00:00 2001 From: Ian Knight Date: Wed, 1 Jun 2016 13:51:44 +0930 Subject: [PATCH 29/62] fixed pep8 error --- tests/functional/openlp_core_common/test_registryproperties.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/functional/openlp_core_common/test_registryproperties.py b/tests/functional/openlp_core_common/test_registryproperties.py index 0f0184876..3f57913e2 100644 --- a/tests/functional/openlp_core_common/test_registryproperties.py +++ b/tests/functional/openlp_core_common/test_registryproperties.py @@ -75,4 +75,3 @@ class TestRegistryProperties(TestCase, RegistryProperties): # THEN the application should be none self.assertEqual(self.application, application, 'The application value should match') - From caeb3d3ff79c6a131e2a337fd599dac52f264413 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Wed, 1 Jun 2016 23:42:54 +0200 Subject: [PATCH 30/62] Found the other tests, Mom! --- .../openlp_core_ui/test_servicemanager.py | 10 +++++----- .../openlp_core_ui/test_slidecontroller.py | 8 ++++---- .../test_listpreviewwidget.py | 20 +++++++++---------- .../openlp_plugins/songs/test_opsproimport.py | 2 +- .../openlp_core_ui/test_settings_form.py | 6 +++--- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/tests/functional/openlp_core_ui/test_servicemanager.py b/tests/functional/openlp_core_ui/test_servicemanager.py index 3c6c20ab5..7882d8a24 100644 --- a/tests/functional/openlp_core_ui/test_servicemanager.py +++ b/tests/functional/openlp_core_ui/test_servicemanager.py @@ -544,7 +544,7 @@ class TestServiceManager(TestCase): @patch(u'openlp.core.ui.servicemanager.Settings') @patch(u'PyQt5.QtCore.QTimer.singleShot') - def single_click_preview_test_true(self, mocked_singleShot, MockedSettings): + def test_single_click_preview_true(self, mocked_singleShot, MockedSettings): """ Test that when "Preview items when clicked in Service Manager" enabled the preview timer starts """ @@ -561,7 +561,7 @@ class TestServiceManager(TestCase): @patch(u'openlp.core.ui.servicemanager.Settings') @patch(u'PyQt5.QtCore.QTimer.singleShot') - def single_click_preview_test_false(self, mocked_singleShot, MockedSettings): + def test_single_click_preview_false(self, mocked_singleShot, MockedSettings): """ Test that when "Preview items when clicked in Service Manager" disabled the preview timer doesn't start """ @@ -578,7 +578,7 @@ class TestServiceManager(TestCase): @patch(u'openlp.core.ui.servicemanager.Settings') @patch(u'PyQt5.QtCore.QTimer.singleShot') @patch(u'openlp.core.ui.servicemanager.ServiceManager.make_live') - def single_click_preview_test_double(self, mocked_make_live, mocked_singleShot, MockedSettings): + def test_single_click_preview_double(self, mocked_make_live, mocked_singleShot, MockedSettings): """ Test that when a double click has registered the preview timer doesn't start """ @@ -594,7 +594,7 @@ class TestServiceManager(TestCase): self.assertEquals(mocked_singleShot.call_count, 0, 'Should not be called') @patch(u'openlp.core.ui.servicemanager.ServiceManager.make_preview') - def single_click_timeout_test_single(self, mocked_make_preview): + def test_single_click_timeout_single(self, mocked_make_preview): """ Test that when a single click has been registered, the item is sent to preview """ @@ -607,7 +607,7 @@ class TestServiceManager(TestCase): @patch(u'openlp.core.ui.servicemanager.ServiceManager.make_preview') @patch(u'openlp.core.ui.servicemanager.ServiceManager.make_live') - def single_click_timeout_test_double(self, mocked_make_live, mocked_make_preview): + def test_single_click_timeout_double(self, mocked_make_live, mocked_make_preview): """ Test that when a double click has been registered, the item does not goes to preview """ diff --git a/tests/functional/openlp_core_ui/test_slidecontroller.py b/tests/functional/openlp_core_ui/test_slidecontroller.py index 3777d5f82..126e67d1f 100644 --- a/tests/functional/openlp_core_ui/test_slidecontroller.py +++ b/tests/functional/openlp_core_ui/test_slidecontroller.py @@ -715,7 +715,7 @@ class TestSlideController(TestCase): @patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager') @patch(u'PyQt5.QtCore.QTimer.singleShot') - def update_preview_test_live(self, mocked_singleShot, mocked_image_manager): + def test_update_preview_live(self, mocked_singleShot, mocked_image_manager): """ Test that the preview screen is updated with a screen grab for live service items """ @@ -758,7 +758,7 @@ class TestSlideController(TestCase): @patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager') @patch(u'PyQt5.QtCore.QTimer.singleShot') - def update_preview_test_pres(self, mocked_singleShot, mocked_image_manager): + def test_update_preview_pres(self, mocked_singleShot, mocked_image_manager): """ Test that the preview screen is updated with the correct preview for presentation service items """ @@ -800,7 +800,7 @@ class TestSlideController(TestCase): @patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager') @patch(u'PyQt5.QtCore.QTimer.singleShot') - def update_preview_test_media(self, mocked_singleShot, mocked_image_manager): + def test_update_preview_media(self, mocked_singleShot, mocked_image_manager): """ Test that the preview screen is updated with the correct preview for media service items """ @@ -842,7 +842,7 @@ class TestSlideController(TestCase): @patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager') @patch(u'PyQt5.QtCore.QTimer.singleShot') - def update_preview_test_image(self, mocked_singleShot, mocked_image_manager): + def test_update_preview_image(self, mocked_singleShot, mocked_image_manager): """ Test that the preview screen is updated with the correct preview for image service items """ diff --git a/tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py b/tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py index 9ccd56a32..45c68219b 100644 --- a/tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py +++ b/tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py @@ -77,7 +77,7 @@ class TestListPreviewWidget(TestCase): @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.image_manager') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight') - def replace_service_item_test_thumbs(self, mocked_setRowHeight, mocked_resizeRowsToContents, + def test_replace_service_item_thumbs(self, mocked_setRowHeight, mocked_resizeRowsToContents, mocked_image_manager): """ Test that thubmails for different slides are loaded properly in replace_service_item. @@ -123,7 +123,7 @@ class TestListPreviewWidget(TestCase): @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight') - def replace_recalculate_layout_test_text(self, mocked_setRowHeight, mocked_resizeRowsToContents): + def test_replace_recalculate_layout_text(self, mocked_setRowHeight, mocked_resizeRowsToContents): """ Test if "Max height for non-text slides..." enabled, txt slides unchanged in replace_service_item & __recalc... """ @@ -155,7 +155,7 @@ class TestListPreviewWidget(TestCase): @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight') - def replace_recalculate_layout_test_img(self, mocked_setRowHeight, mocked_resizeRowsToContents): + def test_replace_recalculate_layout_img(self, mocked_setRowHeight, mocked_resizeRowsToContents): """ Test if "Max height for non-text slides..." disabled, img slides unchanged in replace_service_item & __recalc... """ @@ -192,7 +192,7 @@ class TestListPreviewWidget(TestCase): @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight') - def replace_recalculate_layout_test_img_max(self, mocked_setRowHeight, mocked_resizeRowsToContents): + def test_replace_recalculate_layout_img_max(self, mocked_setRowHeight, mocked_resizeRowsToContents): """ Test if "Max height for non-text slides..." enabled, img slides resized in replace_service_item & __recalc... """ @@ -228,7 +228,7 @@ class TestListPreviewWidget(TestCase): @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.cellWidget') - def row_resized_test_text(self, mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents): + def test_row_resized_text(self, mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents): """ Test if "Max height for non-text slides..." enabled, text-based slides not affected in row_resized. """ @@ -262,7 +262,7 @@ class TestListPreviewWidget(TestCase): @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.cellWidget') - def row_resized_test_img(self, mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents): + def test_row_resized_img(self, mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents): """ Test if "Max height for non-text slides..." disabled, image-based slides not affected in row_resized. """ @@ -299,7 +299,7 @@ class TestListPreviewWidget(TestCase): @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.cellWidget') - def row_resized_test_img_max(self, mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents): + def test_row_resized_img_max(self, mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents): """ Test if "Max height for non-text slides..." enabled, image-based slides are scaled in row_resized. """ @@ -335,7 +335,7 @@ class TestListPreviewWidget(TestCase): @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.scrollToItem') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.item') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.slide_count') - def autoscroll_test_setting_invalid(self, mocked_slide_count, mocked_item, mocked_scrollToItem, mocked_selectRow): + def test_autoscroll_setting_invalid(self, mocked_slide_count, mocked_item, mocked_scrollToItem, mocked_selectRow): """ Test if 'advanced/autoscrolling' setting None or invalid, that no autoscrolling occurs on change_slide(). """ @@ -371,7 +371,7 @@ class TestListPreviewWidget(TestCase): @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.scrollToItem') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.item') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.slide_count') - def autoscroll_test_dist_bounds(self, mocked_slide_count, mocked_item, mocked_scrollToItem, mocked_selectRow): + def test_autoscroll_dist_bounds(self, mocked_slide_count, mocked_item, mocked_scrollToItem, mocked_selectRow): """ Test if 'advanced/autoscrolling' setting asks to scroll beyond list bounds, that it does not beyond. """ @@ -401,7 +401,7 @@ class TestListPreviewWidget(TestCase): @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.scrollToItem') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.item') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.slide_count') - def autoscroll_test_normal(self, mocked_slide_count, mocked_item, mocked_scrollToItem, mocked_selectRow): + def test_autoscroll_normal(self, mocked_slide_count, mocked_item, mocked_scrollToItem, mocked_selectRow): """ Test if 'advanced/autoscrolling' setting valid, autoscrolling called as expected. """ diff --git a/tests/functional/openlp_plugins/songs/test_opsproimport.py b/tests/functional/openlp_plugins/songs/test_opsproimport.py index ad4afee0e..37174baa2 100644 --- a/tests/functional/openlp_plugins/songs/test_opsproimport.py +++ b/tests/functional/openlp_plugins/songs/test_opsproimport.py @@ -148,7 +148,7 @@ class TestOpsProSongImport(TestCase): return data[key] return '' - def _build_test_data(self, test_file, dual_language): + def test__build_data(self, test_file, dual_language): song = MagicMock() song.ID = 100 song.SongNumber = 123 diff --git a/tests/interfaces/openlp_core_ui/test_settings_form.py b/tests/interfaces/openlp_core_ui/test_settings_form.py index 9c95ac6f6..0d334f24f 100644 --- a/tests/interfaces/openlp_core_ui/test_settings_form.py +++ b/tests/interfaces/openlp_core_ui/test_settings_form.py @@ -134,7 +134,7 @@ class TestSettingsForm(TestCase, TestMixin): # THEN the processing stack should still have two items assert len(self.form.processes) == 2, 'No new processes should have been added to the stack' - def register_image_manager_trigger_test_one(self): + def test_register_image_manager_trigger_one(self): """ Test the triggering of the image manager rebuild event from image background change """ @@ -152,7 +152,7 @@ class TestSettingsForm(TestCase, TestMixin): assert self.dummy2.call_count == 0, 'dummy2 should not have been called at all' assert self.dummy3.call_count == 1, 'dummy3 should have been called once' - def register_image_manager_trigger_test_two(self): + def test_register_image_manager_trigger_two(self): """ Test the triggering of the image manager rebuild event from screen dimension change """ @@ -170,7 +170,7 @@ class TestSettingsForm(TestCase, TestMixin): assert self.dummy2.call_count == 1, 'dummy2 should have been called once' assert self.dummy3.call_count == 1, 'dummy3 should have been called once' - def register_image_manager_trigger_test_three(self): + def test_register_image_manager_trigger_three(self): """ Test the triggering of the image manager rebuild event from image background change and a change to the screen dimension. From ec8ace49290a2698f4febcd42bdb5044a6b1cbea Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Thu, 2 Jun 2016 01:14:58 +0200 Subject: [PATCH 31/62] Fixed up some issues and refactored a method that wasn't actually a test. --- .../openlp_plugins/bibles/test_lib.py | 29 ++++---- .../openlp_plugins/songs/test_opsproimport.py | 73 +++++++++++-------- .../songs/forms/test_editverseform.py | 2 +- 3 files changed, 58 insertions(+), 46 deletions(-) diff --git a/tests/functional/openlp_plugins/bibles/test_lib.py b/tests/functional/openlp_plugins/bibles/test_lib.py index 6726da6a9..a8dba0bd9 100644 --- a/tests/functional/openlp_plugins/bibles/test_lib.py +++ b/tests/functional/openlp_plugins/bibles/test_lib.py @@ -26,35 +26,38 @@ from unittest import TestCase from openlp.plugins.bibles import lib from openlp.plugins.bibles.lib import SearchResults -from tests.functional import MagicMock, patch +from tests.functional import patch class TestLib(TestCase): """ Test the functions in the :mod:`lib` module. """ - def test_get_reference_separator(self): + @patch('openlp.plugins.bibles.lib.update_reference_separators') + def test_get_reference_separator(self, mocked_update_reference_separators): """ Test the get_reference_separator method """ - # GIVEN: A list of expected separators + # GIVEN: A list of expected separators and the lib module's constant is empty + lib.REFERENCE_SEPARATORS = None separators = {'sep_r': '\\s*(?:e)\\s*', 'sep_e_default': 'end', 'sep_v_display': 'w', 'sep_l_display': 'r', 'sep_v_default': ':|v|V|verse|verses', 'sep_l': '\\s*(?:r)\\s*', 'sep_l_default': ',|and', 'sep_e': '\\s*(?:t)\\s*', 'sep_v': '\\s*(?:w)\\s*', 'sep_r_display': 'e', 'sep_r_default': '-|to'} - - def side_effect(): + def _update_side_effect(): + """ + Update the references after mocking out the method + """ lib.REFERENCE_SEPARATORS = separators - with patch('openlp.plugins.bibles.lib.update_reference_separators', - **{'side_effect': side_effect}) as mocked_update_reference_separators: + mocked_update_reference_separators.side_effect = _update_side_effect - # WHEN: Calling get_reference_separator - for key, value in separators.items(): - ret = lib.get_reference_separator(key) + # WHEN: Calling get_reference_separator + for key, value in separators.items(): + _ = lib.get_reference_separator(key) - # THEN: get_reference_separator should return the correct separator - self.assertEqual(separators[key], value) - mocked_update_reference_separators.assert_called_once_with() + # THEN: get_reference_separator should return the correct separator + self.assertEqual(separators[key], value) + mocked_update_reference_separators.assert_called_once_with() def test_search_results_creation(self): """ diff --git a/tests/functional/openlp_plugins/songs/test_opsproimport.py b/tests/functional/openlp_plugins/songs/test_opsproimport.py index 37174baa2..239b77c30 100644 --- a/tests/functional/openlp_plugins/songs/test_opsproimport.py +++ b/tests/functional/openlp_plugins/songs/test_opsproimport.py @@ -38,6 +38,35 @@ from tests.functional import patch, MagicMock TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'opsprosongs')) +def _get_item(data, key): + """ + Get an item or return a blank string + """ + if key in data: + return data[key] + return '' + + +def _build_data(test_file, dual_language): + """ + Build the test data + """ + song = MagicMock() + song.ID = 100 + song.SongNumber = 123 + song.SongBookName = 'The Song Book' + song.Title = 'Song Title' + song.CopyrightText = 'Music and text by me' + song.Version = '1' + song.Origin = '...' + lyrics = MagicMock() + test_file = open(os.path.join(TEST_PATH, test_file), 'rb') + lyrics.Lyrics = test_file.read().decode() + lyrics.Type = 1 + lyrics.IsDualLanguage = dual_language + return song, lyrics + + @skipUnless(CAN_RUN_TESTS, 'Not Windows, skipping test') class TestOpsProSongImport(TestCase): """ @@ -72,7 +101,7 @@ class TestOpsProSongImport(TestCase): mocked_manager = MagicMock() importer = OPSProImport(mocked_manager, filenames=[]) importer.finish = MagicMock() - song, lyrics = self._build_test_data('you are so faithfull.txt', False) + song, lyrics = _build_data('you are so faithfull.txt', False) # WHEN: An importer object is created importer.process_song(song, lyrics, []) @@ -80,8 +109,8 @@ class TestOpsProSongImport(TestCase): # THEN: The imported data should look like expected result_file = open(os.path.join(TEST_PATH, 'You are so faithful.json'), 'rb') result_data = json.loads(result_file.read().decode()) - self.assertListEqual(importer.verses, self._get_data(result_data, 'verses')) - self.assertListEqual(importer.verse_order_list_generated, self._get_data(result_data, 'verse_order_list')) + self.assertListEqual(importer.verses, _get_item(result_data, 'verses')) + self.assertListEqual(importer.verse_order_list_generated, _get_item(result_data, 'verse_order_list')) @patch('openlp.plugins.songs.lib.importers.opspro.SongImport') def test_join_and_split(self, mocked_songimport): @@ -92,7 +121,7 @@ class TestOpsProSongImport(TestCase): mocked_manager = MagicMock() importer = OPSProImport(mocked_manager, filenames=[]) importer.finish = MagicMock() - song, lyrics = self._build_test_data('amazing grace.txt', False) + song, lyrics = _build_data('amazing grace.txt', False) # WHEN: An importer object is created importer.process_song(song, lyrics, []) @@ -100,8 +129,8 @@ class TestOpsProSongImport(TestCase): # THEN: The imported data should look like expected result_file = open(os.path.join(TEST_PATH, 'Amazing Grace.json'), 'rb') result_data = json.loads(result_file.read().decode()) - self.assertListEqual(importer.verses, self._get_data(result_data, 'verses')) - self.assertListEqual(importer.verse_order_list_generated, self._get_data(result_data, 'verse_order_list')) + self.assertListEqual(importer.verses, _get_item(result_data, 'verses')) + self.assertListEqual(importer.verse_order_list_generated, _get_item(result_data, 'verse_order_list')) @patch('openlp.plugins.songs.lib.importers.opspro.SongImport') def test_trans_off_tag(self, mocked_songimport): @@ -112,7 +141,7 @@ class TestOpsProSongImport(TestCase): mocked_manager = MagicMock() importer = OPSProImport(mocked_manager, filenames=[]) importer.finish = MagicMock() - song, lyrics = self._build_test_data('amazing grace2.txt', True) + song, lyrics = _build_data('amazing grace2.txt', True) # WHEN: An importer object is created importer.process_song(song, lyrics, []) @@ -120,8 +149,8 @@ class TestOpsProSongImport(TestCase): # THEN: The imported data should look like expected result_file = open(os.path.join(TEST_PATH, 'Amazing Grace.json'), 'rb') result_data = json.loads(result_file.read().decode()) - self.assertListEqual(importer.verses, self._get_data(result_data, 'verses')) - self.assertListEqual(importer.verse_order_list_generated, self._get_data(result_data, 'verse_order_list')) + self.assertListEqual(importer.verses, _get_item(result_data, 'verses')) + self.assertListEqual(importer.verse_order_list_generated, _get_item(result_data, 'verse_order_list')) @patch('openlp.plugins.songs.lib.importers.opspro.SongImport') def test_trans_tag(self, mocked_songimport): @@ -132,7 +161,7 @@ class TestOpsProSongImport(TestCase): mocked_manager = MagicMock() importer = OPSProImport(mocked_manager, filenames=[]) importer.finish = MagicMock() - song, lyrics = self._build_test_data('amazing grace3.txt', True) + song, lyrics = _build_data('amazing grace3.txt', True) # WHEN: An importer object is created importer.process_song(song, lyrics, []) @@ -140,26 +169,6 @@ class TestOpsProSongImport(TestCase): # THEN: The imported data should look like expected result_file = open(os.path.join(TEST_PATH, 'Amazing Grace3.json'), 'rb') result_data = json.loads(result_file.read().decode()) - self.assertListEqual(importer.verses, self._get_data(result_data, 'verses')) - self.assertListEqual(importer.verse_order_list_generated, self._get_data(result_data, 'verse_order_list')) + self.assertListEqual(importer.verses, _get_item(result_data, 'verses')) + self.assertListEqual(importer.verse_order_list_generated, _get_item(result_data, 'verse_order_list')) - def _get_data(self, data, key): - if key in data: - return data[key] - return '' - - def test__build_data(self, test_file, dual_language): - song = MagicMock() - song.ID = 100 - song.SongNumber = 123 - song.SongBookName = 'The Song Book' - song.Title = 'Song Title' - song.CopyrightText = 'Music and text by me' - song.Version = '1' - song.Origin = '...' - lyrics = MagicMock() - test_file = open(os.path.join(TEST_PATH, test_file), 'rb') - lyrics.Lyrics = test_file.read().decode() - lyrics.Type = 1 - lyrics.IsDualLanguage = dual_language - return song, lyrics diff --git a/tests/interfaces/openlp_plugins/songs/forms/test_editverseform.py b/tests/interfaces/openlp_plugins/songs/forms/test_editverseform.py index c4855993f..c3b9ecbd9 100644 --- a/tests/interfaces/openlp_plugins/songs/forms/test_editverseform.py +++ b/tests/interfaces/openlp_plugins/songs/forms/test_editverseform.py @@ -62,7 +62,7 @@ class TestEditVerseForm(TestCase, TestMixin): # THEN: The default value is correct self.assertEqual(self.form.verse_text_edit.toPlainText(), '', 'The verse edit box is empty.') - def type_verse_text_tests(self): + def test_type_verse_text(self): """ Test that typing into the verse text edit box returns the correct text """ From 83e11710f247c3e4f42f82cb75750a426943bc1c Mon Sep 17 00:00:00 2001 From: Ian Knight Date: Thu, 2 Jun 2016 10:45:41 +0930 Subject: [PATCH 32/62] fixed test naming issue --- .../test_listpreviewwidget.py | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py b/tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py index 64239373a..b0279cece 100644 --- a/tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py +++ b/tests/functional/openlp_core_ui_lib/test_listpreviewwidget.py @@ -61,7 +61,7 @@ class TestListPreviewWidget(TestCase): self.mocked_viewport.return_value = self.mocked_viewport_obj self.addCleanup(self.viewport_patcher.stop) - def new_list_preview_widget_test(self): + def test_new_list_preview_widget(self): """ Test that creating an instance of ListPreviewWidget works """ @@ -77,7 +77,7 @@ class TestListPreviewWidget(TestCase): @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.image_manager') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight') - def replace_service_item_test_thumbs(self, mocked_setRowHeight, mocked_resizeRowsToContents, + def test_replace_service_item_thumbs(self, mocked_setRowHeight, mocked_resizeRowsToContents, mocked_image_manager): """ Test that thubmails for different slides are loaded properly in replace_service_item. @@ -123,7 +123,7 @@ class TestListPreviewWidget(TestCase): @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight') - def replace_recalculate_layout_test_text(self, mocked_setRowHeight, mocked_resizeRowsToContents): + def test_replace_recalculate_layout_text(self, mocked_setRowHeight, mocked_resizeRowsToContents): """ Test if "Max height for non-text slides..." enabled, txt slides unchanged in replace_service_item & __recalc... """ @@ -155,7 +155,7 @@ class TestListPreviewWidget(TestCase): @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight') - def replace_recalculate_layout_test_img(self, mocked_setRowHeight, mocked_resizeRowsToContents): + def test_replace_recalculate_layout_img(self, mocked_setRowHeight, mocked_resizeRowsToContents): """ Test if "Max height for non-text slides..." disabled, img slides unchanged in replace_service_item & __recalc... """ @@ -192,7 +192,7 @@ class TestListPreviewWidget(TestCase): @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight') - def replace_recalculate_layout_test_img_max(self, mocked_setRowHeight, mocked_resizeRowsToContents): + def test_replace_recalculate_layout_img_max(self, mocked_setRowHeight, mocked_resizeRowsToContents): """ Test if "Max height for non-text slides..." enabled, img slides resized in replace_service_item & __recalc... """ @@ -227,7 +227,7 @@ class TestListPreviewWidget(TestCase): @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight') - def replace_recalculate_layout_test_img_auto(self, mocked_setRowHeight, mocked_resizeRowsToContents): + def test_replace_recalculate_layout_img_auto(self, mocked_setRowHeight, mocked_resizeRowsToContents): """ Test if "Max height for non-text slides..." auto, img slides resized in replace_service_item & __recalc... """ @@ -266,7 +266,7 @@ class TestListPreviewWidget(TestCase): @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.cellWidget') - def row_resized_test_text(self, mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents): + def test_row_resized_text(self, mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents): """ Test if "Max height for non-text slides..." enabled, text-based slides not affected in row_resized. """ @@ -300,7 +300,7 @@ class TestListPreviewWidget(TestCase): @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.cellWidget') - def row_resized_test_img(self, mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents): + def test_row_resized_img(self, mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents): """ Test if "Max height for non-text slides..." disabled, image-based slides not affected in row_resized. """ @@ -337,7 +337,7 @@ class TestListPreviewWidget(TestCase): @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.cellWidget') - def row_resized_test_img_max(self, mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents): + def test_row_resized_img_max(self, mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents): """ Test if "Max height for non-text slides..." enabled, image-based slides are scaled in row_resized. """ @@ -372,7 +372,7 @@ class TestListPreviewWidget(TestCase): @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.resizeRowsToContents') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.setRowHeight') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.cellWidget') - def row_resized_test_setting_changed(self, mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents): + def test_row_resized_setting_changed(self, mocked_cellWidget, mocked_setRowHeight, mocked_resizeRowsToContents): """ Test if "Max height for non-text slides..." enabled while item live, program doesn't crash on row_resized. """ @@ -408,7 +408,7 @@ class TestListPreviewWidget(TestCase): @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.scrollToItem') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.item') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.slide_count') - def autoscroll_test_setting_invalid(self, mocked_slide_count, mocked_item, mocked_scrollToItem, mocked_selectRow): + def test_autoscroll_setting_invalid(self, mocked_slide_count, mocked_item, mocked_scrollToItem, mocked_selectRow): """ Test if 'advanced/autoscrolling' setting None or invalid, that no autoscrolling occurs on change_slide(). """ @@ -444,7 +444,7 @@ class TestListPreviewWidget(TestCase): @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.scrollToItem') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.item') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.slide_count') - def autoscroll_test_dist_bounds(self, mocked_slide_count, mocked_item, mocked_scrollToItem, mocked_selectRow): + def test_autoscroll_dist_bounds(self, mocked_slide_count, mocked_item, mocked_scrollToItem, mocked_selectRow): """ Test if 'advanced/autoscrolling' setting asks to scroll beyond list bounds, that it does not beyond. """ @@ -474,7 +474,7 @@ class TestListPreviewWidget(TestCase): @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.scrollToItem') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.item') @patch(u'openlp.core.ui.lib.listpreviewwidget.ListPreviewWidget.slide_count') - def autoscroll_test_normal(self, mocked_slide_count, mocked_item, mocked_scrollToItem, mocked_selectRow): + def test_autoscroll_normal(self, mocked_slide_count, mocked_item, mocked_scrollToItem, mocked_selectRow): """ Test if 'advanced/autoscrolling' setting valid, autoscrolling called as expected. """ From 47da0a1c8bad9b3ac4d664cb72bebfd5d0c4d5c2 Mon Sep 17 00:00:00 2001 From: Ian Knight Date: Thu, 2 Jun 2016 20:02:34 +0930 Subject: [PATCH 33/62] Fixed PEP8 Errors --- tests/functional/openlp_plugins/bibles/test_lib.py | 1 + tests/functional/openlp_plugins/songs/test_opsproimport.py | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/openlp_plugins/bibles/test_lib.py b/tests/functional/openlp_plugins/bibles/test_lib.py index a8dba0bd9..27d7f5e51 100644 --- a/tests/functional/openlp_plugins/bibles/test_lib.py +++ b/tests/functional/openlp_plugins/bibles/test_lib.py @@ -43,6 +43,7 @@ class TestLib(TestCase): separators = {'sep_r': '\\s*(?:e)\\s*', 'sep_e_default': 'end', 'sep_v_display': 'w', 'sep_l_display': 'r', 'sep_v_default': ':|v|V|verse|verses', 'sep_l': '\\s*(?:r)\\s*', 'sep_l_default': ',|and', 'sep_e': '\\s*(?:t)\\s*', 'sep_v': '\\s*(?:w)\\s*', 'sep_r_display': 'e', 'sep_r_default': '-|to'} + def _update_side_effect(): """ Update the references after mocking out the method diff --git a/tests/functional/openlp_plugins/songs/test_opsproimport.py b/tests/functional/openlp_plugins/songs/test_opsproimport.py index 239b77c30..8db69b609 100644 --- a/tests/functional/openlp_plugins/songs/test_opsproimport.py +++ b/tests/functional/openlp_plugins/songs/test_opsproimport.py @@ -171,4 +171,3 @@ class TestOpsProSongImport(TestCase): result_data = json.loads(result_file.read().decode()) self.assertListEqual(importer.verses, _get_item(result_data, 'verses')) self.assertListEqual(importer.verse_order_list_generated, _get_item(result_data, 'verse_order_list')) - From 2443b94edaa28715670f9661a0f649538ca2071f Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Mon, 6 Jun 2016 08:16:09 -0700 Subject: [PATCH 34/62] Convert htmlbuilder strings to Template() --- openlp/core/lib/htmlbuilder.py | 181 +++++++++--------- .../openlp_core_lib/test_htmlbuilder.py | 38 ++-- 2 files changed, 116 insertions(+), 103 deletions(-) diff --git a/openlp/core/lib/htmlbuilder.py b/openlp/core/lib/htmlbuilder.py index f0d8ddef2..28976b68c 100644 --- a/openlp/core/lib/htmlbuilder.py +++ b/openlp/core/lib/htmlbuilder.py @@ -390,14 +390,14 @@ is the function which has to be called from outside. The generated and returned import logging from PyQt5 import QtWebKit +from string import Template from openlp.core.common import Settings from openlp.core.lib.theme import BackgroundType, BackgroundGradientType, VerticalType, HorizontalType log = logging.getLogger(__name__) -# TODO: Verify where this is used before converting to python3 -HTMLSRC = """ +HTML_SRC = Template(""" @@ -411,14 +411,14 @@ HTMLSRC = """ -webkit-user-select: none; } body { - %s; + ${bg_css}; } .size { position: absolute; left: 0px; top: 0px; - width: 100%%; - height: 100%%; + width: 100%; + height: 100%; } #black { z-index: 8; @@ -431,14 +431,14 @@ body { #image { z-index: 2; } -%s +${css_additions} #footer { position: absolute; z-index: 6; - %s + ${footer_css} } /* lyric css */ -%s +${lyrics_css} sup { font-size: 0.6em; vertical-align: top; @@ -448,8 +448,8 @@ sup { - - -%s + + +${html_additions}
-""" +""") + +LYRICS_SRC = Template(""" +.lyricstable { + z-index: 5; + position: absolute; + display: table; + ${stable} +} +.lyricscell { + display: table-cell; + word-wrap: break-word; + -webkit-transition: opacity 0.4s ease; + ${lyrics} +} +.lyricsmain { + ${main} +} +""") + +FOOTER_SRC = Template(""" +left: ${left}px; +bottom: ${bottom}px; +width: ${width}px; +font-family: ${family}; +font-size: ${size}pt; +color: ${color}; +text-align: left; +white-space: ${space}; +""") + +LYRICS_FORMAT_SRC = Template(""" +${justify}word-wrap: break-word; +text-align: ${align}; +vertical-align: ${valign}; +font-family: ${font}; +font-size: ${size}pt; +color: ${color}; +line-height: ${line}%; +margin: 0; +padding: 0; +padding-bottom: ${bottom}; +padding-left: ${left}px; +width: ${width}px; +height: ${height}px;${font_style}${font_weight} +""") def build_html(item, screen, is_live, background, image=None, plugins=None): @@ -582,18 +627,17 @@ def build_html(item, screen, is_live, background, image=None, plugins=None): css_additions += plugin.get_display_css() js_additions += plugin.get_display_javascript() html_additions += plugin.get_display_html() - html = HTMLSRC % ( - build_background_css(item, width), - css_additions, - build_footer_css(item, height), - build_lyrics_css(item), - 'true' if theme_data and theme_data.display_slide_transition and is_live else 'false', - js_additions, - bgimage_src, - image_src, - html_additions - ) - return html + return HTML_SRC.substitute(bg_css=build_background_css(item, width), + css_additions=css_additions, + footer_css=build_footer_css(item, height), + lyrics_css=build_lyrics_css(item), + transitions='true' if (theme_data and + theme_data.display_slide_transition and + is_live) else 'false', + js_additions=js_additions, + bg_image=bgimage_src, + image=image_src, + html_additions=html_additions) def webkit_version(): @@ -650,24 +694,6 @@ def build_lyrics_css(item): :param item: Service Item containing theme and location information """ - # TODO: Verify this before converting to python3 - style = """ -.lyricstable { - z-index: 5; - position: absolute; - display: table; - %s -} -.lyricscell { - display: table-cell; - word-wrap: break-word; - -webkit-transition: opacity 0.4s ease; - %s -} -.lyricsmain { - %s -} -""" theme_data = item.theme_data lyricstable = '' lyrics = '' @@ -680,8 +706,7 @@ def build_lyrics_css(item): lyricsmain += ' text-shadow: {theme} {shadow}px ' \ '{shadow}px;'.format(theme=theme_data.font_main_shadow_color, shadow=theme_data.font_main_shadow_size) - lyrics_css = style % (lyricstable, lyrics, lyricsmain) - return lyrics_css + return LYRICS_SRC.substitute(stable=lyricstable, lyrics=lyrics, main=lyricsmain) def build_lyrics_outline_css(theme_data): @@ -710,38 +735,23 @@ def build_lyrics_format_css(theme_data, width, height): """ align = HorizontalType.Names[theme_data.display_horizontal_align] valign = VerticalType.Names[theme_data.display_vertical_align] - if theme_data.font_main_outline: - left_margin = int(theme_data.font_main_outline_size) * 2 - else: - left_margin = 0 - justify = 'white-space:pre-wrap;' + left_margin = (int(theme_data.font_main_outline_size) * 2) if theme_data.font_main_outline else 0 # fix tag incompatibilities - if theme_data.display_horizontal_align == HorizontalType.Justify: - justify = '' - if theme_data.display_vertical_align == VerticalType.Bottom: - padding_bottom = '0.5em' - else: - padding_bottom = '0' - lyrics = '{justify} word-wrap: break-word; ' \ - 'text-align: {align}; vertical-align: {valign}; font-family: {font}; ' \ - 'font-size: {size}pt; color: {color}; line-height: {line:d}%; margin: 0;' \ - 'padding: 0; padding-bottom: {bottom}; padding-left: {left}px; width: {width}px; ' \ - 'height: {height}px; '.format(justify=justify, - align=align, - valign=valign, - font=theme_data.font_main_name, - size=theme_data.font_main_size, - color=theme_data.font_main_color, - line=100 + int(theme_data.font_main_line_adjustment), - bottom=padding_bottom, - left=left_margin, - width=width, - height=height) - if theme_data.font_main_italics: - lyrics += 'font-style:italic; ' - if theme_data.font_main_bold: - lyrics += 'font-weight:bold; ' - return lyrics + justify = '' if (theme_data.display_horizontal_align == HorizontalType.Justify) else 'white-space:pre-wrap;\n' + padding_bottom = '0.5em' if (theme_data.display_vertical_align == VerticalType.Bottom) else '0' + return LYRICS_FORMAT_SRC.substitute(justify=justify, + align=align, + valign=valign, + font=theme_data.font_main_name, + size=theme_data.font_main_size, + color=theme_data.font_main_color, + line='{line:d}'.format(line=100 + int(theme_data.font_main_line_adjustment)), + bottom=padding_bottom, + left=left_margin, + width=width, + height=height, + font_style='\nfont-style:italic;' if theme_data.font_main_italics else '', + font_weight='\nfont-weight:bold;' if theme_data.font_main_bold else '') def build_footer_css(item, height): @@ -751,22 +761,11 @@ def build_footer_css(item, height): :param item: Service Item to be processed. :param height: """ - style = """ - left: {left}px; - bottom: {bottom}px; - width: {width}px; - font-family: {family}; - font-size: {size}pt; - color: {color}; - text-align: left; - white-space: {space}; - """ theme = item.theme_data if not theme or not item.footer: return '' bottom = height - int(item.footer.y()) - int(item.footer.height()) whitespace = 'normal' if Settings().value('themes/wrap footer') else 'nowrap' - lyrics_html = style.format(left=item.footer.x(), bottom=bottom, width=item.footer.width(), - family=theme.font_footer_name, size=theme.font_footer_size, - color=theme.font_footer_color, space=whitespace) - return lyrics_html + return FOOTER_SRC.substitute(left=item.footer.x(), bottom=bottom, width=item.footer.width(), + family=theme.font_footer_name, size=theme.font_footer_size, + color=theme.font_footer_color, space=whitespace) diff --git a/tests/functional/openlp_core_lib/test_htmlbuilder.py b/tests/functional/openlp_core_lib/test_htmlbuilder.py index 48c60b55f..5f385e3eb 100644 --- a/tests/functional/openlp_core_lib/test_htmlbuilder.py +++ b/tests/functional/openlp_core_lib/test_htmlbuilder.py @@ -182,19 +182,33 @@ LYRICS_CSS = """ } """ LYRICS_OUTLINE_CSS = ' -webkit-text-stroke: 0.125em #000000; -webkit-text-fill-color: #FFFFFF; ' -LYRICS_FORMAT_CSS = ' word-wrap: break-word; text-align: justify; vertical-align: bottom; ' + \ - 'font-family: Arial; font-size: 40pt; color: #FFFFFF; line-height: 108%; margin: 0;padding: 0; ' + \ - 'padding-bottom: 0.5em; padding-left: 2px; width: 1580px; height: 810px; font-style:italic; font-weight:bold; ' +LYRICS_FORMAT_CSS = """ +word-wrap: break-word; +text-align: justify; +vertical-align: bottom; +font-family: Arial; +font-size: 40pt; +color: #FFFFFF; +line-height: 108%; +margin: 0; +padding: 0; +padding-bottom: 0.5em; +padding-left: 2px; +width: 1580px; +height: 810px; +font-style:italic; +font-weight:bold; +""" FOOTER_CSS_BASE = """ - left: 10px; - bottom: 0px; - width: 1260px; - font-family: Arial; - font-size: 12pt; - color: #FFFFFF; - text-align: left; - white-space: %s; - """ +left: 10px; +bottom: 0px; +width: 1260px; +font-family: Arial; +font-size: 12pt; +color: #FFFFFF; +text-align: left; +white-space: %s; +""" FOOTER_CSS = FOOTER_CSS_BASE % ('nowrap') FOOTER_CSS_WRAP = FOOTER_CSS_BASE % ('normal') FOOTER_CSS_INVALID = '' From 0d2745a1d18f278d9a1d1998497b587815f7c535 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Tue, 7 Jun 2016 09:35:06 +0200 Subject: [PATCH 35/62] Fix bug #1589815 by first reducing the string to digits only and then checking if there's anything left. --- .../plugins/songs/lib/importers/opensong.py | 2 +- .../songs/test_opensongimport.py | 6 +- tests/helpers/songfileimport.py | 3 +- tests/resources/opensongsongs/Amazing Grace | 2 +- .../opensongsongs/Amazing Grace with bad CCLI | 56 +++++++++++++++++++ .../Amazing Grace without CCLI.json | 42 ++++++++++++++ 6 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 tests/resources/opensongsongs/Amazing Grace with bad CCLI create mode 100644 tests/resources/opensongsongs/Amazing Grace without CCLI.json diff --git a/openlp/plugins/songs/lib/importers/opensong.py b/openlp/plugins/songs/lib/importers/opensong.py index a1bfacbcb..161f8cd68 100644 --- a/openlp/plugins/songs/lib/importers/opensong.py +++ b/openlp/plugins/songs/lib/importers/opensong.py @@ -156,8 +156,8 @@ class OpenSongImport(SongImport): ustring = str(root.__getattr__(attr)) if isinstance(fn_or_string, str): if attr in ['ccli']: + ustring = ''.join(re.findall('\d+', ustring)) if ustring: - ustring = ''.join(re.findall('\d+', ustring)) setattr(self, fn_or_string, int(ustring)) else: setattr(self, fn_or_string, None) diff --git a/tests/functional/openlp_plugins/songs/test_opensongimport.py b/tests/functional/openlp_plugins/songs/test_opensongimport.py index 7d51527b8..d1386005f 100644 --- a/tests/functional/openlp_plugins/songs/test_opensongimport.py +++ b/tests/functional/openlp_plugins/songs/test_opensongimport.py @@ -22,13 +22,13 @@ """ This module contains tests for the OpenSong song importer. """ - import os from unittest import TestCase -from tests.helpers.songfileimport import SongImportTestHelper from openlp.plugins.songs.lib.importers.opensong import OpenSongImport from openlp.core.common import Registry + +from tests.helpers.songfileimport import SongImportTestHelper from tests.functional import patch, MagicMock TEST_PATH = os.path.abspath( @@ -54,6 +54,8 @@ class TestOpenSongFileImport(SongImportTestHelper): self.load_external_result_data(os.path.join(TEST_PATH, 'One, Two, Three, Four, Five.json'))) self.file_import([os.path.join(TEST_PATH, 'Amazing Grace2')], self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json'))) + self.file_import([os.path.join(TEST_PATH, 'Amazing Grace with bad CCLI')], + self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace without CCLI.json'))) class TestOpenSongImport(TestCase): diff --git a/tests/helpers/songfileimport.py b/tests/helpers/songfileimport.py index bc4ebc9b5..9a9ab7d2b 100644 --- a/tests/helpers/songfileimport.py +++ b/tests/helpers/songfileimport.py @@ -29,6 +29,7 @@ from unittest import TestCase from openlp.plugins.songs.lib.importers.opensong import OpenSongImport from openlp.core.common import Registry + from tests.functional import patch, MagicMock, call log = logging.getLogger(__name__) @@ -36,7 +37,7 @@ log = logging.getLogger(__name__) class SongImportTestHelper(TestCase): """ - This class is designed to be a helper class to reduce repition when testing the import of song files. + This class is designed to be a helper class to reduce repetition when testing the import of song files. """ def __init__(self, *args, **kwargs): super(SongImportTestHelper, self).__init__(*args, **kwargs) diff --git a/tests/resources/opensongsongs/Amazing Grace b/tests/resources/opensongsongs/Amazing Grace index 97062dc21..6b2c172b5 100644 --- a/tests/resources/opensongsongs/Amazing Grace +++ b/tests/resources/opensongsongs/Amazing Grace @@ -53,4 +53,4 @@ - \ No newline at end of file + diff --git a/tests/resources/opensongsongs/Amazing Grace with bad CCLI b/tests/resources/opensongsongs/Amazing Grace with bad CCLI new file mode 100644 index 000000000..292d4a825 --- /dev/null +++ b/tests/resources/opensongsongs/Amazing Grace with bad CCLI @@ -0,0 +1,56 @@ + + + Amazing Grace (Demonstration) + John Newton, Edwin Excell & John P. Rees + Public Domain + V1 V2 V3 V4 V5 + + + GE + God: Assurance/Grace/Salvation + Worship: Praise + + + + [V] +;Test the chords format +;Chords beging with . +;Verses begin with their verse number +;Link words with _ +;Comments begin with ; +. D D7 G D +1A______ma________zing grace! How sweet the sound! +2'Twas grace that taught my heart to fear, +3The Lord has pro____mised good to me, +4Thro' ma________ny dan____gers, toils and snares +5When we've been there ten thou__sand years, + +. Bm E A A7 +1That saved a wretch like me! +2And grace my fears re___lieved. +3His Word my hope se___cures. +4I have al___rea____dy come. +5Bright shi___ning as the sun, + +. D D7 G D +1I once was lost, but now am found; +2How pre___cious did that grace ap____pear, +3He will my shield and por___tion be +4'Tis grace that brought me safe thus far, +5We've no less days to sing God's praise, + +. Bm A G D +1Was blind, but now I see. +2The hour I first be_lieved. +3As long as life en_dures. +4And grace will lead me home. +5Than when we first be_gun. + + + Demonstration Songs 0 + + + + + + diff --git a/tests/resources/opensongsongs/Amazing Grace without CCLI.json b/tests/resources/opensongsongs/Amazing Grace without CCLI.json new file mode 100644 index 000000000..799fd33d9 --- /dev/null +++ b/tests/resources/opensongsongs/Amazing Grace without CCLI.json @@ -0,0 +1,42 @@ +{ + "authors": [ + "John Newton", + "Edwin Excell", + "John P. Rees" + ], + "ccli_number": null, + "comments": "\n\n\n", + "copyright": "Public Domain ", + "song_book_name": "Demonstration Songs", + "song_number": 0, + "title": "Amazing Grace (Demonstration)", + "topics": [ + "Assurance", + "Grace", + "Praise", + "Salvation" + ], + "verse_order_list": [], + "verses": [ + [ + "Amazing grace! How sweet the sound!\nThat saved a wretch like me!\nI once was lost, but now am found;\nWas blind, but now I see.", + "v1" + ], + [ + "'Twas grace that taught my heart to fear,\nAnd grace my fears relieved.\nHow precious did that grace appear,\nThe hour I first believed.", + "v2" + ], + [ + "The Lord has promised good to me,\nHis Word my hope secures.\nHe will my shield and portion be\nAs long as life endures.", + "v3" + ], + [ + "Thro' many dangers, toils and snares\nI have already come.\n'Tis grace that brought me safe thus far,\nAnd grace will lead me home.", + "v4" + ], + [ + "When we've been there ten thousand years,\nBright shining as the sun,\nWe've no less days to sing God's praise,\nThan when we first begun.", + "v5" + ] + ] +} From 5fe54b59075c2b9da658e0ee0a14cac38c2b697a Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Tue, 7 Jun 2016 06:12:22 -0700 Subject: [PATCH 36/62] Beauty spa for the htmlbuilder --- openlp/core/lib/htmlbuilder.py | 361 +++++++++--------- .../openlp_core_lib/test_htmlbuilder.py | 361 +++++++++--------- 2 files changed, 361 insertions(+), 361 deletions(-) diff --git a/openlp/core/lib/htmlbuilder.py b/openlp/core/lib/htmlbuilder.py index 28976b68c..6f2fee68c 100644 --- a/openlp/core/lib/htmlbuilder.py +++ b/openlp/core/lib/htmlbuilder.py @@ -398,200 +398,199 @@ from openlp.core.lib.theme import BackgroundType, BackgroundGradientType, Vertic log = logging.getLogger(__name__) HTML_SRC = Template(""" - - - -OpenLP Display - - - - - - -${html_additions} -
- -
- - -""") + function show_text_completed(){ + return (timer == null); + } + + + + + + ${html_additions} +
+ +
+ + + """) LYRICS_SRC = Template(""" -.lyricstable { - z-index: 5; - position: absolute; - display: table; - ${stable} -} -.lyricscell { - display: table-cell; - word-wrap: break-word; - -webkit-transition: opacity 0.4s ease; - ${lyrics} -} -.lyricsmain { - ${main} -} -""") + .lyricstable { + z-index: 5; + position: absolute; + display: table; + ${stable} + } + .lyricscell { + display: table-cell; + word-wrap: break-word; + -webkit-transition: opacity 0.4s ease; + ${lyrics} + } + .lyricsmain { + ${main} + } + """) FOOTER_SRC = Template(""" -left: ${left}px; -bottom: ${bottom}px; -width: ${width}px; -font-family: ${family}; -font-size: ${size}pt; -color: ${color}; -text-align: left; -white-space: ${space}; -""") + left: ${left}px; + bottom: ${bottom}px; + width: ${width}px; + font-family: ${family}; + font-size: ${size}pt; + color: ${color}; + text-align: left; + white-space: ${space}; + """) LYRICS_FORMAT_SRC = Template(""" -${justify}word-wrap: break-word; -text-align: ${align}; -vertical-align: ${valign}; -font-family: ${font}; -font-size: ${size}pt; -color: ${color}; -line-height: ${line}%; -margin: 0; -padding: 0; -padding-bottom: ${bottom}; -padding-left: ${left}px; -width: ${width}px; -height: ${height}px;${font_style}${font_weight} -""") + ${justify}word-wrap: break-word; + text-align: ${align}; + vertical-align: ${valign}; + font-family: ${font}; + font-size: ${size}pt; + color: ${color}; + line-height: ${line}%; + margin: 0; + padding: 0; + padding-bottom: ${bottom}; + padding-left: ${left}px; + width: ${width}px; + height: ${height}px;${font_style}${font_weight} + """) def build_html(item, screen, is_live, background, image=None, plugins=None): @@ -737,7 +736,7 @@ def build_lyrics_format_css(theme_data, width, height): valign = VerticalType.Names[theme_data.display_vertical_align] left_margin = (int(theme_data.font_main_outline_size) * 2) if theme_data.font_main_outline else 0 # fix tag incompatibilities - justify = '' if (theme_data.display_horizontal_align == HorizontalType.Justify) else 'white-space:pre-wrap;\n' + justify = '' if (theme_data.display_horizontal_align == HorizontalType.Justify) else ' white-space: pre-wrap;\n' padding_bottom = '0.5em' if (theme_data.display_vertical_align == VerticalType.Bottom) else '0' return LYRICS_FORMAT_SRC.substitute(justify=justify, align=align, @@ -750,8 +749,8 @@ def build_lyrics_format_css(theme_data, width, height): left=left_margin, width=width, height=height, - font_style='\nfont-style:italic;' if theme_data.font_main_italics else '', - font_weight='\nfont-weight:bold;' if theme_data.font_main_bold else '') + font_style='\n font-style: italic;' if theme_data.font_main_italics else '', + font_weight='\n font-weight: bold;' if theme_data.font_main_bold else '') def build_footer_css(item, height): diff --git a/tests/functional/openlp_core_lib/test_htmlbuilder.py b/tests/functional/openlp_core_lib/test_htmlbuilder.py index 5f385e3eb..e76faa311 100644 --- a/tests/functional/openlp_core_lib/test_htmlbuilder.py +++ b/tests/functional/openlp_core_lib/test_htmlbuilder.py @@ -14,201 +14,200 @@ from tests.functional import MagicMock, patch from tests.helpers.testmixin import TestMixin HTML = """ - - - -OpenLP Display - - - - - - -plugin HTML -
- -
- - -""" + function show_text_completed(){ + return (timer == null); + } + + + + + + plugin HTML +
+ +
+ + + """ BACKGROUND_CSS_RADIAL = 'background: -webkit-gradient(radial, 5 50%, 100, 5 50%, 5, from(#000000), to(#FFFFFF)) fixed' LYRICS_CSS = """ -.lyricstable { - z-index: 5; - position: absolute; - display: table; - left: 10px; top: 20px; -} -.lyricscell { - display: table-cell; - word-wrap: break-word; - -webkit-transition: opacity 0.4s ease; - lyrics_format_css -} -.lyricsmain { - text-shadow: #000000 5px 5px; -} -""" + .lyricstable { + z-index: 5; + position: absolute; + display: table; + left: 10px; top: 20px; + } + .lyricscell { + display: table-cell; + word-wrap: break-word; + -webkit-transition: opacity 0.4s ease; + lyrics_format_css + } + .lyricsmain { + text-shadow: #000000 5px 5px; + } + """ LYRICS_OUTLINE_CSS = ' -webkit-text-stroke: 0.125em #000000; -webkit-text-fill-color: #FFFFFF; ' LYRICS_FORMAT_CSS = """ -word-wrap: break-word; -text-align: justify; -vertical-align: bottom; -font-family: Arial; -font-size: 40pt; -color: #FFFFFF; -line-height: 108%; -margin: 0; -padding: 0; -padding-bottom: 0.5em; -padding-left: 2px; -width: 1580px; -height: 810px; -font-style:italic; -font-weight:bold; -""" + word-wrap: break-word; + text-align: justify; + vertical-align: bottom; + font-family: Arial; + font-size: 40pt; + color: #FFFFFF; + line-height: 108%; + margin: 0; + padding: 0; + padding-bottom: 0.5em; + padding-left: 2px; + width: 1580px; + height: 810px; + font-style: italic; + font-weight: bold; + """ FOOTER_CSS_BASE = """ -left: 10px; -bottom: 0px; -width: 1260px; -font-family: Arial; -font-size: 12pt; -color: #FFFFFF; -text-align: left; -white-space: %s; -""" + left: 10px; + bottom: 0px; + width: 1260px; + font-family: Arial; + font-size: 12pt; + color: #FFFFFF; + text-align: left; + white-space: %s; + """ FOOTER_CSS = FOOTER_CSS_BASE % ('nowrap') FOOTER_CSS_WRAP = FOOTER_CSS_BASE % ('normal') FOOTER_CSS_INVALID = '' @@ -257,6 +256,8 @@ class Htmbuilder(TestCase, TestMixin): # WHEN: Create the html. html = build_html(item, screen, is_live, background, plugins=plugins) + self.maxDiff = None + # THEN: The returned html should match. self.assertEqual(html, HTML, 'The returned html should match') From 828741ec84f9d2a175990295722088043e4846d7 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Tue, 7 Jun 2016 06:21:07 -0700 Subject: [PATCH 37/62] Remove testing verbosity flag --- tests/functional/openlp_core_lib/test_htmlbuilder.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/functional/openlp_core_lib/test_htmlbuilder.py b/tests/functional/openlp_core_lib/test_htmlbuilder.py index e76faa311..31885c2e2 100644 --- a/tests/functional/openlp_core_lib/test_htmlbuilder.py +++ b/tests/functional/openlp_core_lib/test_htmlbuilder.py @@ -256,8 +256,6 @@ class Htmbuilder(TestCase, TestMixin): # WHEN: Create the html. html = build_html(item, screen, is_live, background, plugins=plugins) - self.maxDiff = None - # THEN: The returned html should match. self.assertEqual(html, HTML, 'The returned html should match') From b84dbb15a2f077642f641eb775e81095c9a6e2ad Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Wed, 8 Jun 2016 13:26:01 -0700 Subject: [PATCH 38/62] Oops in string format --- openlp/plugins/bibles/forms/editbibledialog.py | 2 +- openlp/plugins/songs/lib/mediaitem.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openlp/plugins/bibles/forms/editbibledialog.py b/openlp/plugins/bibles/forms/editbibledialog.py index ca3bea4ed..f1e833637 100644 --- a/openlp/plugins/bibles/forms/editbibledialog.py +++ b/openlp/plugins/bibles/forms/editbibledialog.py @@ -104,7 +104,7 @@ class Ui_EditBibleDialog(object): for book in BiblesResourcesDB.get_books(): self.book_name_label[book['abbreviation']] = QtWidgets.QLabel(self.book_name_widget) self.book_name_label[book['abbreviation']].setObjectName( - 'book_name_label[{name}]'.format(book=book['abbreviation'])) + 'book_name_label[{book}]'.format(book=book['abbreviation'])) self.book_name_edit[book['abbreviation']] = QtWidgets.QLineEdit(self.book_name_widget) self.book_name_edit[book['abbreviation']].setObjectName( 'book_name_edit[{name}]'.format(name=book['abbreviation'])) diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index f52abb86f..b89858019 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -603,7 +603,7 @@ class SongMediaItem(MediaManagerItem): else: verse_index = VerseType.from_tag(verse[0]['type']) verse_tag = VerseType.translated_tags[verse_index] - verse_def = '{tag}{label}'.format(tzg=verse_tag, text=verse[0]['label']) + verse_def = '{tag}{text}'.format(tag=verse_tag, text=verse[0]['label']) service_item.add_from_text(verse[1], verse_def) service_item.title = song.title author_list = self.generate_footer(service_item, song) From e222a11390c16f2486a82b9d52f9138f3a04d254 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Wed, 8 Jun 2016 13:41:21 -0700 Subject: [PATCH 39/62] String format oops --- openlp/core/ui/firsttimeform.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openlp/core/ui/firsttimeform.py b/openlp/core/ui/firsttimeform.py index cadb4814f..183c577ef 100644 --- a/openlp/core/ui/firsttimeform.py +++ b/openlp/core/ui/firsttimeform.py @@ -571,7 +571,7 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties): text = translate('OpenLP.FirstTimeWizard', 'Download complete. Click the {button} button to start OpenLP.' ).format(button=clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton))) - self.progress_label.setText() + self.progress_label.setText(text) else: if self.has_run_wizard: text = translate('OpenLP.FirstTimeWizard', @@ -582,7 +582,7 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties): text = translate('OpenLP.FirstTimeWizard', 'Click the {button} button to start OpenLP.' ).format(button=clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton))) - self.progress_label.setText() + self.progress_label.setText(text) self.finish_button.setVisible(True) self.finish_button.setEnabled(True) self.cancel_button.setVisible(False) From aedcecc7ffa37b390b4cb3077f719f91c581e9be Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Wed, 8 Jun 2016 19:57:21 -0700 Subject: [PATCH 40/62] String format oops --- openlp/core/ui/firsttimeform.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/core/ui/firsttimeform.py b/openlp/core/ui/firsttimeform.py index 183c577ef..9ae2e0898 100644 --- a/openlp/core/ui/firsttimeform.py +++ b/openlp/core/ui/firsttimeform.py @@ -565,7 +565,7 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties): if self.has_run_wizard: text = translate('OpenLP.FirstTimeWizard', 'Download complete. Click the {button} button to return to OpenLP.' - ).format(text=clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton))) + ).format(button=clean_button_text(self.buttonText(QtWidgets.QWizard.FinishButton))) self.progress_label.setText(text) else: text = translate('OpenLP.FirstTimeWizard', From 41c0d3fcf9c01430ab36d8c42f01021f5d8bdf88 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 14 Jun 2016 21:11:57 +0200 Subject: [PATCH 41/62] Fix various pyodbc related issues. Fixes bug 1590657. Fixes: https://launchpad.net/bugs/1590657 --- .../plugins/songs/lib/importers/mediashout.py | 28 +++++++++++-------- openlp/plugins/songs/lib/importers/opspro.py | 6 ++-- .../songs/lib/importers/worshipcenterpro.py | 2 +- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/openlp/plugins/songs/lib/importers/mediashout.py b/openlp/plugins/songs/lib/importers/mediashout.py index cb3a19640..af9b855a0 100644 --- a/openlp/plugins/songs/lib/importers/mediashout.py +++ b/openlp/plugins/songs/lib/importers/mediashout.py @@ -24,15 +24,17 @@ The :mod:`mediashout` module provides the functionality for importing a MediaShout database into the OpenLP database. """ -# WARNING: See https://docs.python.org/2/library/sqlite3.html for value substitution +# WARNING: See https://docs.python.org/3/library/sqlite3.html for value substitution # in SQL statements import pyodbc +import logging from openlp.core.lib import translate from openlp.plugins.songs.lib.importers.songimport import SongImport VERSE_TAGS = ['V', 'C', 'B', 'O', 'P', 'I', 'E'] +log = logging.getLogger(__name__) class MediaShoutImport(SongImport): @@ -44,17 +46,19 @@ class MediaShoutImport(SongImport): """ Initialise the MediaShout importer. """ - SongImport.__init__(self, manager, **kwargs) + super(MediaShoutImport, self).__init__(manager, **kwargs) + #SongImport.__init__(self, manager, **kwargs) def do_import(self): """ Receive a single file to import. """ try: - conn = pyodbc.connect('DRIVER={Microsoft Access Driver (*.mdb)};DBQ={source};' - 'PWD=6NOZ4eHK7k'.format(sorce=self.import_source)) - except: + conn = pyodbc.connect('DRIVER={{Microsoft Access Driver (*.mdb)}};DBQ={source};' + 'PWD=6NOZ4eHK7k'.format(source=self.import_source)) + except Exception as e: # Unfortunately no specific exception type + log.exception(e) self.log_error(self.import_source, translate('SongsPlugin.MediaShoutImport', 'Unable to open the MediaShout database.')) return @@ -63,17 +67,19 @@ class MediaShoutImport(SongImport): songs = cursor.fetchall() self.import_wizard.progress_bar.setMaximum(len(songs)) for song in songs: + topics = [] if self.stop_import_flag: break - cursor.execute('SELECT Type, Number, Text FROM Verses WHERE Record = ? ORDER BY Type, Number', song.Record) + cursor.execute('SELECT Type, Number, Text FROM Verses WHERE Record = ? ORDER BY Type, Number', float(song.Record)) verses = cursor.fetchall() - cursor.execute('SELECT Type, Number, POrder FROM PlayOrder WHERE Record = ? ORDER BY POrder', song.Record) + cursor.execute('SELECT Type, Number, POrder FROM PlayOrder WHERE Record = ? ORDER BY POrder', float(song.Record)) verse_order = cursor.fetchall() - cursor.execute('SELECT Name FROM Themes INNER JOIN SongThemes ON SongThemes.ThemeId = Themes.ThemeId ' - 'WHERE SongThemes.Record = ?', song.Record) - topics = cursor.fetchall() + if cursor.tables(table='TableName', tableType='TABLE').fetchone(): + cursor.execute('SELECT Name FROM Themes INNER JOIN SongThemes ON SongThemes.ThemeId = Themes.ThemeId ' + 'WHERE SongThemes.Record = ?', float(song.Record)) + topics = cursor.fetchall() cursor.execute('SELECT Name FROM Groups INNER JOIN SongGroups ON SongGroups.GroupId = Groups.GroupId ' - 'WHERE SongGroups.Record = ?', song.Record) + 'WHERE SongGroups.Record = ?', float(song.Record)) topics += cursor.fetchall() self.process_song(song, verses, verse_order, topics) diff --git a/openlp/plugins/songs/lib/importers/opspro.py b/openlp/plugins/songs/lib/importers/opspro.py index 8f9674deb..03c5001c6 100644 --- a/openlp/plugins/songs/lib/importers/opspro.py +++ b/openlp/plugins/songs/lib/importers/opspro.py @@ -55,7 +55,7 @@ class OPSProImport(SongImport): """ password = self.extract_mdb_password() try: - conn = pyodbc.connect('DRIVER={Microsoft Access Driver (*.mdb)};DBQ={source};' + conn = pyodbc.connect('DRIVER={{Microsoft Access Driver (*.mdb)}};DBQ={source};' 'PWD={password}'.format(source=self.import_source, password=password)) except (pyodbc.DatabaseError, pyodbc.IntegrityError, pyodbc.InternalError, pyodbc.OperationalError) as e: log.warning('Unable to connect the OPS Pro database {source}. {error}'.format(source=self.import_source, @@ -74,11 +74,11 @@ class OPSProImport(SongImport): break # Type means: 0=Original, 1=Projection, 2=Own cursor.execute('SELECT Lyrics, Type, IsDualLanguage FROM Lyrics WHERE SongID = ? AND Type < 2 ' - 'ORDER BY Type DESC', song.ID) + 'ORDER BY Type DESC', float(song.ID)) lyrics = cursor.fetchone() cursor.execute('SELECT CategoryName FROM Category INNER JOIN SongCategory ' 'ON Category.ID = SongCategory.CategoryID WHERE SongCategory.SongID = ? ' - 'ORDER BY CategoryName', song.ID) + 'ORDER BY CategoryName', float(song.ID)) topics = cursor.fetchall() try: self.process_song(song, lyrics, topics) diff --git a/openlp/plugins/songs/lib/importers/worshipcenterpro.py b/openlp/plugins/songs/lib/importers/worshipcenterpro.py index df04823e8..3d5cbe9ba 100644 --- a/openlp/plugins/songs/lib/importers/worshipcenterpro.py +++ b/openlp/plugins/songs/lib/importers/worshipcenterpro.py @@ -49,7 +49,7 @@ class WorshipCenterProImport(SongImport): Receive a single file to import. """ try: - conn = pyodbc.connect('DRIVER={Microsoft Access Driver (*.mdb)};' + conn = pyodbc.connect('DRIVER={{Microsoft Access Driver (*.mdb)}};' 'DBQ={source}'.format(source=self.import_source)) except (pyodbc.DatabaseError, pyodbc.IntegrityError, pyodbc.InternalError, pyodbc.OperationalError) as e: log.warning('Unable to connect the WorshipCenter Pro ' From 4fc4fa896959b4b0f0e73ee669aa05e81604b747 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 14 Jun 2016 22:36:51 +0200 Subject: [PATCH 42/62] pep8 fixes --- openlp/plugins/songs/lib/importers/mediashout.py | 7 ++++--- openlp/plugins/songs/lib/importers/videopsalm.py | 1 - 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openlp/plugins/songs/lib/importers/mediashout.py b/openlp/plugins/songs/lib/importers/mediashout.py index af9b855a0..a3bd7bbbc 100644 --- a/openlp/plugins/songs/lib/importers/mediashout.py +++ b/openlp/plugins/songs/lib/importers/mediashout.py @@ -47,7 +47,6 @@ class MediaShoutImport(SongImport): Initialise the MediaShout importer. """ super(MediaShoutImport, self).__init__(manager, **kwargs) - #SongImport.__init__(self, manager, **kwargs) def do_import(self): """ @@ -70,9 +69,11 @@ class MediaShoutImport(SongImport): topics = [] if self.stop_import_flag: break - cursor.execute('SELECT Type, Number, Text FROM Verses WHERE Record = ? ORDER BY Type, Number', float(song.Record)) + cursor.execute('SELECT Type, Number, Text FROM Verses WHERE Record = ? ORDER BY Type, Number', + float(song.Record)) verses = cursor.fetchall() - cursor.execute('SELECT Type, Number, POrder FROM PlayOrder WHERE Record = ? ORDER BY POrder', float(song.Record)) + cursor.execute('SELECT Type, Number, POrder FROM PlayOrder WHERE Record = ? ORDER BY POrder', + float(song.Record)) verse_order = cursor.fetchall() if cursor.tables(table='TableName', tableType='TABLE').fetchone(): cursor.execute('SELECT Name FROM Themes INNER JOIN SongThemes ON SongThemes.ThemeId = Themes.ThemeId ' diff --git a/openlp/plugins/songs/lib/importers/videopsalm.py b/openlp/plugins/songs/lib/importers/videopsalm.py index 781abfeaf..25fd4d8eb 100644 --- a/openlp/plugins/songs/lib/importers/videopsalm.py +++ b/openlp/plugins/songs/lib/importers/videopsalm.py @@ -118,4 +118,3 @@ class VideoPsalmImport(SongImport): self.log_error('Could not import {title}'.format(title=self.title)) except Exception as e: self.log_error(song_file.name, translate('SongsPlugin.VideoPsalmImport', 'Error: {error}').format(error=e)) - From 76ffe35621d13e151bb06287d15edd71359941ae Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Fri, 17 Jun 2016 15:06:55 -0700 Subject: [PATCH 43/62] bug 1593882 - fix authenticated connection but bin not set --- openlp/core/lib/projector/pjlink1.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/openlp/core/lib/projector/pjlink1.py b/openlp/core/lib/projector/pjlink1.py index ce06b3625..e5db478c2 100644 --- a/openlp/core/lib/projector/pjlink1.py +++ b/openlp/core/lib/projector/pjlink1.py @@ -344,16 +344,25 @@ class PJLink1(QTcpSocket): return elif data_check[1] == '0' and self.pin is not None: # Pin set and no authentication needed + log.warning('({ip}) Regular connection but PIN set'.format(ip=self.name)) self.disconnect_from_host() self.change_status(E_AUTHENTICATION) - log.debug('({ip}) emitting projectorNoAuthentication() signal'.format(ip=self.name)) + log.debug('({ip}) Emitting projectorNoAuthentication() signal'.format(ip=self.name)) self.projectorNoAuthentication.emit(self.name) return elif data_check[1] == '1': # Authenticated login with salt - log.debug('({ip}) Setting hash with salt="{data}"'.format(ip=self.ip, data=data_check[2])) - log.debug('({ip}) pin="{data}"'.format(ip=self.ip, data=self.pin)) - salt = qmd5_hash(salt=data_check[2].encode('ascii'), data=self.pin.encode('ascii')) + if pin is None: + log.warning('({ip}) Authenticated connection but no pin set'.format(ip=self.name)) + self.disconnect_from_host() + self.change_status(E_AUTHENTICATION) + log.debug('({ip}) Emitting projectorNoAuthentication() signal'.format(ip=self.name)) + self.projectorNoAuthentication.emit(self.name) + return + else: + log.debug('({ip}) Setting hash with salt="{data}"'.format(ip=self.ip, data=data_check[2])) + log.debug('({ip}) pin="{data}"'.format(ip=self.ip, data=self.pin)) + salt = qmd5_hash(salt=data_check[2].encode('ascii'), data=self.pin.encode('ascii')) else: salt = None # We're connected at this point, so go ahead and do regular I/O From c64df391aa726b5f771f632e2cca855df66ef046 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Fri, 17 Jun 2016 15:46:21 -0700 Subject: [PATCH 44/62] bug 1593882 fix --- openlp/core/lib/projector/pjlink1.py | 4 ++-- .../openlp_core_lib/test_projector_pjlink1.py | 24 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/openlp/core/lib/projector/pjlink1.py b/openlp/core/lib/projector/pjlink1.py index e5db478c2..3e9a8b422 100644 --- a/openlp/core/lib/projector/pjlink1.py +++ b/openlp/core/lib/projector/pjlink1.py @@ -352,7 +352,7 @@ class PJLink1(QTcpSocket): return elif data_check[1] == '1': # Authenticated login with salt - if pin is None: + if self.pin is None: log.warning('({ip}) Authenticated connection but no pin set'.format(ip=self.name)) self.disconnect_from_host() self.change_status(E_AUTHENTICATION) @@ -362,7 +362,7 @@ class PJLink1(QTcpSocket): else: log.debug('({ip}) Setting hash with salt="{data}"'.format(ip=self.ip, data=data_check[2])) log.debug('({ip}) pin="{data}"'.format(ip=self.ip, data=self.pin)) - salt = qmd5_hash(salt=data_check[2].encode('ascii'), data=self.pin.encode('ascii')) + salt = qmd5_hash(salt=data_check[2].encode('ascii'), data=self.pin.encode('ascii')).encode('utf-8') else: salt = None # We're connected at this point, so go ahead and do regular I/O diff --git a/tests/functional/openlp_core_lib/test_projector_pjlink1.py b/tests/functional/openlp_core_lib/test_projector_pjlink1.py index 4928e5d0c..6cdff4ff6 100644 --- a/tests/functional/openlp_core_lib/test_projector_pjlink1.py +++ b/tests/functional/openlp_core_lib/test_projector_pjlink1.py @@ -332,3 +332,27 @@ class TestPJLink(TestCase): self.assertFalse(pjlink.send_busy, 'Projector send_busy should be False') self.assertTrue(mock_timer.called, 'Projector timer.stop() should have been called') self.assertTrue(mock_socket_timer.called, 'Projector socket_timer.stop() should have been called') + + @patch.object(pjlink_test, 'send_command') + @patch.object(pjlink_test, 'waitForReadyRead') + @patch.object(pjlink_test, 'projectorNoAuthentication') + @patch.object(pjlink_test, 'timer') + @patch.object(pjlink_test, 'socket_timer') + def test_bug_1593882_no_pin_authenticated_connection(self, mock_socket_timer, + mock_timer, + mock_no_authentication, + mock_ready_read, + mock_send_command): + """ + Test bug 1593882 no pin and authenticated request exception + """ + # GIVEN: Test object and mocks + pjlink = pjlink_test + pjlink.pin = None + mock_ready_read.return_value = True + + # WHEN: call with authentication request and pin not set + pjlink.check_login(data='PJLink 1 123abc') + + # THEN: No Authentication signal should have been sent + mock_no_authentication.called_with(pjlink.name, 'projectorNoAuthentication should have been called') From aaba690c972899c4b396de2662e446aad8c7e8ce Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Fri, 17 Jun 2016 16:05:26 -0700 Subject: [PATCH 45/62] Fix call to wrong signal on error --- openlp/core/lib/projector/pjlink1.py | 4 ++-- .../functional/openlp_core_lib/test_projector_pjlink1.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/openlp/core/lib/projector/pjlink1.py b/openlp/core/lib/projector/pjlink1.py index 3e9a8b422..8d02cc0b1 100644 --- a/openlp/core/lib/projector/pjlink1.py +++ b/openlp/core/lib/projector/pjlink1.py @@ -356,8 +356,8 @@ class PJLink1(QTcpSocket): log.warning('({ip}) Authenticated connection but no pin set'.format(ip=self.name)) self.disconnect_from_host() self.change_status(E_AUTHENTICATION) - log.debug('({ip}) Emitting projectorNoAuthentication() signal'.format(ip=self.name)) - self.projectorNoAuthentication.emit(self.name) + log.debug('({ip}) Emitting projectorAuthentication() signal'.format(ip=self.name)) + self.projectorAuthentication.emit(self.name) return else: log.debug('({ip}) Setting hash with salt="{data}"'.format(ip=self.ip, data=data_check[2])) diff --git a/tests/functional/openlp_core_lib/test_projector_pjlink1.py b/tests/functional/openlp_core_lib/test_projector_pjlink1.py index 6cdff4ff6..cb9b7751f 100644 --- a/tests/functional/openlp_core_lib/test_projector_pjlink1.py +++ b/tests/functional/openlp_core_lib/test_projector_pjlink1.py @@ -335,12 +335,12 @@ class TestPJLink(TestCase): @patch.object(pjlink_test, 'send_command') @patch.object(pjlink_test, 'waitForReadyRead') - @patch.object(pjlink_test, 'projectorNoAuthentication') + @patch.object(pjlink_test, 'projectorAuthentication') @patch.object(pjlink_test, 'timer') @patch.object(pjlink_test, 'socket_timer') def test_bug_1593882_no_pin_authenticated_connection(self, mock_socket_timer, mock_timer, - mock_no_authentication, + mock_authentication, mock_ready_read, mock_send_command): """ @@ -352,7 +352,7 @@ class TestPJLink(TestCase): mock_ready_read.return_value = True # WHEN: call with authentication request and pin not set - pjlink.check_login(data='PJLink 1 123abc') + pjlink.check_login(data=TEST_CONNECT_AUTHENTICATE) # THEN: No Authentication signal should have been sent - mock_no_authentication.called_with(pjlink.name, 'projectorNoAuthentication should have been called') + mock_authentication.called_with(pjlink.name, 'projectorAuthentication should have been called') From d1ff2385aecc6c286ce5a6096f1814bd1a4b1643 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Fri, 17 Jun 2016 16:48:32 -0700 Subject: [PATCH 46/62] bug 1593883 fix - switch from qmd5_hash to md5_hash --- openlp/core/common/__init__.py | 12 ++++++------ openlp/core/lib/projector/pjlink1.py | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/openlp/core/common/__init__.py b/openlp/core/common/__init__.py index f1abd8fe6..5da4d6dc4 100644 --- a/openlp/core/common/__init__.py +++ b/openlp/core/common/__init__.py @@ -206,9 +206,9 @@ def md5_hash(salt, data=None): """ log.debug('md5_hash(salt="{text}")'.format(text=salt)) hash_obj = hashlib.new('md5') - hash_obj.update(salt) + hash_obj.update(salt.encode('ascii')) if data: - hash_obj.update(data) + hash_obj.update(data.encode('ascii')) hash_value = hash_obj.hexdigest() log.debug('md5_hash() returning "{text}"'.format(text=hash_value)) return hash_value @@ -225,11 +225,11 @@ def qmd5_hash(salt, data=None): """ log.debug('qmd5_hash(salt="{text}"'.format(text=salt)) hash_obj = QHash(QHash.Md5) - hash_obj.addData(salt) - hash_obj.addData(data) + hash_obj.addData(salt.encode('ascii')) + hash_obj.addData(data.encode('ascii')) hash_value = hash_obj.result().toHex() - log.debug('qmd5_hash() returning "{text}"'.format(text=hash_value)) - return hash_value.data() + log.debug('qmd5_hash() returning "{hash}"'.format(hash=hash_value)) + return hash_value def clean_button_text(button_text): diff --git a/openlp/core/lib/projector/pjlink1.py b/openlp/core/lib/projector/pjlink1.py index 8d02cc0b1..89781f0ef 100644 --- a/openlp/core/lib/projector/pjlink1.py +++ b/openlp/core/lib/projector/pjlink1.py @@ -49,7 +49,7 @@ from codecs import decode from PyQt5.QtCore import pyqtSignal, pyqtSlot from PyQt5.QtNetwork import QAbstractSocket, QTcpSocket -from openlp.core.common import translate, qmd5_hash +from openlp.core.common import translate, md5_hash from openlp.core.lib.projector.constants import * # Shortcuts @@ -362,7 +362,7 @@ class PJLink1(QTcpSocket): else: log.debug('({ip}) Setting hash with salt="{data}"'.format(ip=self.ip, data=data_check[2])) log.debug('({ip}) pin="{data}"'.format(ip=self.ip, data=self.pin)) - salt = qmd5_hash(salt=data_check[2].encode('ascii'), data=self.pin.encode('ascii')).encode('utf-8') + salt = md5_hash(salt=data_check[2], data=self.pin) else: salt = None # We're connected at this point, so go ahead and do regular I/O From 7e8eb2151027a1f7dfa5296d287696dadae314bb Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Fri, 17 Jun 2016 16:54:04 -0700 Subject: [PATCH 47/62] Pep8 and notes about hashing --- openlp/core/lib/projector/pjlink1.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openlp/core/lib/projector/pjlink1.py b/openlp/core/lib/projector/pjlink1.py index 89781f0ef..302fc13ee 100644 --- a/openlp/core/lib/projector/pjlink1.py +++ b/openlp/core/lib/projector/pjlink1.py @@ -297,6 +297,8 @@ class PJLink1(QTcpSocket): Processes the initial connection and authentication (if needed). Starts poll timer if connection is established. + NOTE: Qt md5 hash function doesn't work with projector authentication. Use the python md5 hash function. + :param data: Optional data if called from another routine """ log.debug('({ip}) check_login(data="{data}")'.format(ip=self.ip, data=data)) From 7cc56af2bb69583b4d2b5ea0febc991d1142e6e2 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Fri, 17 Jun 2016 19:02:53 -0700 Subject: [PATCH 48/62] bugfix 1593883 pjlink authenticatino test --- openlp/core/common/__init__.py | 3 +- .../openlp_core_lib/test_projector_pjlink1.py | 30 +++++++++++++++++-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/openlp/core/common/__init__.py b/openlp/core/common/__init__.py index 5da4d6dc4..488fbc63b 100644 --- a/openlp/core/common/__init__.py +++ b/openlp/core/common/__init__.py @@ -226,7 +226,8 @@ def qmd5_hash(salt, data=None): log.debug('qmd5_hash(salt="{text}"'.format(text=salt)) hash_obj = QHash(QHash.Md5) hash_obj.addData(salt.encode('ascii')) - hash_obj.addData(data.encode('ascii')) + if data: + hash_obj.addData(data.encode('ascii')) hash_value = hash_obj.result().toHex() log.debug('qmd5_hash() returning "{hash}"'.format(hash=hash_value)) return hash_value diff --git a/tests/functional/openlp_core_lib/test_projector_pjlink1.py b/tests/functional/openlp_core_lib/test_projector_pjlink1.py index cb9b7751f..1c56e5bec 100644 --- a/tests/functional/openlp_core_lib/test_projector_pjlink1.py +++ b/tests/functional/openlp_core_lib/test_projector_pjlink1.py @@ -30,7 +30,7 @@ from openlp.core.lib.projector.constants import E_PARAMETER, ERROR_STRING, S_OFF S_COOLDOWN, PJLINK_POWR_STATUS from tests.functional import patch -from tests.resources.projector.data import TEST_PIN, TEST_SALT, TEST_CONNECT_AUTHENTICATE +from tests.resources.projector.data import TEST_PIN, TEST_SALT, TEST_CONNECT_AUTHENTICATE, TEST_HASH pjlink_test = PJLink1(name='test', ip='127.0.0.1', pin=TEST_PIN, no_poll=True) @@ -355,4 +355,30 @@ class TestPJLink(TestCase): pjlink.check_login(data=TEST_CONNECT_AUTHENTICATE) # THEN: No Authentication signal should have been sent - mock_authentication.called_with(pjlink.name, 'projectorAuthentication should have been called') + mock_authentication.assert_called_with(pjlink.name, 'projectorAuthentication should have been called') + + @patch.object(pjlink_test, 'waitForReadyRead') + @patch.object(pjlink_test, 'state') + @patch.object(pjlink_test, '_send_command') + @patch.object(pjlink_test, 'timer') + @patch.object(pjlink_test, 'socket_timer') + def test_bug_1593883_pjlink_authentication(self, mock_socket_timer, + mock_timer, + mock_send_command, + mock_state, + mock_waitForReadyRead): + """ + Test bugfix 1593883 pjlink authentication + """ + # GIVEN: Test object and data + pjlink = pjlink_test + pjlink_pin = TEST_PIN + mock_state.return_value = pjlink.ConnectedState + mock_waitForReadyRead.return_value = True + + # WHEN: Athenticated connection is called + pjlink.check_login(data=TEST_CONNECT_AUTHENTICATE) + + # THEN: send_command should have the proper authentication + self.assertEquals("{test}".format(test=mock_send_command.call_args_list[0]), + "call(data='{hash}%1CLSS ?\\r')".format(hash=TEST_HASH)) From 8806a06ab9c449ac0142634a69069bc68a497aea Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Fri, 17 Jun 2016 19:45:02 -0700 Subject: [PATCH 49/62] Test cleanups --- openlp/core/common/__init__.py | 8 ++++---- openlp/core/lib/projector/pjlink1.py | 2 +- .../openlp_core_common/test_projector_utilities.py | 4 ++-- .../functional/openlp_core_lib/test_projector_pjlink1.py | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/openlp/core/common/__init__.py b/openlp/core/common/__init__.py index 488fbc63b..a5c86314c 100644 --- a/openlp/core/common/__init__.py +++ b/openlp/core/common/__init__.py @@ -206,9 +206,9 @@ def md5_hash(salt, data=None): """ log.debug('md5_hash(salt="{text}")'.format(text=salt)) hash_obj = hashlib.new('md5') - hash_obj.update(salt.encode('ascii')) + hash_obj.update(salt) if data: - hash_obj.update(data.encode('ascii')) + hash_obj.update(data) hash_value = hash_obj.hexdigest() log.debug('md5_hash() returning "{text}"'.format(text=hash_value)) return hash_value @@ -225,9 +225,9 @@ def qmd5_hash(salt, data=None): """ log.debug('qmd5_hash(salt="{text}"'.format(text=salt)) hash_obj = QHash(QHash.Md5) - hash_obj.addData(salt.encode('ascii')) + hash_obj.addData(salt) if data: - hash_obj.addData(data.encode('ascii')) + hash_obj.addData(data) hash_value = hash_obj.result().toHex() log.debug('qmd5_hash() returning "{hash}"'.format(hash=hash_value)) return hash_value diff --git a/openlp/core/lib/projector/pjlink1.py b/openlp/core/lib/projector/pjlink1.py index 302fc13ee..330e02b73 100644 --- a/openlp/core/lib/projector/pjlink1.py +++ b/openlp/core/lib/projector/pjlink1.py @@ -364,7 +364,7 @@ class PJLink1(QTcpSocket): else: log.debug('({ip}) Setting hash with salt="{data}"'.format(ip=self.ip, data=data_check[2])) log.debug('({ip}) pin="{data}"'.format(ip=self.ip, data=self.pin)) - salt = md5_hash(salt=data_check[2], data=self.pin) + salt = md5_hash(salt=data_check[2].encode('ascii'), data=self.pin.encode('ascii')) else: salt = None # We're connected at this point, so go ahead and do regular I/O diff --git a/tests/functional/openlp_core_common/test_projector_utilities.py b/tests/functional/openlp_core_common/test_projector_utilities.py index aebdd7509..72609956d 100644 --- a/tests/functional/openlp_core_common/test_projector_utilities.py +++ b/tests/functional/openlp_core_common/test_projector_utilities.py @@ -147,7 +147,7 @@ class testProjectorUtilities(TestCase): hash_ = qmd5_hash(salt=salt.encode('ascii'), data=pin.encode('ascii')) # THEN: Validate return has is same - self.assertEquals(hash_.decode('ascii'), test_hash, 'Qt-MD5 should have returned a good hash') + self.assertEquals(hash_, test_hash, 'Qt-MD5 should have returned a good hash') def test_qmd5_hash_bad(self): """ @@ -157,7 +157,7 @@ class testProjectorUtilities(TestCase): hash_ = qmd5_hash(salt=pin.encode('ascii'), data=salt.encode('ascii')) # THEN: return data is different - self.assertNotEquals(hash_.decode('ascii'), test_hash, 'Qt-MD5 should have returned a bad hash') + self.assertNotEquals(hash_, test_hash, 'Qt-MD5 should have returned a bad hash') def test_md5_non_ascii_string(self): """ diff --git a/tests/functional/openlp_core_lib/test_projector_pjlink1.py b/tests/functional/openlp_core_lib/test_projector_pjlink1.py index 1c56e5bec..815b26493 100644 --- a/tests/functional/openlp_core_lib/test_projector_pjlink1.py +++ b/tests/functional/openlp_core_lib/test_projector_pjlink1.py @@ -355,7 +355,7 @@ class TestPJLink(TestCase): pjlink.check_login(data=TEST_CONNECT_AUTHENTICATE) # THEN: No Authentication signal should have been sent - mock_authentication.assert_called_with(pjlink.name, 'projectorAuthentication should have been called') + mock_authentication.emit.assert_called_with(pjlink.name) @patch.object(pjlink_test, 'waitForReadyRead') @patch.object(pjlink_test, 'state') @@ -372,7 +372,7 @@ class TestPJLink(TestCase): """ # GIVEN: Test object and data pjlink = pjlink_test - pjlink_pin = TEST_PIN + pjlink.pin = TEST_PIN mock_state.return_value = pjlink.ConnectedState mock_waitForReadyRead.return_value = True @@ -380,5 +380,5 @@ class TestPJLink(TestCase): pjlink.check_login(data=TEST_CONNECT_AUTHENTICATE) # THEN: send_command should have the proper authentication - self.assertEquals("{test}".format(test=mock_send_command.call_args_list[0]), + self.assertEquals("{test}".format(test=mock_send_command.call_args), "call(data='{hash}%1CLSS ?\\r')".format(hash=TEST_HASH)) From f911bdafa94d8d95c7f6b8602483bf4ac69f8aff Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Sun, 26 Jun 2016 17:08:28 -0700 Subject: [PATCH 50/62] Format fix --- openlp/plugins/presentations/lib/powerpointcontroller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/plugins/presentations/lib/powerpointcontroller.py b/openlp/plugins/presentations/lib/powerpointcontroller.py index ebc394623..ccc519b68 100644 --- a/openlp/plugins/presentations/lib/powerpointcontroller.py +++ b/openlp/plugins/presentations/lib/powerpointcontroller.py @@ -362,7 +362,7 @@ class PowerpointDocument(PresentationDocument): # it is the powerpoint presentation window. (left, top, right, bottom) = win32gui.GetWindowRect(hwnd) window_title = win32gui.GetWindowText(hwnd) - log.debug('window size: left=left:d}, top={top:d}, ' + log.debug('window size: left={left:d}, top={top:d}, ' 'right={right:d}, bottom={bottom:d}'.format(left=left, top=top, right=right, bottom=bottom)) log.debug('compare size: {y:d} and {top:d}, {height:d} and {vertical:d}, ' '{x:d} and {left}, {width:d} and {horizontal:d}'.format(y=size.y(), From 04cb827911d945d401dedc5cc6aee2452c9c47cd Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Mon, 27 Jun 2016 23:19:53 +0200 Subject: [PATCH 51/62] Started work on using pylint for code analysing. --- tests/utils/test_pylint.py | 52 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 tests/utils/test_pylint.py diff --git a/tests/utils/test_pylint.py b/tests/utils/test_pylint.py new file mode 100644 index 000000000..cf09a387a --- /dev/null +++ b/tests/utils/test_pylint.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2016 OpenLP Developers # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### +""" +Package to test for proper bzr tags. +""" +import os +import logging +from unittest import TestCase + +from pylint import epylint as lint +import multiprocessing + +log = logging.getLogger(__name__) + + +class TestPylint(TestCase): + + def test_pylint(self): + """ + Test for pylint errors + """ + # GIVEN: The openlp base folder + path = os.path.normpath(os.path.join(os.path.dirname(__file__), '..', '..', 'openlp')) + + # WHEN: Running pylint + (pylint_stdout, pylint_stderr) = lint.py_run('{path} --disable=all --enable=missing-format-argument-key,unused-format-string-argument -r n -j {cpu_count}'.format(path='openlp', cpu_count=multiprocessing.cpu_count()), return_std=True) + stdout = pylint_stdout.read() + stderr = pylint_stderr.read() + log.debug(stdout) + log.debug(stderr) + + # THEN: The output should be empty + self.assertEqual(stdout, '', 'PyLint should find no errors') From 668f10a14b52131da74e9d198486438cf063778d Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 28 Jun 2016 22:44:50 +0200 Subject: [PATCH 52/62] more pylint --- tests/utils/test_pylint.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/tests/utils/test_pylint.py b/tests/utils/test_pylint.py index cf09a387a..6f98e9a33 100644 --- a/tests/utils/test_pylint.py +++ b/tests/utils/test_pylint.py @@ -27,9 +27,6 @@ import logging from unittest import TestCase from pylint import epylint as lint -import multiprocessing - -log = logging.getLogger(__name__) class TestPylint(TestCase): @@ -39,14 +36,18 @@ class TestPylint(TestCase): Test for pylint errors """ # GIVEN: The openlp base folder - path = os.path.normpath(os.path.join(os.path.dirname(__file__), '..', '..', 'openlp')) + enabled_checks = 'missing-format-argument-key,unused-format-string-argument' + disabled_checks = 'all' - # WHEN: Running pylint - (pylint_stdout, pylint_stderr) = lint.py_run('{path} --disable=all --enable=missing-format-argument-key,unused-format-string-argument -r n -j {cpu_count}'.format(path='openlp', cpu_count=multiprocessing.cpu_count()), return_std=True) + # WHEN: Running pylint + (pylint_stdout, pylint_stderr) = \ + lint.py_run('{path} --disable={disabled} --enable={enabled} --reports=no'.format(path='openlp', + disabled=disabled_checks, + enabled=enabled_checks), + return_std=True) stdout = pylint_stdout.read() stderr = pylint_stderr.read() - log.debug(stdout) - log.debug(stderr) + print(stdout) # THEN: The output should be empty - self.assertEqual(stdout, '', 'PyLint should find no errors') + self.assertTrue(stdout == '', 'PyLint should find no errors') From 1cf078be76b903a72e09f22b15f426ecafe02e98 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Fri, 1 Jul 2016 23:14:24 +0200 Subject: [PATCH 53/62] Add pylintrc file --- pylintrc | 379 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 379 insertions(+) create mode 100644 pylintrc diff --git a/pylintrc b/pylintrc new file mode 100644 index 000000000..367695e13 --- /dev/null +++ b/pylintrc @@ -0,0 +1,379 @@ +[MASTER] + +# Specify a configuration file. +#rcfile= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore=vlc.py + +# Pickle collected data for later comparisons. +persistent=yes + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + +# Use multiple processes to speed up Pylint. +jobs=4 + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code +extension-pkg-whitelist= + +# Allow optimization of some AST trees. This will activate a peephole AST +# optimizer, which will apply various small optimizations. For instance, it can +# be used to obtain the result of joining multiple strings with the addition +# operator. Joining a lot of strings can lead to a maximum recursion error in +# Pylint and this flag can prevent that. It has one side effect, the resulting +# AST will be different than the one from reality. +optimize-ast=no + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED +confidence= + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time. See also the "--disable" option for examples. +#enable= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once).You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use"--disable=all --enable=classes +# --disable=W" +disable=reload-builtin,too-many-locals,no-name-in-module,hex-method,bad-builtin,old-raise-syntax,bad-continuation,reduce-builtin,unicode-builtin,unused-wildcard-import,apply-builtin,no-member,filter-builtin-not-iterating,execfile-builtin,import-star-module-level,input-builtin,duplicate-code,old-division,print-statement,cmp-method,fixme,no-absolute-import,cmp-builtin,no-self-use,too-many-nested-blocks,standarderror-builtin,long-builtin,raising-string,delslice-method,metaclass-assignment,coerce-builtin,old-octal-literal,basestring-builtin,xrange-builtin,line-too-long,suppressed-message,unused-variable,round-builtin,raw_input-builtin,too-many-instance-attributes,unused-argument,next-method-called,oct-method,attribute-defined-outside-init,too-many-public-methods,too-many-statements,logging-format-interpolation,map-builtin-not-iterating,buffer-builtin,parameter-unpacking,range-builtin-not-iterating,intern-builtin,wrong-import-position,coerce-method,useless-suppression,using-cmp-argument,dict-view-method,backtick,old-ne-operator,missing-docstring,setslice-method,access-member-before-definition,long-suffix,too-few-public-methods,file-builtin,zip-builtin-not-iterating,invalid-name,getslice-method,unpacking-in-except,too-many-arguments,dict-iter-method,unichr-builtin,too-many-lines,too-many-branches,wildcard-import,indexing-exception,nonzero-method + + +[REPORTS] + +# Set the output format. Available formats are text, parseable, colorized, msvs +# (visual studio) and html. You can also give a reporter class, eg +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Put messages in a separate file for each module / package specified on the +# command line instead of printing them on stdout. Reports (if any) will be +# written in a file name "pylint_global.[txt|html]". +files-output=no + +# Tells whether to display a full report or only the messages +reports=no + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details +#msg-template= + + +[SPELLING] + +# Spelling dictionary name. Available dictionaries: en_ZA (myspell), en_US +# (myspell), en_GB (myspell), en_AU (myspell), da_DK (myspell), en (aspell), +# en_CA (aspell). +spelling-dict= + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to indicated private dictionary in +# --spelling-private-dict-file option instead of raising a message. +spelling-store-unknown-words=no + + +[SIMILARITIES] + +# Minimum lines number of a similarity. +min-similarity-lines=4 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + + +[LOGGING] + +# Logging modules to check that the string format arguments are in logging +# function parameter format +logging-modules=logging + + +[BASIC] + +# List of builtins function names that should not be used, separated by a comma +bad-functions=map,filter + +# Good variable names which should always be accepted, separated by a comma +good-names=i,j,k,ex,Run,_ + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo,bar,baz,toto,tutu,tata + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Include a hint for the correct naming format with invalid-name +include-naming-hint=no + +# Regular expression matching correct class attribute names +class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Naming hint for class attribute names +class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Regular expression matching correct attribute names +attr-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for attribute names +attr-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct variable names +variable-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for variable names +variable-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct argument names +argument-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for argument names +argument-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct function names +function-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for function names +function-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct method names +method-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for method names +method-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct class names +class-rgx=[A-Z_][a-zA-Z0-9]+$ + +# Naming hint for class names +class-name-hint=[A-Z_][a-zA-Z0-9]+$ + +# Regular expression matching correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Naming hint for module names +module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Regular expression matching correct inline iteration names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Naming hint for inline iteration names +inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ + +# Regular expression matching correct constant names +const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Naming hint for constant names +const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=^_ + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + + +[ELIF] + +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 + + +[FORMAT] + +# Maximum number of characters on a single line. +max-line-length=100 + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + +# List of optional constructs for which whitespace checking is disabled. `dict- +# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. +# `trailing-comma` allows a space between comma and closing bracket: (a, ). +# `empty-line` allows space-only lines. +no-space-check=trailing-comma,dict-separator + +# Maximum number of lines in a module +max-module-lines=1000 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME,XXX,TODO + + +[VARIABLES] + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# A regular expression matching the name of dummy variables (i.e. expectedly +# not used). +dummy-variables-rgx=_$|dummy + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_,_cb + + +[TYPECHECK] + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis. It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# List of classes names for which member attributes should not be checked +# (useful for classes with attributes dynamically set). This supports can work +# with qualified names. +ignored-classes= + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members= + + +[DESIGN] + +# Maximum number of arguments for function / method +max-args=5 + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.* + +# Maximum number of locals for function / method body +max-locals=15 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of branch for function / method body +max-branches=12 + +# Maximum number of statements in function / method body +max-statements=50 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + +# Maximum number of boolean expressions in a if statement +max-bool-expr=5 + + +[IMPORTS] + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=optparse + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + + +[CLASSES] + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__,__new__,setUp + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=mcs + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict,_fields,_replace,_source,_make + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=Exception From 8aa917c89c1a5e406682f3cd2eeb9717f71f4dc4 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Fri, 1 Jul 2016 23:17:20 +0200 Subject: [PATCH 54/62] A bunch of fixes suggested by pylint. --- openlp/core/common/actions.py | 2 +- openlp/core/common/db.py | 5 ++-- openlp/core/common/languagemanager.py | 2 +- openlp/core/common/settings.py | 2 +- openlp/core/common/uistrings.py | 2 +- openlp/core/common/versionchecker.py | 4 +-- openlp/core/lib/__init__.py | 2 +- openlp/core/lib/db.py | 4 +-- openlp/core/lib/htmlbuilder.py | 4 +-- openlp/core/lib/imagemanager.py | 2 +- openlp/core/lib/pluginmanager.py | 1 - openlp/core/lib/projector/db.py | 25 ++++++++--------- openlp/core/lib/projector/pjlink1.py | 28 +++++++++---------- openlp/core/lib/renderer.py | 2 +- openlp/core/lib/serviceitem.py | 2 +- openlp/core/lib/theme.py | 7 ++--- openlp/core/lib/webpagereader.py | 3 +- openlp/core/ui/exceptionform.py | 3 +- openlp/core/ui/firsttimeform.py | 4 +-- openlp/core/ui/formattingtagcontroller.py | 2 +- openlp/core/ui/lib/spelltextedit.py | 2 +- openlp/core/ui/maindisplay.py | 8 +++--- openlp/core/ui/mainwindow.py | 1 - openlp/core/ui/media/__init__.py | 4 +-- openlp/core/ui/media/mediacontroller.py | 5 ++-- openlp/core/ui/media/playertab.py | 4 ++- openlp/core/ui/media/vlcplayer.py | 3 +- openlp/core/ui/media/webkitplayer.py | 4 +-- openlp/core/ui/projector/sourceselectform.py | 14 +++++----- openlp/core/ui/projector/tab.py | 2 +- openlp/core/ui/servicemanager.py | 4 +-- openlp/core/ui/slidecontroller.py | 1 - openlp/core/ui/themeform.py | 4 +-- openlp/core/ui/thememanager.py | 2 +- .../presentations/lib/messagelistener.py | 2 +- .../presentations/lib/pdfcontroller.py | 6 ++-- .../presentations/lib/pptviewcontroller.py | 4 +-- .../presentations/presentationplugin.py | 2 +- .../openlp_core_lib/test_serviceitem.py | 2 -- tests/utils/test_pylint.py | 9 ++++-- 40 files changed, 92 insertions(+), 97 deletions(-) diff --git a/openlp/core/common/actions.py b/openlp/core/common/actions.py index d22ef8fd1..5e5dd2e05 100644 --- a/openlp/core/common/actions.py +++ b/openlp/core/common/actions.py @@ -138,7 +138,7 @@ class CategoryList(object): for category in self.categories: if category.name == key: return category - raise KeyError('Category "{keY}" does not exist.'.format(key=key)) + raise KeyError('Category "{key}" does not exist.'.format(key=key)) def __len__(self): """ diff --git a/openlp/core/common/db.py b/openlp/core/common/db.py index 1e18167ab..1fd7a6521 100644 --- a/openlp/core/common/db.py +++ b/openlp/core/common/db.py @@ -22,11 +22,12 @@ """ The :mod:`db` module provides helper functions for database related methods. """ -import sqlalchemy import logging - from copy import deepcopy +import sqlalchemy + + log = logging.getLogger(__name__) diff --git a/openlp/core/common/languagemanager.py b/openlp/core/common/languagemanager.py index 58262ffb5..099e84af6 100644 --- a/openlp/core/common/languagemanager.py +++ b/openlp/core/common/languagemanager.py @@ -168,7 +168,7 @@ def format_time(text, local_time): """ return local_time.strftime(match.group()) - return re.sub('\%[a-zA-Z]', match_formatting, text) + return re.sub(r'\%[a-zA-Z]', match_formatting, text) def get_locale_key(string): diff --git a/openlp/core/common/settings.py b/openlp/core/common/settings.py index d4e114c74..a812e856b 100644 --- a/openlp/core/common/settings.py +++ b/openlp/core/common/settings.py @@ -26,7 +26,7 @@ import datetime import logging import os -from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt5 import QtCore, QtGui from openlp.core.common import ThemeLevel, SlideLimits, UiStrings, is_win, is_linux diff --git a/openlp/core/common/uistrings.py b/openlp/core/common/uistrings.py index 91db10fcf..dccc3bdb4 100644 --- a/openlp/core/common/uistrings.py +++ b/openlp/core/common/uistrings.py @@ -68,7 +68,7 @@ class UiStrings(object): self.Default = translate('OpenLP.Ui', 'Default') self.DefaultColor = translate('OpenLP.Ui', 'Default Color:') self.DefaultServiceName = translate('OpenLP.Ui', 'Service %Y-%m-%d %H-%M', - 'This may not contain any of the following characters: /\\?*|<>\[\]":+\n' + 'This may not contain any of the following characters: /\\?*|<>[]":+\n' 'See http://docs.python.org/library/datetime' '.html#strftime-strptime-behavior for more information.') self.Delete = translate('OpenLP.Ui', '&Delete') diff --git a/openlp/core/common/versionchecker.py b/openlp/core/common/versionchecker.py index fb706968b..25479884f 100644 --- a/openlp/core/common/versionchecker.py +++ b/openlp/core/common/versionchecker.py @@ -10,10 +10,10 @@ from datetime import datetime from distutils.version import LooseVersion from subprocess import Popen, PIPE -from openlp.core.common import AppLocation, Settings - from PyQt5 import QtCore +from openlp.core.common import AppLocation, Settings + log = logging.getLogger(__name__) APPLICATION_VERSION = {} diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index a7e01bd24..fed6df05c 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -95,7 +95,7 @@ def get_text_file_string(text_file): content = None try: file_handle = open(text_file, 'r', encoding='utf-8') - if not file_handle.read(3) == '\xEF\xBB\xBF': + if file_handle.read(3) != '\xEF\xBB\xBF': # no BOM was found file_handle.seek(0) content = file_handle.read() diff --git a/openlp/core/lib/db.py b/openlp/core/lib/db.py index 3decb0a3b..d77432181 100644 --- a/openlp/core/lib/db.py +++ b/openlp/core/lib/db.py @@ -178,9 +178,9 @@ def upgrade_db(url, upgrade): version_meta = Metadata.populate(key='version', value=int(upgrade.__version__)) session.commit() upgrade_version = upgrade.__version__ - version_meta = int(version_meta.value) + version = int(version_meta.value) session.close() - return version_meta, upgrade_version + return version, upgrade_version def delete_database(plugin_name, db_file_name=None): diff --git a/openlp/core/lib/htmlbuilder.py b/openlp/core/lib/htmlbuilder.py index 6f2fee68c..456925d5a 100644 --- a/openlp/core/lib/htmlbuilder.py +++ b/openlp/core/lib/htmlbuilder.py @@ -389,8 +389,8 @@ is the function which has to be called from outside. The generated and returned """ import logging -from PyQt5 import QtWebKit from string import Template +from PyQt5 import QtWebKit from openlp.core.common import Settings from openlp.core.lib.theme import BackgroundType, BackgroundGradientType, VerticalType, HorizontalType @@ -647,7 +647,7 @@ def webkit_version(): webkit_ver = float(QtWebKit.qWebKitVersion()) log.debug('Webkit version = {version}'.format(version=webkit_ver)) except AttributeError: - webkit_ver = 0 + webkit_ver = 0.0 return webkit_ver diff --git a/openlp/core/lib/imagemanager.py b/openlp/core/lib/imagemanager.py index 1c25fca25..7e0cd3212 100644 --- a/openlp/core/lib/imagemanager.py +++ b/openlp/core/lib/imagemanager.py @@ -272,7 +272,7 @@ class ImageManager(QtCore.QObject): Add image to cache if it is not already there. """ log.debug('add_image {path}'.format(path=path)) - if not (path, source, width, height) in self._cache: + if (path, source, width, height) not in self._cache: image = Image(path, source, background, width, height) self._cache[(path, source, width, height)] = image self._conversion_queue.put((image.priority, image.secondary_priority, image)) diff --git a/openlp/core/lib/pluginmanager.py b/openlp/core/lib/pluginmanager.py index 4eb4c2f01..98f49a2c6 100644 --- a/openlp/core/lib/pluginmanager.py +++ b/openlp/core/lib/pluginmanager.py @@ -23,7 +23,6 @@ Provide plugin management """ import os -import sys import imp from openlp.core.lib import Plugin, PluginStatus diff --git a/openlp/core/lib/projector/db.py b/openlp/core/lib/projector/db.py index 98778e695..9d223b0e1 100644 --- a/openlp/core/lib/projector/db.py +++ b/openlp/core/lib/projector/db.py @@ -40,13 +40,12 @@ log.debug('projector.lib.db module loaded') from sqlalchemy import Column, ForeignKey, Integer, MetaData, String, and_ from sqlalchemy.ext.declarative import declarative_base, declared_attr -from sqlalchemy.orm import backref, relationship +from sqlalchemy.orm import relationship from openlp.core.lib.db import Manager, init_db, init_url from openlp.core.lib.projector.constants import PJLINK_DEFAULT_CODES -metadata = MetaData() -Base = declarative_base(metadata) +Base = declarative_base(MetaData()) class CommonBase(object): @@ -54,8 +53,8 @@ class CommonBase(object): Base class to automate table name and ID column. """ @declared_attr - def __tablename__(cls): - return cls.__name__.lower() + def __tablename__(self): + return self.__name__.lower() id = Column(Integer, primary_key=True) @@ -257,7 +256,7 @@ class ProjectorDB(Manager): projector = self.get_object_filtered(Projector, Projector.id == dbid) if projector is None: # Not found - log.warn('get_projector_by_id() did not find {data}'.format(data=id)) + log.warning('get_projector_by_id() did not find {data}'.format(data=id)) return None log.debug('get_projectorby_id() returning 1 entry for "{entry}" id="{data}"'.format(entry=dbid, data=projector.id)) @@ -290,7 +289,7 @@ class ProjectorDB(Manager): projector = self.get_object_filtered(Projector, Projector.ip == ip) if projector is None: # Not found - log.warn('get_projector_by_ip() did not find {ip}'.format(ip=ip)) + log.warning('get_projector_by_ip() did not find {ip}'.format(ip=ip)) return None log.debug('get_projectorby_ip() returning 1 entry for "{ip}" id="{data}"'.format(ip=ip, data=projector.id)) @@ -307,7 +306,7 @@ class ProjectorDB(Manager): projector = self.get_object_filtered(Projector, Projector.name == name) if projector is None: # Not found - log.warn('get_projector_by_name() did not find "{name}"'.format(name=name)) + log.warning('get_projector_by_name() did not find "{name}"'.format(name=name)) return None log.debug('get_projector_by_name() returning one entry for "{name}" id="{data}"'.format(name=name, data=projector.id)) @@ -324,7 +323,7 @@ class ProjectorDB(Manager): """ old_projector = self.get_object_filtered(Projector, Projector.ip == projector.ip) if old_projector is not None: - log.warn('add_new() skipping entry ip="{ip}" (Already saved)'.format(ip=old_projector.ip)) + log.warning('add_new() skipping entry ip="{ip}" (Already saved)'.format(ip=old_projector.ip)) return False log.debug('add_new() saving new entry') log.debug('ip="{ip}", name="{name}", location="{location}"'.format(ip=projector.ip, @@ -408,10 +407,10 @@ class ProjectorDB(Manager): :param source: ProjectorSource id :returns: ProjetorSource instance or None """ - source_entry = self.get_object_filtered(ProjetorSource, ProjectorSource.id == source) + source_entry = self.get_object_filtered(ProjectorSource, ProjectorSource.id == source) if source_entry is None: # Not found - log.warn('get_source_by_id() did not find "{source}"'.format(source=source)) + log.warning('get_source_by_id() did not find "{source}"'.format(source=source)) return None log.debug('get_source_by_id() returning one entry for "{source}""'.format(source=source)) return source_entry @@ -430,8 +429,8 @@ class ProjectorDB(Manager): if source_entry is None: # Not found - log.warn('get_source_by_id() not found') - log.warn('code="{code}" projector_id="{data}"'.format(code=code, data=projector_id)) + log.warning('get_source_by_id() not found') + log.warning('code="{code}" projector_id="{data}"'.format(code=code, data=projector_id)) return None log.debug('get_source_by_id() returning one entry') log.debug('code="{code}" projector_id="{data}"'.format(code=code, data=projector_id)) diff --git a/openlp/core/lib/projector/pjlink1.py b/openlp/core/lib/projector/pjlink1.py index ce06b3625..834b589d8 100644 --- a/openlp/core/lib/projector/pjlink1.py +++ b/openlp/core/lib/projector/pjlink1.py @@ -310,10 +310,10 @@ class PJLink1(QTcpSocket): read = self.readLine(self.maxSize) dontcare = self.readLine(self.maxSize) # Clean out the trailing \r\n if read is None: - log.warn('({ip}) read is None - socket error?'.format(ip=self.ip)) + log.warning('({ip}) read is None - socket error?'.format(ip=self.ip)) return elif len(read) < 8: - log.warn('({ip}) Not enough data read)'.format(ip=self.ip)) + log.warning('({ip}) Not enough data read)'.format(ip=self.ip)) return data = decode(read, 'ascii') # Possibility of extraneous data on input when reading. @@ -402,7 +402,7 @@ class PJLink1(QTcpSocket): self.projectorReceivedData.emit() return elif '=' not in data: - log.warn('({ip}) get_data(): Invalid packet received'.format(ip=self.ip)) + log.warning('({ip}) get_data(): Invalid packet received'.format(ip=self.ip)) self.send_busy = False self.projectorReceivedData.emit() return @@ -410,15 +410,15 @@ class PJLink1(QTcpSocket): try: (prefix, class_, cmd, data) = (data_split[0][0], data_split[0][1], data_split[0][2:], data_split[1]) except ValueError as e: - log.warn('({ip}) get_data(): Invalid packet - expected header + command + data'.format(ip=self.ip)) - log.warn('({ip}) get_data(): Received data: "{data}"'.format(ip=self.ip, data=data_in.strip())) + log.warning('({ip}) get_data(): Invalid packet - expected header + command + data'.format(ip=self.ip)) + log.warning('({ip}) get_data(): Received data: "{data}"'.format(ip=self.ip, data=data_in.strip())) self.change_status(E_INVALID_DATA) self.send_busy = False self.projectorReceivedData.emit() return if not (self.pjlink_class in PJLINK_VALID_CMD and cmd in PJLINK_VALID_CMD[self.pjlink_class]): - log.warn('({ip}) get_data(): Invalid packet - unknown command "{data}"'.format(ip=self.ip, data=cmd)) + log.warning('({ip}) get_data(): Invalid packet - unknown command "{data}"'.format(ip=self.ip, data=cmd)) self.send_busy = False self.projectorReceivedData.emit() return @@ -461,7 +461,7 @@ class PJLink1(QTcpSocket): :param queue: Option to force add to queue rather than sending directly """ if self.state() != self.ConnectedState: - log.warn('({ip}) send_command(): Not connected - returning'.format(ip=self.ip)) + log.warning('({ip}) send_command(): Not connected - returning'.format(ip=self.ip)) self.send_queue = [] return self.projectorNetwork.emit(S_NETWORK_SENDING) @@ -577,7 +577,7 @@ class PJLink1(QTcpSocket): if cmd in self.PJLINK1_FUNC: self.PJLINK1_FUNC[cmd](data) else: - log.warn('({ip}) Invalid command {data}'.format(ip=self.ip, data=cmd)) + log.warning('({ip}) Invalid command {data}'.format(ip=self.ip, data=cmd)) self.send_busy = False self.projectorReceivedData.emit() @@ -596,7 +596,7 @@ class PJLink1(QTcpSocket): fill = {'Hours': int(data_dict[0]), 'On': False if data_dict[1] == '0' else True} except ValueError: # In case of invalid entry - log.warn('({ip}) process_lamp(): Invalid data "{data}"'.format(ip=self.ip, data=data)) + log.warning('({ip}) process_lamp(): Invalid data "{data}"'.format(ip=self.ip, data=data)) return lamps.append(fill) data_dict.pop(0) # Remove lamp hours @@ -623,7 +623,7 @@ class PJLink1(QTcpSocket): self.send_command('INST') else: # Log unknown status response - log.warn('({ip}) Unknown power response: {data}'.format(ip=self.ip, data=data)) + log.warning('({ip}) Unknown power response: {data}'.format(ip=self.ip, data=data)) return def process_avmt(self, data): @@ -648,7 +648,7 @@ class PJLink1(QTcpSocket): shutter = True mute = True else: - log.warn('({ip}) Unknown shutter response: {data}'.format(ip=self.ip, data=data)) + log.warning('({ip}) Unknown shutter response: {data}'.format(ip=self.ip, data=data)) update_icons = shutter != self.shutter update_icons = update_icons or mute != self.mute self.shutter = shutter @@ -797,7 +797,7 @@ class PJLink1(QTcpSocket): Initiate connection to projector. """ if self.state() == self.ConnectedState: - log.warn('({ip}) connect_to_host(): Already connected - returning'.format(ip=self.ip)) + log.warning('({ip}) connect_to_host(): Already connected - returning'.format(ip=self.ip)) return self.change_status(S_CONNECTING) self.connectToHost(self.ip, self.port if type(self.port) is int else int(self.port)) @@ -809,9 +809,9 @@ class PJLink1(QTcpSocket): """ if abort or self.state() != self.ConnectedState: if abort: - log.warn('({ip}) disconnect_from_host(): Aborting connection'.format(ip=self.ip)) + log.warning('({ip}) disconnect_from_host(): Aborting connection'.format(ip=self.ip)) else: - log.warn('({ip}) disconnect_from_host(): Not connected - returning'.format(ip=self.ip)) + log.warning('({ip}) disconnect_from_host(): Not connected - returning'.format(ip=self.ip)) self.reset_information() self.disconnectFromHost() try: diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 0d233a9c4..48d1cd05b 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -531,7 +531,7 @@ def words_split(line): :param line: Line to be split """ # this parse we are to be wordy - return re.split('\s+', line) + return re.split(r'\s+', line) def get_start_tags(raw_text): diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index c0a819390..1344bfeea 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -34,7 +34,7 @@ import ntpath from PyQt5 import QtGui from openlp.core.common import RegistryProperties, Settings, translate, AppLocation, md5_hash -from openlp.core.lib import ImageSource, build_icon, clean_tags, expand_tags, create_thumb +from openlp.core.lib import ImageSource, build_icon, clean_tags, expand_tags log = logging.getLogger(__name__) diff --git a/openlp/core/lib/theme.py b/openlp/core/lib/theme.py index 4e84d353b..e24613aa6 100644 --- a/openlp/core/lib/theme.py +++ b/openlp/core/lib/theme.py @@ -23,7 +23,6 @@ Provide the theme XML and handling functions for OpenLP v2 themes. """ import os -import re import logging import json @@ -477,12 +476,12 @@ class ThemeXML(object): if element == 'weight': element = 'bold' if value == 'Normal': - value = False + ret_value = False else: - value = True + ret_value = True if element == 'proportion': element = 'size' - return False, master, element, value + return False, master, element, ret_value def _create_attr(self, master, element, value): """ diff --git a/openlp/core/lib/webpagereader.py b/openlp/core/lib/webpagereader.py index 260ef1556..52c98bbaf 100644 --- a/openlp/core/lib/webpagereader.py +++ b/openlp/core/lib/webpagereader.py @@ -179,5 +179,4 @@ def get_web_page(url, header=None, update_openlp=False): return page -__all__ = ['get_application_version', 'check_latest_version', - 'get_web_page'] +__all__ = ['get_web_page'] diff --git a/openlp/core/ui/exceptionform.py b/openlp/core/ui/exceptionform.py index 216780584..7e97cb796 100644 --- a/openlp/core/ui/exceptionform.py +++ b/openlp/core/ui/exceptionform.py @@ -32,8 +32,6 @@ import sqlalchemy from PyQt5 import Qt, QtCore, QtGui, QtWebKit, QtWidgets from lxml import etree -from openlp.core.common import RegistryProperties, is_linux - try: import migrate MIGRATE_VERSION = getattr(migrate, '__version__', '< 0.7') @@ -74,6 +72,7 @@ except ImportError: from openlp.core.common import Settings, UiStrings, translate from openlp.core.common.versionchecker import get_application_version +from openlp.core.common import RegistryProperties, is_linux from .exceptiondialog import Ui_ExceptionDialog diff --git a/openlp/core/ui/firsttimeform.py b/openlp/core/ui/firsttimeform.py index 9ae2e0898..a0eec54a4 100644 --- a/openlp/core/ui/firsttimeform.py +++ b/openlp/core/ui/firsttimeform.py @@ -666,14 +666,14 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties): if missed_files: file_list = '' for entry in missed_files: - file_list += '{text}
'.format(text=entry) + file_list += '{text}
'.format(text=entry) msg = QtWidgets.QMessageBox() msg.setIcon(QtWidgets.QMessageBox.Warning) msg.setWindowTitle(translate('OpenLP.FirstTimeWizard', 'Network Error')) msg.setText(translate('OpenLP.FirstTimeWizard', 'Unable to download some files')) msg.setInformativeText(translate('OpenLP.FirstTimeWizard', 'The following files were not able to be ' - 'downloaded:
{text}'.format(text=file_list))) + 'downloaded:
{text}'.format(text=file_list))) msg.setStandardButtons(msg.Ok) ans = msg.exec() return True diff --git a/openlp/core/ui/formattingtagcontroller.py b/openlp/core/ui/formattingtagcontroller.py index 161930cb6..5a0511842 100644 --- a/openlp/core/ui/formattingtagcontroller.py +++ b/openlp/core/ui/formattingtagcontroller.py @@ -84,7 +84,7 @@ class FormattingTagController(object): 'desc': desc, 'start tag': '{{{tag}}}'.format(tag=tag), 'start html': start_html, - 'end tag': '{/{tag}}}'.format(tag=tag), + 'end tag': '{{{tag}}}'.format(tag=tag), 'end html': end_html, 'protected': False, 'temporary': False diff --git a/openlp/core/ui/lib/spelltextedit.py b/openlp/core/ui/lib/spelltextedit.py index 8b6b552be..5fd983128 100644 --- a/openlp/core/ui/lib/spelltextedit.py +++ b/openlp/core/ui/lib/spelltextedit.py @@ -164,7 +164,7 @@ class Highlighter(QtGui.QSyntaxHighlighter): """ Provides a text highlighter for pointing out spelling errors in text. """ - WORDS = '(?iu)[\w\']+' + WORDS = r'(?iu)[\w\']+' def __init__(self, *args): """ diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index 00f4be7ca..ff5acb975 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -33,7 +33,7 @@ import html import logging import os -from PyQt5 import QtCore, QtWidgets, QtWebKit, QtWebKitWidgets, QtOpenGL, QtGui, QtMultimedia +from PyQt5 import QtCore, QtWidgets, QtWebKit, QtWebKitWidgets, QtGui, QtMultimedia from openlp.core.common import AppLocation, Registry, RegistryProperties, OpenLPMixin, Settings, translate,\ is_macosx, is_win @@ -468,9 +468,9 @@ class MainDisplay(OpenLPMixin, Display, RegistryProperties): self.service_item.theme_data.background_filename, ImageSource.Theme) if image_path: image_bytes = self.image_manager.get_image_bytes(image_path, ImageSource.ImagePlugin) - html = build_html(self.service_item, self.screen, self.is_live, background, image_bytes, - plugins=self.plugin_manager.plugins) - self.web_view.setHtml(html) + created_html = build_html(self.service_item, self.screen, self.is_live, background, image_bytes, + plugins=self.plugin_manager.plugins) + self.web_view.setHtml(created_html) if service_item.foot_text: self.footer(service_item.foot_text) # if was hidden keep it hidden diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index ccd12727c..63048eac5 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -46,7 +46,6 @@ from openlp.core.ui.firsttimeform import FirstTimeForm from openlp.core.ui.media import MediaController from openlp.core.ui.printserviceform import PrintServiceForm from openlp.core.ui.projector.manager import ProjectorManager -from openlp.core.ui.lib.toolbar import OpenLPToolbar from openlp.core.ui.lib.dockwidget import OpenLPDockWidget from openlp.core.ui.lib.mediadockmanager import MediaDockManager diff --git a/openlp/core/ui/media/__init__.py b/openlp/core/ui/media/__init__.py index 248aca6f2..b51391583 100644 --- a/openlp/core/ui/media/__init__.py +++ b/openlp/core/ui/media/__init__.py @@ -24,10 +24,10 @@ The :mod:`~openlp.core.ui.media` module contains classes and objects for media p """ import logging -from openlp.core.common import Settings - from PyQt5 import QtCore +from openlp.core.common import Settings + log = logging.getLogger(__name__ + '.__init__') diff --git a/openlp/core/ui/media/mediacontroller.py b/openlp/core/ui/media/mediacontroller.py index 021ea5281..d404ee02e 100644 --- a/openlp/core/ui/media/mediacontroller.py +++ b/openlp/core/ui/media/mediacontroller.py @@ -38,7 +38,6 @@ from openlp.core.ui.media.mediaplayer import MediaPlayer from openlp.core.ui.media import MediaState, MediaInfo, MediaType, get_media_players, set_media_players,\ parse_optical_path from openlp.core.ui.lib.toolbar import OpenLPToolbar -from openlp.core.ui.lib.dockwidget import OpenLPDockWidget log = logging.getLogger(__name__) @@ -175,7 +174,7 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties): log.debug('_check_available_media_players') controller_dir = os.path.join(AppLocation.get_directory(AppLocation.AppDir), 'core', 'ui', 'media') for filename in os.listdir(controller_dir): - if filename.endswith('player.py') and not filename == 'mediaplayer.py': + if filename.endswith('player.py') and filename != 'mediaplayer.py': path = os.path.join(controller_dir, filename) if os.path.isfile(path): module_name = 'openlp.core.ui.media.' + os.path.splitext(filename)[0] @@ -554,7 +553,7 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties): default_player = [used_players[0]] if service_item.processor and service_item.processor != UiStrings().Automatic: # check to see if the player is usable else use the default one. - if not service_item.processor.lower() in used_players: + if service_item.processor.lower() not in used_players: used_players = default_player else: used_players = [service_item.processor.lower()] diff --git a/openlp/core/ui/media/playertab.py b/openlp/core/ui/media/playertab.py index 1fca21450..c76fc3300 100644 --- a/openlp/core/ui/media/playertab.py +++ b/openlp/core/ui/media/playertab.py @@ -224,9 +224,11 @@ class PlayerTab(SettingsTab): self.settings_form.register_post_process('mediaitem_media_rebuild') self.settings_form.register_post_process('config_screen_changed') - def post_set_up(self): + def post_set_up(self, post_update=False): """ Late setup for players as the MediaController has to be initialised first. + + :param post_update: Indicates if called before or after updates. """ for key, player in self.media_players.items(): player = self.media_players[key] diff --git a/openlp/core/ui/media/vlcplayer.py b/openlp/core/ui/media/vlcplayer.py index 9c2110e22..48b0602fe 100644 --- a/openlp/core/ui/media/vlcplayer.py +++ b/openlp/core/ui/media/vlcplayer.py @@ -112,7 +112,6 @@ def get_vlc(): # This needs to happen on module load and not in get_vlc(), otherwise it can cause crashes on some DE on some setups # (reported on Gnome3, Unity, Cinnamon, all GTK+ based) when using native filedialogs... if is_linux() and 'nose' not in sys.argv[0] and get_vlc(): - import ctypes try: try: x11 = ctypes.cdll.LoadLibrary('libX11.so.6') @@ -233,7 +232,7 @@ class VlcPlayer(MediaPlayer): """ vlc = get_vlc() start = datetime.now() - while not media_state == display.vlc_media.get_state(): + while media_state != display.vlc_media.get_state(): if display.vlc_media.get_state() == vlc.State.Error: return False self.application.process_events() diff --git a/openlp/core/ui/media/webkitplayer.py b/openlp/core/ui/media/webkitplayer.py index 19221ace0..5cd982951 100644 --- a/openlp/core/ui/media/webkitplayer.py +++ b/openlp/core/ui/media/webkitplayer.py @@ -22,10 +22,10 @@ """ The :mod:`~openlp.core.ui.media.webkit` module contains our WebKit video player """ -from PyQt5 import QtGui, QtWebKitWidgets - import logging +from PyQt5 import QtGui, QtWebKitWidgets + from openlp.core.common import Settings from openlp.core.lib import translate from openlp.core.ui.media import MediaState diff --git a/openlp/core/ui/projector/sourceselectform.py b/openlp/core/ui/projector/sourceselectform.py index 7d73f6a5a..5ee1ac403 100644 --- a/openlp/core/ui/projector/sourceselectform.py +++ b/openlp/core/ui/projector/sourceselectform.py @@ -141,23 +141,23 @@ def Build_Tab(group, source_key, default, projector, projectordb, edit=False): return widget, button_count, buttonchecked -def set_button_tooltip(bar): +def set_button_tooltip(button_bar): """ Set the toolip for the standard buttons used - :param bar: QDialogButtonBar instance to update + :param button_bar: QDialogButtonBar instance to update """ - for button in bar.buttons(): - if bar.standardButton(button) == QDialogButtonBox.Cancel: + for button in button_bar.buttons(): + if button_bar.standardButton(button) == QDialogButtonBox.Cancel: button.setToolTip(translate('OpenLP.SourceSelectForm', 'Ignoring current changes and return to OpenLP')) - elif bar.standardButton(button) == QDialogButtonBox.Reset: + elif button_bar.standardButton(button) == QDialogButtonBox.Reset: button.setToolTip(translate('OpenLP.SourceSelectForm', 'Delete all user-defined text and revert to PJLink default text')) - elif bar.standardButton(button) == QDialogButtonBox.Discard: + elif button_bar.standardButton(button) == QDialogButtonBox.Discard: button.setToolTip(translate('OpenLP.SourceSelectForm', 'Discard changes and reset to previous user-defined text')) - elif bar.standardButton(button) == QDialogButtonBox.Ok: + elif button_bar.standardButton(button) == QDialogButtonBox.Ok: button.setToolTip(translate('OpenLP.SourceSelectForm', 'Save changes and return to OpenLP')) else: diff --git a/openlp/core/ui/projector/tab.py b/openlp/core/ui/projector/tab.py index 1b87209c0..ff4bdee17 100644 --- a/openlp/core/ui/projector/tab.py +++ b/openlp/core/ui/projector/tab.py @@ -133,7 +133,7 @@ class ProjectorTab(SettingsTab): settings.setValue('socket timeout', self.socket_timeout_spin_box.value()) settings.setValue('poll time', self.socket_poll_spin_box.value()) settings.setValue('source dialog type', self.dialog_type_combo_box.currentIndex()) - settings.endGroup + settings.endGroup() def on_dialog_type_combo_box_changed(self): self.dialog_type = self.dialog_type_combo_box.currentIndex() diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 907cb49a6..aa31dfbf8 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -774,7 +774,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa else: critical_error_message_box(message=translate('OpenLP.ServiceManager', 'File is not a valid service.')) self.log_error('File contains no service data') - except (IOError, NameError, zipfile.BadZipfile): + except (IOError, NameError): self.log_exception('Problem loading service file {name}'.format(name=file_name)) critical_error_message_box(message=translate('OpenLP.ServiceManager', 'File could not be opened because it is corrupt.')) @@ -1327,7 +1327,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa """ The theme may have changed in the settings dialog so make sure the theme combo box is in the correct state. """ - visible = not self.renderer.theme_level == ThemeLevel.Global + visible = self.renderer.theme_level != ThemeLevel.Global self.toolbar.actions['theme_combo_box'].setVisible(visible) self.toolbar.actions['theme_label'].setVisible(visible) self.regenerate_service_items() diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 9379bb96f..8b5ce5e34 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -37,7 +37,6 @@ from openlp.core.lib import ItemCapabilities, ServiceItem, ImageSource, ServiceI build_html from openlp.core.lib.ui import create_action from openlp.core.ui.lib.toolbar import OpenLPToolbar -from openlp.core.ui.lib.dockwidget import OpenLPDockWidget from openlp.core.ui.lib.listpreviewwidget import ListPreviewWidget from openlp.core.ui import HideMode, MainDisplay, Display, DisplayControllerType diff --git a/openlp/core/ui/themeform.py b/openlp/core/ui/themeform.py index 475bfc0b7..a0ab5f45b 100644 --- a/openlp/core/ui/themeform.py +++ b/openlp/core/ui/themeform.py @@ -249,7 +249,7 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties): NOTE the font_main_override is the inverse of the check box value """ if self.update_theme_allowed: - self.theme.font_main_override = not (value == QtCore.Qt.Checked) + self.theme.font_main_override = (value != QtCore.Qt.Checked) def on_footer_position_check_box_state_changed(self, value): """ @@ -257,7 +257,7 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties): NOTE the font_footer_override is the inverse of the check box value """ if self.update_theme_allowed: - self.theme.font_footer_override = not (value == QtCore.Qt.Checked) + self.theme.font_footer_override = (value != QtCore.Qt.Checked) def exec(self, edit=False): """ diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index 70ca9fd88..341a8061e 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -583,7 +583,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage out_file.write(theme_zip.read(name)) out_file.close() except (IOError, zipfile.BadZipfile): - self.log_exception('Importing theme from zip failed {name|'.format(name=file_name)) + self.log_exception('Importing theme from zip failed {name}'.format(name=file_name)) raise ValidationError except ValidationError: critical_error_message_box(translate('OpenLP.ThemeManager', 'Validation Error'), diff --git a/openlp/plugins/presentations/lib/messagelistener.py b/openlp/plugins/presentations/lib/messagelistener.py index 992ba9b5c..097b9dc38 100644 --- a/openlp/plugins/presentations/lib/messagelistener.py +++ b/openlp/plugins/presentations/lib/messagelistener.py @@ -28,7 +28,7 @@ from PyQt5 import QtCore from openlp.core.common import Registry from openlp.core.ui import HideMode -from openlp.core.lib import ServiceItemContext, ServiceItem +from openlp.core.lib import ServiceItemContext from openlp.plugins.presentations.lib.pdfcontroller import PDF_CONTROLLER_FILETYPES log = logging.getLogger(__name__) diff --git a/openlp/plugins/presentations/lib/pdfcontroller.py b/openlp/plugins/presentations/lib/pdfcontroller.py index dd67031bd..6045d5326 100644 --- a/openlp/plugins/presentations/lib/pdfcontroller.py +++ b/openlp/plugins/presentations/lib/pdfcontroller.py @@ -80,7 +80,7 @@ class PdfController(PresentationController): found_mutool = re.search('usage: mutool.*', decoded_line, re.IGNORECASE) if found_mutool: # Test that mutool contains mudraw - if re.search('draw\s+--\s+convert document.*', runlog.decode(), re.IGNORECASE | re.MULTILINE): + if re.search(r'draw\s+--\s+convert document.*', runlog.decode(), re.IGNORECASE | re.MULTILINE): program_type = 'mutool' break found_gs = re.search('GPL Ghostscript.*', decoded_line, re.IGNORECASE) @@ -215,8 +215,8 @@ class PdfDocument(PresentationDocument): height = 0.0 for line in runlog.splitlines(): try: - width = float(re.search('.*Size: x: (\d+\.?\d*), y: \d+.*', line.decode()).group(1)) - height = float(re.search('.*Size: x: \d+\.?\d*, y: (\d+\.?\d*).*', line.decode()).group(1)) + width = float(re.search(r'.*Size: x: (\d+\.?\d*), y: \d+.*', line.decode()).group(1)) + height = float(re.search(r'.*Size: x: \d+\.?\d*, y: (\d+\.?\d*).*', line.decode()).group(1)) break except AttributeError: continue diff --git a/openlp/plugins/presentations/lib/pptviewcontroller.py b/openlp/plugins/presentations/lib/pptviewcontroller.py index 54d8f5170..43eb69454 100644 --- a/openlp/plugins/presentations/lib/pptviewcontroller.py +++ b/openlp/plugins/presentations/lib/pptviewcontroller.py @@ -181,13 +181,13 @@ class PptviewDocument(PresentationDocument): index = -1 list_to_add = None # check if it is a slide - match = re.search("slides/slide(.+)\.xml", zip_info.filename) + match = re.search(r'slides/slide(.+)\.xml', zip_info.filename) if match: index = int(match.group(1)) - 1 node_type = 'ctrTitle' list_to_add = titles # or a note - match = re.search("notesSlides/notesSlide(.+)\.xml", zip_info.filename) + match = re.search(r'notesSlides/notesSlide(.+)\.xml', zip_info.filename) if match: index = int(match.group(1)) - 1 node_type = 'body' diff --git a/openlp/plugins/presentations/presentationplugin.py b/openlp/plugins/presentations/presentationplugin.py index dc0614086..ca0ecba82 100644 --- a/openlp/plugins/presentations/presentationplugin.py +++ b/openlp/plugins/presentations/presentationplugin.py @@ -124,7 +124,7 @@ class PresentationPlugin(Plugin): log.debug('check_pre_conditions') controller_dir = os.path.join(AppLocation.get_directory(AppLocation.PluginsDir), 'presentations', 'lib') for filename in os.listdir(controller_dir): - if filename.endswith('controller.py') and not filename == 'presentationcontroller.py': + if filename.endswith('controller.py') and filename != 'presentationcontroller.py': path = os.path.join(controller_dir, filename) if os.path.isfile(path): module_name = 'openlp.plugins.presentations.lib.' + os.path.splitext(filename)[0] diff --git a/tests/functional/openlp_core_lib/test_serviceitem.py b/tests/functional/openlp_core_lib/test_serviceitem.py index e1c73b3ca..d18a4d049 100644 --- a/tests/functional/openlp_core_lib/test_serviceitem.py +++ b/tests/functional/openlp_core_lib/test_serviceitem.py @@ -112,7 +112,6 @@ class TestServiceItem(TestCase): # WHEN: adding an image from a saved Service and mocked exists line = convert_file_service_item(TEST_PATH, 'serviceitem_image_1.osj') with patch('openlp.core.ui.servicemanager.os.path.exists') as mocked_exists,\ - patch('openlp.core.lib.serviceitem.create_thumb') as mocked_create_thumb,\ patch('openlp.core.lib.serviceitem.AppLocation.get_section_data_path') as \ mocked_get_section_data_path: mocked_exists.return_value = True @@ -164,7 +163,6 @@ class TestServiceItem(TestCase): line2 = convert_file_service_item(TEST_PATH, 'serviceitem_image_2.osj', 1) with patch('openlp.core.ui.servicemanager.os.path.exists') as mocked_exists, \ - patch('openlp.core.lib.serviceitem.create_thumb') as mocked_create_thumb, \ patch('openlp.core.lib.serviceitem.AppLocation.get_section_data_path') as \ mocked_get_section_data_path: mocked_exists.return_value = True diff --git a/tests/utils/test_pylint.py b/tests/utils/test_pylint.py index 6f98e9a33..6db43464e 100644 --- a/tests/utils/test_pylint.py +++ b/tests/utils/test_pylint.py @@ -27,6 +27,7 @@ import logging from unittest import TestCase from pylint import epylint as lint +from pylint.__pkginfo__ import pylint_version class TestPylint(TestCase): @@ -37,17 +38,19 @@ class TestPylint(TestCase): """ # GIVEN: The openlp base folder enabled_checks = 'missing-format-argument-key,unused-format-string-argument' - disabled_checks = 'all' + #disabled_checks = 'all' + disabled_checks = '' # WHEN: Running pylint (pylint_stdout, pylint_stderr) = \ lint.py_run('{path} --disable={disabled} --enable={enabled} --reports=no'.format(path='openlp', disabled=disabled_checks, enabled=enabled_checks), - return_std=True) + return_std=True, script='pylint3') stdout = pylint_stdout.read() stderr = pylint_stderr.read() print(stdout) + print(stderr) # THEN: The output should be empty - self.assertTrue(stdout == '', 'PyLint should find no errors') + self.assertTrue(stdout == 's', 'PyLint should find no errors') From 9294aadae9eb25a2a11396e4c6cb1836a8410e29 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 5 Jul 2016 22:30:33 +0200 Subject: [PATCH 55/62] Changes to pylint test --- tests/utils/test_pylint.py | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/tests/utils/test_pylint.py b/tests/utils/test_pylint.py index 6db43464e..d4e744e55 100644 --- a/tests/utils/test_pylint.py +++ b/tests/utils/test_pylint.py @@ -24,11 +24,14 @@ Package to test for proper bzr tags. """ import os import logging -from unittest import TestCase - -from pylint import epylint as lint -from pylint.__pkginfo__ import pylint_version +import platform +from unittest import TestCase, SkipTest +try: + from pylint import epylint as lint + from pylint.__pkginfo__ import version +except ImportError: + raise SkipTest('pylint not installed - skipping tests using pylint.') class TestPylint(TestCase): @@ -36,17 +39,20 @@ class TestPylint(TestCase): """ Test for pylint errors """ - # GIVEN: The openlp base folder + # GIVEN: Some checks to disable and enable, and the pylint script + disabled_checks = 'no-member,import-error,no-name-in-module' enabled_checks = 'missing-format-argument-key,unused-format-string-argument' - #disabled_checks = 'all' - disabled_checks = '' + if 'arch' in platform.dist()[0].lower(): + pylint_script = 'pylint' + else: + pylint_script = 'pylint3' # WHEN: Running pylint (pylint_stdout, pylint_stderr) = \ - lint.py_run('{path} --disable={disabled} --enable={enabled} --reports=no'.format(path='openlp', - disabled=disabled_checks, - enabled=enabled_checks), - return_std=True, script='pylint3') + lint.py_run('openlp --errors-only --disable={disabled} --enable={enabled} --reports=no --output-format=parseable'.format( + disabled=disabled_checks, + enabled=enabled_checks), + return_std=True, script=pylint_script) stdout = pylint_stdout.read() stderr = pylint_stderr.read() print(stdout) From 99e6ab6657eb1dec65d9a31aca04619214798d24 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 5 Jul 2016 22:31:29 +0200 Subject: [PATCH 56/62] Fix various issues as suggested by pylint --- openlp/core/lib/theme.py | 1 + openlp/plugins/bibles/lib/manager.py | 2 +- openlp/plugins/bibles/lib/opensong.py | 2 +- openlp/plugins/songs/lib/importers/cclifile.py | 1 + openlp/plugins/songs/lib/importers/dreambeam.py | 4 ++-- openlp/plugins/songs/lib/importers/easyworship.py | 3 +++ openlp/plugins/songs/lib/importers/openlyrics.py | 2 +- openlp/plugins/songs/lib/importers/presentationmanager.py | 1 + pylintrc | 2 +- 9 files changed, 12 insertions(+), 6 deletions(-) diff --git a/openlp/core/lib/theme.py b/openlp/core/lib/theme.py index e24613aa6..fc20037e7 100644 --- a/openlp/core/lib/theme.py +++ b/openlp/core/lib/theme.py @@ -164,6 +164,7 @@ class ThemeXML(object): jsn = get_text_file_string(json_file) jsn = json.loads(jsn) self.expand_json(jsn) + self.background_filename = None def expand_json(self, var, prev=None): """ diff --git a/openlp/plugins/bibles/lib/manager.py b/openlp/plugins/bibles/lib/manager.py index d1465475d..1c55222f2 100644 --- a/openlp/plugins/bibles/lib/manager.py +++ b/openlp/plugins/bibles/lib/manager.py @@ -370,7 +370,7 @@ class BibleManager(RegistryProperties): """ log.debug('save_meta data {bible}, {version}, {copyright}, {perms}'.format(bible=bible, version=version, - cr=copyright, + copyright=copyright, perms=permissions)) self.db_cache[bible].save_meta('name', version) self.db_cache[bible].save_meta('copyright', copyright) diff --git a/openlp/plugins/bibles/lib/opensong.py b/openlp/plugins/bibles/lib/opensong.py index af3ef64c0..9c01a1fe0 100644 --- a/openlp/plugins/bibles/lib/opensong.py +++ b/openlp/plugins/bibles/lib/opensong.py @@ -117,7 +117,7 @@ class OpenSongBible(BibleDB): if len(verse_parts) > 1: number = int(verse_parts[0]) except TypeError: - log.warning('Illegal verse number: {verse:d}'.format(verse.attrib['n'])) + log.warning('Illegal verse number: {verse:d}'.format(verse=verse.attrib['n'])) verse_number = number else: verse_number += 1 diff --git a/openlp/plugins/songs/lib/importers/cclifile.py b/openlp/plugins/songs/lib/importers/cclifile.py index 800509ab2..b17f78129 100644 --- a/openlp/plugins/songs/lib/importers/cclifile.py +++ b/openlp/plugins/songs/lib/importers/cclifile.py @@ -255,6 +255,7 @@ class CCLIFileImport(SongImport): song_author = '' verse_start = False for line in text_list: + verse_type= 'v' clean_line = line.strip() if not clean_line: if line_number == 0: diff --git a/openlp/plugins/songs/lib/importers/dreambeam.py b/openlp/plugins/songs/lib/importers/dreambeam.py index 9371adc56..8c435bfd5 100644 --- a/openlp/plugins/songs/lib/importers/dreambeam.py +++ b/openlp/plugins/songs/lib/importers/dreambeam.py @@ -124,8 +124,8 @@ class DreamBeamImport(SongImport): if hasattr(song_xml, 'Sequence'): for lyrics_sequence_item in (song_xml.Sequence.iterchildren()): item = lyrics_sequence_item.get('Type')[:1] - self.verse_order_list.append("{item}{number}".format(item=item), - lyrics_sequence_item.get('Number')) + number = lyrics_sequence_item.get('Number') + self.verse_order_list.append("{item}{number}".format(item=item, number=number)) if hasattr(song_xml, 'Notes'): self.comments = str(song_xml.Notes.text) else: diff --git a/openlp/plugins/songs/lib/importers/easyworship.py b/openlp/plugins/songs/lib/importers/easyworship.py index cdffe9292..9db30838f 100644 --- a/openlp/plugins/songs/lib/importers/easyworship.py +++ b/openlp/plugins/songs/lib/importers/easyworship.py @@ -27,6 +27,7 @@ import os import struct import re import zlib +import logging from openlp.core.lib import translate from openlp.plugins.songs.lib import VerseType @@ -38,6 +39,8 @@ SLIDE_BREAK_REGEX = re.compile(r'\n *?\n[\n ]*') NUMBER_REGEX = re.compile(r'[0-9]+') NOTE_REGEX = re.compile(r'\(.*?\)') +log = logging.getLogger(__name__) + class FieldDescEntry: def __init__(self, name, field_type, size): diff --git a/openlp/plugins/songs/lib/importers/openlyrics.py b/openlp/plugins/songs/lib/importers/openlyrics.py index 84b667ce4..fcbe8fbfb 100644 --- a/openlp/plugins/songs/lib/importers/openlyrics.py +++ b/openlp/plugins/songs/lib/importers/openlyrics.py @@ -67,7 +67,7 @@ class OpenLyricsImport(SongImport): xml = etree.tostring(parsed_file).decode() self.open_lyrics.xml_to_song(xml) except etree.XMLSyntaxError: - log.exception('XML syntax error in file {path}'.format(file_path)) + log.exception('XML syntax error in file {path}'.format(path=file_path)) self.log_error(file_path, SongStrings.XMLSyntaxError) except OpenLyricsError as exception: log.exception('OpenLyricsException {error:d} in file {name}: {text}'.format(error=exception.type, diff --git a/openlp/plugins/songs/lib/importers/presentationmanager.py b/openlp/plugins/songs/lib/importers/presentationmanager.py index 34a94dec2..f10bd0ed6 100644 --- a/openlp/plugins/songs/lib/importers/presentationmanager.py +++ b/openlp/plugins/songs/lib/importers/presentationmanager.py @@ -30,6 +30,7 @@ import re import chardet from lxml import objectify, etree +from openlp.core.common import translate from openlp.core.ui.lib.wizard import WizardStrings from .songimport import SongImport diff --git a/pylintrc b/pylintrc index 367695e13..92d83ffaa 100644 --- a/pylintrc +++ b/pylintrc @@ -19,7 +19,7 @@ persistent=yes load-plugins= # Use multiple processes to speed up Pylint. -jobs=4 +#jobs=4 # Allow loading of arbitrary C extensions. Extensions are imported into the # active Python interpreter and may run arbitrary code. From 1992a513394a8e661824fbdb8f0c821219535906 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Wed, 6 Jul 2016 21:48:57 +0200 Subject: [PATCH 57/62] More pylint-fixes --- openlp/core/lib/db.py | 30 +++++------ openlp/plugins/bibles/lib/osis.py | 2 - openlp/plugins/bibles/lib/zefania.py | 2 - .../plugins/songs/lib/importers/cclifile.py | 2 +- tests/utils/test_pylint.py | 53 ++++++++++++++++--- 5 files changed, 62 insertions(+), 27 deletions(-) diff --git a/openlp/core/lib/db.py b/openlp/core/lib/db.py index d77432181..f42c3b5fc 100644 --- a/openlp/core/lib/db.py +++ b/openlp/core/lib/db.py @@ -122,6 +122,21 @@ def get_upgrade_op(session): return Operations(context) +class BaseModel(object): + """ + BaseModel provides a base object with a set of generic functions + """ + @classmethod + def populate(cls, **kwargs): + """ + Creates an instance of a class and populates it, returning the instance + """ + instance = cls() + for key, value in kwargs.items(): + instance.__setattr__(key, value) + return instance + + def upgrade_db(url, upgrade): """ Upgrade a database. @@ -197,21 +212,6 @@ def delete_database(plugin_name, db_file_name=None): return delete_file(db_file_path) -class BaseModel(object): - """ - BaseModel provides a base object with a set of generic functions - """ - @classmethod - def populate(cls, **kwargs): - """ - Creates an instance of a class and populates it, returning the instance - """ - instance = cls() - for key, value in kwargs.items(): - instance.__setattr__(key, value) - return instance - - class Manager(object): """ Provide generic object persistence management diff --git a/openlp/plugins/bibles/lib/osis.py b/openlp/plugins/bibles/lib/osis.py index c0a3bec81..85aea70b3 100644 --- a/openlp/plugins/bibles/lib/osis.py +++ b/openlp/plugins/bibles/lib/osis.py @@ -126,8 +126,6 @@ class OSISBible(BibleDB): # Remove div-tags in the book etree.strip_tags(book, ('{http://www.bibletechnologies.net/2003/OSIS/namespace}div')) book_ref_id = self.get_book_ref_id_by_name(book.get('osisID'), num_books, language_id) - if not book_ref_id: - book_ref_id = self.get_book_ref_id_by_localised_name(book.get('osisID')) if not book_ref_id: log.error('Importing books from "{name}" failed'.format(name=self.filename)) return False diff --git a/openlp/plugins/bibles/lib/zefania.py b/openlp/plugins/bibles/lib/zefania.py index 0ea96a2a3..482d98107 100644 --- a/openlp/plugins/bibles/lib/zefania.py +++ b/openlp/plugins/bibles/lib/zefania.py @@ -86,8 +86,6 @@ class ZefaniaBible(BibleDB): continue if bname: book_ref_id = self.get_book_ref_id_by_name(bname, num_books, language_id) - if not book_ref_id: - book_ref_id = self.get_book_ref_id_by_localised_name(bname) else: log.debug('Could not find a name, will use number, basically a guess.') book_ref_id = int(bnumber) diff --git a/openlp/plugins/songs/lib/importers/cclifile.py b/openlp/plugins/songs/lib/importers/cclifile.py index b17f78129..58ceefebc 100644 --- a/openlp/plugins/songs/lib/importers/cclifile.py +++ b/openlp/plugins/songs/lib/importers/cclifile.py @@ -255,7 +255,7 @@ class CCLIFileImport(SongImport): song_author = '' verse_start = False for line in text_list: - verse_type= 'v' + verse_type = 'v' clean_line = line.strip() if not clean_line: if line_number == 0: diff --git a/tests/utils/test_pylint.py b/tests/utils/test_pylint.py index d4e744e55..dc6c83909 100644 --- a/tests/utils/test_pylint.py +++ b/tests/utils/test_pylint.py @@ -33,6 +33,13 @@ try: except ImportError: raise SkipTest('pylint not installed - skipping tests using pylint.') +from openlp.core.common import is_win + +TOLERATED_ERRORS = {'registryproperties.py': ['access-member-before-definition'], + 'opensong.py': ['no-name-in-module'], + 'maindisplay.py': ['no-name-in-module']} + + class TestPylint(TestCase): def test_pylint(self): @@ -40,23 +47,55 @@ class TestPylint(TestCase): Test for pylint errors """ # GIVEN: Some checks to disable and enable, and the pylint script - disabled_checks = 'no-member,import-error,no-name-in-module' + disabled_checks = 'import-error,no-member' enabled_checks = 'missing-format-argument-key,unused-format-string-argument' - if 'arch' in platform.dist()[0].lower(): + if is_win() or 'arch' in platform.dist()[0].lower(): pylint_script = 'pylint' else: pylint_script = 'pylint3' # WHEN: Running pylint (pylint_stdout, pylint_stderr) = \ - lint.py_run('openlp --errors-only --disable={disabled} --enable={enabled} --reports=no --output-format=parseable'.format( - disabled=disabled_checks, - enabled=enabled_checks), + lint.py_run('openlp --errors-only --disable={disabled} --enable={enabled} ' + '--reports=no --output-format=parseable'.format(disabled=disabled_checks, + enabled=enabled_checks), return_std=True, script=pylint_script) stdout = pylint_stdout.read() stderr = pylint_stderr.read() - print(stdout) + filtered_stdout = self._filter_tolerated_errors(stdout) + print(filtered_stdout) print(stderr) # THEN: The output should be empty - self.assertTrue(stdout == 's', 'PyLint should find no errors') + self.assertTrue(filtered_stdout == '', 'PyLint should find no errors') + + def _filter_tolerated_errors(self, pylint_output): + """ + Filter out errors we tolerate. + """ + filtered_output = '' + for line in pylint_output.splitlines(): + # Filter out module info lines + if line.startswith('**'): + continue + # Filter out undefined-variable error releated to WindowsError + elif 'undefined-variable' in line and 'WindowsError' in line: + continue + # Filter out PyQt related errors + elif ('no-name-in-module' in line or 'no-member' in line) and 'PyQt5' in line: + continue + elif self._is_line_tolerated(line): + continue + else: + filtered_output += line + '\n' + return filtered_output.strip() + + def _is_line_tolerated(self, line): + """ + Check if line constains a tolerated error + """ + for filename in TOLERATED_ERRORS: + for tolerated_error in TOLERATED_ERRORS[filename]: + if filename in line and tolerated_error in line: + return True + return False From de3f4046b7a452120cb90d147eee46adfb99ed00 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Fri, 8 Jul 2016 12:19:08 -0700 Subject: [PATCH 58/62] Convert md5sum calls to utf-8 for non-ascii pins --- openlp/core/common/__init__.py | 22 ++++++++++++++----- openlp/core/lib/projector/pjlink1.py | 11 +++++----- .../test_projector_utilities.py | 10 ++++----- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/openlp/core/common/__init__.py b/openlp/core/common/__init__.py index a5c86314c..9afc08c8f 100644 --- a/openlp/core/common/__init__.py +++ b/openlp/core/common/__init__.py @@ -195,7 +195,7 @@ def verify_ip_address(addr): return True if verify_ipv4(addr) else verify_ipv6(addr) -def md5_hash(salt, data=None): +def md5_hash(salt=None, data=None): """ Returns the hashed output of md5sum on salt,data using Python3 hashlib @@ -205,8 +205,11 @@ def md5_hash(salt, data=None): :returns: str """ log.debug('md5_hash(salt="{text}")'.format(text=salt)) + if not salt and not data: + return None hash_obj = hashlib.new('md5') - hash_obj.update(salt) + if salt: + hash_obj.update(salt) if data: hash_obj.update(data) hash_value = hash_obj.hexdigest() @@ -214,18 +217,25 @@ def md5_hash(salt, data=None): return hash_value -def qmd5_hash(salt, data=None): +def qmd5_hash(salt=None, data=None): """ Returns the hashed output of MD5Sum on salt, data - using PyQt5.QCryptographicHash. + using PyQt5.QCryptographicHash. Function returns a + QByteArray instead of a text string. + If you need a string instead, call with + + result = str(qmd5_hash(salt=..., data=...), encoding='ascii') :param salt: Initial salt :param data: OPTIONAL Data to hash - :returns: str + :returns: QByteArray """ log.debug('qmd5_hash(salt="{text}"'.format(text=salt)) + if salt is None and data is None: + return None hash_obj = QHash(QHash.Md5) - hash_obj.addData(salt) + if salt: + hash_obj.addData(salt) if data: hash_obj.addData(data) hash_value = hash_obj.result().toHex() diff --git a/openlp/core/lib/projector/pjlink1.py b/openlp/core/lib/projector/pjlink1.py index 330e02b73..71c3e450d 100644 --- a/openlp/core/lib/projector/pjlink1.py +++ b/openlp/core/lib/projector/pjlink1.py @@ -49,7 +49,7 @@ from codecs import decode from PyQt5.QtCore import pyqtSignal, pyqtSlot from PyQt5.QtNetwork import QAbstractSocket, QTcpSocket -from openlp.core.common import translate, md5_hash +from openlp.core.common import translate, qmd5_hash from openlp.core.lib.projector.constants import * # Shortcuts @@ -364,14 +364,15 @@ class PJLink1(QTcpSocket): else: log.debug('({ip}) Setting hash with salt="{data}"'.format(ip=self.ip, data=data_check[2])) log.debug('({ip}) pin="{data}"'.format(ip=self.ip, data=self.pin)) - salt = md5_hash(salt=data_check[2].encode('ascii'), data=self.pin.encode('ascii')) + data_hash = str(qmd5_hash(salt=data_check[2].encode('utf-8'), data=self.pin.encode('utf-8')), + encoding='ascii') else: - salt = None - # We're connected at this point, so go ahead and do regular I/O + data_hash = None + # We're connected at this point, so go ahead and setup regular I/O self.readyRead.connect(self.get_data) self.projectorReceivedData.connect(self._send_command) # Initial data we should know about - self.send_command(cmd='CLSS', salt=salt) + self.send_command(cmd='CLSS', salt=data_hash) self.waitForReadyRead() if (not self.no_poll) and (self.state() == self.ConnectedState): log.debug('({ip}) Starting timer'.format(ip=self.ip)) diff --git a/tests/functional/openlp_core_common/test_projector_utilities.py b/tests/functional/openlp_core_common/test_projector_utilities.py index 72609956d..75ecd582a 100644 --- a/tests/functional/openlp_core_common/test_projector_utilities.py +++ b/tests/functional/openlp_core_common/test_projector_utilities.py @@ -124,7 +124,7 @@ class testProjectorUtilities(TestCase): Test MD5 hash from salt+data pass (python) """ # WHEN: Given a known salt+data - hash_ = md5_hash(salt=salt.encode('ascii'), data=pin.encode('ascii')) + hash_ = md5_hash(salt=salt.encode('utf-8'), data=pin.encode('utf-8')) # THEN: Validate return has is same self.assertEquals(hash_, test_hash, 'MD5 should have returned a good hash') @@ -134,7 +134,7 @@ class testProjectorUtilities(TestCase): Test MD5 hash from salt+data fail (python) """ # WHEN: Given a different salt+hash - hash_ = md5_hash(salt=pin.encode('ascii'), data=salt.encode('ascii')) + hash_ = md5_hash(salt=pin.encode('utf-8'), data=salt.encode('utf-8')) # THEN: return data is different self.assertNotEquals(hash_, test_hash, 'MD5 should have returned a bad hash') @@ -144,7 +144,7 @@ class testProjectorUtilities(TestCase): Test MD5 hash from salt+data pass (Qt) """ # WHEN: Given a known salt+data - hash_ = qmd5_hash(salt=salt.encode('ascii'), data=pin.encode('ascii')) + hash_ = qmd5_hash(salt=salt.encode('utf-8'), data=pin.encode('utf-8')) # THEN: Validate return has is same self.assertEquals(hash_, test_hash, 'Qt-MD5 should have returned a good hash') @@ -154,7 +154,7 @@ class testProjectorUtilities(TestCase): Test MD5 hash from salt+hash fail (Qt) """ # WHEN: Given a different salt+hash - hash_ = qmd5_hash(salt=pin.encode('ascii'), data=salt.encode('ascii')) + hash_ = qmd5_hash(salt=pin.encode('utf-8'), data=salt.encode('utf-8')) # THEN: return data is different self.assertNotEquals(hash_, test_hash, 'Qt-MD5 should have returned a bad hash') @@ -174,7 +174,7 @@ class testProjectorUtilities(TestCase): Test MD5 hash with non-ascii string - bug 1417809 """ # WHEN: Non-ascii string is hashed - hash_ = md5_hash(salt=test_non_ascii_string.encode('utf-8'), data=None) + hash_ = md5_hash(data=test_non_ascii_string.encode('utf-8')) # THEN: Valid MD5 hash should be returned self.assertEqual(hash_, test_non_ascii_hash, 'Qt-MD5 should have returned a valid hash') From 3cdd42bfe0180504c7971f596af98e9adb0a88ce Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Sun, 17 Jul 2016 00:20:56 +0200 Subject: [PATCH 59/62] Catch the PermissionError too --- openlp/core/ui/servicemanager.py | 9 +- .../openlp_core_ui/test_servicemanager.py | 310 ++++++++++-------- 2 files changed, 176 insertions(+), 143 deletions(-) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 907cb49a6..7c01b4191 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -480,9 +480,10 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa :return: service array """ service = [] - core = {'lite-service': self._save_lite, - 'service-theme': self.service_theme - } + core = { + 'lite-service': self._save_lite, + 'service-theme': self.service_theme + } service.append({'openlp_core': core}) return service @@ -658,7 +659,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa if success: try: shutil.copy(temp_file_name, path_file_name) - except shutil.Error: + except (shutil.Error, PermissionError): return self.save_file_as() self.main_window.add_recent_file(path_file_name) self.set_modified(False) diff --git a/tests/functional/openlp_core_ui/test_servicemanager.py b/tests/functional/openlp_core_ui/test_servicemanager.py index 7882d8a24..1697eb1f6 100644 --- a/tests/functional/openlp_core_ui/test_servicemanager.py +++ b/tests/functional/openlp_core_ui/test_servicemanager.py @@ -22,10 +22,12 @@ """ Package to test the openlp.core.ui.slidecontroller package. """ -import PyQt5 +import os from unittest import TestCase -from openlp.core.common import Registry, ThemeLevel, Settings +import PyQt5 + +from openlp.core.common import Registry, ThemeLevel from openlp.core.lib import ServiceItem, ServiceItemType, ItemCapabilities from openlp.core.ui import ServiceManager @@ -33,6 +35,9 @@ from tests.functional import MagicMock, patch class TestServiceManager(TestCase): + """ + Test the service manager + """ def setUp(self): """ @@ -108,20 +113,20 @@ class TestServiceManager(TestCase): # WHEN I define a context menu service_manager.context_menu(1) # THEN the following calls should have occurred. - self.assertEquals(service_manager.edit_action.setVisible.call_count, 1, 'Should have been called once') - self.assertEquals(service_manager.rename_action.setVisible.call_count, 1, 'Should have been called once') - self.assertEquals(service_manager.create_custom_action.setVisible.call_count, 1, 'Should have been called once') - self.assertEquals(service_manager.maintain_action.setVisible.call_count, 1, 'Should have been called once') - self.assertEquals(service_manager.notes_action.setVisible.call_count, 1, 'Should have been called once') - self.assertEquals(service_manager.time_action.setVisible.call_count, 1, 'Should have been called once') - self.assertEquals(service_manager.auto_start_action.setVisible.call_count, 1, 'Should have been called once') - self.assertEquals(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 1, - 'Should have been called once') - self.assertEquals(service_manager.auto_play_slides_once.setChecked.call_count, 0, 'Should not be called') - self.assertEquals(service_manager.auto_play_slides_loop.setChecked.call_count, 0, 'Should not be called') - self.assertEquals(service_manager.timed_slide_interval.setChecked.call_count, 0, 'Should not be called') - self.assertEquals(service_manager.theme_menu.menuAction().setVisible.call_count, 1, - 'Should have been called once') + self.assertEqual(service_manager.edit_action.setVisible.call_count, 1, 'Should have been called once') + self.assertEqual(service_manager.rename_action.setVisible.call_count, 1, 'Should have been called once') + self.assertEqual(service_manager.create_custom_action.setVisible.call_count, 1, 'Should have been called once') + self.assertEqual(service_manager.maintain_action.setVisible.call_count, 1, 'Should have been called once') + self.assertEqual(service_manager.notes_action.setVisible.call_count, 1, 'Should have been called once') + self.assertEqual(service_manager.time_action.setVisible.call_count, 1, 'Should have been called once') + self.assertEqual(service_manager.auto_start_action.setVisible.call_count, 1, 'Should have been called once') + self.assertEqual(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 1, + 'Should have been called once') + self.assertEqual(service_manager.auto_play_slides_once.setChecked.call_count, 0, 'Should not be called') + self.assertEqual(service_manager.auto_play_slides_loop.setChecked.call_count, 0, 'Should not be called') + self.assertEqual(service_manager.timed_slide_interval.setChecked.call_count, 0, 'Should not be called') + self.assertEqual(service_manager.theme_menu.menuAction().setVisible.call_count, 1, + 'Should have been called once') def test_build_song_context_menu(self): """ @@ -139,12 +144,10 @@ class TestServiceManager(TestCase): service_manager.service_manager_list = MagicMock() service_manager.service_manager_list.itemAt.return_value = item service_item = ServiceItem(None) - service_item.add_capability(ItemCapabilities.CanEdit) - service_item.add_capability(ItemCapabilities.CanPreview) - service_item.add_capability(ItemCapabilities.CanLoop) - service_item.add_capability(ItemCapabilities.OnLoadUpdate) - service_item.add_capability(ItemCapabilities.AddIfNewItem) - service_item.add_capability(ItemCapabilities.CanSoftBreak) + for capability in [ItemCapabilities.CanEdit, ItemCapabilities.CanPreview, ItemCapabilities.CanLoop, + ItemCapabilities.OnLoadUpdate, ItemCapabilities.AddIfNewItem, + ItemCapabilities.CanSoftBreak]: + service_item.add_capability(capability) service_item.service_item_type = ServiceItemType.Text service_item.edit_id = 1 service_item._display_frames.append(MagicMock()) @@ -165,29 +168,29 @@ class TestServiceManager(TestCase): # WHEN I define a context menu service_manager.context_menu(1) # THEN the following calls should have occurred. - self.assertEquals(service_manager.edit_action.setVisible.call_count, 2, 'Should have be called twice') - self.assertEquals(service_manager.rename_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.create_custom_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.maintain_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.notes_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.time_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.auto_start_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 1, - 'Should have be called once') - self.assertEquals(service_manager.auto_play_slides_once.setChecked.call_count, 0, 'Should not be called') - self.assertEquals(service_manager.auto_play_slides_loop.setChecked.call_count, 0, 'Should not be called') - self.assertEquals(service_manager.timed_slide_interval.setChecked.call_count, 0, 'Should not be called') - self.assertEquals(service_manager.theme_menu.menuAction().setVisible.call_count, 2, - 'Should have be called twice') + self.assertEqual(service_manager.edit_action.setVisible.call_count, 2, 'Should have be called twice') + self.assertEqual(service_manager.rename_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.create_custom_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.maintain_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.notes_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.time_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.auto_start_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 1, + 'Should have be called once') + self.assertEqual(service_manager.auto_play_slides_once.setChecked.call_count, 0, 'Should not be called') + self.assertEqual(service_manager.auto_play_slides_loop.setChecked.call_count, 0, 'Should not be called') + self.assertEqual(service_manager.timed_slide_interval.setChecked.call_count, 0, 'Should not be called') + self.assertEqual(service_manager.theme_menu.menuAction().setVisible.call_count, 2, + 'Should have be called twice') # THEN we add a 2nd display frame service_item._display_frames.append(MagicMock()) service_manager.context_menu(1) # THEN the following additional calls should have occurred. - self.assertEquals(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 2, - 'Should have be called twice') - self.assertEquals(service_manager.auto_play_slides_once.setChecked.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.auto_play_slides_loop.setChecked.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.timed_slide_interval.setChecked.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 2, + 'Should have be called twice') + self.assertEqual(service_manager.auto_play_slides_once.setChecked.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.auto_play_slides_loop.setChecked.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.timed_slide_interval.setChecked.call_count, 1, 'Should have be called once') def test_build_bible_context_menu(self): """ @@ -205,11 +208,10 @@ class TestServiceManager(TestCase): service_manager.service_manager_list = MagicMock() service_manager.service_manager_list.itemAt.return_value = item service_item = ServiceItem(None) - service_item.add_capability(ItemCapabilities.NoLineBreaks) - service_item.add_capability(ItemCapabilities.CanPreview) - service_item.add_capability(ItemCapabilities.CanLoop) - service_item.add_capability(ItemCapabilities.CanWordSplit) - service_item.add_capability(ItemCapabilities.CanEditTitle) + for capability in [ItemCapabilities.NoLineBreaks, ItemCapabilities.CanPreview, + ItemCapabilities.CanLoop, ItemCapabilities.CanWordSplit, + ItemCapabilities.CanEditTitle]: + service_item.add_capability(capability) service_item.service_item_type = ServiceItemType.Text service_item.edit_id = 1 service_item._display_frames.append(MagicMock()) @@ -230,29 +232,29 @@ class TestServiceManager(TestCase): # WHEN I define a context menu service_manager.context_menu(1) # THEN the following calls should have occurred. - self.assertEquals(service_manager.edit_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.rename_action.setVisible.call_count, 2, 'Should have be called twice') - self.assertEquals(service_manager.create_custom_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.maintain_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.notes_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.time_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.auto_start_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 1, - 'Should have be called once') - self.assertEquals(service_manager.auto_play_slides_once.setChecked.call_count, 0, 'Should not be called') - self.assertEquals(service_manager.auto_play_slides_loop.setChecked.call_count, 0, 'Should not be called') - self.assertEquals(service_manager.timed_slide_interval.setChecked.call_count, 0, 'Should not be called') - self.assertEquals(service_manager.theme_menu.menuAction().setVisible.call_count, 2, - 'Should have be called twice') + self.assertEqual(service_manager.edit_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.rename_action.setVisible.call_count, 2, 'Should have be called twice') + self.assertEqual(service_manager.create_custom_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.maintain_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.notes_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.time_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.auto_start_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 1, + 'Should have be called once') + self.assertEqual(service_manager.auto_play_slides_once.setChecked.call_count, 0, 'Should not be called') + self.assertEqual(service_manager.auto_play_slides_loop.setChecked.call_count, 0, 'Should not be called') + self.assertEqual(service_manager.timed_slide_interval.setChecked.call_count, 0, 'Should not be called') + self.assertEqual(service_manager.theme_menu.menuAction().setVisible.call_count, 2, + 'Should have be called twice') # THEN we add a 2nd display frame service_item._display_frames.append(MagicMock()) service_manager.context_menu(1) # THEN the following additional calls should have occurred. - self.assertEquals(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 2, - 'Should have be called twice') - self.assertEquals(service_manager.auto_play_slides_once.setChecked.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.auto_play_slides_loop.setChecked.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.timed_slide_interval.setChecked.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 2, + 'Should have be called twice') + self.assertEqual(service_manager.auto_play_slides_once.setChecked.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.auto_play_slides_loop.setChecked.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.timed_slide_interval.setChecked.call_count, 1, 'Should have be called once') def test_build_custom_context_menu(self): """ @@ -295,29 +297,29 @@ class TestServiceManager(TestCase): # WHEN I define a context menu service_manager.context_menu(1) # THEN the following calls should have occurred. - self.assertEquals(service_manager.edit_action.setVisible.call_count, 2, 'Should have be called twice') - self.assertEquals(service_manager.rename_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.create_custom_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.maintain_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.notes_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.time_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.auto_start_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 1, + self.assertEqual(service_manager.edit_action.setVisible.call_count, 2, 'Should have be called twice') + self.assertEqual(service_manager.rename_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.create_custom_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.maintain_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.notes_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.time_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.auto_start_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.auto_play_slides_once.setChecked.call_count, 0, 'Should not be called') - self.assertEquals(service_manager.auto_play_slides_loop.setChecked.call_count, 0, 'Should not be called') - self.assertEquals(service_manager.timed_slide_interval.setChecked.call_count, 0, 'Should not be called') - self.assertEquals(service_manager.theme_menu.menuAction().setVisible.call_count, 2, + self.assertEqual(service_manager.auto_play_slides_once.setChecked.call_count, 0, 'Should not be called') + self.assertEqual(service_manager.auto_play_slides_loop.setChecked.call_count, 0, 'Should not be called') + self.assertEqual(service_manager.timed_slide_interval.setChecked.call_count, 0, 'Should not be called') + self.assertEqual(service_manager.theme_menu.menuAction().setVisible.call_count, 2, 'Should have be called twice') # THEN we add a 2nd display frame service_item._display_frames.append(MagicMock()) service_manager.context_menu(1) # THEN the following additional calls should have occurred. - self.assertEquals(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 2, + self.assertEqual(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 2, 'Should have be called twice') - self.assertEquals(service_manager.auto_play_slides_once.setChecked.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.auto_play_slides_loop.setChecked.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.timed_slide_interval.setChecked.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.auto_play_slides_once.setChecked.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.auto_play_slides_loop.setChecked.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.timed_slide_interval.setChecked.call_count, 1, 'Should have be called once') def test_build_image_context_menu(self): """ @@ -358,29 +360,29 @@ class TestServiceManager(TestCase): # WHEN I define a context menu service_manager.context_menu(1) # THEN the following calls should have occurred. - self.assertEquals(service_manager.edit_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.rename_action.setVisible.call_count, 2, 'Should have be called twice') - self.assertEquals(service_manager.create_custom_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.maintain_action.setVisible.call_count, 2, 'Should have be called twice') - self.assertEquals(service_manager.notes_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.time_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.auto_start_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 1, + self.assertEqual(service_manager.edit_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.rename_action.setVisible.call_count, 2, 'Should have be called twice') + self.assertEqual(service_manager.create_custom_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.maintain_action.setVisible.call_count, 2, 'Should have be called twice') + self.assertEqual(service_manager.notes_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.time_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.auto_start_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.auto_play_slides_once.setChecked.call_count, 0, 'Should not be called') - self.assertEquals(service_manager.auto_play_slides_loop.setChecked.call_count, 0, 'Should not be called') - self.assertEquals(service_manager.timed_slide_interval.setChecked.call_count, 0, 'Should not be called') - self.assertEquals(service_manager.theme_menu.menuAction().setVisible.call_count, 1, + self.assertEqual(service_manager.auto_play_slides_once.setChecked.call_count, 0, 'Should not be called') + self.assertEqual(service_manager.auto_play_slides_loop.setChecked.call_count, 0, 'Should not be called') + self.assertEqual(service_manager.timed_slide_interval.setChecked.call_count, 0, 'Should not be called') + self.assertEqual(service_manager.theme_menu.menuAction().setVisible.call_count, 1, 'Should have be called once') # THEN we add a 2nd display frame and regenerate the menu. service_item._raw_frames.append(MagicMock()) service_manager.context_menu(1) # THEN the following additional calls should have occurred. - self.assertEquals(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 2, + self.assertEqual(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 2, 'Should have be called twice') - self.assertEquals(service_manager.auto_play_slides_once.setChecked.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.auto_play_slides_loop.setChecked.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.timed_slide_interval.setChecked.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.auto_play_slides_once.setChecked.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.auto_play_slides_loop.setChecked.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.timed_slide_interval.setChecked.call_count, 1, 'Should have be called once') def test_build_media_context_menu(self): """ @@ -419,25 +421,25 @@ class TestServiceManager(TestCase): # WHEN I define a context menu service_manager.context_menu(1) # THEN the following calls should have occurred. - self.assertEquals(service_manager.edit_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.rename_action.setVisible.call_count, 2, 'Should have be called twice') - self.assertEquals(service_manager.create_custom_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.maintain_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.notes_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.time_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.auto_start_action.setVisible.call_count, 2, 'Should have be called twice') - self.assertEquals(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 1, + self.assertEqual(service_manager.edit_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.rename_action.setVisible.call_count, 2, 'Should have be called twice') + self.assertEqual(service_manager.create_custom_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.maintain_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.notes_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.time_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.auto_start_action.setVisible.call_count, 2, 'Should have be called twice') + self.assertEqual(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.auto_play_slides_once.setChecked.call_count, 0, 'Should not be called') - self.assertEquals(service_manager.auto_play_slides_loop.setChecked.call_count, 0, 'Should not be called') - self.assertEquals(service_manager.timed_slide_interval.setChecked.call_count, 0, 'Should not be called') - self.assertEquals(service_manager.theme_menu.menuAction().setVisible.call_count, 1, + self.assertEqual(service_manager.auto_play_slides_once.setChecked.call_count, 0, 'Should not be called') + self.assertEqual(service_manager.auto_play_slides_loop.setChecked.call_count, 0, 'Should not be called') + self.assertEqual(service_manager.timed_slide_interval.setChecked.call_count, 0, 'Should not be called') + self.assertEqual(service_manager.theme_menu.menuAction().setVisible.call_count, 1, 'Should have be called once') # THEN I change the length of the media and regenerate the menu. service_item.set_media_length(5) service_manager.context_menu(1) # THEN the following additional calls should have occurred. - self.assertEquals(service_manager.time_action.setVisible.call_count, 3, 'Should have be called three times') + self.assertEqual(service_manager.time_action.setVisible.call_count, 3, 'Should have be called three times') def test_build_presentation_pdf_context_menu(self): """ @@ -477,19 +479,19 @@ class TestServiceManager(TestCase): # WHEN I define a context menu service_manager.context_menu(1) # THEN the following calls should have occurred. - self.assertEquals(service_manager.edit_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.rename_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.create_custom_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.maintain_action.setVisible.call_count, 2, 'Should have be called twice') - self.assertEquals(service_manager.notes_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.time_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.auto_start_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 1, + self.assertEqual(service_manager.edit_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.rename_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.create_custom_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.maintain_action.setVisible.call_count, 2, 'Should have be called twice') + self.assertEqual(service_manager.notes_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.time_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.auto_start_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.auto_play_slides_once.setChecked.call_count, 0, 'Should not be called') - self.assertEquals(service_manager.auto_play_slides_loop.setChecked.call_count, 0, 'Should not be called') - self.assertEquals(service_manager.timed_slide_interval.setChecked.call_count, 0, 'Should not be called') - self.assertEquals(service_manager.theme_menu.menuAction().setVisible.call_count, 1, + self.assertEqual(service_manager.auto_play_slides_once.setChecked.call_count, 0, 'Should not be called') + self.assertEqual(service_manager.auto_play_slides_loop.setChecked.call_count, 0, 'Should not be called') + self.assertEqual(service_manager.timed_slide_interval.setChecked.call_count, 0, 'Should not be called') + self.assertEqual(service_manager.theme_menu.menuAction().setVisible.call_count, 1, 'Should have be called once') def test_build_presentation_non_pdf_context_menu(self): @@ -527,19 +529,19 @@ class TestServiceManager(TestCase): # WHEN I define a context menu service_manager.context_menu(1) # THEN the following calls should have occurred. - self.assertEquals(service_manager.edit_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.rename_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.create_custom_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.maintain_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.notes_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.time_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.auto_start_action.setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 1, + self.assertEqual(service_manager.edit_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.rename_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.create_custom_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.maintain_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.notes_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.time_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.auto_start_action.setVisible.call_count, 1, 'Should have be called once') + self.assertEqual(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 1, 'Should have be called once') - self.assertEquals(service_manager.auto_play_slides_once.setChecked.call_count, 0, 'Should not be called') - self.assertEquals(service_manager.auto_play_slides_loop.setChecked.call_count, 0, 'Should not be called') - self.assertEquals(service_manager.timed_slide_interval.setChecked.call_count, 0, 'Should not be called') - self.assertEquals(service_manager.theme_menu.menuAction().setVisible.call_count, 1, + self.assertEqual(service_manager.auto_play_slides_once.setChecked.call_count, 0, 'Should not be called') + self.assertEqual(service_manager.auto_play_slides_loop.setChecked.call_count, 0, 'Should not be called') + self.assertEqual(service_manager.timed_slide_interval.setChecked.call_count, 0, 'Should not be called') + self.assertEqual(service_manager.theme_menu.menuAction().setVisible.call_count, 1, 'Should have be called once') @patch(u'openlp.core.ui.servicemanager.Settings') @@ -573,7 +575,7 @@ class TestServiceManager(TestCase): # WHEN: on_single_click_preview() is called service_manager.on_single_click_preview() # THEN: timer should not be started - self.assertEquals(mocked_singleShot.call_count, 0, 'Should not be called') + self.assertEqual(mocked_singleShot.call_count, 0, 'Should not be called') @patch(u'openlp.core.ui.servicemanager.Settings') @patch(u'PyQt5.QtCore.QTimer.singleShot') @@ -591,7 +593,8 @@ class TestServiceManager(TestCase): service_manager.on_double_click_live() service_manager.on_single_click_preview() # THEN: timer should not be started - self.assertEquals(mocked_singleShot.call_count, 0, 'Should not be called') + mocked_make_live.assert_called_with() + self.assertEqual(mocked_singleShot.call_count, 0, 'Should not be called') @patch(u'openlp.core.ui.servicemanager.ServiceManager.make_preview') def test_single_click_timeout_single(self, mocked_make_preview): @@ -603,7 +606,7 @@ class TestServiceManager(TestCase): # WHEN: on_single_click_preview() is called service_manager.on_single_click_preview_timeout() # THEN: make_preview() should have been called - self.assertEquals(mocked_make_preview.call_count, 1, 'Should have been called once') + self.assertEqual(mocked_make_preview.call_count, 1, 'ServiceManager.make_preview() should have been called once') @patch(u'openlp.core.ui.servicemanager.ServiceManager.make_preview') @patch(u'openlp.core.ui.servicemanager.ServiceManager.make_live') @@ -616,5 +619,34 @@ class TestServiceManager(TestCase): # WHEN: on_single_click_preview() is called after a double click service_manager.on_double_click_live() service_manager.on_single_click_preview_timeout() - # THEN: make_preview() should have been called - self.assertEquals(mocked_make_preview.call_count, 0, 'Should not be called') + # THEN: make_preview() should not have been called + self.assertEqual(mocked_make_preview.call_count, 0, 'ServiceManager.make_preview() should not be called') + + @patch(u'openlp.core.ui.servicemanager.shutil.copy') + @patch(u'openlp.core.ui.servicemanager.zipfile') + @patch(u'openlp.core.ui.servicemanager.ServiceManager.save_file_as') + def test_save_raises_permission_error(self, mocked_save_file_as, mocked_zipfile, mocked_shutil_copy): + """ + Test that when a PermissionError is raised when trying to save a file, it is handled correctly + """ + # GIVEN: A service manager, a service to save + mocked_main_window = MagicMock() + mocked_main_window.service_manager_settings_section = 'servicemanager' + Registry().register('main_window', mocked_main_window) + Registry().register('application', MagicMock()) + service_manager = ServiceManager(None) + service_manager._file_name = os.path.join('temp', 'filename.osz') + service_manager._save_lite = False + service_manager.service_items = [] + service_manager.service_theme = 'Default' + mocked_save_file_as.return_value = True + mocked_zipfile.ZipFile.return_value = MagicMock() + mocked_shutil_copy.side_effect = PermissionError + + # WHEN: The service is saved and a PermissionError is thrown + result = service_manager.save_local_file() + + # THEN: The "save_as" method is called to save the service + self.assertTrue(result) + mocked_save_file_as.assert_called_with() + From 97d65864623b308021d9a1a628e962e8d1403998 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Sun, 17 Jul 2016 21:12:00 +0200 Subject: [PATCH 60/62] Fixed another part of the permission denied error --- openlp/core/ui/servicemanager.py | 2 +- .../openlp_core_ui/test_servicemanager.py | 31 ++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 7c01b4191..578217ea6 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -598,7 +598,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa if success: try: shutil.copy(temp_file_name, path_file_name) - except shutil.Error: + except (shutil.Error, PermissionError): return self.save_file_as() except OSError as ose: QtWidgets.QMessageBox.critical(self, translate('OpenLP.ServiceManager', 'Error Saving File'), diff --git a/tests/functional/openlp_core_ui/test_servicemanager.py b/tests/functional/openlp_core_ui/test_servicemanager.py index 1697eb1f6..5a337d786 100644 --- a/tests/functional/openlp_core_ui/test_servicemanager.py +++ b/tests/functional/openlp_core_ui/test_servicemanager.py @@ -625,7 +625,7 @@ class TestServiceManager(TestCase): @patch(u'openlp.core.ui.servicemanager.shutil.copy') @patch(u'openlp.core.ui.servicemanager.zipfile') @patch(u'openlp.core.ui.servicemanager.ServiceManager.save_file_as') - def test_save_raises_permission_error(self, mocked_save_file_as, mocked_zipfile, mocked_shutil_copy): + def test_save_file_raises_permission_error(self, mocked_save_file_as, mocked_zipfile, mocked_shutil_copy): """ Test that when a PermissionError is raised when trying to save a file, it is handled correctly """ @@ -639,6 +639,35 @@ class TestServiceManager(TestCase): service_manager._save_lite = False service_manager.service_items = [] service_manager.service_theme = 'Default' + service_manager.service_manager_list = MagicMock() + mocked_save_file_as.return_value = True + mocked_zipfile.ZipFile.return_value = MagicMock() + mocked_shutil_copy.side_effect = PermissionError + + # WHEN: The service is saved and a PermissionError is thrown + result = service_manager.save_file() + + # THEN: The "save_as" method is called to save the service + self.assertTrue(result) + mocked_save_file_as.assert_called_with() + + @patch(u'openlp.core.ui.servicemanager.shutil.copy') + @patch(u'openlp.core.ui.servicemanager.zipfile') + @patch(u'openlp.core.ui.servicemanager.ServiceManager.save_file_as') + def test_save_local_file_raises_permission_error(self, mocked_save_file_as, mocked_zipfile, mocked_shutil_copy): + """ + Test that when a PermissionError is raised when trying to save a local file, it is handled correctly + """ + # GIVEN: A service manager, a service to save + mocked_main_window = MagicMock() + mocked_main_window.service_manager_settings_section = 'servicemanager' + Registry().register('main_window', mocked_main_window) + Registry().register('application', MagicMock()) + service_manager = ServiceManager(None) + service_manager._file_name = os.path.join('temp', 'filename.osz') + service_manager._save_lite = False + service_manager.service_items = [] + service_manager.service_theme = 'Default' mocked_save_file_as.return_value = True mocked_zipfile.ZipFile.return_value = MagicMock() mocked_shutil_copy.side_effect = PermissionError From 65fe62d69f1ae10ffc3c11676bbccc34106caa5b Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Sun, 17 Jul 2016 21:33:10 +0200 Subject: [PATCH 61/62] Fix some linting issues --- .../openlp_core_ui/test_servicemanager.py | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/tests/functional/openlp_core_ui/test_servicemanager.py b/tests/functional/openlp_core_ui/test_servicemanager.py index 5a337d786..853baf1f0 100644 --- a/tests/functional/openlp_core_ui/test_servicemanager.py +++ b/tests/functional/openlp_core_ui/test_servicemanager.py @@ -305,18 +305,18 @@ class TestServiceManager(TestCase): self.assertEqual(service_manager.time_action.setVisible.call_count, 1, 'Should have be called once') self.assertEqual(service_manager.auto_start_action.setVisible.call_count, 1, 'Should have be called once') self.assertEqual(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 1, - 'Should have be called once') + 'Should have be called once') self.assertEqual(service_manager.auto_play_slides_once.setChecked.call_count, 0, 'Should not be called') self.assertEqual(service_manager.auto_play_slides_loop.setChecked.call_count, 0, 'Should not be called') self.assertEqual(service_manager.timed_slide_interval.setChecked.call_count, 0, 'Should not be called') self.assertEqual(service_manager.theme_menu.menuAction().setVisible.call_count, 2, - 'Should have be called twice') + 'Should have be called twice') # THEN we add a 2nd display frame service_item._display_frames.append(MagicMock()) service_manager.context_menu(1) # THEN the following additional calls should have occurred. self.assertEqual(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 2, - 'Should have be called twice') + 'Should have be called twice') self.assertEqual(service_manager.auto_play_slides_once.setChecked.call_count, 1, 'Should have be called once') self.assertEqual(service_manager.auto_play_slides_loop.setChecked.call_count, 1, 'Should have be called once') self.assertEqual(service_manager.timed_slide_interval.setChecked.call_count, 1, 'Should have be called once') @@ -368,18 +368,18 @@ class TestServiceManager(TestCase): self.assertEqual(service_manager.time_action.setVisible.call_count, 1, 'Should have be called once') self.assertEqual(service_manager.auto_start_action.setVisible.call_count, 1, 'Should have be called once') self.assertEqual(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 1, - 'Should have be called once') + 'Should have be called once') self.assertEqual(service_manager.auto_play_slides_once.setChecked.call_count, 0, 'Should not be called') self.assertEqual(service_manager.auto_play_slides_loop.setChecked.call_count, 0, 'Should not be called') self.assertEqual(service_manager.timed_slide_interval.setChecked.call_count, 0, 'Should not be called') self.assertEqual(service_manager.theme_menu.menuAction().setVisible.call_count, 1, - 'Should have be called once') + 'Should have be called once') # THEN we add a 2nd display frame and regenerate the menu. service_item._raw_frames.append(MagicMock()) service_manager.context_menu(1) # THEN the following additional calls should have occurred. self.assertEqual(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 2, - 'Should have be called twice') + 'Should have be called twice') self.assertEqual(service_manager.auto_play_slides_once.setChecked.call_count, 1, 'Should have be called once') self.assertEqual(service_manager.auto_play_slides_loop.setChecked.call_count, 1, 'Should have be called once') self.assertEqual(service_manager.timed_slide_interval.setChecked.call_count, 1, 'Should have be called once') @@ -429,12 +429,12 @@ class TestServiceManager(TestCase): self.assertEqual(service_manager.time_action.setVisible.call_count, 1, 'Should have be called once') self.assertEqual(service_manager.auto_start_action.setVisible.call_count, 2, 'Should have be called twice') self.assertEqual(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 1, - 'Should have be called once') + 'Should have be called once') self.assertEqual(service_manager.auto_play_slides_once.setChecked.call_count, 0, 'Should not be called') self.assertEqual(service_manager.auto_play_slides_loop.setChecked.call_count, 0, 'Should not be called') self.assertEqual(service_manager.timed_slide_interval.setChecked.call_count, 0, 'Should not be called') self.assertEqual(service_manager.theme_menu.menuAction().setVisible.call_count, 1, - 'Should have be called once') + 'Should have be called once') # THEN I change the length of the media and regenerate the menu. service_item.set_media_length(5) service_manager.context_menu(1) @@ -487,12 +487,12 @@ class TestServiceManager(TestCase): self.assertEqual(service_manager.time_action.setVisible.call_count, 1, 'Should have be called once') self.assertEqual(service_manager.auto_start_action.setVisible.call_count, 1, 'Should have be called once') self.assertEqual(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 1, - 'Should have be called once') + 'Should have be called once') self.assertEqual(service_manager.auto_play_slides_once.setChecked.call_count, 0, 'Should not be called') self.assertEqual(service_manager.auto_play_slides_loop.setChecked.call_count, 0, 'Should not be called') self.assertEqual(service_manager.timed_slide_interval.setChecked.call_count, 0, 'Should not be called') self.assertEqual(service_manager.theme_menu.menuAction().setVisible.call_count, 1, - 'Should have be called once') + 'Should have be called once') def test_build_presentation_non_pdf_context_menu(self): """ @@ -537,12 +537,12 @@ class TestServiceManager(TestCase): self.assertEqual(service_manager.time_action.setVisible.call_count, 1, 'Should have be called once') self.assertEqual(service_manager.auto_start_action.setVisible.call_count, 1, 'Should have be called once') self.assertEqual(service_manager.auto_play_slides_menu.menuAction().setVisible.call_count, 1, - 'Should have be called once') + 'Should have be called once') self.assertEqual(service_manager.auto_play_slides_once.setChecked.call_count, 0, 'Should not be called') self.assertEqual(service_manager.auto_play_slides_loop.setChecked.call_count, 0, 'Should not be called') self.assertEqual(service_manager.timed_slide_interval.setChecked.call_count, 0, 'Should not be called') self.assertEqual(service_manager.theme_menu.menuAction().setVisible.call_count, 1, - 'Should have be called once') + 'Should have be called once') @patch(u'openlp.core.ui.servicemanager.Settings') @patch(u'PyQt5.QtCore.QTimer.singleShot') @@ -606,7 +606,8 @@ class TestServiceManager(TestCase): # WHEN: on_single_click_preview() is called service_manager.on_single_click_preview_timeout() # THEN: make_preview() should have been called - self.assertEqual(mocked_make_preview.call_count, 1, 'ServiceManager.make_preview() should have been called once') + self.assertEqual(mocked_make_preview.call_count, 1, + 'ServiceManager.make_preview() should have been called once') @patch(u'openlp.core.ui.servicemanager.ServiceManager.make_preview') @patch(u'openlp.core.ui.servicemanager.ServiceManager.make_live') From 785257020dc6fd24e00b119640b132e62058cd78 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Sun, 17 Jul 2016 21:46:06 +0200 Subject: [PATCH 62/62] Fix some linting issues --- tests/functional/openlp_core_ui/test_servicemanager.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/functional/openlp_core_ui/test_servicemanager.py b/tests/functional/openlp_core_ui/test_servicemanager.py index 853baf1f0..3e4af8c97 100644 --- a/tests/functional/openlp_core_ui/test_servicemanager.py +++ b/tests/functional/openlp_core_ui/test_servicemanager.py @@ -679,4 +679,3 @@ class TestServiceManager(TestCase): # THEN: The "save_as" method is called to save the service self.assertTrue(result) mocked_save_file_as.assert_called_with() -