diff --git a/openlp/plugins/remotes/deploy.py b/openlp/core/api/deploy.py similarity index 96% rename from openlp/plugins/remotes/deploy.py rename to openlp/core/api/deploy.py index 44c628837..9b1e6e793 100644 --- a/openlp/plugins/remotes/deploy.py +++ b/openlp/core/api/deploy.py @@ -63,7 +63,7 @@ def download_and_check(callback=None): sha256, version = download_sha256() file_size = get_url_file_size('https://get.openlp.org/webclient/site.zip') callback.setRange(0, file_size) - if url_get_file(callback, '{host}{name}'.format(host='https://get.openlp.org/webclient/', name='site.zip'), + if url_get_file(callback, 'https://get.openlp.org/webclient/site.zip', AppLocation.get_section_data_path('remotes') / 'site.zip', sha256=sha256): deploy_zipfile(str(AppLocation.get_section_data_path('remotes')), 'site.zip') diff --git a/openlp/plugins/remotes/endpoint.py b/openlp/core/api/endpoint/remote.py similarity index 90% rename from openlp/plugins/remotes/endpoint.py rename to openlp/core/api/endpoint/remote.py index a9b0d0815..4741ada15 100644 --- a/openlp/plugins/remotes/endpoint.py +++ b/openlp/core/api/endpoint/remote.py @@ -21,18 +21,13 @@ ############################################################################### import logging -import os - from openlp.core.api.http.endpoint import Endpoint from openlp.core.api.endpoint.core import TRANSLATED_STRINGS -from openlp.core.common import AppLocation -static_dir = os.path.join(str(AppLocation.get_section_data_path('remotes'))) - log = logging.getLogger(__name__) -remote_endpoint = Endpoint('remote', template_dir=static_dir, static_dir=static_dir) +remote_endpoint = Endpoint('remote', template_dir='remotes', static_dir='remotes') @remote_endpoint.route('{view}') diff --git a/openlp/core/api/endpoint/service.py b/openlp/core/api/endpoint/service.py index acb139b43..4e3b53fbb 100644 --- a/openlp/core/api/endpoint/service.py +++ b/openlp/core/api/endpoint/service.py @@ -23,7 +23,7 @@ import logging import json from openlp.core.api.http.endpoint import Endpoint -from openlp.core.api.http import register_endpoint, requires_auth +from openlp.core.api.http import requires_auth from openlp.core.common import Registry diff --git a/openlp/core/api/http/server.py b/openlp/core/api/http/server.py index a7ec34903..2a2ec7292 100644 --- a/openlp/core/api/http/server.py +++ b/openlp/core/api/http/server.py @@ -26,17 +26,24 @@ with OpenLP. It uses JSON to communicate with the remotes. """ import logging +import time -from PyQt5 import QtCore +from PyQt5 import QtCore, QtWidgets from waitress import serve from openlp.core.api.http import register_endpoint from openlp.core.api.http import application -from openlp.core.common import RegistryMixin, RegistryProperties, OpenLPMixin, Settings, Registry +from openlp.core.common import AppLocation, RegistryMixin, RegistryProperties, OpenLPMixin, \ + Settings, Registry, UiStrings, check_directory_exists +from openlp.core.lib import translate + +from openlp.core.api.deploy import download_and_check, download_sha256 from openlp.core.api.poll import Poller from openlp.core.api.endpoint.controller import controller_endpoint, api_controller_endpoint from openlp.core.api.endpoint.core import chords_endpoint, stage_endpoint, blank_endpoint, main_endpoint from openlp.core.api.endpoint.service import service_endpoint, api_service_endpoint +from openlp.core.api.endpoint.remote import remote_endpoint + log = logging.getLogger(__name__) @@ -59,6 +66,7 @@ class HttpWorker(QtCore.QObject): """ address = Settings().value('api/ip address') port = Settings().value('api/port') + Registry().execute('get_website_version') serve(application, host=address, port=port) def stop(self): @@ -79,11 +87,15 @@ class HttpServer(RegistryMixin, RegistryProperties, OpenLPMixin): self.worker.moveToThread(self.thread) self.thread.started.connect(self.worker.run) self.thread.start() + Registry().register_function('download_website', self.first_time) + Registry().register_function('get_website_version', self.website_version) + Registry().set_flag('website_version', '0.0') def bootstrap_post_set_up(self): """ Register the poll return service and start the servers. """ + self.initialise() self.poller = Poller() Registry().register('poller', self.poller) application.initialise() @@ -95,3 +107,79 @@ class HttpServer(RegistryMixin, RegistryProperties, OpenLPMixin): register_endpoint(main_endpoint) register_endpoint(service_endpoint) register_endpoint(api_service_endpoint) + register_endpoint(remote_endpoint) + + @staticmethod + def initialise(): + """ + Create the internal file structure if it does not exist + :return: + """ + check_directory_exists(AppLocation.get_section_data_path('remotes') / 'assets') + check_directory_exists(AppLocation.get_section_data_path('remotes') / 'images') + check_directory_exists(AppLocation.get_section_data_path('remotes') / 'static') + check_directory_exists(AppLocation.get_section_data_path('remotes') / 'static' / 'index') + check_directory_exists(AppLocation.get_section_data_path('remotes') / 'templates') + + def first_time(self): + """ + Import web site code if active + """ + self.application.process_events() + progress = DownloadProgressDialog(self) + progress.forceShow() + self.application.process_events() + time.sleep(1) + download_and_check(progress) + self.application.process_events() + time.sleep(1) + progress.close() + self.application.process_events() + Settings().setValue('remotes/download version', self.version) + + def website_version(self): + """ + Download and save the website version and sha256 + :return: None + """ + sha256, self.version = download_sha256() + Registry().set_flag('website_sha256', sha256) + Registry().set_flag('website_version', self.version) + + +class DownloadProgressDialog(QtWidgets.QProgressDialog): + """ + Local class to handle download display based and supporting httputils:get_web_page + """ + def __init__(self, parent): + super(DownloadProgressDialog, self).__init__(parent.main_window) + self.parent = parent + self.setWindowModality(QtCore.Qt.WindowModal) + self.setWindowTitle(translate('RemotePlugin', 'Importing Website')) + self.setLabelText(UiStrings().StartingImport) + self.setCancelButton(None) + self.setRange(0, 1) + self.setMinimumDuration(0) + self.was_cancelled = False + self.previous_size = 0 + + def _download_progress(self, count, block_size): + """ + Calculate and display the download progress. + """ + increment = (count * block_size) - self.previous_size + self._increment_progress_bar(None, increment) + self.previous_size = count * block_size + + def _increment_progress_bar(self, status_text, increment=1): + """ + Update the wizard progress page. + + :param status_text: Current status information to display. + :param increment: The value to increment the progress bar by. + """ + if status_text: + self.setText(status_text) + if increment > 0: + self.setValue(self.value() + increment) + self.parent.application.process_events() diff --git a/openlp/core/api/tab.py b/openlp/core/api/tab.py index 3ec8c4515..7f645d6c6 100644 --- a/openlp/core/api/tab.py +++ b/openlp/core/api/tab.py @@ -129,36 +129,21 @@ class ApiTab(SettingsTab): self.master_version_value.setObjectName('master_version_value') self.update_site_layout.addRow(self.master_version_label, self.master_version_value) self.left_layout.addWidget(self.update_site_group_box) - self.android_app_group_box = QtWidgets.QGroupBox(self.right_column) - self.android_app_group_box.setObjectName('android_app_group_box') - self.right_layout.addWidget(self.android_app_group_box) - self.android_qr_layout = QtWidgets.QVBoxLayout(self.android_app_group_box) - self.android_qr_layout.setObjectName('android_qr_layout') - self.android_qr_code_label = QtWidgets.QLabel(self.android_app_group_box) - self.android_qr_code_label.setPixmap(QtGui.QPixmap(':/remotes/android_app_qr.png')) - self.android_qr_code_label.setAlignment(QtCore.Qt.AlignCenter) - self.android_qr_code_label.setObjectName('android_qr_code_label') - self.android_qr_layout.addWidget(self.android_qr_code_label) - self.android_qr_description_label = QtWidgets.QLabel(self.android_app_group_box) - self.android_qr_description_label.setObjectName('android_qr_description_label') - self.android_qr_description_label.setOpenExternalLinks(True) - self.android_qr_description_label.setWordWrap(True) - self.android_qr_layout.addWidget(self.android_qr_description_label) - self.ios_app_group_box = QtWidgets.QGroupBox(self.right_column) - self.ios_app_group_box.setObjectName('ios_app_group_box') - self.right_layout.addWidget(self.ios_app_group_box) - self.ios_qr_layout = QtWidgets.QVBoxLayout(self.ios_app_group_box) - self.ios_qr_layout.setObjectName('ios_qr_layout') - self.ios_qr_code_label = QtWidgets.QLabel(self.ios_app_group_box) - self.ios_qr_code_label.setPixmap(QtGui.QPixmap(':/remotes/ios_app_qr.png')) - self.ios_qr_code_label.setAlignment(QtCore.Qt.AlignCenter) - self.ios_qr_code_label.setObjectName('ios_qr_code_label') - self.ios_qr_layout.addWidget(self.ios_qr_code_label) - self.ios_qr_description_label = QtWidgets.QLabel(self.ios_app_group_box) - self.ios_qr_description_label.setObjectName('ios_qr_description_label') - self.ios_qr_description_label.setOpenExternalLinks(True) - self.ios_qr_description_label.setWordWrap(True) - self.ios_qr_layout.addWidget(self.ios_qr_description_label) + self.app_group_box = QtWidgets.QGroupBox(self.right_column) + self.app_group_box.setObjectName('app_group_box') + self.right_layout.addWidget(self.app_group_box) + self.app_qr_layout = QtWidgets.QVBoxLayout(self.app_group_box) + self.app_qr_layout.setObjectName('app_qr_layout') + self.app_qr_code_label = QtWidgets.QLabel(self.app_group_box) + self.app_qr_code_label.setPixmap(QtGui.QPixmap(':/remotes/app_qr.svg')) + self.app_qr_code_label.setAlignment(QtCore.Qt.AlignCenter) + self.app_qr_code_label.setObjectName('app_qr_code_label') + self.app_qr_layout.addWidget(self.app_qr_code_label) + self.app_qr_description_label = QtWidgets.QLabel(self.app_group_box) + self.app_qr_description_label.setObjectName('app_qr_description_label') + self.app_qr_description_label.setOpenExternalLinks(True) + self.app_qr_description_label.setWordWrap(True) + self.app_qr_layout.addWidget(self.app_qr_description_label) self.left_layout.addStretch() self.right_layout.addStretch() self.twelve_hour_check_box.stateChanged.connect(self.on_twelve_hour_check_box_changed) @@ -195,16 +180,11 @@ class ApiTab(SettingsTab): self.twelve_hour_check_box.setText(translate('RemotePlugin.RemoteTab', 'Display stage time in 12h format')) self.thumbnails_check_box.setText(translate('RemotePlugin.RemoteTab', '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( + self.app_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'Remote App')) + self.app_qr_description_label.setText( 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.').format(qr='https://itunes.apple.com/app/id1096218725')) + 'Scan the QR code or click download to download an app for your mobile device' + ).format(qr='https://openlp.org/#mobile-app-downloads')) self.user_login_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'User Authentication')) self.aa = UiStrings() self.update_site_group_box.setTitle(UiStrings().WebDownloadText) @@ -222,6 +202,8 @@ class ApiTab(SettingsTab): self.remote_url.setText('{url}'.format(url=http_url)) http_url_temp = http_url + 'stage' self.stage_url.setText('{url}'.format(url=http_url_temp)) + http_url_temp = http_url + 'chords' + self.chords_url.setText('{url}'.format(url=http_url_temp)) http_url_temp = http_url + 'main' self.live_url.setText('{url}'.format(url=http_url_temp)) diff --git a/openlp/core/common/settings.py b/openlp/core/common/settings.py index 0540ff81e..ca59d4e6f 100644 --- a/openlp/core/common/settings.py +++ b/openlp/core/common/settings.py @@ -178,6 +178,7 @@ class Settings(QtCore.QSettings): 'images/background color': '#000000', 'media/players': 'system,webkit', 'media/override player': QtCore.Qt.Unchecked, + 'remotes/download version': '0.0', 'players/background color': '#000000', 'servicemanager/last directory': None, 'servicemanager/last file': None, diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index 3d561ea84..124b158e8 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -426,10 +426,10 @@ class ServiceItem(RegistryProperties): self.background_audio = [] for filename in header['background_audio']: # Give them real file paths. - filepath = filename + filepath = str(filename) if path: # Windows can handle both forward and backward slashes, so we use ntpath to get the basename - filepath = os.path.join(path, ntpath.basename(filename)) + filepath = os.path.join(path, ntpath.basename(str(filename))) self.background_audio.append(filepath) self.theme_overwritten = header.get('theme_overwritten', False) if self.service_item_type == ServiceItemType.Text: diff --git a/openlp/core/ui/maindisplay.py b/openlp/core/ui/maindisplay.py index 8c8940369..097d92699 100644 --- a/openlp/core/ui/maindisplay.py +++ b/openlp/core/ui/maindisplay.py @@ -684,7 +684,7 @@ class AudioPlayer(OpenLPMixin, QtCore.QObject): if not isinstance(file_names, list): file_names = [file_names] for file_name in file_names: - self.playlist.addMedia(QtMultimedia.QMediaContent(QtCore.QUrl.fromLocalFile(file_name))) + self.playlist.addMedia(QtMultimedia.QMediaContent(QtCore.QUrl.fromLocalFile(str(file_name)))) def next(self): """ diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index b5b77d265..153034e33 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -561,7 +561,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa service_item = item['service_item'].get_service_repr(self._save_lite) if service_item['header']['background_audio']: for i, file_name in enumerate(service_item['header']['background_audio']): - new_file = os.path.join('audio', item['service_item'].unique_identifier, file_name) + new_file = os.path.join('audio', item['service_item'].unique_identifier, str(file_name)) audio_files.append((file_name, new_file)) service_item['header']['background_audio'][i] = new_file # Add the service item to the service. @@ -586,6 +586,8 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa for write_from in write_list: zip_file.write(write_from, write_from) for audio_from, audio_to in audio_files: + audio_from = str(audio_from) + audio_to = str(audio_to) if audio_from.startswith('audio'): # When items are saved, they get new unique_identifier. Let's copy the file to the new location. # Unused files can be ignored, OpenLP automatically cleans up the service manager dir on exit. diff --git a/openlp/core/ui/slidecontroller.py b/openlp/core/ui/slidecontroller.py index 23352c215..26bbeb38d 100644 --- a/openlp/core/ui/slidecontroller.py +++ b/openlp/core/ui/slidecontroller.py @@ -868,7 +868,7 @@ class SlideController(DisplayController, RegistryProperties): self.track_menu.clear() for counter in range(len(self.service_item.background_audio)): action = self.track_menu.addAction( - os.path.basename(self.service_item.background_audio[counter])) + os.path.basename(str(self.service_item.background_audio[counter]))) action.setData(counter) action.triggered.connect(self.on_track_triggered) self.display.audio_player.repeat = \ diff --git a/openlp/plugins/bibles/endpoint.py b/openlp/plugins/bibles/endpoint.py index 08a945e7c..4d34eb966 100644 --- a/openlp/plugins/bibles/endpoint.py +++ b/openlp/plugins/bibles/endpoint.py @@ -62,7 +62,7 @@ def bibles_service(request): :param request: The http request object. """ - service(request, 'bibles', log) + return service(request, 'bibles', log) @api_bibles_endpoint.route('bibles/search') @@ -95,6 +95,6 @@ def bibles_service_api(request): :param request: The http request object. """ try: - search(request, 'bibles', log) + return search(request, 'bibles', log) except NotFound: return {'results': {'items': []}} diff --git a/openlp/plugins/custom/endpoint.py b/openlp/plugins/custom/endpoint.py index 687ffaa1b..ca5c39088 100644 --- a/openlp/plugins/custom/endpoint.py +++ b/openlp/plugins/custom/endpoint.py @@ -62,7 +62,7 @@ def custom_service(request): :param request: The http request object. """ - service(request, 'custom', log) + return service(request, 'custom', log) @api_custom_endpoint.route('custom/search') @@ -95,6 +95,6 @@ def custom_service_api(request): :param request: The http request object. """ try: - search(request, 'custom', log) + return search(request, 'custom', log) except NotFound: return {'results': {'items': []}} diff --git a/openlp/plugins/images/endpoint.py b/openlp/plugins/images/endpoint.py index ca82da00a..05c1e64b4 100644 --- a/openlp/plugins/images/endpoint.py +++ b/openlp/plugins/images/endpoint.py @@ -75,7 +75,7 @@ def images_service(request): :param request: The http request object. """ - service(request, 'images', log) + return service(request, 'images', log) @api_images_endpoint.route('images/search') @@ -108,6 +108,6 @@ def images_service_api(request): :param request: The http request object. """ try: - search(request, 'images', log) + return search(request, 'images', log) except NotFound: return {'results': {'items': []}} diff --git a/openlp/plugins/media/endpoint.py b/openlp/plugins/media/endpoint.py index 014c3c790..c7b703358 100644 --- a/openlp/plugins/media/endpoint.py +++ b/openlp/plugins/media/endpoint.py @@ -62,7 +62,7 @@ def media_service(request): :param request: The http request object. """ - service(request, 'media', log) + return service(request, 'media', log) @api_media_endpoint.route('media/search') @@ -95,6 +95,6 @@ def media_service_api(request): :param request: The http request object. """ try: - search(request, 'media', log) + return search(request, 'media', log) except NotFound: return {'results': {'items': []}} diff --git a/openlp/plugins/presentations/endpoint.py b/openlp/plugins/presentations/endpoint.py index ce622083c..99c828b4b 100644 --- a/openlp/plugins/presentations/endpoint.py +++ b/openlp/plugins/presentations/endpoint.py @@ -76,7 +76,7 @@ def presentations_service(request): :param request: The http request object. """ - service(request, 'presentations', log) + return service(request, 'presentations', log) @api_presentations_endpoint.route('presentations/search') @@ -109,6 +109,6 @@ def presentations_service_api(request): :param request: The http request object. """ try: - search(request, 'presentations', log) + return search(request, 'presentations', log) except NotFound: return {'results': {'items': []}} diff --git a/openlp/plugins/remotes/__init__.py b/openlp/plugins/remotes/__init__.py deleted file mode 100644 index ea62548f4..000000000 --- a/openlp/plugins/remotes/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- -# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 - -############################################################################### -# OpenLP - Open Source Lyrics Projection # -# --------------------------------------------------------------------------- # -# Copyright (c) 2008-2017 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 # -############################################################################### diff --git a/openlp/plugins/remotes/remoteplugin.py b/openlp/plugins/remotes/remoteplugin.py deleted file mode 100644 index 1344c66d1..000000000 --- a/openlp/plugins/remotes/remoteplugin.py +++ /dev/null @@ -1,155 +0,0 @@ -# -*- coding: utf-8 -*- -# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 - -############################################################################### -# OpenLP - Open Source Lyrics Projection # -# --------------------------------------------------------------------------- # -# Copyright (c) 2008-2017 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 # -############################################################################### - -import logging -import os -import time - -from PyQt5 import QtCore, QtWidgets - -from openlp.core.api.http import register_endpoint -from openlp.core.common import AppLocation, Registry, Settings, OpenLPMixin, UiStrings, check_directory_exists -from openlp.core.lib import Plugin, StringContent, translate, build_icon -from openlp.plugins.remotes.endpoint import remote_endpoint -from openlp.plugins.remotes.deploy import download_and_check, download_sha256 - -log = logging.getLogger(__name__) -__default_settings__ = { - 'remotes/download version': '0000_00_00' -} - - -class RemotesPlugin(Plugin, OpenLPMixin): - log.info('Remotes Plugin loaded') - - def __init__(self): - """ - remotes constructor - """ - super(RemotesPlugin, self).__init__('remotes', __default_settings__, {}) - self.icon_path = ':/plugins/plugin_remote.png' - self.icon = build_icon(self.icon_path) - self.weight = -1 - register_endpoint(remote_endpoint) - Registry().register_function('download_website', self.first_time) - Registry().register_function('get_website_version', self.website_version) - Registry().set_flag('website_version', '0001_01_01') - - def initialise(self): - """ - Create the internal file structure if it does not exist - :return: - """ - check_directory_exists(AppLocation.get_section_data_path('remotes') / 'assets') - check_directory_exists(AppLocation.get_section_data_path('remotes') / 'images') - check_directory_exists(AppLocation.get_section_data_path('remotes') / 'static') - check_directory_exists(AppLocation.get_section_data_path('remotes') / 'static', 'index') - check_directory_exists(AppLocation.get_section_data_path('remotes') / 'templates') - - @staticmethod - def about(): - """ - Information about this plugin - """ - about_text = translate( - 'RemotePlugin', - 'Web Interface' - '
The web interface plugin provides the ability to develop web based interfaces using OpenLP web ' - 'services.\nPredefined interfaces can be download as well as custom developed interfaces.') - return about_text - - def set_plugin_text_strings(self): - """ - Called to define all translatable texts of the plugin - """ - # Name PluginList - self.text_strings[StringContent.Name] = { - 'singular': translate('RemotePlugin', 'Web Interface', 'name singular'), - 'plural': translate('RemotePlugin', 'Web Interface', 'name plural') - } - # Name for MediaDockManager, SettingsManager - self.text_strings[StringContent.VisibleName] = { - 'title': translate('RemotePlugin', 'Web Remote', 'container title') - } - - def first_time(self): - """ - Import web site code if active - """ - self.application.process_events() - progress = Progress(self) - progress.forceShow() - self.application.process_events() - time.sleep(1) - download_and_check(progress) - self.application.process_events() - time.sleep(1) - progress.close() - self.application.process_events() - Settings().setValue('remotes/download version', self.version) - - def website_version(self): - """ - Download and save the website version and sha256 - :return: None - """ - sha256, self.version = download_sha256() - Registry().set_flag('website_sha256', sha256) - Registry().set_flag('website_version', self.version) - - -class Progress(QtWidgets.QProgressDialog): - """ - Local class to handle download display based and supporting httputils:get_web_page - """ - def __init__(self, parent): - super(Progress, self).__init__(parent.main_window) - self.parent = parent - self.setWindowModality(QtCore.Qt.WindowModal) - self.setWindowTitle(translate('RemotePlugin', 'Importing Website')) - self.setLabelText(UiStrings().StartingImport) - self.setCancelButton(None) - self.setRange(0, 1) - self.setMinimumDuration(0) - self.was_cancelled = False - self.previous_size = 0 - - def _download_progress(self, count, block_size): - """ - Calculate and display the download progress. - """ - increment = (count * block_size) - self.previous_size - self._increment_progress_bar(None, increment) - self.previous_size = count * block_size - - def _increment_progress_bar(self, status_text, increment=1): - """ - Update the wizard progress page. - - :param status_text: Current status information to display. - :param increment: The value to increment the progress bar by. - """ - if status_text: - self.setText(status_text) - if increment > 0: - self.setValue(self.value() + increment) - self.parent.application.process_events() diff --git a/openlp/plugins/songs/endpoint.py b/openlp/plugins/songs/endpoint.py index 8711fcccd..c8af62764 100644 --- a/openlp/plugins/songs/endpoint.py +++ b/openlp/plugins/songs/endpoint.py @@ -62,7 +62,7 @@ def songs_service(request): :param request: The http request object. """ - service(request, 'songs', log) + return service(request, 'songs', log) @api_songs_endpoint.route('songs/search') @@ -95,6 +95,6 @@ def songs_service_api(request): :param request: The http request object. """ try: - search(request, 'songs', log) + return service(request, 'songs', log) except NotFound: return {'results': {'items': []}} diff --git a/openlp/plugins/songs/forms/editsongform.py b/openlp/plugins/songs/forms/editsongform.py index a8c0ed32f..db7053b91 100644 --- a/openlp/plugins/songs/forms/editsongform.py +++ b/openlp/plugins/songs/forms/editsongform.py @@ -23,27 +23,25 @@ The :mod:`~openlp.plugins.songs.forms.editsongform` module contains the form used to edit songs. """ - import logging -import re import os -import shutil +import re from PyQt5 import QtCore, QtWidgets from openlp.core.common import Registry, RegistryProperties, AppLocation, UiStrings, check_directory_exists, translate -from openlp.core.common.path import Path, path_to_str +from openlp.core.common.languagemanager import get_natural_key +from openlp.core.common.path import copyfile from openlp.core.lib import PluginStatus, MediaType, create_separated_list from openlp.core.lib.ui import set_case_insensitive_completer, critical_error_message_box, find_and_set_in_combo_box from openlp.core.ui.lib.filedialog import FileDialog -from openlp.core.common.languagemanager import get_natural_key -from openlp.plugins.songs.lib import VerseType, clean_song -from openlp.plugins.songs.lib.db import Book, Song, Author, AuthorType, Topic, MediaFile, SongBookEntry -from openlp.plugins.songs.lib.ui import SongStrings -from openlp.plugins.songs.lib.openlyricsxml import SongXML from openlp.plugins.songs.forms.editsongdialog import Ui_EditSongDialog from openlp.plugins.songs.forms.editverseform import EditVerseForm from openlp.plugins.songs.forms.mediafilesform import MediaFilesForm +from openlp.plugins.songs.lib import VerseType, clean_song +from openlp.plugins.songs.lib.db import Book, Song, Author, AuthorType, Topic, MediaFile, SongBookEntry +from openlp.plugins.songs.lib.openlyricsxml import SongXML +from openlp.plugins.songs.lib.ui import SongStrings log = logging.getLogger(__name__) @@ -545,9 +543,9 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties): songbook_entry.entry) self.audio_list_widget.clear() for media in self.song.media_files: - media_file = QtWidgets.QListWidgetItem(os.path.split(media.file_name)[1]) - media_file.setData(QtCore.Qt.UserRole, media.file_name) - self.audio_list_widget.addItem(media_file) + item = QtWidgets.QListWidgetItem(media.file_path.name) + item.setData(QtCore.Qt.UserRole, media.file_path) + self.audio_list_widget.addItem(item) self.title_edit.setFocus() # Hide or show the preview button. self.preview_button.setVisible(preview) @@ -927,12 +925,11 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties): Loads file(s) from the filesystem. """ filters = '{text} (*)'.format(text=UiStrings().AllFiles) - file_paths, selected_filter = FileDialog.getOpenFileNames( - self, translate('SongsPlugin.EditSongForm', 'Open File(s)'), Path(), filters) + file_paths, filter_used = FileDialog.getOpenFileNames( + parent=self, caption=translate('SongsPlugin.EditSongForm', 'Open File(s)'), filter=filters) for file_path in file_paths: - filename = path_to_str(file_path) - item = QtWidgets.QListWidgetItem(os.path.split(str(filename))[1]) - item.setData(QtCore.Qt.UserRole, filename) + item = QtWidgets.QListWidgetItem(file_path.name) + item.setData(QtCore.Qt.UserRole, file_path) self.audio_list_widget.addItem(item) def on_audio_add_from_media_button_clicked(self): @@ -940,9 +937,9 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties): Loads file(s) from the media plugin. """ if self.media_form.exec(): - for filename in self.media_form.get_selected_files(): - item = QtWidgets.QListWidgetItem(os.path.split(str(filename))[1]) - item.setData(QtCore.Qt.UserRole, filename) + for file_path in self.media_form.get_selected_files(): + item = QtWidgets.QListWidgetItem(file_path.name) + item.setData(QtCore.Qt.UserRole, file_path) self.audio_list_widget.addItem(item) def on_audio_remove_button_clicked(self): @@ -1066,34 +1063,33 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties): # Save the song here because we need a valid id for the audio files. clean_song(self.manager, self.song) self.manager.save_object(self.song) - audio_files = [a.file_name for a in self.song.media_files] - log.debug(audio_files) - save_path = os.path.join(str(AppLocation.get_section_data_path(self.media_item.plugin.name)), 'audio', - str(self.song.id)) - check_directory_exists(Path(save_path)) + audio_paths = [a.file_path for a in self.song.media_files] + log.debug(audio_paths) + save_path = AppLocation.get_section_data_path(self.media_item.plugin.name) / 'audio' / str(self.song.id) + check_directory_exists(save_path) self.song.media_files = [] - files = [] + file_paths = [] for row in range(self.audio_list_widget.count()): item = self.audio_list_widget.item(row) - filename = item.data(QtCore.Qt.UserRole) - if not filename.startswith(save_path): - old_file, filename = filename, os.path.join(save_path, os.path.split(filename)[1]) - shutil.copyfile(old_file, filename) - files.append(filename) + file_path = item.data(QtCore.Qt.UserRole) + if save_path not in file_path.parents: + old_file_path, file_path = file_path, save_path / file_path.name + copyfile(old_file_path, file_path) + file_paths.append(file_path) media_file = MediaFile() - media_file.file_name = filename + media_file.file_path = file_path media_file.type = 'audio' media_file.weight = row self.song.media_files.append(media_file) - for audio in audio_files: - if audio not in files: + for audio_path in audio_paths: + if audio_path not in file_paths: try: - os.remove(audio) + audio_path.unlink() except: - log.exception('Could not remove file: {audio}'.format(audio=audio)) - if not files: + log.exception('Could not remove file: {audio}'.format(audio=audio_path)) + if not file_paths: try: - os.rmdir(save_path) + save_path.rmdir() except OSError: log.exception('Could not remove directory: {path}'.format(path=save_path)) clean_song(self.manager, self.song) diff --git a/openlp/plugins/songs/forms/mediafilesform.py b/openlp/plugins/songs/forms/mediafilesform.py index 10e9334f7..8718471ea 100644 --- a/openlp/plugins/songs/forms/mediafilesform.py +++ b/openlp/plugins/songs/forms/mediafilesform.py @@ -41,12 +41,19 @@ class MediaFilesForm(QtWidgets.QDialog, Ui_MediaFilesDialog): QtCore.Qt.WindowCloseButtonHint) self.setupUi(self) - def populate_files(self, files): + def populate_files(self, file_paths): + """ + :param list[openlp.core.common.path.Path] file_paths: + :return: + """ self.file_list_widget.clear() - for file in files: - item = QtWidgets.QListWidgetItem(os.path.split(file)[1]) - item.setData(QtCore.Qt.UserRole, file) + for file_path in file_paths: + item = QtWidgets.QListWidgetItem(file_path.name) + item.setData(QtCore.Qt.UserRole, file_path) self.file_list_widget.addItem(item) def get_selected_files(self): + """ + :rtype: list[openlp.core.common.path.Path] + """ return [item.data(QtCore.Qt.UserRole) for item in self.file_list_widget.selectedItems()] diff --git a/openlp/plugins/songs/forms/songexportform.py b/openlp/plugins/songs/forms/songexportform.py index 03ac9ee22..582d63a84 100644 --- a/openlp/plugins/songs/forms/songexportform.py +++ b/openlp/plugins/songs/forms/songexportform.py @@ -27,9 +27,10 @@ import logging from PyQt5 import QtCore, QtWidgets -from openlp.core.common import Registry, UiStrings, translate -from openlp.core.lib import create_separated_list, build_icon +from openlp.core.common import Registry, Settings, UiStrings, translate +from openlp.core.lib import create_separated_list from openlp.core.lib.ui import critical_error_message_box +from openlp.core.ui.lib import PathEdit, PathType from openlp.core.ui.lib.wizard import OpenLPWizard, WizardStrings from openlp.plugins.songs.lib.db import Song from openlp.plugins.songs.lib.openlyricsexport import OpenLyricsExport @@ -76,7 +77,6 @@ class SongExportForm(OpenLPWizard): self.search_line_edit.textEdited.connect(self.on_search_line_edit_changed) self.uncheck_button.clicked.connect(self.on_uncheck_button_clicked) self.check_button.clicked.connect(self.on_check_button_clicked) - self.directory_button.clicked.connect(self.on_directory_button_clicked) def add_custom_pages(self): """ @@ -120,21 +120,15 @@ class SongExportForm(OpenLPWizard): self.grid_layout.setObjectName('range_layout') self.selected_list_widget = QtWidgets.QListWidget(self.export_song_page) self.selected_list_widget.setObjectName('selected_list_widget') - self.grid_layout.addWidget(self.selected_list_widget, 1, 0, 1, 1) - # FIXME: self.horizontal_layout is already defined above?!?!? Replace with Path Eidt! - self.horizontal_layout = QtWidgets.QHBoxLayout() - self.horizontal_layout.setObjectName('horizontal_layout') + self.grid_layout.addWidget(self.selected_list_widget, 1, 0, 1, 2) + self.output_directory_path_edit = PathEdit( + self.export_song_page, PathType.Directories, + dialog_caption=translate('SongsPlugin.ExportWizardForm', 'Select Destination Folder'), show_revert=False) + self.output_directory_path_edit.path = Settings().value('songs/last directory export') self.directory_label = QtWidgets.QLabel(self.export_song_page) self.directory_label.setObjectName('directory_label') - self.horizontal_layout.addWidget(self.directory_label) - self.directory_line_edit = QtWidgets.QLineEdit(self.export_song_page) - self.directory_line_edit.setObjectName('directory_line_edit') - self.horizontal_layout.addWidget(self.directory_line_edit) - self.directory_button = QtWidgets.QToolButton(self.export_song_page) - self.directory_button.setIcon(build_icon(':/exports/export_load.png')) - self.directory_button.setObjectName('directory_button') - self.horizontal_layout.addWidget(self.directory_button) - self.grid_layout.addLayout(self.horizontal_layout, 0, 0, 1, 1) + self.grid_layout.addWidget(self.directory_label, 0, 0) + self.grid_layout.addWidget(self.output_directory_path_edit, 0, 1) self.export_song_layout.addLayout(self.grid_layout) self.addPage(self.export_song_page) @@ -188,11 +182,12 @@ class SongExportForm(OpenLPWizard): self.selected_list_widget.addItem(song) return True elif self.currentPage() == self.export_song_page: - if not self.directory_line_edit.text(): + if not self.output_directory_path_edit.path: critical_error_message_box( translate('SongsPlugin.ExportWizardForm', 'No Save Location specified'), translate('SongsPlugin.ExportWizardForm', 'You need to specify a directory.')) return False + Settings().setValue('songs/last directory export', self.output_directory_path_edit.path) return True elif self.currentPage() == self.progress_page: self.available_list_widget.clear() @@ -211,8 +206,6 @@ class SongExportForm(OpenLPWizard): self.finish_button.setVisible(False) self.cancel_button.setVisible(True) self.available_list_widget.clear() - self.selected_list_widget.clear() - self.directory_line_edit.clear() self.search_line_edit.clear() # Load the list of songs. self.application.set_busy_cursor() @@ -247,7 +240,7 @@ class SongExportForm(OpenLPWizard): song.data(QtCore.Qt.UserRole) for song in find_list_widget_items(self.selected_list_widget) ] - exporter = OpenLyricsExport(self, songs, self.directory_line_edit.text()) + exporter = OpenLyricsExport(self, songs, self.output_directory_path_edit.path) try: if exporter.do_export(): self.progress_label.setText( @@ -291,15 +284,6 @@ class SongExportForm(OpenLPWizard): if not item.isHidden(): item.setCheckState(QtCore.Qt.Checked) - def on_directory_button_clicked(self): - """ - Called when the *directory_button* was clicked. Opens a dialog and writes - the path to *directory_line_edit*. - """ - self.get_folder( - translate('SongsPlugin.ExportWizardForm', 'Select Destination Folder'), - self.directory_line_edit, 'last directory export') - def find_list_widget_items(list_widget, text=''): """ diff --git a/openlp/plugins/songs/forms/songimportform.py b/openlp/plugins/songs/forms/songimportform.py index 502d40126..5a88ad4cb 100644 --- a/openlp/plugins/songs/forms/songimportform.py +++ b/openlp/plugins/songs/forms/songimportform.py @@ -22,15 +22,13 @@ """ The song import functions for OpenLP. """ -import codecs import logging -import os from PyQt5 import QtCore, QtWidgets from openlp.core.common import RegistryProperties, Settings, UiStrings, translate -from openlp.core.common.path import path_to_str, str_to_path from openlp.core.lib.ui import critical_error_message_box +from openlp.core.ui.lib import PathEdit, PathType from openlp.core.ui.lib.filedialog import FileDialog from openlp.core.ui.lib.wizard import OpenLPWizard, WizardStrings from openlp.plugins.songs.lib.importer import SongFormat, SongFormatSelect @@ -93,9 +91,7 @@ class SongImportForm(OpenLPWizard, RegistryProperties): self.format_widgets[song_format]['addButton'].clicked.connect(self.on_add_button_clicked) self.format_widgets[song_format]['removeButton'].clicked.connect(self.on_remove_button_clicked) else: - self.format_widgets[song_format]['browseButton'].clicked.connect(self.on_browse_button_clicked) - self.format_widgets[song_format]['file_path_edit'].textChanged.\ - connect(self.on_filepath_edit_text_changed) + self.format_widgets[song_format]['path_edit'].pathChanged.connect(self.on_path_edit_path_changed) def add_custom_pages(self): """ @@ -155,7 +151,6 @@ class SongImportForm(OpenLPWizard, RegistryProperties): self.format_widgets[format_list]['removeButton'].setText( translate('SongsPlugin.ImportWizardForm', 'Remove File(s)')) else: - self.format_widgets[format_list]['browseButton'].setText(UiStrings().Browse) f_label = 'Filename:' if select_mode == SongFormatSelect.SingleFolder: f_label = 'Folder:' @@ -172,16 +167,11 @@ class SongImportForm(OpenLPWizard, RegistryProperties): self.error_save_to_button.setText(translate('SongsPlugin.ImportWizardForm', 'Save to File')) # Align all QFormLayouts towards each other. formats = [f for f in SongFormat.get_format_list() if 'filepathLabel' in self.format_widgets[f]] - labels = [self.format_widgets[f]['filepathLabel'] for f in formats] + labels = [self.format_widgets[f]['filepathLabel'] for f in formats] + [self.format_label] # Get max width of all labels - max_label_width = max(self.format_label.minimumSizeHint().width(), - max([label.minimumSizeHint().width() for label in labels])) - self.format_spacer.changeSize(max_label_width, 0, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) - spacers = [self.format_widgets[f]['filepathSpacer'] for f in formats] - for index, spacer in enumerate(spacers): - spacer.changeSize( - max_label_width - labels[index].minimumSizeHint().width(), 0, - QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) + max_label_width = max(labels, key=lambda label: label.minimumSizeHint().width()).minimumSizeHint().width() + for label in labels: + label.setFixedWidth(max_label_width) # Align descriptionLabels with rest of layout for format_list in SongFormat.get_format_list(): if SongFormat.get(format_list, 'descriptionText') is not None: @@ -209,13 +199,13 @@ class SongImportForm(OpenLPWizard, RegistryProperties): Settings().setValue('songs/last import type', this_format) select_mode, class_, error_msg = SongFormat.get(this_format, 'selectMode', 'class', 'invalidSourceMsg') if select_mode == SongFormatSelect.MultipleFiles: - import_source = self.get_list_of_files(self.format_widgets[this_format]['file_list_widget']) + import_source = self.get_list_of_paths(self.format_widgets[this_format]['file_list_widget']) error_title = UiStrings().IFSp focus_button = self.format_widgets[this_format]['addButton'] else: - import_source = self.format_widgets[this_format]['file_path_edit'].text() + import_source = self.format_widgets[this_format]['path_edit'].path error_title = (UiStrings().IFSs if select_mode == SongFormatSelect.SingleFile else UiStrings().IFdSs) - focus_button = self.format_widgets[this_format]['browseButton'] + focus_button = self.format_widgets[this_format]['path_edit'] if not class_.is_valid_source(import_source): critical_error_message_box(error_title, error_msg) focus_button.setFocus() @@ -238,20 +228,23 @@ class SongImportForm(OpenLPWizard, RegistryProperties): if filters: filters += ';;' filters += '{text} (*)'.format(text=UiStrings().AllFiles) - file_paths, selected_filter = FileDialog.getOpenFileNames( - self, title, Settings().value(self.plugin.settings_section + '/last directory import'), filters) + file_paths, filter_used = FileDialog.getOpenFileNames( + self, title, + Settings().value(self.plugin.settings_section + '/last directory import'), filters) + for file_path in file_paths: + list_item = QtWidgets.QListWidgetItem(str(file_path)) + list_item.setData(QtCore.Qt.UserRole, file_path) + listbox.addItem(list_item) if file_paths: - file_names = [path_to_str(file_path) for file_path in file_paths] - listbox.addItems(file_names) Settings().setValue(self.plugin.settings_section + '/last directory import', file_paths[0].parent) - def get_list_of_files(self, list_box): + def get_list_of_paths(self, list_box): """ Return a list of file from the list_box :param list_box: The source list box """ - return [list_box.item(i).text() for i in range(list_box.count())] + return [list_box.item(i).data(QtCore.Qt.UserRole) for i in range(list_box.count())] def remove_selected_items(self, list_box): """ @@ -263,20 +256,6 @@ class SongImportForm(OpenLPWizard, RegistryProperties): item = list_box.takeItem(list_box.row(item)) del item - def on_browse_button_clicked(self): - """ - Browse for files or a directory. - """ - this_format = self.current_format - 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: - self.get_file_name(WizardStrings.OpenTypeFile.format(file_type=format_name), - file_path_edit, 'last directory import', ext_filter) - elif select_mode == SongFormatSelect.SingleFolder: - self.get_folder( - WizardStrings.OpenTypeFolder.format(folder_name=format_name), file_path_edit, 'last directory import') - def on_add_button_clicked(self): """ Add a file or directory. @@ -296,7 +275,7 @@ class SongImportForm(OpenLPWizard, RegistryProperties): self.remove_selected_items(self.format_widgets[self.current_format]['file_list_widget']) self.source_page.completeChanged.emit() - def on_filepath_edit_text_changed(self): + def on_path_edit_path_changed(self): """ Called when the content of the Filename/Folder edit box changes. """ @@ -317,8 +296,6 @@ class SongImportForm(OpenLPWizard, RegistryProperties): select_mode = SongFormat.get(format_list, 'selectMode') if select_mode == SongFormatSelect.MultipleFiles: self.format_widgets[format_list]['file_list_widget'].clear() - else: - self.format_widgets[format_list]['file_path_edit'].setText('') self.error_report_text_edit.clear() self.error_report_text_edit.setHidden(True) self.error_copy_to_button.setHidden(True) @@ -341,14 +318,14 @@ class SongImportForm(OpenLPWizard, RegistryProperties): select_mode = SongFormat.get(source_format, 'selectMode') if select_mode == SongFormatSelect.SingleFile: importer = self.plugin.import_songs(source_format, - filename=self.format_widgets[source_format]['file_path_edit'].text()) + file_path=self.format_widgets[source_format]['path_edit'].path) elif select_mode == SongFormatSelect.SingleFolder: importer = self.plugin.import_songs(source_format, - folder=self.format_widgets[source_format]['file_path_edit'].text()) + folder_path=self.format_widgets[source_format]['path_edit'].path) else: importer = self.plugin.import_songs( source_format, - filenames=self.get_list_of_files(self.format_widgets[source_format]['file_list_widget'])) + file_paths=self.get_list_of_paths(self.format_widgets[source_format]['file_list_widget'])) importer.do_import() self.progress_label.setText(WizardStrings.FinishedImport) @@ -366,18 +343,17 @@ class SongImportForm(OpenLPWizard, RegistryProperties): """ file_path, filter_used = FileDialog.getSaveFileName( self, Settings().value(self.plugin.settings_section + '/last directory import')) - if not file_path: + if file_path is None: return - with file_path.open('w', encoding='utf-8') as report_file: - report_file.write(self.error_report_text_edit.toPlainText()) + file_path.write_text(self.error_report_text_edit.toPlainText(), encoding='utf-8') def add_file_select_item(self): """ Add a file selection page. """ this_format = self.current_format - prefix, can_disable, description_text, select_mode = \ - SongFormat.get(this_format, 'prefix', 'canDisable', 'descriptionText', 'selectMode') + format_name, prefix, can_disable, description_text, select_mode, filters = \ + SongFormat.get(this_format, 'name', 'prefix', 'canDisable', 'descriptionText', 'selectMode', 'filter') page = QtWidgets.QWidget() page.setObjectName(prefix + 'Page') if can_disable: @@ -403,26 +379,23 @@ class SongImportForm(OpenLPWizard, RegistryProperties): if select_mode == SongFormatSelect.SingleFile or select_mode == SongFormatSelect.SingleFolder: file_path_layout = QtWidgets.QHBoxLayout() file_path_layout.setObjectName(prefix + '_file_path_layout') - file_path_layout.setContentsMargins(0, self.format_v_spacing, 0, 0) file_path_label = QtWidgets.QLabel(import_widget) - file_path_label.setObjectName(prefix + 'FilepathLabel') file_path_layout.addWidget(file_path_label) - file_path_spacer = QtWidgets.QSpacerItem(0, 0, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) - file_path_layout.addSpacerItem(file_path_spacer) - file_path_edit = QtWidgets.QLineEdit(import_widget) - file_path_edit.setObjectName(prefix + '_file_path_edit') - file_path_layout.addWidget(file_path_edit) - browse_button = QtWidgets.QToolButton(import_widget) - browse_button.setIcon(self.open_icon) - browse_button.setObjectName(prefix + 'BrowseButton') - file_path_layout.addWidget(browse_button) + if select_mode == SongFormatSelect.SingleFile: + path_type = PathType.Files + dialog_caption = WizardStrings.OpenTypeFile.format(file_type=format_name) + else: + path_type = PathType.Directories + dialog_caption = WizardStrings.OpenTypeFolder.format(folder_name=format_name) + path_edit = PathEdit( + parent=import_widget, path_type=path_type, dialog_caption=dialog_caption, show_revert=False) + path_edit.filters = path_edit.filters + filters + path_edit.path = Settings().value(self.plugin.settings_section + '/last directory import') + file_path_layout.addWidget(path_edit) import_layout.addLayout(file_path_layout) import_layout.addSpacerItem(self.stack_spacer) self.format_widgets[this_format]['filepathLabel'] = file_path_label - self.format_widgets[this_format]['filepathSpacer'] = file_path_spacer - self.format_widgets[this_format]['file_path_layout'] = file_path_layout - self.format_widgets[this_format]['file_path_edit'] = file_path_edit - self.format_widgets[this_format]['browseButton'] = browse_button + self.format_widgets[this_format]['path_edit'] = path_edit elif select_mode == SongFormatSelect.MultipleFiles: file_list_widget = QtWidgets.QListWidget(import_widget) file_list_widget.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) @@ -496,6 +469,8 @@ class SongImportSourcePage(QtWidgets.QWizardPage): * or if SingleFolder mode, the specified folder exists When this method returns True, the wizard's Next button is enabled. + + :rtype: bool """ wizard = self.wizard() this_format = wizard.current_format @@ -505,10 +480,10 @@ class SongImportSourcePage(QtWidgets.QWizardPage): if wizard.format_widgets[this_format]['file_list_widget'].count() > 0: return True else: - file_path = str(wizard.format_widgets[this_format]['file_path_edit'].text()) + file_path = wizard.format_widgets[this_format]['path_edit'].path if file_path: - if select_mode == SongFormatSelect.SingleFile and os.path.isfile(file_path): + if select_mode == SongFormatSelect.SingleFile and file_path.is_file(): return True - elif select_mode == SongFormatSelect.SingleFolder and os.path.isdir(file_path): + elif select_mode == SongFormatSelect.SingleFolder and file_path.is_dir(): return True return False diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index b342edc19..68effbe9b 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -534,13 +534,13 @@ def delete_song(song_id, song_plugin): media_files = song_plugin.manager.get_all_objects(MediaFile, MediaFile.song_id == song_id) for media_file in media_files: try: - os.remove(media_file.file_name) + media_file.file_path.unlink() except OSError: - log.exception('Could not remove file: {name}'.format(name=media_file.file_name)) + log.exception('Could not remove file: {name}'.format(name=media_file.file_path)) try: - save_path = os.path.join(str(AppLocation.get_section_data_path(song_plugin.name)), 'audio', str(song_id)) - if os.path.exists(save_path): - os.rmdir(save_path) + save_path = AppLocation.get_section_data_path(song_plugin.name) / 'audio' / str(song_id) + if save_path.exists(): + save_path.rmdir() except OSError: 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 ccfab466a..5910bd1a8 100644 --- a/openlp/plugins/songs/lib/db.py +++ b/openlp/plugins/songs/lib/db.py @@ -23,14 +23,15 @@ The :mod:`db` module provides the database and schema that is the backend for the Songs plugin """ - +from contextlib import suppress from sqlalchemy import Column, ForeignKey, Table, types from sqlalchemy.orm import mapper, relation, reconstructor from sqlalchemy.sql.expression import func, text -from openlp.core.lib.db import BaseModel, init_db +from openlp.core.common.applocation import AppLocation from openlp.core.common.languagemanager import get_natural_key from openlp.core.lib import translate +from openlp.core.lib.db import BaseModel, PathType, init_db class Author(BaseModel): @@ -238,7 +239,7 @@ def init_schema(url): **media_files Table** * id - * file_name + * _file_path * type **song_books Table** @@ -305,7 +306,7 @@ def init_schema(url): 'media_files', metadata, Column('id', types.Integer(), primary_key=True), Column('song_id', types.Integer(), ForeignKey('songs.id'), default=None), - Column('file_name', types.Unicode(255), nullable=False), + Column('file_path', PathType, nullable=False), Column('type', types.Unicode(64), nullable=False, default='audio'), Column('weight', types.Integer(), default=0) ) diff --git a/openlp/plugins/songs/lib/importers/cclifile.py b/openlp/plugins/songs/lib/importers/cclifile.py index 75f86b07d..223263183 100644 --- a/openlp/plugins/songs/lib/importers/cclifile.py +++ b/openlp/plugins/songs/lib/importers/cclifile.py @@ -19,11 +19,9 @@ # with this program; if not, write to the Free Software Foundation, Inc., 59 # # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### - -import logging -import os import chardet import codecs +import logging from openlp.core.lib import translate from openlp.plugins.songs.lib import VerseType @@ -48,7 +46,7 @@ class CCLIFileImport(SongImport): :param manager: The song manager for the running OpenLP installation. :param kwargs: The files to be imported. """ - super(CCLIFileImport, self).__init__(manager, **kwargs) + super().__init__(manager, **kwargs) def do_import(self): """ @@ -56,37 +54,35 @@ class CCLIFileImport(SongImport): """ log.debug('Starting CCLI File Import') self.import_wizard.progress_bar.setMaximum(len(self.import_source)) - for filename in self.import_source: - filename = str(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) - try: - str(detect_content, 'utf-8') - details = {'confidence': 1, 'encoding': 'utf-8'} - except UnicodeDecodeError: - details = chardet.detect(detect_content) - detect_file.close() - infile = codecs.open(filename, 'r', details['encoding']) - if not infile.read(1) == '\ufeff': + for file_path in self.import_source: + log.debug('Importing CCLI File: {name}'.format(name=file_path)) + if file_path.is_file(): + with file_path.open('rb') as detect_file: + detect_content = detect_file.read(2048) + try: + str(detect_content, 'utf-8') + details = {'confidence': 1, 'encoding': 'utf-8'} + except UnicodeDecodeError: + details = chardet.detect(detect_content) + in_file = codecs.open(str(file_path), 'r', details['encoding']) + if not in_file.read(1) == '\ufeff': # not UTF or no BOM was found - infile.seek(0) - lines = infile.readlines() - infile.close() - ext = os.path.splitext(filename)[1] - if ext.lower() == '.usr' or ext.lower() == '.bin': - log.info('SongSelect USR format file found: {name}'.format(name=filename)) + in_file.seek(0) + lines = in_file.readlines() + in_file.close() + ext = file_path.suffix.lower() + if ext == '.usr' or ext == '.bin': + log.info('SongSelect USR format file found: {name}'.format(name=file_path)) if not self.do_import_usr_file(lines): - self.log_error(filename) - elif ext.lower() == '.txt': - log.info('SongSelect TEXT format file found: {name}'.format(name=filename)) + self.log_error(file_path) + elif ext == '.txt': + log.info('SongSelect TEXT format file found: {name}'.format(name=file_path)) if not self.do_import_txt_file(lines): - self.log_error(filename) + self.log_error(file_path) else: - self.log_error(filename, translate('SongsPlugin.CCLIFileImport', 'The file does not have a valid ' - 'extension.')) - log.info('Extension {name} is not valid'.format(name=filename)) + self.log_error(file_path, translate('SongsPlugin.CCLIFileImport', + 'The file does not have a valid extension.')) + log.info('Extension {name} is not valid'.format(name=file_path)) if self.stop_import_flag: return diff --git a/openlp/plugins/songs/lib/importers/chordpro.py b/openlp/plugins/songs/lib/importers/chordpro.py index 4f185a713..2250e65f1 100644 --- a/openlp/plugins/songs/lib/importers/chordpro.py +++ b/openlp/plugins/songs/lib/importers/chordpro.py @@ -47,12 +47,11 @@ class ChordProImport(SongImport): """ def do_import(self): self.import_wizard.progress_bar.setMaximum(len(self.import_source)) - for filename in self.import_source: + for file_path in self.import_source: if self.stop_import_flag: return - song_file = open(filename, 'rt') - self.do_import_file(song_file) - song_file.close() + with file_path.open('rt') as song_file: + self.do_import_file(song_file) def do_import_file(self, song_file): """ diff --git a/openlp/plugins/songs/lib/importers/dreambeam.py b/openlp/plugins/songs/lib/importers/dreambeam.py index 1854a5978..094827792 100644 --- a/openlp/plugins/songs/lib/importers/dreambeam.py +++ b/openlp/plugins/songs/lib/importers/dreambeam.py @@ -78,27 +78,29 @@ class DreamBeamImport(SongImport): def do_import(self): """ - Receive a single file or a list of files to import. + Receive a single file_path or a list of files to import. """ if isinstance(self.import_source, list): self.import_wizard.progress_bar.setMaximum(len(self.import_source)) - for file in self.import_source: + for file_path in self.import_source: if self.stop_import_flag: return self.set_defaults() parser = etree.XMLParser(remove_blank_text=True) try: - parsed_file = etree.parse(open(file, 'r'), parser) + with file_path.open('r') as xml_file: + parsed_file = etree.parse(xml_file, parser) except etree.XMLSyntaxError: - log.exception('XML syntax error in file {name}'.format(name=file)) - self.log_error(file, SongStrings.XMLSyntaxError) + log.exception('XML syntax error in file_path {name}'.format(name=file_path)) + self.log_error(file_path, SongStrings.XMLSyntaxError) continue xml = etree.tostring(parsed_file).decode() song_xml = objectify.fromstring(xml) if song_xml.tag != 'DreamSong': self.log_error( - file, - translate('SongsPlugin.DreamBeamImport', 'Invalid DreamBeam song file. Missing DreamSong tag.')) + file_path, + translate('SongsPlugin.DreamBeamImport', + 'Invalid DreamBeam song file_path. Missing DreamSong tag.')) continue if hasattr(song_xml, 'Version'): self.version = float(song_xml.Version.text) @@ -144,4 +146,4 @@ class DreamBeamImport(SongImport): else: self.parse_author(author_copyright) if not self.finish(): - self.log_error(file) + self.log_error(file_path) diff --git a/openlp/plugins/songs/lib/importers/easyslides.py b/openlp/plugins/songs/lib/importers/easyslides.py index 7c2ffd2c9..a1ffb7b7c 100644 --- a/openlp/plugins/songs/lib/importers/easyslides.py +++ b/openlp/plugins/songs/lib/importers/easyslides.py @@ -47,7 +47,7 @@ class EasySlidesImport(SongImport): def do_import(self): log.info('Importing EasySlides XML file {source}'.format(source=self.import_source)) parser = etree.XMLParser(remove_blank_text=True, recover=True) - parsed_file = etree.parse(self.import_source, parser) + parsed_file = etree.parse(str(self.import_source), parser) xml = etree.tostring(parsed_file).decode() song_xml = objectify.fromstring(xml) self.import_wizard.progress_bar.setMaximum(len(song_xml.Item)) diff --git a/openlp/plugins/songs/lib/importers/easyworship.py b/openlp/plugins/songs/lib/importers/easyworship.py index 03f671c52..ac22029a3 100644 --- a/openlp/plugins/songs/lib/importers/easyworship.py +++ b/openlp/plugins/songs/lib/importers/easyworship.py @@ -22,14 +22,15 @@ """ The :mod:`easyworship` module provides the functionality for importing EasyWorship song databases into OpenLP. """ - -import os -import struct -import re -import zlib import logging +import os +import re +import struct +import zlib + import sqlite3 +from openlp.core.common.path import Path from openlp.core.lib import translate from openlp.plugins.songs.lib import VerseType from openlp.plugins.songs.lib import retrieve_windows_encoding, strip_rtf @@ -76,9 +77,11 @@ class EasyWorshipSongImport(SongImport): """ Determines the type of file to import and calls the appropiate method """ - if self.import_source.lower().endswith('ews'): + self.import_source = Path(self.import_source) + ext = self.import_source.suffix.lower() + if ext == '.ews': self.import_ews() - elif self.import_source.endswith('DB'): + elif ext == '.db': self.import_db() else: self.import_sqlite_db() @@ -91,11 +94,11 @@ class EasyWorshipSongImport(SongImport): or here: http://wiki.openlp.org/Development:EasyWorship_EWS_Format """ # Open ews file if it exists - if not os.path.isfile(self.import_source): + if not self.import_source.is_file(): log.debug('Given ews file does not exists.') return # Make sure there is room for at least a header and one entry - if os.path.getsize(self.import_source) < 892: + if self.import_source.stat().st_size < 892: log.debug('Given ews file is to small to contain valid data.') return # Take a stab at how text is encoded @@ -104,7 +107,7 @@ class EasyWorshipSongImport(SongImport): if not self.encoding: log.debug('No encoding set.') return - self.ews_file = open(self.import_source, 'rb') + self.ews_file = self.import_source.open('rb') # EWS header, version '1.6'/' 3'/' 5': # Offset Field Data type Length Details # -------------------------------------------------------------------------------------------------- @@ -199,23 +202,22 @@ class EasyWorshipSongImport(SongImport): Import the songs from the database """ # Open the DB and MB files if they exist - import_source_mb = self.import_source.replace('.DB', '.MB') - if not os.path.isfile(self.import_source): + import_source_mb = self.import_source.with_suffix('.MB') + if not self.import_source.is_file(): self.log_error(self.import_source, translate('SongsPlugin.EasyWorshipSongImport', 'This file does not exist.')) return - if not os.path.isfile(import_source_mb): + if not import_source_mb.is_file(): self.log_error(self.import_source, translate('SongsPlugin.EasyWorshipSongImport', 'Could not find the "Songs.MB" file. It must be in the same ' 'folder as the "Songs.DB" file.')) return - db_size = os.path.getsize(self.import_source) - if db_size < 0x800: + if self.import_source.stat().st_size < 0x800: self.log_error(self.import_source, translate('SongsPlugin.EasyWorshipSongImport', 'This file is not a valid EasyWorship database.')) return - db_file = open(self.import_source, 'rb') - self.memo_file = open(import_source_mb, 'rb') + db_file = self.import_source.open('rb') + self.memo_file = import_source_mb.open('rb') # Don't accept files that are clearly not paradox files record_size, header_size, block_size, first_block, num_fields = struct.unpack(' 4: @@ -340,52 +342,34 @@ class EasyWorshipSongImport(SongImport): db_file.close() self.memo_file.close() - def _find_file(self, base_path, path_list): - """ - Find the specified file, with the option of the file being at any level in the specified directory structure. - - :param base_path: the location search in - :param path_list: the targeted file, preceded by directories that may be their parents relative to the base_path - :return: path for targeted file - """ - target_file = '' - while len(path_list) > 0: - target_file = os.path.join(path_list[-1], target_file) - path_list = path_list[:len(path_list) - 1] - full_path = os.path.join(base_path, target_file) - full_path = full_path[:len(full_path) - 1] - if os.path.isfile(full_path): - return full_path - return '' - def import_sqlite_db(self): """ Import the songs from an EasyWorship 6 SQLite database """ - songs_db_path = self._find_file(self.import_source, ["Databases", "Data", "Songs.db"]) - song_words_db_path = self._find_file(self.import_source, ["Databases", "Data", "SongWords.db"]) - invalid_dir_msg = 'This does not appear to be a valid Easy Worship 6 database directory.' + songs_db_path = next(self.import_source.rglob('Songs.db'), None) + song_words_db_path = next(self.import_source.rglob('SongWords.db'), None) + invalid_dir_msg = translate('SongsPlugin.EasyWorshipSongImport', + 'This does not appear to be a valid Easy Worship 6 database directory.') + invalid_db_msg = translate('SongsPlugin.EasyWorshipSongImport', 'This is not a valid Easy Worship 6 database.') # check to see if needed files are there - if not os.path.isfile(songs_db_path): - self.log_error(songs_db_path, translate('SongsPlugin.EasyWorshipSongImport', invalid_dir_msg)) + if not (songs_db_path and songs_db_path.is_file()): + self.log_error(self.import_source, invalid_dir_msg) return - if not os.path.isfile(song_words_db_path): - self.log_error(song_words_db_path, translate('SongsPlugin.EasyWorshipSongImport', invalid_dir_msg)) + if not (song_words_db_path and song_words_db_path.is_file()): + self.log_error(self.import_source, invalid_dir_msg) return # get database handles - songs_conn = sqlite3.connect(songs_db_path) - words_conn = sqlite3.connect(song_words_db_path) + songs_conn = sqlite3.connect(str(songs_db_path)) + words_conn = sqlite3.connect(str(song_words_db_path)) if songs_conn is None or words_conn is None: - self.log_error(self.import_source, translate('SongsPlugin.EasyWorshipSongImport', - 'This is not a valid Easy Worship 6 database.')) + self.log_error(self.import_source, invalid_db_msg) songs_conn.close() words_conn.close() return songs_db = songs_conn.cursor() words_db = words_conn.cursor() if songs_conn is None or words_conn is None: - self.log_error(self.import_source, translate('SongsPlugin.EasyWorshipSongImport', - 'This is not a valid Easy Worship 6 database.')) + self.log_error(self.import_source, invalid_db_msg) songs_conn.close() words_conn.close() return diff --git a/openlp/plugins/songs/lib/importers/foilpresenter.py b/openlp/plugins/songs/lib/importers/foilpresenter.py index 06f45c89c..98ec9d6ac 100644 --- a/openlp/plugins/songs/lib/importers/foilpresenter.py +++ b/openlp/plugins/songs/lib/importers/foilpresenter.py @@ -82,10 +82,8 @@ The XML of `Foilpresenter `_ songs is of the format:: """ - import logging import re -import os from lxml import etree, objectify @@ -121,10 +119,9 @@ class FoilPresenterImport(SongImport): for file_path in self.import_source: if self.stop_import_flag: return - self.import_wizard.increment_progress_bar( - WizardStrings.ImportingType.format(source=os.path.basename(file_path))) + self.import_wizard.increment_progress_bar(WizardStrings.ImportingType.format(source=file_path.name)) try: - parsed_file = etree.parse(file_path, parser) + parsed_file = etree.parse(str(file_path), parser) xml = etree.tostring(parsed_file).decode() self.foil_presenter.xml_to_song(xml) except etree.XMLSyntaxError: diff --git a/openlp/plugins/songs/lib/importers/lyrix.py b/openlp/plugins/songs/lib/importers/lyrix.py index 6bb8717a2..87df138a0 100644 --- a/openlp/plugins/songs/lib/importers/lyrix.py +++ b/openlp/plugins/songs/lib/importers/lyrix.py @@ -50,12 +50,11 @@ class LyrixImport(SongImport): if not isinstance(self.import_source, list): return self.import_wizard.progress_bar.setMaximum(len(self.import_source)) - for filename in self.import_source: + for file_path in self.import_source: if self.stop_import_flag: return - song_file = open(filename, 'rt', encoding='cp1251') - self.do_import_file(song_file) - song_file.close() + with file_path.open('rt', encoding='cp1251') as song_file: + self.do_import_file(song_file) def do_import_file(self, file): """ diff --git a/openlp/plugins/songs/lib/importers/openlp.py b/openlp/plugins/songs/lib/importers/openlp.py index a42e7e37c..2e348a867 100644 --- a/openlp/plugins/songs/lib/importers/openlp.py +++ b/openlp/plugins/songs/lib/importers/openlp.py @@ -266,7 +266,7 @@ class OpenLPSongImport(SongImport): if has_media_files and song.media_files: for media_file in song.media_files: existing_media_file = self.manager.get_object_filtered( - MediaFile, MediaFile.file_name == media_file.file_name) + MediaFile, MediaFile.file_path == media_file.file_path) if existing_media_file: new_song.media_files.append(existing_media_file) else: diff --git a/openlp/plugins/songs/lib/importers/openlyrics.py b/openlp/plugins/songs/lib/importers/openlyrics.py index 09cc1ef91..44f5f96bf 100644 --- a/openlp/plugins/songs/lib/importers/openlyrics.py +++ b/openlp/plugins/songs/lib/importers/openlyrics.py @@ -23,9 +23,7 @@ The :mod:`openlyrics` module provides the functionality for importing songs which are saved as OpenLyrics files. """ - import logging -import os from lxml import etree @@ -58,12 +56,11 @@ class OpenLyricsImport(SongImport): for file_path in self.import_source: if self.stop_import_flag: return - self.import_wizard.increment_progress_bar( - WizardStrings.ImportingType.format(source=os.path.basename(file_path))) + self.import_wizard.increment_progress_bar(WizardStrings.ImportingType.format(source=file_path.name)) try: # Pass a file object, because lxml does not cope with some # special characters in the path (see lp:757673 and lp:744337). - parsed_file = etree.parse(open(file_path, 'rb'), parser) + parsed_file = etree.parse(file_path.open('rb'), parser) xml = etree.tostring(parsed_file).decode() self.open_lyrics.xml_to_song(xml) except etree.XMLSyntaxError: diff --git a/openlp/plugins/songs/lib/importers/openoffice.py b/openlp/plugins/songs/lib/importers/openoffice.py index af32dd3fa..f03f7b4a4 100644 --- a/openlp/plugins/songs/lib/importers/openoffice.py +++ b/openlp/plugins/songs/lib/importers/openoffice.py @@ -20,7 +20,6 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### import logging -import os import time from PyQt5 import QtCore @@ -70,12 +69,11 @@ class OpenOfficeImport(SongImport): log.error(exc) return self.import_wizard.progress_bar.setMaximum(len(self.import_source)) - for filename in self.import_source: + for file_path in self.import_source: if self.stop_import_flag: break - filename = str(filename) - if os.path.isfile(filename): - self.open_ooo_file(filename) + if file_path.is_file(): + self.open_ooo_file(file_path) if self.document: self.process_ooo_document() self.close_ooo_file() @@ -144,12 +142,7 @@ class OpenOfficeImport(SongImport): Open the passed file in OpenOffice.org Impress """ self.file_path = file_path - if is_win(): - url = file_path.replace('\\', '/') - url = url.replace(':', '|').replace(' ', '%20') - url = 'file:///' + url - else: - url = uno.systemPathToFileUrl(file_path) + url = file_path.as_uri() properties = [] properties.append(self.create_property('Hidden', True)) properties = tuple(properties) @@ -159,7 +152,7 @@ class OpenOfficeImport(SongImport): self.document.supportsService("com.sun.star.text.TextDocument"): self.close_ooo_file() else: - self.import_wizard.increment_progress_bar('Processing file ' + file_path, 0) + self.import_wizard.increment_progress_bar('Processing file {file_path}'.format(file_path=file_path), 0) except AttributeError: log.exception("open_ooo_file failed: {url}".format(url=url)) return diff --git a/openlp/plugins/songs/lib/importers/opensong.py b/openlp/plugins/songs/lib/importers/opensong.py index e184b2847..3f6e76685 100644 --- a/openlp/plugins/songs/lib/importers/opensong.py +++ b/openlp/plugins/songs/lib/importers/opensong.py @@ -19,7 +19,6 @@ # with this program; if not, write to the Free Software Foundation, Inc., 59 # # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### - import logging import re @@ -116,12 +115,11 @@ class OpenSongImport(SongImport): if not isinstance(self.import_source, list): return self.import_wizard.progress_bar.setMaximum(len(self.import_source)) - for filename in self.import_source: + for file_path in self.import_source: if self.stop_import_flag: return - song_file = open(filename, 'rb') - self.do_import_file(song_file) - song_file.close() + with file_path.open('rb') as song_file: + self.do_import_file(song_file) def do_import_file(self, file): """ diff --git a/openlp/plugins/songs/lib/importers/opspro.py b/openlp/plugins/songs/lib/importers/opspro.py index dd6082778..3ede706f4 100644 --- a/openlp/plugins/songs/lib/importers/opspro.py +++ b/openlp/plugins/songs/lib/importers/opspro.py @@ -231,16 +231,15 @@ class OPSProImport(SongImport): xor_pattern_2k = (0xa1, 0xec, 0x7a, 0x9c, 0xe1, 0x28, 0x34, 0x8a, 0x73, 0x7b, 0xd2, 0xdf, 0x50) # Access97 XOR of the source xor_pattern_97 = (0x86, 0xfb, 0xec, 0x37, 0x5d, 0x44, 0x9c, 0xfa, 0xc6, 0x5e, 0x28, 0xe6, 0x13) - mdb = open(self.import_source, 'rb') - mdb.seek(0x14) - version = struct.unpack('B', mdb.read(1))[0] - # Get encrypted logo - mdb.seek(0x62) - EncrypFlag = struct.unpack('B', mdb.read(1))[0] - # Get encrypted password - mdb.seek(0x42) - encrypted_password = mdb.read(26) - mdb.close() + with self.import_source.open('rb') as mdb_file: + mdb_file.seek(0x14) + version = struct.unpack('B', mdb_file.read(1))[0] + # Get encrypted logo + mdb_file.seek(0x62) + EncrypFlag = struct.unpack('B', mdb_file.read(1))[0] + # Get encrypted password + mdb_file.seek(0x42) + encrypted_password = mdb_file.read(26) # "Decrypt" the password based on the version decrypted_password = '' if version < 0x01: diff --git a/openlp/plugins/songs/lib/importers/powerpraise.py b/openlp/plugins/songs/lib/importers/powerpraise.py index a652cf58c..a08652e3f 100644 --- a/openlp/plugins/songs/lib/importers/powerpraise.py +++ b/openlp/plugins/songs/lib/importers/powerpraise.py @@ -23,8 +23,6 @@ The :mod:`powerpraiseimport` module provides the functionality for importing Powerpraise song files into the current database. """ - -import os from lxml import objectify from openlp.core.ui.lib.wizard import WizardStrings @@ -41,10 +39,10 @@ class PowerPraiseImport(SongImport): for file_path in self.import_source: if self.stop_import_flag: return - self.import_wizard.increment_progress_bar( - WizardStrings.ImportingType.format(source=os.path.basename(file_path))) - root = objectify.parse(open(file_path, 'rb')).getroot() - self.process_song(root) + self.import_wizard.increment_progress_bar(WizardStrings.ImportingType.format(source=file_path.name)) + with file_path.open('rb') as xml_file: + root = objectify.parse(xml_file).getroot() + self.process_song(root) def process_song(self, root): self.set_defaults() diff --git a/openlp/plugins/songs/lib/importers/powersong.py b/openlp/plugins/songs/lib/importers/powersong.py index ca5947021..fd51ec7e6 100644 --- a/openlp/plugins/songs/lib/importers/powersong.py +++ b/openlp/plugins/songs/lib/importers/powersong.py @@ -72,10 +72,14 @@ class PowerSongImport(SongImport): Checks if source is a PowerSong 1.0 folder: * is a directory * contains at least one \*.song file + + :param openlp.core.common.path.Path import_source: Should be a Path object that fulfills the above criteria + :return: If the source is valid + :rtype: bool """ - if os.path.isdir(import_source): - for file in os.listdir(import_source): - if fnmatch.fnmatch(file, '*.song'): + if import_source.is_dir(): + for file_path in import_source.iterdir(): + if file_path.suffix == '.song': return True return False diff --git a/openlp/plugins/songs/lib/importers/presentationmanager.py b/openlp/plugins/songs/lib/importers/presentationmanager.py index 4031431ba..2ea23679b 100644 --- a/openlp/plugins/songs/lib/importers/presentationmanager.py +++ b/openlp/plugins/songs/lib/importers/presentationmanager.py @@ -23,13 +23,11 @@ The :mod:`presentationmanager` module provides the functionality for importing Presentationmanager song files into the current database. """ -import os import re -import chardet from lxml import objectify, etree -from openlp.core.common import translate +from openlp.core.common import get_file_encoding, translate from openlp.core.ui.lib.wizard import WizardStrings from .songimport import SongImport @@ -44,17 +42,14 @@ class PresentationManagerImport(SongImport): for file_path in self.import_source: if self.stop_import_flag: return - self.import_wizard.increment_progress_bar( - WizardStrings.ImportingType.format(source=os.path.basename(file_path))) + self.import_wizard.increment_progress_bar(WizardStrings.ImportingType.format(source=file_path.name)) try: - tree = etree.parse(file_path, parser=etree.XMLParser(recover=True)) + tree = etree.parse(str(file_path), parser=etree.XMLParser(recover=True)) except etree.XMLSyntaxError: # Try to detect encoding and use it - file = open(file_path, mode='rb') - encoding = chardet.detect(file.read())['encoding'] - file.close() + encoding = get_file_encoding(file_path)['encoding'] # Open file with detected encoding and remove encoding declaration - text = open(file_path, mode='r', encoding=encoding).read() + text = file_path.read_text(encoding=encoding) text = re.sub('.+\?>\n', '', text) try: tree = etree.fromstring(text, parser=etree.XMLParser(recover=True)) @@ -80,6 +75,11 @@ class PresentationManagerImport(SongImport): return '' def process_song(self, root, file_path): + """ + :param root: + :param openlp.core.common.path.Path file_path: Path to the file to process + :rtype: None + """ self.set_defaults() attrs = None if hasattr(root, 'attributes'): @@ -123,4 +123,4 @@ class PresentationManagerImport(SongImport): self.verse_order_list = verse_order_list if not self.finish(): - self.log_error(os.path.basename(file_path)) + self.log_error(file_path.name) diff --git a/openlp/plugins/songs/lib/importers/propresenter.py b/openlp/plugins/songs/lib/importers/propresenter.py index 9a3fa372d..582b1a6ee 100644 --- a/openlp/plugins/songs/lib/importers/propresenter.py +++ b/openlp/plugins/songs/lib/importers/propresenter.py @@ -23,8 +23,6 @@ The :mod:`propresenter` module provides the functionality for importing ProPresenter song files into the current installation database. """ - -import os import base64 import logging from lxml import objectify @@ -47,11 +45,17 @@ class ProPresenterImport(SongImport): if self.stop_import_flag: return self.import_wizard.increment_progress_bar( - WizardStrings.ImportingType.format(source=os.path.basename(file_path))) - root = objectify.parse(open(file_path, 'rb')).getroot() - self.process_song(root, file_path) + WizardStrings.ImportingType.format(source=file_path.name)) + with file_path.open('rb') as xml_file: + root = objectify.parse(xml_file).getroot() + self.process_song(root, file_path) - def process_song(self, root, filename): + def process_song(self, root, file_path): + """ + :param root: + :param openlp.core.common.path.Path file_path: Path to the file thats being imported + :rtype: None + """ self.set_defaults() # Extract ProPresenter versionNumber @@ -64,9 +68,7 @@ class ProPresenterImport(SongImport): # Title self.title = root.get('CCLISongTitle') if not self.title or self.title == '': - self.title = os.path.basename(filename) - if self.title[-5:-1] == '.pro': - self.title = self.title[:-5] + self.title = file_path.stem # Notes self.comments = root.get('notes') # Author diff --git a/openlp/plugins/songs/lib/importers/songbeamer.py b/openlp/plugins/songs/lib/importers/songbeamer.py index ff8b1f7a6..346b1588d 100644 --- a/openlp/plugins/songs/lib/importers/songbeamer.py +++ b/openlp/plugins/songs/lib/importers/songbeamer.py @@ -112,7 +112,7 @@ class SongBeamerImport(SongImport): if not isinstance(self.import_source, list): return self.import_wizard.progress_bar.setMaximum(len(self.import_source)) - for import_file in self.import_source: + for file_path in self.import_source: # TODO: check that it is a valid SongBeamer file if self.stop_import_flag: return @@ -120,20 +120,19 @@ class SongBeamerImport(SongImport): self.current_verse = '' self.current_verse_type = VerseType.tags[VerseType.Verse] self.chord_table = None - file_name = os.path.split(import_file)[1] - if os.path.isfile(import_file): + if file_path.is_file(): # Detect the encoding - self.input_file_encoding = get_file_encoding(Path(import_file))['encoding'] + self.input_file_encoding = get_file_encoding(file_path)['encoding'] # The encoding should only be ANSI (cp1252), UTF-8, Unicode, Big-Endian-Unicode. # So if it doesn't start with 'u' we default to cp1252. See: # https://forum.songbeamer.com/viewtopic.php?p=419&sid=ca4814924e37c11e4438b7272a98b6f2 if not self.input_file_encoding.lower().startswith('u'): self.input_file_encoding = 'cp1252' - infile = open(import_file, 'rt', encoding=self.input_file_encoding) - song_data = infile.readlines() + with file_path.open(encoding=self.input_file_encoding) as song_file: + song_data = song_file.readlines() else: continue - self.title = file_name.split('.sng')[0] + self.title = file_path.stem read_verses = False # The first verse separator doesn't count, but the others does, so line count starts at -1 line_number = -1 @@ -185,7 +184,7 @@ class SongBeamerImport(SongImport): # inserted by songbeamer, but are manually added headings. So restart the loop, and # count tags as lines. self.set_defaults() - self.title = file_name.split('.sng')[0] + self.title = file_path.stem verse_tags_mode = VerseTagMode.ContainsNoTagsRestart read_verses = False # The first verseseparator doesn't count, but the others does, so linecount starts at -1 @@ -207,7 +206,7 @@ class SongBeamerImport(SongImport): self.replace_html_tags() self.add_verse(self.current_verse, self.current_verse_type) if not self.finish(): - self.log_error(import_file) + self.log_error(file_path) def insert_chords(self, line_number, line): """ @@ -414,14 +413,15 @@ class SongBeamerImport(SongImport): """ # The path is relative to SongBeamers Song folder if is_win(): - user_doc_folder = os.path.expandvars('$DOCUMENTS') + user_doc_path = Path(os.path.expandvars('$DOCUMENTS')) elif is_macosx(): - user_doc_folder = os.path.join(os.path.expanduser('~'), 'Documents') + user_doc_path = Path.home() / 'Documents' else: # SongBeamer only runs on mac and win... return - audio_file_path = os.path.normpath(os.path.join(user_doc_folder, 'SongBeamer', 'Songs', audio_file_path)) - if os.path.isfile(audio_file_path): + audio_file_path = user_doc_path / 'SongBeamer' / 'Songs' / audio_file_path + if audio_file_path.is_file(): self.add_media_file(audio_file_path) else: - log.debug('Could not import mediafile "%s" since it does not exists!' % audio_file_path) + log.debug('Could not import mediafile "{audio_file_path}" since it does not exists!' + .format(audio_file_path=audio_file_path)) diff --git a/openlp/plugins/songs/lib/importers/songimport.py b/openlp/plugins/songs/lib/importers/songimport.py index ff190f0e0..a74aaf9e7 100644 --- a/openlp/plugins/songs/lib/importers/songimport.py +++ b/openlp/plugins/songs/lib/importers/songimport.py @@ -22,13 +22,11 @@ import logging import re -import shutil -import os from PyQt5 import QtCore from openlp.core.common import Registry, AppLocation, check_directory_exists, translate -from openlp.core.common.path import Path +from openlp.core.common.path import copyfile from openlp.core.ui.lib.wizard import WizardStrings from openlp.plugins.songs.lib import clean_song, VerseType from openlp.plugins.songs.lib.db import Song, Author, Topic, Book, MediaFile @@ -62,14 +60,14 @@ class SongImport(QtCore.QObject): """ self.manager = manager QtCore.QObject.__init__(self) - if 'filename' in kwargs: - self.import_source = kwargs['filename'] - elif 'filenames' in kwargs: - self.import_source = kwargs['filenames'] - elif 'folder' in kwargs: - self.import_source = kwargs['folder'] + if 'file_path' in kwargs: + self.import_source = kwargs['file_path'] + elif 'file_paths' in kwargs: + self.import_source = kwargs['file_paths'] + elif 'folder_path' in kwargs: + self.import_source = kwargs['folder_path'] else: - raise KeyError('Keyword arguments "filename[s]" or "folder" not supplied.') + raise KeyError('Keyword arguments "file_path[s]" or "folder_path" not supplied.') log.debug(self.import_source) self.import_wizard = None self.song = None @@ -270,13 +268,13 @@ class SongImport(QtCore.QObject): return self.authors.append((author, type)) - def add_media_file(self, filename, weight=0): + def add_media_file(self, file_path, weight=0): """ Add a media file to the list """ - if filename in [x[0] for x in self.media_files]: + if file_path in [x[0] for x in self.media_files]: return - self.media_files.append((filename, weight)) + self.media_files.append((file_path, weight)) def add_verse(self, verse_text, verse_def='v', lang=None): """ @@ -403,29 +401,30 @@ class SongImport(QtCore.QObject): self.manager.save_object(song) # Now loop through the media files, copy them to the correct location, # and save the song again. - for filename, weight in self.media_files: - media_file = self.manager.get_object_filtered(MediaFile, MediaFile.file_name == filename) + for file_path, weight in self.media_files: + media_file = self.manager.get_object_filtered(MediaFile, MediaFile.file_path == file_path) if not media_file: - if os.path.dirname(filename): - filename = self.copy_media_file(song.id, filename) - song.media_files.append(MediaFile.populate(file_name=filename, weight=weight)) + if file_path.parent: + file_path = self.copy_media_file(song.id, file_path) + song.media_files.append(MediaFile.populate(file_path=file_path, weight=weight)) self.manager.save_object(song) self.set_defaults() return True - def copy_media_file(self, song_id, filename): + def copy_media_file(self, song_id, file_path): """ This method copies the media file to the correct location and returns the new file location. :param song_id: - :param filename: The file to copy. + :param openlp.core.common.path.Path file_path: The file to copy. + :return: The new location of the file + :rtype: openlp.core.common.path.Path """ if not hasattr(self, 'save_path'): - self.save_path = os.path.join(str(AppLocation.get_section_data_path(self.import_wizard.plugin.name)), - 'audio', str(song_id)) - check_directory_exists(Path(self.save_path)) - if not filename.startswith(self.save_path): - old_file, filename = filename, os.path.join(self.save_path, os.path.split(filename)[1]) - shutil.copyfile(old_file, filename) - return filename + self.save_path = AppLocation.get_section_data_path(self.import_wizard.plugin.name) / 'audio' / str(song_id) + check_directory_exists(self.save_path) + if self.save_path not in file_path.parents: + old_path, file_path = file_path, self.save_path / file_path.name + copyfile(old_path, file_path) + return file_path diff --git a/openlp/plugins/songs/lib/importers/songpro.py b/openlp/plugins/songs/lib/importers/songpro.py index 30f19128a..261c2c728 100644 --- a/openlp/plugins/songs/lib/importers/songpro.py +++ b/openlp/plugins/songs/lib/importers/songpro.py @@ -25,6 +25,7 @@ songs into the OpenLP database. """ import re +from openlp.core.common.path import Path from openlp.plugins.songs.lib import strip_rtf from openlp.plugins.songs.lib.importers.songimport import SongImport @@ -72,7 +73,8 @@ class SongProImport(SongImport): Receive a single file or a list of files to import. """ self.encoding = None - with open(self.import_source, 'rt', errors='ignore') as songs_file: + self.import_source = Path(self.import_source) + with self.import_source.open('rt', errors='ignore') as songs_file: self.import_wizard.progress_bar.setMaximum(0) tag = '' text = '' diff --git a/openlp/plugins/songs/lib/importers/songshowplus.py b/openlp/plugins/songs/lib/importers/songshowplus.py index b0841b672..2fcf414dd 100644 --- a/openlp/plugins/songs/lib/importers/songshowplus.py +++ b/openlp/plugins/songs/lib/importers/songshowplus.py @@ -23,7 +23,6 @@ The :mod:`songshowplus` module provides the functionality for importing SongShow Plus songs into the OpenLP database. """ -import os import logging import re import struct @@ -93,97 +92,95 @@ class SongShowPlusImport(SongImport): if not isinstance(self.import_source, list): return self.import_wizard.progress_bar.setMaximum(len(self.import_source)) - for file in self.import_source: + for file_path in self.import_source: if self.stop_import_flag: return self.ssp_verse_order_list = [] self.other_count = 0 self.other_list = {} - file_name = os.path.split(file)[1] - self.import_wizard.increment_progress_bar(WizardStrings.ImportingType.format(source=file_name), 0) - 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 - next_block_starts, = struct.unpack("I", song_data.read(4)) - next_block_starts += song_data.tell() - if block_key in (VERSE, CHORUS, BRIDGE): - null, verse_no, = struct.unpack("BB", song_data.read(2)) - elif block_key == CUSTOM_VERSE: - 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: %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)) - elif length_descriptor_size == 2: - length_descriptor = 1 - elif length_descriptor_size == 9: - length_descriptor = 0 - else: - length_descriptor, = struct.unpack("B", song_data.read(1)) - 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: - authors = self.decode(data).split(" / ") - for author in authors: - if author.find(",") != -1: - author_parts = author.split(", ") - author = author_parts[1] + " " + author_parts[0] - self.parse_author(author) - elif block_key == COPYRIGHT: - self.add_copyright(self.decode(data)) - elif block_key == CCLI_NO: - # Try to get the CCLI number even if the field contains additional text - match = re.search(r'\d+', self.decode(data)) - if match: - self.ccli_number = int(match.group()) + self.import_wizard.increment_progress_bar(WizardStrings.ImportingType.format(source=file_path.name), 0) + with file_path.open('rb') as song_file: + while True: + block_key, = struct.unpack("I", song_file.read(4)) + log.debug('block_key: %d' % block_key) + # The file ends with 4 NULL's + if block_key == 0: + break + next_block_starts, = struct.unpack("I", song_file.read(4)) + next_block_starts += song_file.tell() + if block_key in (VERSE, CHORUS, BRIDGE): + null, verse_no, = struct.unpack("BB", song_file.read(2)) + elif block_key == CUSTOM_VERSE: + null, verse_name_length, = struct.unpack("BB", song_file.read(2)) + verse_name = self.decode(song_file.read(verse_name_length)) + length_descriptor_size, = struct.unpack("B", song_file.read(1)) + 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_file.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_file.read(4)) + elif length_descriptor_size == 2: + length_descriptor = 1 + elif length_descriptor_size == 9: + length_descriptor = 0 else: - 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), "{tag}{number}".format(tag=VerseType.tags[VerseType.Verse], - number=verse_no)) - elif block_key == CHORUS: - 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), "{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: - self.comments = self.decode(data) - elif block_key == VERSE_ORDER: - verse_tag = self.to_openlp_verse_tag(self.decode(data), True) - if verse_tag: - if not isinstance(verse_tag, str): - verse_tag = self.decode(verse_tag) - self.ssp_verse_order_list.append(verse_tag) - elif block_key == SONG_BOOK: - self.song_book_name = self.decode(data) - elif block_key == CUSTOM_VERSE: - verse_tag = self.to_openlp_verse_tag(verse_name) - self.add_verse(self.decode(data), verse_tag) - else: - 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() - if not self.finish(): - self.log_error(file) + length_descriptor, = struct.unpack("B", song_file.read(1)) + log.debug('length_descriptor: %d' % length_descriptor) + data = song_file.read(length_descriptor) + log.debug(data) + if block_key == TITLE: + self.title = self.decode(data) + elif block_key == AUTHOR: + authors = self.decode(data).split(" / ") + for author in authors: + if author.find(",") != -1: + author_parts = author.split(", ") + author = author_parts[1] + " " + author_parts[0] + self.parse_author(author) + elif block_key == COPYRIGHT: + self.add_copyright(self.decode(data)) + elif block_key == CCLI_NO: + # Try to get the CCLI number even if the field contains additional text + match = re.search(r'\d+', self.decode(data)) + if match: + self.ccli_number = int(match.group()) + else: + 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), "{tag}{number}".format(tag=VerseType.tags[VerseType.Verse], + number=verse_no)) + elif block_key == CHORUS: + 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), "{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: + self.comments = self.decode(data) + elif block_key == VERSE_ORDER: + verse_tag = self.to_openlp_verse_tag(self.decode(data), True) + if verse_tag: + if not isinstance(verse_tag, str): + verse_tag = self.decode(verse_tag) + self.ssp_verse_order_list.append(verse_tag) + elif block_key == SONG_BOOK: + self.song_book_name = self.decode(data) + elif block_key == CUSTOM_VERSE: + verse_tag = self.to_openlp_verse_tag(verse_name) + self.add_verse(self.decode(data), verse_tag) + else: + log.debug("Unrecognised blockKey: {key}, data: {data}".format(key=block_key, data=data)) + song_file.seek(next_block_starts) + self.verse_order_list = self.ssp_verse_order_list + if not self.finish(): + self.log_error(file_path) def to_openlp_verse_tag(self, verse_name, ignore_unique=False): """ diff --git a/openlp/plugins/songs/lib/importers/sundayplus.py b/openlp/plugins/songs/lib/importers/sundayplus.py index caa92abf4..e0ce16aa1 100644 --- a/openlp/plugins/songs/lib/importers/sundayplus.py +++ b/openlp/plugins/songs/lib/importers/sundayplus.py @@ -19,11 +19,8 @@ # with this program; if not, write to the Free Software Foundation, Inc., 59 # # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### - import os import re -import logging - from openlp.plugins.songs.lib import VerseType, retrieve_windows_encoding from openlp.plugins.songs.lib import strip_rtf @@ -60,12 +57,11 @@ class SundayPlusImport(SongImport): def do_import(self): self.import_wizard.progress_bar.setMaximum(len(self.import_source)) - for filename in self.import_source: + for file_path in self.import_source: if self.stop_import_flag: return - song_file = open(filename, 'rb') - self.do_import_file(song_file) - song_file.close() + with file_path.open('rb') as song_file: + self.do_import_file(song_file) def do_import_file(self, file): """ diff --git a/openlp/plugins/songs/lib/importers/videopsalm.py b/openlp/plugins/songs/lib/importers/videopsalm.py index 5e7f0e8ef..ef020997a 100644 --- a/openlp/plugins/songs/lib/importers/videopsalm.py +++ b/openlp/plugins/songs/lib/importers/videopsalm.py @@ -22,13 +22,12 @@ """ The :mod:`lyrix` module provides the functionality for importing songs which are exproted from Lyrix.""" - -import logging import json -import os +import logging import re from openlp.core.common import translate, Settings +from openlp.core.common.path import Path from openlp.plugins.songs.lib.importers.songimport import SongImport from openlp.plugins.songs.lib.db import AuthorType @@ -50,11 +49,10 @@ class VideoPsalmImport(SongImport): """ Process the VideoPsalm file - pass in a file-like object, not a file path. """ + self.import_source = Path(self.import_source) self.set_defaults() - # Open SongBook file - song_file = open(self.import_source, 'rt', encoding='utf-8-sig') try: - file_content = song_file.read() + file_content = self.import_source.read_text(encoding='utf-8-sig') processed_content = '' inside_quotes = False # The VideoPsalm format is not valid json, it uses illegal line breaks and unquoted keys, this must be fixed @@ -89,7 +87,7 @@ class VideoPsalmImport(SongImport): songs = songbook['Songs'] self.import_wizard.progress_bar.setMaximum(len(songs)) songbook_name = songbook['Text'] - media_folder = os.path.normpath(os.path.join(os.path.dirname(song_file.name), '..', 'Audio')) + media_path = Path('..', 'Audio') for song in songs: self.song_book_name = songbook_name if 'Text' in song: @@ -114,7 +112,7 @@ class VideoPsalmImport(SongImport): if 'Theme' in song: self.topics = song['Theme'].splitlines() if 'AudioFile' in song: - self.add_media_file(os.path.join(media_folder, song['AudioFile'])) + self.add_media_file(media_path / song['AudioFile']) if 'Memo1' in song: self.add_comment(song['Memo1']) if 'Memo2' in song: @@ -132,4 +130,5 @@ class VideoPsalmImport(SongImport): if not self.finish(): 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)) + self.log_error(self.import_source.name, + translate('SongsPlugin.VideoPsalmImport', 'Error: {error}').format(error=e)) diff --git a/openlp/plugins/songs/lib/importers/wordsofworship.py b/openlp/plugins/songs/lib/importers/wordsofworship.py index 4ab362214..62ad367bf 100644 --- a/openlp/plugins/songs/lib/importers/wordsofworship.py +++ b/openlp/plugins/songs/lib/importers/wordsofworship.py @@ -25,6 +25,7 @@ Worship songs into the OpenLP database. """ import os import logging +from openlp.core.common.path import Path from openlp.core.common import translate from openlp.plugins.songs.lib.importers.songimport import SongImport @@ -100,62 +101,60 @@ class WordsOfWorshipImport(SongImport): """ if isinstance(self.import_source, list): self.import_wizard.progress_bar.setMaximum(len(self.import_source)) - for source in self.import_source: + for file_path in self.import_source: if self.stop_import_flag: return self.set_defaults() - song_data = open(source, 'rb') - if song_data.read(19).decode() != 'WoW File\nSong Words': - self.log_error(source, - translate('SongsPlugin.WordsofWorshipSongImport', - '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) - no_of_blocks = ord(song_data.read(1)) - song_data.seek(66) - if song_data.read(16).decode() != 'CSongDoc::CBlock': - self.log_error(source, - translate('SongsPlugin.WordsofWorshipSongImport', - '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) - for block in range(no_of_blocks): - skip_char_at_end = True - self.lines_to_read = ord(song_data.read(4)[:1]) - block_text = '' - while self.lines_to_read: - self.line_text = str(song_data.read(ord(song_data.read(1))), 'cp1252') - if skip_char_at_end: - skip_char = ord(song_data.read(1)) - # Check if we really should skip a char. In some wsg files we shouldn't - if skip_char != 0: - song_data.seek(-1, os.SEEK_CUR) - skip_char_at_end = False - if block_text: - block_text += '\n' - block_text += self.line_text - self.lines_to_read -= 1 - block_type = BLOCK_TYPES[ord(song_data.read(4)[:1])] - # Blocks are separated by 2 bytes, skip them, but not if - # this is the last block! - if block + 1 < no_of_blocks: - song_data.seek(2, os.SEEK_CUR) - self.add_verse(block_text, block_type) - # Now to extract the author - author_length = ord(song_data.read(1)) - if author_length: - self.parse_author(str(song_data.read(author_length), 'cp1252')) - # Finally the copyright - copyright_length = ord(song_data.read(1)) - if copyright_length: - self.add_copyright(str(song_data.read(copyright_length), 'cp1252')) - file_name = os.path.split(source)[1] - # Get the song title - self.title = file_name.rpartition('.')[0] - song_data.close() - if not self.finish(): - self.log_error(source) + with file_path.open('rb') as song_data: + if song_data.read(19).decode() != 'WoW File\nSong Words': + self.log_error(file_path, + translate('SongsPlugin.WordsofWorshipSongImport', + '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) + no_of_blocks = ord(song_data.read(1)) + song_data.seek(66) + if song_data.read(16).decode() != 'CSongDoc::CBlock': + self.log_error(file_path, + translate('SongsPlugin.WordsofWorshipSongImport', + '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) + for block in range(no_of_blocks): + skip_char_at_end = True + self.lines_to_read = ord(song_data.read(4)[:1]) + block_text = '' + while self.lines_to_read: + self.line_text = str(song_data.read(ord(song_data.read(1))), 'cp1252') + if skip_char_at_end: + skip_char = ord(song_data.read(1)) + # Check if we really should skip a char. In some wsg files we shouldn't + if skip_char != 0: + song_data.seek(-1, os.SEEK_CUR) + skip_char_at_end = False + if block_text: + block_text += '\n' + block_text += self.line_text + self.lines_to_read -= 1 + block_type = BLOCK_TYPES[ord(song_data.read(4)[:1])] + # Blocks are separated by 2 bytes, skip them, but not if + # this is the last block! + if block + 1 < no_of_blocks: + song_data.seek(2, os.SEEK_CUR) + self.add_verse(block_text, block_type) + # Now to extract the author + author_length = ord(song_data.read(1)) + if author_length: + self.parse_author(str(song_data.read(author_length), 'cp1252')) + # Finally the copyright + copyright_length = ord(song_data.read(1)) + if copyright_length: + self.add_copyright(str(song_data.read(copyright_length), 'cp1252')) + # Get the song title + self.title = file_path.stem + if not self.finish(): + self.log_error(file_path) diff --git a/openlp/plugins/songs/lib/importers/worshipassistant.py b/openlp/plugins/songs/lib/importers/worshipassistant.py index 35a555e53..b4cb87576 100644 --- a/openlp/plugins/songs/lib/importers/worshipassistant.py +++ b/openlp/plugins/songs/lib/importers/worshipassistant.py @@ -28,7 +28,7 @@ import csv import logging import re -from openlp.core.common import translate +from openlp.core.common import get_file_encoding, translate from openlp.plugins.songs.lib import VerseType from openlp.plugins.songs.lib.importers.songimport import SongImport @@ -81,19 +81,16 @@ class WorshipAssistantImport(SongImport): Receive a CSV file to import. """ # Get encoding - detect_file = open(self.import_source, 'rb') - detect_content = detect_file.read() - details = chardet.detect(detect_content) - detect_file.close() - songs_file = open(self.import_source, 'r', encoding=details['encoding']) - songs_reader = csv.DictReader(songs_file, escapechar='\\') - try: - records = list(songs_reader) - except csv.Error as e: - self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Error reading CSV file.'), - translate('SongsPlugin.WorshipAssistantImport', - 'Line {number:d}: {error}').format(number=songs_reader.line_num, error=e)) - return + encoding = get_file_encoding(self.import_source)['encoding'] + with self.import_source.open('r', encoding=encoding) as songs_file: + songs_reader = csv.DictReader(songs_file, escapechar='\\') + try: + records = list(songs_reader) + except csv.Error as e: + self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Error reading CSV file.'), + translate('SongsPlugin.WorshipAssistantImport', + 'Line {number:d}: {error}').format(number=songs_reader.line_num, error=e)) + return num_records = len(records) log.info('{count} records found in CSV file'.format(count=num_records)) self.import_wizard.progress_bar.setMaximum(num_records) @@ -185,4 +182,3 @@ class WorshipAssistantImport(SongImport): 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/zionworx.py b/openlp/plugins/songs/lib/importers/zionworx.py index 6bf7c8b01..b4aec2c16 100644 --- a/openlp/plugins/songs/lib/importers/zionworx.py +++ b/openlp/plugins/songs/lib/importers/zionworx.py @@ -76,7 +76,7 @@ class ZionWorxImport(SongImport): Receive a CSV file (from a ZionWorx database dump) to import. """ # Encoding should always be ISO-8859-1 - with open(self.import_source, 'rt', encoding='ISO-8859-1') as songs_file: + with self.import_source.open('rt', encoding='ISO-8859-1') as songs_file: field_names = ['SongNum', 'Title1', 'Title2', 'Lyrics', 'Writer', 'Copyright', 'Keywords', 'DefaultStyle'] songs_reader = csv.DictReader(songs_file, field_names) diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 31bd18b62..6632387f5 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -22,25 +22,24 @@ import logging import os -import shutil from PyQt5 import QtCore, QtWidgets from sqlalchemy.sql import and_, or_ from openlp.core.common import Registry, AppLocation, Settings, check_directory_exists, UiStrings, translate -from openlp.core.common.path import Path +from openlp.core.common.languagemanager import get_natural_key +from openlp.core.common.path import copyfile from openlp.core.lib import MediaManagerItem, ItemCapabilities, PluginStatus, ServiceItemContext, \ check_item_selected, create_separated_list from openlp.core.lib.ui import create_widget_action -from openlp.core.common.languagemanager import get_natural_key from openlp.plugins.songs.forms.editsongform import EditSongForm -from openlp.plugins.songs.forms.songmaintenanceform import SongMaintenanceForm -from openlp.plugins.songs.forms.songimportform import SongImportForm from openlp.plugins.songs.forms.songexportform import SongExportForm +from openlp.plugins.songs.forms.songimportform import SongImportForm +from openlp.plugins.songs.forms.songmaintenanceform import SongMaintenanceForm from openlp.plugins.songs.lib import VerseType, clean_string, delete_song from openlp.plugins.songs.lib.db import Author, AuthorType, Song, Book, MediaFile, SongBookEntry, Topic -from openlp.plugins.songs.lib.ui import SongStrings from openlp.plugins.songs.lib.openlyricsxml import OpenLyrics, SongXML +from openlp.plugins.songs.lib.ui import SongStrings log = logging.getLogger(__name__) @@ -88,11 +87,11 @@ class SongMediaItem(MediaManagerItem): def _update_background_audio(self, song, item): song.media_files = [] for i, bga in enumerate(item.background_audio): - dest_file = os.path.join( - str(AppLocation.get_section_data_path(self.plugin.name)), 'audio', str(song.id), os.path.split(bga)[1]) - check_directory_exists(Path(os.path.split(dest_file)[0])) - shutil.copyfile(os.path.join(str(AppLocation.get_section_data_path('servicemanager')), bga), dest_file) - song.media_files.append(MediaFile.populate(weight=i, file_name=dest_file)) + dest_path =\ + AppLocation.get_section_data_path(self.plugin.name) / 'audio' / str(song.id) / os.path.split(bga)[1] + check_directory_exists(dest_path.parent) + copyfile(AppLocation.get_section_data_path('servicemanager') / bga, dest_path) + song.media_files.append(MediaFile.populate(weight=i, file_path=dest_path)) self.plugin.manager.save_object(song, True) def add_end_header_bar(self): @@ -534,14 +533,13 @@ class SongMediaItem(MediaManagerItem): '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( - str(AppLocation.get_section_data_path(self.plugin.name)), 'audio', str(new_song.id)) - check_directory_exists(Path(save_path)) + save_path = AppLocation.get_section_data_path(self.plugin.name) / 'audio' / str(new_song.id) + check_directory_exists(save_path) for media_file in old_song.media_files: - new_media_file_name = os.path.join(save_path, os.path.basename(media_file.file_name)) - shutil.copyfile(media_file.file_name, new_media_file_name) + new_media_file_path = save_path / media_file.file_path.name + copyfile(media_file.file_path, new_media_file_path) new_media_file = MediaFile() - new_media_file.file_name = new_media_file_name + new_media_file.file_path = new_media_file_path new_media_file.type = media_file.type new_media_file.weight = media_file.weight new_song.media_files.append(new_media_file) @@ -613,7 +611,7 @@ class SongMediaItem(MediaManagerItem): # Add the audio file to the service item. if song.media_files: service_item.add_capability(ItemCapabilities.HasBackgroundAudio) - service_item.background_audio = [m.file_name for m in song.media_files] + service_item.background_audio = [m.file_path for m in song.media_files] return True def generate_footer(self, item, song): diff --git a/openlp/plugins/songs/lib/openlyricsexport.py b/openlp/plugins/songs/lib/openlyricsexport.py index 04677396b..430e37da5 100644 --- a/openlp/plugins/songs/lib/openlyricsexport.py +++ b/openlp/plugins/songs/lib/openlyricsexport.py @@ -24,12 +24,10 @@ The :mod:`openlyricsexport` module provides the functionality for exporting song format. """ import logging -import os from lxml import etree from openlp.core.common import RegistryProperties, check_directory_exists, translate, clean_filename -from openlp.core.common.path import Path from openlp.plugins.songs.lib.openlyricsxml import OpenLyrics log = logging.getLogger(__name__) @@ -42,13 +40,16 @@ class OpenLyricsExport(RegistryProperties): def __init__(self, parent, songs, save_path): """ Initialise the export. + + :param openlp.core.common.path.Path save_path: The directory to save the exported songs in + :rtype: None """ log.debug('initialise OpenLyricsExport') self.parent = parent self.manager = parent.plugin.manager self.songs = songs self.save_path = save_path - check_directory_exists(Path(self.save_path)) + check_directory_exists(self.save_path) def do_export(self): """ @@ -69,15 +70,15 @@ class OpenLyricsExport(RegistryProperties): 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 = '{name}.xml'.format(name=filename[0:250 - len(self.save_path)]) + path_length = len(str(self.save_path)) + filename_with_ext = '{name}.xml'.format(name=filename[0:250 - path_length]) # Make sure we're not overwriting an existing file conflicts = 0 - while os.path.exists(os.path.join(self.save_path, filename_with_ext)): + while (self.save_path / filename_with_ext).exists(): conflicts += 1 - filename_with_ext = '{name}-{extra}.xml'.format(name=filename[0:247 - len(self.save_path)], - extra=conflicts) + filename_with_ext = '{name}-{extra}.xml'.format(name=filename[0:247 - path_length], 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', - xml_declaration=True, pretty_print=True) + with (self.save_path / filename_with_ext).open('wb') as out_file: + tree.write(out_file, encoding='utf-8', xml_declaration=True, pretty_print=True) return True diff --git a/openlp/plugins/songs/lib/upgrade.py b/openlp/plugins/songs/lib/upgrade.py index 5b55d7985..bc7c95624 100644 --- a/openlp/plugins/songs/lib/upgrade.py +++ b/openlp/plugins/songs/lib/upgrade.py @@ -23,16 +23,20 @@ The :mod:`upgrade` module provides a way for the database and schema that is the backend for the Songs plugin """ +import json import logging from sqlalchemy import Table, Column, ForeignKey, types from sqlalchemy.sql.expression import func, false, null, text +from openlp.core.common import AppLocation from openlp.core.common.db import drop_columns -from openlp.core.lib.db import get_upgrade_op +from openlp.core.common.json import OpenLPJsonEncoder +from openlp.core.common.path import Path +from openlp.core.lib.db import PathType, get_upgrade_op log = logging.getLogger(__name__) -__version__ = 6 +__version__ = 7 # TODO: When removing an upgrade path the ftw-data needs updating to the minimum supported version @@ -162,3 +166,28 @@ def upgrade_6(session, metadata): op.drop_column('songs', 'song_number') # Finally, clean up our mess in people's databases op.execute('DELETE FROM songs_songbooks WHERE songbook_id = 0') + + +def upgrade_7(session, metadata): + """ + Version 7 upgrade - Move file path from old db to JSON encoded path to new db. Upgrade added in 2.5 dev + """ + log.debug('Starting upgrade_7 for file_path to JSON') + old_table = Table('media_files', metadata, autoload=True) + if 'file_path' not in [col.name for col in old_table.c.values()]: + op = get_upgrade_op(session) + op.add_column('media_files', Column('file_path', PathType())) + conn = op.get_bind() + results = conn.execute('SELECT * FROM media_files') + data_path = AppLocation.get_data_path() + for row in results.fetchall(): + file_path_json = json.dumps(Path(row.file_name), cls=OpenLPJsonEncoder, base_path=data_path) + sql = 'UPDATE media_files SET file_path = \'{file_path_json}\' WHERE id = {id}'.format( + file_path_json=file_path_json, id=row.id) + conn.execute(sql) + # Drop old columns + if metadata.bind.url.get_dialect().name == 'sqlite': + drop_columns(op, 'media_files', ['file_name', ]) + else: + op.drop_constraint('media_files', 'foreignkey') + op.drop_column('media_files', 'filenames') diff --git a/openlp/plugins/songs/reporting.py b/openlp/plugins/songs/reporting.py index 066a0ea26..8f06906e7 100644 --- a/openlp/plugins/songs/reporting.py +++ b/openlp/plugins/songs/reporting.py @@ -31,7 +31,6 @@ from openlp.core.lib.ui import critical_error_message_box from openlp.core.ui.lib.filedialog import FileDialog from openlp.plugins.songs.lib.db import Song - log = logging.getLogger(__name__) @@ -58,9 +57,9 @@ def report_song_list(): report_file_path.with_suffix('.csv') Registry().get('application').set_busy_cursor() try: - with report_file_path.open('wt') as file_handle: + with report_file_path.open('wt') as export_file: fieldnames = ('Title', 'Alternative Title', 'Copyright', 'Author(s)', 'Song Book', 'Topic') - writer = csv.DictWriter(file_handle, fieldnames=fieldnames, quoting=csv.QUOTE_ALL) + writer = csv.DictWriter(export_file, fieldnames=fieldnames, quoting=csv.QUOTE_ALL) headers = dict((n, n) for n in fieldnames) writer.writerow(headers) song_list = plugin.manager.get_all_objects(Song) diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py index 1edb999dc..728fee5a9 100644 --- a/openlp/plugins/songs/songsplugin.py +++ b/openlp/plugins/songs/songsplugin.py @@ -37,7 +37,6 @@ from openlp.core.common.actions import ActionList from openlp.core.lib import Plugin, StringContent, build_icon from openlp.core.lib.db import Manager from openlp.core.lib.ui import create_action - from openlp.plugins.songs import reporting from openlp.plugins.songs.endpoint import api_songs_endpoint, songs_endpoint from openlp.plugins.songs.forms.duplicatesongremovalform import DuplicateSongRemovalForm @@ -50,7 +49,6 @@ from openlp.plugins.songs.lib.mediaitem import SongMediaItem from openlp.plugins.songs.lib.mediaitem import SongSearch from openlp.plugins.songs.lib.songstab import SongsTab - log = logging.getLogger(__name__) __default_settings__ = { 'songs/db type': 'sqlite', @@ -340,7 +338,7 @@ class SongsPlugin(Plugin): progress.forceShow() self.application.process_events() for db in song_dbs: - importer = OpenLPSongImport(self.manager, filename=db) + importer = OpenLPSongImport(self.manager, file_path=db) importer.do_import(progress) self.application.process_events() progress.setValue(song_count) diff --git a/resources/images/android_app_qr.png b/resources/images/android_app_qr.png deleted file mode 100644 index e7cd3fe92..000000000 Binary files a/resources/images/android_app_qr.png and /dev/null differ diff --git a/resources/images/app_qr.svg b/resources/images/app_qr.svg new file mode 100644 index 000000000..f384070b1 --- /dev/null +++ b/resources/images/app_qr.svg @@ -0,0 +1,446 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/resources/images/ios_app_qr.png b/resources/images/ios_app_qr.png deleted file mode 100644 index c7244fc33..000000000 Binary files a/resources/images/ios_app_qr.png and /dev/null differ diff --git a/resources/images/openlp-2.qrc b/resources/images/openlp-2.qrc index 1a50dbe78..ee6dfe358 100644 --- a/resources/images/openlp-2.qrc +++ b/resources/images/openlp-2.qrc @@ -183,7 +183,6 @@ projector_warmup.png - android_app_qr.png - ios_app_qr.png - - + app_qr.svg + + \ No newline at end of file diff --git a/tests/functional/openlp_plugins/remotes/test_deploy.py b/tests/functional/openlp_core_api/test_deploy.py similarity index 96% rename from tests/functional/openlp_plugins/remotes/test_deploy.py rename to tests/functional/openlp_core_api/test_deploy.py index 1909b94fd..273894b99 100644 --- a/tests/functional/openlp_plugins/remotes/test_deploy.py +++ b/tests/functional/openlp_core_api/test_deploy.py @@ -22,14 +22,12 @@ import os import shutil - from tempfile import mkdtemp from unittest import TestCase -from openlp.plugins.remotes.deploy import deploy_zipfile +from openlp.core.api.deploy import deploy_zipfile - -TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources')) +TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'resources')) class TestRemoteDeploy(TestCase): @@ -54,6 +52,7 @@ class TestRemoteDeploy(TestCase): Remote Deploy tests - test the dummy zip file is processed correctly """ # GIVEN: A new downloaded zip file + aa = TEST_PATH zip_file = os.path.join(TEST_PATH, 'remotes', 'site.zip') app_root = os.path.join(self.app_root, 'site.zip') shutil.copyfile(zip_file, app_root) diff --git a/tests/functional/openlp_plugins/images/test_upgrade.py b/tests/functional/openlp_plugins/images/test_upgrade.py index c80e9c3c9..f5ac85b5b 100644 --- a/tests/functional/openlp_plugins/images/test_upgrade.py +++ b/tests/functional/openlp_plugins/images/test_upgrade.py @@ -79,5 +79,6 @@ class TestImageDBUpgrade(TestCase, TestMixin): 2: Path('/', 'test', 'dir', 'image2.jpg'), 3: Path('/', 'test', 'dir', 'subdir', 'image3.jpg')} + self.assertEqual(len(upgraded_results), 3) for result in upgraded_results: self.assertEqual(expected_result_data[result.id], result.file_path) diff --git a/tests/functional/openlp_plugins/remotes/__init__.py b/tests/functional/openlp_plugins/remotes/__init__.py deleted file mode 100644 index ea62548f4..000000000 --- a/tests/functional/openlp_plugins/remotes/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- -# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 - -############################################################################### -# OpenLP - Open Source Lyrics Projection # -# --------------------------------------------------------------------------- # -# Copyright (c) 2008-2017 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 # -############################################################################### diff --git a/tests/functional/openlp_plugins/songs/test_chordproimport.py b/tests/functional/openlp_plugins/songs/test_chordproimport.py index b096fcb15..51ab19f25 100644 --- a/tests/functional/openlp_plugins/songs/test_chordproimport.py +++ b/tests/functional/openlp_plugins/songs/test_chordproimport.py @@ -24,6 +24,8 @@ This module contains tests for the OpenSong song importer. """ import os +from openlp.core.common.path import Path + from tests.helpers.songfileimport import SongImportTestHelper from unittest.mock import patch, MagicMock @@ -48,5 +50,5 @@ class TestChordProFileImport(SongImportTestHelper): mocked_returned_settings.value.side_effect = lambda value: True if value == 'songs/enable chords' else False mocked_settings.return_value = mocked_returned_settings # Do the test import - self.file_import([os.path.join(TEST_PATH, 'swing-low.chordpro')], + self.file_import([Path(TEST_PATH, 'swing-low.chordpro')], self.load_external_result_data(os.path.join(TEST_PATH, 'swing-low.json'))) diff --git a/tests/functional/openlp_plugins/songs/test_easyslidesimport.py b/tests/functional/openlp_plugins/songs/test_easyslidesimport.py index bfe9abcc2..6e0e6848b 100644 --- a/tests/functional/openlp_plugins/songs/test_easyslidesimport.py +++ b/tests/functional/openlp_plugins/songs/test_easyslidesimport.py @@ -21,9 +21,10 @@ """ This module contains tests for the EasySlides song importer. """ - import os +from openlp.core.common.path import Path + from tests.helpers.songfileimport import SongImportTestHelper TEST_PATH = os.path.abspath( @@ -41,7 +42,7 @@ class TestEasySlidesFileImport(SongImportTestHelper): """ Test that loading an EasySlides file works correctly on various files """ - self.file_import(os.path.join(TEST_PATH, 'amazing-grace.xml'), + self.file_import(Path(TEST_PATH, 'amazing-grace.xml'), self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json'))) - self.file_import(os.path.join(TEST_PATH, 'Export_2017-01-12_BB.xml'), + self.file_import(Path(TEST_PATH, 'Export_2017-01-12_BB.xml'), self.load_external_result_data(os.path.join(TEST_PATH, 'Export_2017-01-12_BB.json'))) diff --git a/tests/functional/openlp_plugins/songs/test_ewimport.py b/tests/functional/openlp_plugins/songs/test_ewimport.py index ab0727136..2440c1271 100644 --- a/tests/functional/openlp_plugins/songs/test_ewimport.py +++ b/tests/functional/openlp_plugins/songs/test_ewimport.py @@ -97,7 +97,7 @@ class EasyWorshipSongImportLogger(EasyWorshipSongImport): _title_assignment_list = [] def __init__(self, manager): - EasyWorshipSongImport.__init__(self, manager, filenames=[]) + EasyWorshipSongImport.__init__(self, manager, file_paths=[]) @property def title(self): @@ -180,7 +180,7 @@ class TestEasyWorshipSongImport(TestCase): mocked_manager = MagicMock() # WHEN: An importer object is created - importer = EasyWorshipSongImport(mocked_manager, filenames=[]) + importer = EasyWorshipSongImport(mocked_manager, file_paths=[]) # THEN: The importer object should not be None self.assertIsNotNone(importer, 'Import should not be none') @@ -192,7 +192,7 @@ class TestEasyWorshipSongImport(TestCase): # GIVEN: A mocked out SongImport class, a mocked out "manager" and a list of field descriptions. with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'): mocked_manager = MagicMock() - importer = EasyWorshipSongImport(mocked_manager, filenames=[]) + importer = EasyWorshipSongImport(mocked_manager, file_paths=[]) importer.field_descriptions = TEST_FIELD_DESCS # WHEN: Called with a field name that exists @@ -210,7 +210,7 @@ class TestEasyWorshipSongImport(TestCase): # GIVEN: A mocked out SongImport class, a mocked out "manager" and a list of field descriptions with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'): mocked_manager = MagicMock() - importer = EasyWorshipSongImport(mocked_manager, filenames=[]) + importer = EasyWorshipSongImport(mocked_manager, file_paths=[]) importer.field_descriptions = TEST_FIELD_DESCS # WHEN: Called with a field name that does not exist @@ -229,7 +229,7 @@ class TestEasyWorshipSongImport(TestCase): with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'), \ patch('openlp.plugins.songs.lib.importers.easyworship.struct') as mocked_struct: mocked_manager = MagicMock() - importer = EasyWorshipSongImport(mocked_manager, filenames=[]) + importer = EasyWorshipSongImport(mocked_manager, file_paths=[]) # WHEN: db_set_record_struct is called with a list of field descriptions return_value = importer.db_set_record_struct(TEST_FIELD_DESCS) @@ -246,7 +246,7 @@ class TestEasyWorshipSongImport(TestCase): # GIVEN: A mocked out SongImport class, a mocked out "manager", an encoding and some test data and known results with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'): mocked_manager = MagicMock() - importer = EasyWorshipSongImport(mocked_manager, filenames=[]) + importer = EasyWorshipSongImport(mocked_manager, file_paths=[]) importer.encoding = TEST_DATA_ENCODING importer.fields = TEST_FIELDS importer.field_descriptions = TEST_FIELD_DESCS @@ -270,7 +270,7 @@ class TestEasyWorshipSongImport(TestCase): with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'): mocked_manager = MagicMock() mocked_memo_file = MagicMock() - importer = EasyWorshipSongImport(mocked_manager, filenames=[]) + importer = EasyWorshipSongImport(mocked_manager, file_paths=[]) importer.memo_file = mocked_memo_file importer.encoding = TEST_DATA_ENCODING @@ -294,44 +294,25 @@ class TestEasyWorshipSongImport(TestCase): else: mocked_memo_file.seek.assert_any_call(call[0], call[1]) - def test_do_import_source(self): - """ - Test the :mod:`do_import` module opens the correct files - """ - # GIVEN: A mocked out SongImport class, a mocked out "manager" - with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'), \ - patch('openlp.plugins.songs.lib.importers.easyworship.os.path') as mocked_os_path: - mocked_manager = MagicMock() - importer = EasyWorshipSongImport(mocked_manager, filenames=[]) - mocked_os_path.isfile.side_effect = [True, False] - - # WHEN: Supplied with an import source - importer.import_source = 'Songs.DB' - - # THEN: do_import should return None having called os.path.isfile - self.assertIsNone(importer.do_import(), 'do_import should return None') - mocked_os_path.isfile.assert_any_call('Songs.DB') - mocked_os_path.isfile.assert_any_call('Songs.MB') - def test_do_import_source_invalid(self): """ Test the :mod:`do_import` module produces an error when Songs.MB not found. """ # GIVEN: A mocked out SongImport class, a mocked out "manager" with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'), \ - patch('openlp.plugins.songs.lib.importers.easyworship.os.path') as mocked_os_path: + patch('openlp.plugins.songs.lib.importers.easyworship.Path.is_file', side_effect=[True, False]): mocked_manager = MagicMock() - importer = EasyWorshipSongImport(mocked_manager, filenames=[]) - importer.log_error = MagicMock() - mocked_os_path.isfile.side_effect = [True, False] + importer = EasyWorshipSongImport(mocked_manager, file_paths=[]) + with patch.object(importer, 'log_error') as mocked_log_error: - # WHEN: do_import is supplied with an import source (Songs.MB missing) - importer.import_source = 'Songs.DB' - importer.do_import() + # WHEN: do_import is supplied with an import source (Songs.MB missing) + importer.import_source = 'Songs.DB' + importer.do_import() - # THEN: do_import should have logged an error that the Songs.MB file could not be found. - 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.') + # THEN: do_import should have logged an error that the Songs.MB file could not be found. + mocked_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 test_do_import_database_validity(self): """ @@ -339,18 +320,19 @@ class TestEasyWorshipSongImport(TestCase): """ # GIVEN: A mocked out SongImport class, os.path and a mocked out "manager" with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'), \ - patch('openlp.plugins.songs.lib.importers.easyworship.os.path') as mocked_os_path: + patch('openlp.plugins.songs.lib.importers.easyworship.Path.is_file', return_value=True), \ + patch('openlp.plugins.songs.lib.importers.easyworship.Path.stat') as mocked_stat: + mocked_manager = MagicMock() - importer = EasyWorshipSongImport(mocked_manager, filenames=[]) - mocked_os_path.isfile.return_value = True + importer = EasyWorshipSongImport(mocked_manager, file_paths=[]) importer.import_source = 'Songs.DB' # WHEN: DB file size is less than 0x800 - mocked_os_path.getsize.return_value = 0x7FF + mocked_stat.return_value.st_size = 0x7FF - # THEN: do_import should return None having called os.path.isfile + # THEN: do_import should return None having called Path.stat() 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') + mocked_stat.assert_called_once_with() def test_do_import_memo_validty(self): """ @@ -358,13 +340,12 @@ class TestEasyWorshipSongImport(TestCase): """ # GIVEN: A mocked out SongImport class, a mocked out "manager" with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'), \ - patch('openlp.plugins.songs.lib.importers.easyworship.os.path') as mocked_os_path, \ - patch('builtins.open') as mocked_open, \ + patch('openlp.plugins.songs.lib.importers.easyworship.Path.is_file', return_value=True), \ + patch('openlp.plugins.songs.lib.importers.easyworship.Path.stat', **{'return_value.st_size': 0x800}), \ + patch('openlp.plugins.songs.lib.importers.easyworship.Path.open') as mocked_open, \ patch('openlp.plugins.songs.lib.importers.easyworship.struct') as mocked_struct: mocked_manager = MagicMock() - importer = EasyWorshipSongImport(mocked_manager, filenames=[]) - mocked_os_path.isfile.return_value = True - mocked_os_path.getsize.return_value = 0x800 + importer = EasyWorshipSongImport(mocked_manager, file_paths=[]) importer.import_source = 'Songs.DB' # WHEN: Unpacking first 35 bytes of Memo file @@ -385,14 +366,14 @@ class TestEasyWorshipSongImport(TestCase): """ # GIVEN: A mocked out SongImport class, a mocked out "manager" with patch('openlp.plugins.songs.lib.importers.easyworship.SongImport'), \ - patch('openlp.plugins.songs.lib.importers.easyworship.os.path') as mocked_os_path, \ + patch('openlp.plugins.songs.lib.importers.easyworship.Path.is_file', return_value=True), \ + patch('openlp.plugins.songs.lib.importers.easyworship.Path.stat', **{'return_value.st_size': 0x800}), \ + patch('openlp.plugins.songs.lib.importers.easyworship.Path.open'), \ patch('builtins.open'), patch('openlp.plugins.songs.lib.importers.easyworship.struct') as mocked_struct, \ - patch('openlp.plugins.songs.lib.importers.easyworship.retrieve_windows_encoding') as \ + patch('openlp.plugins.songs.lib.importers.easyworship.retrieve_windows_encoding') as \ mocked_retrieve_windows_encoding: mocked_manager = MagicMock() - importer = EasyWorshipSongImport(mocked_manager, filenames=[]) - mocked_os_path.isfile.return_value = True - mocked_os_path.getsize.return_value = 0x800 + importer = EasyWorshipSongImport(mocked_manager, file_paths=[]) importer.import_source = 'Songs.DB' # WHEN: Unpacking the code page diff --git a/tests/functional/openlp_plugins/songs/test_lyriximport.py b/tests/functional/openlp_plugins/songs/test_lyriximport.py index 32644e033..2732b3154 100644 --- a/tests/functional/openlp_plugins/songs/test_lyriximport.py +++ b/tests/functional/openlp_plugins/songs/test_lyriximport.py @@ -22,7 +22,8 @@ This module contains tests for the LyriX song importer. """ import os -from unittest.mock import patch + +from openlp.core.common.path import Path from tests.helpers.songfileimport import SongImportTestHelper @@ -41,9 +42,9 @@ class TestLyrixFileImport(SongImportTestHelper): """ Test that loading an LyriX file works correctly on various files """ - self.file_import([os.path.join(TEST_PATH, 'A06.TXT')], + self.file_import([Path(TEST_PATH, 'A06.TXT')], self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json'))) - self.file_import([os.path.join(TEST_PATH, 'A002.TXT')], + self.file_import([Path(TEST_PATH, 'A002.TXT')], self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace2.json'))) - self.file_import([os.path.join(TEST_PATH, 'AO05.TXT')], + self.file_import([Path(TEST_PATH, 'AO05.TXT')], self.load_external_result_data(os.path.join(TEST_PATH, 'in die regterhand.json'))) diff --git a/tests/functional/openlp_plugins/songs/test_mediashout.py b/tests/functional/openlp_plugins/songs/test_mediashout.py index 7e828df89..2726f8f95 100644 --- a/tests/functional/openlp_plugins/songs/test_mediashout.py +++ b/tests/functional/openlp_plugins/songs/test_mediashout.py @@ -51,7 +51,7 @@ class TestMediaShoutImport(TestCase): """ # GIVEN: A MediaShoutImport class # WHEN: It is created - importer = MediaShoutImport(MagicMock(), filename='mediashout.db') + importer = MediaShoutImport(MagicMock(), file_path='mediashout.db') # THEN: It should not be None self.assertIsNotNone(importer) @@ -62,7 +62,7 @@ class TestMediaShoutImport(TestCase): Test that do_import exits early when unable to connect to the database """ # GIVEN: A MediaShoutImport instance - importer = MediaShoutImport(MagicMock(), filename='mediashout.db') + importer = MediaShoutImport(MagicMock(), file_path='mediashout.db') mocked_pyodbc.connect.side_effect = Exception('Unable to connect') # WHEN: do_import is called @@ -89,7 +89,7 @@ class TestMediaShoutImport(TestCase): group = GroupRecord('Hymns') # GIVEN: A MediaShoutImport instance and a bunch of stuff mocked out - importer = MediaShoutImport(MagicMock(), filename='mediashout.db') + importer = MediaShoutImport(MagicMock(), file_path='mediashout.db') mocked_cursor = MagicMock() mocked_cursor.fetchall.side_effect = [[song], [verse], [play_order], [theme], [group]] mocked_cursor.tables.fetchone.return_value = True @@ -124,7 +124,7 @@ class TestMediaShoutImport(TestCase): song = SongRecord(1, 'Amazing Grace', 'William Wilberforce', 'Public Domain', 1, '654321', '') # GIVEN: A MediaShoutImport instance and a bunch of stuff mocked out - importer = MediaShoutImport(MagicMock(), filename='mediashout.db') + importer = MediaShoutImport(MagicMock(), file_path='mediashout.db') mocked_cursor = MagicMock() mocked_cursor.fetchall.return_value = [song] mocked_connection = MagicMock() @@ -158,7 +158,7 @@ class TestMediaShoutImport(TestCase): play_order = PlayOrderRecord(0, 1, 1) theme = ThemeRecord('Grace') group = GroupRecord('Hymns') - importer = MediaShoutImport(MagicMock(), filename='mediashout.db') + importer = MediaShoutImport(MagicMock(), file_path='mediashout.db') # WHEN: A song is processed with patch.object(importer, 'set_defaults') as mocked_set_defaults, \ @@ -200,7 +200,7 @@ class TestMediaShoutImport(TestCase): play_order = PlayOrderRecord(0, 1, 1) theme = ThemeRecord('Grace') group = GroupRecord('Hymns') - importer = MediaShoutImport(MagicMock(), filename='mediashout.db') + importer = MediaShoutImport(MagicMock(), file_path='mediashout.db') # WHEN: A song is processed with patch.object(importer, 'set_defaults') as mocked_set_defaults, \ diff --git a/tests/functional/openlp_plugins/songs/test_openlpimporter.py b/tests/functional/openlp_plugins/songs/test_openlpimporter.py index 70eda660a..9a8f6b6a7 100644 --- a/tests/functional/openlp_plugins/songs/test_openlpimporter.py +++ b/tests/functional/openlp_plugins/songs/test_openlpimporter.py @@ -48,7 +48,7 @@ class TestOpenLPImport(TestCase): mocked_manager = MagicMock() # WHEN: An importer object is created - importer = OpenLPSongImport(mocked_manager, filenames=[]) + importer = OpenLPSongImport(mocked_manager, file_paths=[]) # THEN: The importer object should not be None self.assertIsNotNone(importer, 'Import should not be none') @@ -61,7 +61,7 @@ class TestOpenLPImport(TestCase): with patch('openlp.plugins.songs.lib.importers.openlp.SongImport'): mocked_manager = MagicMock() mocked_import_wizard = MagicMock() - importer = OpenLPSongImport(mocked_manager, filenames=[]) + importer = OpenLPSongImport(mocked_manager, file_paths=[]) importer.import_wizard = mocked_import_wizard importer.stop_import_flag = True diff --git a/tests/functional/openlp_plugins/songs/test_openlyricsexport.py b/tests/functional/openlp_plugins/songs/test_openlyricsexport.py index bf74ec02b..5335110d5 100644 --- a/tests/functional/openlp_plugins/songs/test_openlyricsexport.py +++ b/tests/functional/openlp_plugins/songs/test_openlyricsexport.py @@ -22,14 +22,14 @@ """ This module contains tests for the OpenLyrics song importer. """ -import os import shutil from tempfile import mkdtemp from unittest import TestCase from unittest.mock import MagicMock, patch -from openlp.plugins.songs.lib.openlyricsexport import OpenLyricsExport from openlp.core.common import Registry +from openlp.core.common.path import Path, rmtree +from openlp.plugins.songs.lib.openlyricsexport import OpenLyricsExport from tests.helpers.testmixin import TestMixin @@ -43,13 +43,13 @@ class TestOpenLyricsExport(TestCase, TestMixin): Create the registry """ Registry.create() - self.temp_folder = mkdtemp() + self.temp_folder = Path(mkdtemp()) def tearDown(self): """ Cleanup """ - shutil.rmtree(self.temp_folder) + rmtree(self.temp_folder) def test_export_same_filename(self): """ @@ -73,7 +73,9 @@ class TestOpenLyricsExport(TestCase, TestMixin): ol_export.do_export() # THEN: The exporter should have created 2 files - self.assertTrue(os.path.exists(os.path.join(self.temp_folder, - '%s (%s).xml' % (song.title, author.display_name)))) - self.assertTrue(os.path.exists(os.path.join(self.temp_folder, - '%s (%s)-1.xml' % (song.title, author.display_name)))) + self.assertTrue((self.temp_folder / + '{title} ({display_name}).xml'.format( + title=song.title, display_name=author.display_name)).exists()) + self.assertTrue((self.temp_folder / + '{title} ({display_name})-1.xml'.format( + title=song.title, display_name=author.display_name)).exists()) diff --git a/tests/functional/openlp_plugins/songs/test_openlyricsimport.py b/tests/functional/openlp_plugins/songs/test_openlyricsimport.py index b87ee988c..ac4e40665 100644 --- a/tests/functional/openlp_plugins/songs/test_openlyricsimport.py +++ b/tests/functional/openlp_plugins/songs/test_openlyricsimport.py @@ -29,10 +29,11 @@ from unittest.mock import MagicMock, patch from lxml import etree, objectify +from openlp.core.common import Registry, Settings +from openlp.core.common.path import Path from openlp.plugins.songs.lib.importers.openlyrics import OpenLyricsImport from openlp.plugins.songs.lib.importers.songimport import SongImport from openlp.plugins.songs.lib.openlyricsxml import OpenLyrics -from openlp.core.common import Registry, Settings from tests.helpers.testmixin import TestMixin @@ -109,7 +110,7 @@ class TestOpenLyricsImport(TestCase, TestMixin): mocked_manager = MagicMock() # WHEN: An importer object is created - importer = OpenLyricsImport(mocked_manager, filenames=[]) + importer = OpenLyricsImport(mocked_manager, file_paths=[]) # THEN: The importer should be an instance of SongImport self.assertIsInstance(importer, SongImport) @@ -122,13 +123,13 @@ class TestOpenLyricsImport(TestCase, TestMixin): for song_file in SONG_TEST_DATA: mocked_manager = MagicMock() mocked_import_wizard = MagicMock() - importer = OpenLyricsImport(mocked_manager, filenames=[]) + importer = OpenLyricsImport(mocked_manager, file_paths=[]) importer.import_wizard = mocked_import_wizard importer.open_lyrics = MagicMock() importer.open_lyrics.xml_to_song = MagicMock() # WHEN: Importing each file - importer.import_source = [os.path.join(TEST_PATH, song_file)] + importer.import_source = [Path(TEST_PATH, song_file)] importer.do_import() # THEN: The xml_to_song() method should have been called diff --git a/tests/functional/openlp_plugins/songs/test_openoffice.py b/tests/functional/openlp_plugins/songs/test_openoffice.py index b276078d4..3351123d7 100644 --- a/tests/functional/openlp_plugins/songs/test_openoffice.py +++ b/tests/functional/openlp_plugins/songs/test_openoffice.py @@ -54,7 +54,7 @@ class TestOpenOfficeImport(TestCase, TestMixin): mocked_manager = MagicMock() # WHEN: An importer object is created - importer = OpenOfficeImport(mocked_manager, filenames=[]) + importer = OpenOfficeImport(mocked_manager, file_paths=[]) # THEN: The importer object should not be None self.assertIsNotNone(importer, 'Import should not be none') @@ -66,7 +66,7 @@ class TestOpenOfficeImport(TestCase, TestMixin): """ # GIVEN: A mocked out SongImport class, a mocked out "manager" and a document that raises an exception mocked_manager = MagicMock() - importer = OpenOfficeImport(mocked_manager, filenames=[]) + importer = OpenOfficeImport(mocked_manager, file_paths=[]) importer.document = MagicMock() importer.document.close = MagicMock(side_effect=Exception()) diff --git a/tests/functional/openlp_plugins/songs/test_opensongimport.py b/tests/functional/openlp_plugins/songs/test_opensongimport.py index 2b67e8f19..f84ddf724 100644 --- a/tests/functional/openlp_plugins/songs/test_opensongimport.py +++ b/tests/functional/openlp_plugins/songs/test_opensongimport.py @@ -27,6 +27,7 @@ from unittest import TestCase from unittest.mock import patch, MagicMock from openlp.core.common import Registry +from openlp.core.common.path import Path from openlp.plugins.songs.lib.importers.opensong import OpenSongImport from tests.helpers.songfileimport import SongImportTestHelper @@ -52,15 +53,15 @@ class TestOpenSongFileImport(SongImportTestHelper): mocked_returned_settings.value.side_effect = lambda value: True if value == 'songs/enable chords' else False mocked_settings.return_value = mocked_returned_settings # Do the test import - self.file_import([os.path.join(TEST_PATH, 'Amazing Grace')], + self.file_import([Path(TEST_PATH, 'Amazing Grace')], self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json'))) - self.file_import([os.path.join(TEST_PATH, 'Beautiful Garden Of Prayer')], + self.file_import([Path(TEST_PATH, 'Beautiful Garden Of Prayer')], self.load_external_result_data(os.path.join(TEST_PATH, 'Beautiful Garden Of Prayer.json'))) - self.file_import([os.path.join(TEST_PATH, 'One, Two, Three, Four, Five')], + self.file_import([Path(TEST_PATH, 'One, Two, Three, Four, Five')], 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.file_import([Path(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.file_import([Path(TEST_PATH, 'Amazing Grace with bad CCLI')], self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace without CCLI.json'))) @@ -83,7 +84,7 @@ class TestOpenSongImport(TestCase): mocked_manager = MagicMock() # WHEN: An importer object is created - importer = OpenSongImport(mocked_manager, filenames=[]) + importer = OpenSongImport(mocked_manager, file_paths=[]) # THEN: The importer object should not be None self.assertIsNotNone(importer, 'Import should not be none') @@ -96,7 +97,7 @@ class TestOpenSongImport(TestCase): with patch('openlp.plugins.songs.lib.importers.opensong.SongImport'): mocked_manager = MagicMock() mocked_import_wizard = MagicMock() - importer = OpenSongImport(mocked_manager, filenames=[]) + importer = OpenSongImport(mocked_manager, file_paths=[]) importer.import_wizard = mocked_import_wizard importer.stop_import_flag = True @@ -117,7 +118,7 @@ class TestOpenSongImport(TestCase): with patch('openlp.plugins.songs.lib.importers.opensong.SongImport'): mocked_manager = MagicMock() mocked_import_wizard = MagicMock() - importer = OpenSongImport(mocked_manager, filenames=[]) + importer = OpenSongImport(mocked_manager, file_paths=[]) importer.import_wizard = mocked_import_wizard importer.stop_import_flag = True diff --git a/tests/functional/openlp_plugins/songs/test_opsproimport.py b/tests/functional/openlp_plugins/songs/test_opsproimport.py index 7042bdb9e..4558b74f2 100644 --- a/tests/functional/openlp_plugins/songs/test_opsproimport.py +++ b/tests/functional/openlp_plugins/songs/test_opsproimport.py @@ -86,7 +86,7 @@ class TestOpsProSongImport(TestCase): mocked_manager = MagicMock() # WHEN: An importer object is created - importer = OPSProImport(mocked_manager, filenames=[]) + importer = OPSProImport(mocked_manager, file_paths=[]) # THEN: The importer object should not be None self.assertIsNotNone(importer, 'Import should not be none') @@ -98,7 +98,7 @@ class TestOpsProSongImport(TestCase): """ # GIVEN: A mocked out SongImport class, a mocked out "manager" and a mocked song and lyrics entry mocked_manager = MagicMock() - importer = OPSProImport(mocked_manager, filenames=[]) + importer = OPSProImport(mocked_manager, file_paths=[]) importer.finish = MagicMock() song, lyrics = _build_data('you are so faithfull.txt', False) @@ -118,7 +118,7 @@ class TestOpsProSongImport(TestCase): """ # GIVEN: A mocked out SongImport class, a mocked out "manager" and a mocked song and lyrics entry mocked_manager = MagicMock() - importer = OPSProImport(mocked_manager, filenames=[]) + importer = OPSProImport(mocked_manager, file_paths=[]) importer.finish = MagicMock() song, lyrics = _build_data('amazing grace.txt', False) @@ -138,7 +138,7 @@ class TestOpsProSongImport(TestCase): """ # GIVEN: A mocked out SongImport class, a mocked out "manager" and a mocked song and lyrics entry mocked_manager = MagicMock() - importer = OPSProImport(mocked_manager, filenames=[]) + importer = OPSProImport(mocked_manager, file_paths=[]) importer.finish = MagicMock() song, lyrics = _build_data('amazing grace2.txt', True) @@ -158,7 +158,7 @@ class TestOpsProSongImport(TestCase): """ # GIVEN: A mocked out SongImport class, a mocked out "manager" and a mocked song and lyrics entry mocked_manager = MagicMock() - importer = OPSProImport(mocked_manager, filenames=[]) + importer = OPSProImport(mocked_manager, file_paths=[]) importer.finish = MagicMock() song, lyrics = _build_data('amazing grace3.txt', True) diff --git a/tests/functional/openlp_plugins/songs/test_powerpraiseimport.py b/tests/functional/openlp_plugins/songs/test_powerpraiseimport.py index d85506d9c..cd668f684 100644 --- a/tests/functional/openlp_plugins/songs/test_powerpraiseimport.py +++ b/tests/functional/openlp_plugins/songs/test_powerpraiseimport.py @@ -26,8 +26,9 @@ ProPresenter song files into the current installation database. import os +from openlp.core.common.path import Path + from tests.helpers.songfileimport import SongImportTestHelper -from openlp.core.common import Registry TEST_PATH = os.path.abspath( os.path.join(os.path.dirname(__file__), '..', '..', '..', 'resources', 'powerpraisesongs')) @@ -44,7 +45,7 @@ class TestPowerPraiseFileImport(SongImportTestHelper): """ Test that loading a PowerPraise file works correctly """ - self.file_import([os.path.join(TEST_PATH, 'Naher, mein Gott zu Dir.ppl')], + self.file_import([Path(TEST_PATH, 'Naher, mein Gott zu Dir.ppl')], self.load_external_result_data(os.path.join(TEST_PATH, 'Naher, mein Gott zu Dir.json'))) - self.file_import([os.path.join(TEST_PATH, 'You are so faithful.ppl')], + self.file_import([Path(TEST_PATH, 'You are so faithful.ppl')], self.load_external_result_data(os.path.join(TEST_PATH, 'You are so faithful.json'))) diff --git a/tests/functional/openlp_plugins/songs/test_presentationmanagerimport.py b/tests/functional/openlp_plugins/songs/test_presentationmanagerimport.py index c8c496dde..5391c31af 100644 --- a/tests/functional/openlp_plugins/songs/test_presentationmanagerimport.py +++ b/tests/functional/openlp_plugins/songs/test_presentationmanagerimport.py @@ -22,9 +22,10 @@ """ This module contains tests for the PresentationManager song importer. """ - import os +from openlp.core.common.path import Path + from tests.helpers.songfileimport import SongImportTestHelper TEST_PATH = os.path.abspath( @@ -42,7 +43,7 @@ class TestPresentationManagerFileImport(SongImportTestHelper): """ Test that loading a PresentationManager file works correctly """ - self.file_import([os.path.join(TEST_PATH, 'Great Is Thy Faithfulness.sng')], + self.file_import([Path(TEST_PATH, 'Great Is Thy Faithfulness.sng')], self.load_external_result_data(os.path.join(TEST_PATH, 'Great Is Thy Faithfulness.json'))) - self.file_import([os.path.join(TEST_PATH, 'Amazing Grace.sng')], + self.file_import([Path(TEST_PATH, 'Amazing Grace.sng')], self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json'))) diff --git a/tests/functional/openlp_plugins/songs/test_propresenterimport.py b/tests/functional/openlp_plugins/songs/test_propresenterimport.py index 777ff9e58..e93dd6d9f 100644 --- a/tests/functional/openlp_plugins/songs/test_propresenterimport.py +++ b/tests/functional/openlp_plugins/songs/test_propresenterimport.py @@ -23,9 +23,10 @@ The :mod:`propresenterimport` module provides the functionality for importing ProPresenter song files into the current installation database. """ - import os +from openlp.core.common.path import Path + from tests.helpers.songfileimport import SongImportTestHelper TEST_PATH = os.path.abspath( @@ -43,19 +44,19 @@ class TestProPresenterFileImport(SongImportTestHelper): """ Test that loading a ProPresenter 4 file works correctly """ - self.file_import([os.path.join(TEST_PATH, 'Amazing Grace.pro4')], + self.file_import([Path(TEST_PATH, 'Amazing Grace.pro4')], self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json'))) def test_pro5_song_import(self): """ Test that loading a ProPresenter 5 file works correctly """ - self.file_import([os.path.join(TEST_PATH, 'Amazing Grace.pro5')], + self.file_import([Path(TEST_PATH, 'Amazing Grace.pro5')], self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json'))) def test_pro6_song_import(self): """ Test that loading a ProPresenter 6 file works correctly """ - self.file_import([os.path.join(TEST_PATH, 'Amazing Grace.pro6')], + self.file_import([Path(TEST_PATH, 'Amazing Grace.pro6')], self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json'))) diff --git a/tests/functional/openlp_plugins/songs/test_songbeamerimport.py b/tests/functional/openlp_plugins/songs/test_songbeamerimport.py index fc44cf97f..0084fa688 100644 --- a/tests/functional/openlp_plugins/songs/test_songbeamerimport.py +++ b/tests/functional/openlp_plugins/songs/test_songbeamerimport.py @@ -26,8 +26,9 @@ import os from unittest import TestCase from unittest.mock import MagicMock, patch -from openlp.plugins.songs.lib.importers.songbeamer import SongBeamerImport, SongBeamerTypes from openlp.core.common import Registry +from openlp.core.common.path import Path +from openlp.plugins.songs.lib.importers.songbeamer import SongBeamerImport, SongBeamerTypes from tests.helpers.songfileimport import SongImportTestHelper @@ -51,18 +52,18 @@ class TestSongBeamerFileImport(SongImportTestHelper): mocked_returned_settings = MagicMock() mocked_returned_settings.value.side_effect = lambda value: True if value == 'songs/enable chords' else False mocked_settings.return_value = mocked_returned_settings - self.file_import([os.path.join(TEST_PATH, 'Amazing Grace.sng')], + self.file_import([Path(TEST_PATH, 'Amazing Grace.sng')], self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json'))) - self.file_import([os.path.join(TEST_PATH, 'Lobsinget dem Herrn.sng')], + self.file_import([Path(TEST_PATH, 'Lobsinget dem Herrn.sng')], self.load_external_result_data(os.path.join(TEST_PATH, 'Lobsinget dem Herrn.json'))) - self.file_import([os.path.join(TEST_PATH, 'When I Call On You.sng')], + self.file_import([Path(TEST_PATH, 'When I Call On You.sng')], self.load_external_result_data(os.path.join(TEST_PATH, 'When I Call On You.json'))) def test_cp1252_encoded_file(self): """ Test that a CP1252 encoded file get's decoded properly. """ - self.file_import([os.path.join(TEST_PATH, 'cp1252song.sng')], + self.file_import([Path(TEST_PATH, 'cp1252song.sng')], self.load_external_result_data(os.path.join(TEST_PATH, 'cp1252song.json'))) @@ -78,7 +79,7 @@ class TestSongBeamerImport(TestCase): self.song_import_patcher = patch('openlp.plugins.songs.lib.importers.songbeamer.SongImport') self.song_import_patcher.start() mocked_manager = MagicMock() - self.importer = SongBeamerImport(mocked_manager, filenames=[]) + self.importer = SongBeamerImport(mocked_manager, file_paths=[]) def tearDown(self): """ @@ -95,7 +96,7 @@ class TestSongBeamerImport(TestCase): mocked_manager = MagicMock() # WHEN: An importer object is created - importer = SongBeamerImport(mocked_manager, filenames=[]) + importer = SongBeamerImport(mocked_manager, file_paths=[]) # THEN: The importer object should not be None self.assertIsNotNone(importer, 'Import should not be none') diff --git a/tests/functional/openlp_plugins/songs/test_songproimport.py b/tests/functional/openlp_plugins/songs/test_songproimport.py index b41ae7b0e..4e874165b 100644 --- a/tests/functional/openlp_plugins/songs/test_songproimport.py +++ b/tests/functional/openlp_plugins/songs/test_songproimport.py @@ -23,9 +23,10 @@ The :mod:`songproimport` module provides the functionality for importing SongPro song files into the current installation database. """ - import os +from openlp.core.common.path import Path + from tests.helpers.songfileimport import SongImportTestHelper TEST_PATH = os.path.abspath( @@ -43,5 +44,5 @@ class TestSongProFileImport(SongImportTestHelper): """ Test that loading an SongPro file works correctly """ - self.file_import(os.path.join(TEST_PATH, 'amazing-grace.txt'), + self.file_import(Path(TEST_PATH, 'amazing-grace.txt'), self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json'))) diff --git a/tests/functional/openlp_plugins/songs/test_songselect.py b/tests/functional/openlp_plugins/songs/test_songselect.py index 8583e0a17..9a92e3788 100644 --- a/tests/functional/openlp_plugins/songs/test_songselect.py +++ b/tests/functional/openlp_plugins/songs/test_songselect.py @@ -31,6 +31,7 @@ from urllib.error import URLError from PyQt5 import QtWidgets from openlp.core import Registry +from openlp.core.common.path import Path from openlp.plugins.songs.forms.songselectform import SongSelectForm, SearchWorker from openlp.plugins.songs.lib import Song from openlp.plugins.songs.lib.songselect import SongSelectImport, LOGIN_PAGE, LOGOUT_URL, BASE_URL @@ -810,15 +811,15 @@ class TestSongSelectFileImport(SongImportTestHelper): def __init__(self, *args, **kwargs): self.importer_class_name = 'CCLIFileImport' self.importer_module_name = 'cclifile' - super(TestSongSelectFileImport, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def test_song_import(self): """ Test that loading an OpenSong file works correctly on various files """ - self.file_import([os.path.join(TEST_PATH, 'TestSong.bin')], + self.file_import([Path(TEST_PATH, 'TestSong.bin')], self.load_external_result_data(os.path.join(TEST_PATH, 'TestSong-bin.json'))) - self.file_import([os.path.join(TEST_PATH, 'TestSong.txt')], + self.file_import([Path(TEST_PATH, 'TestSong.txt')], self.load_external_result_data(os.path.join(TEST_PATH, 'TestSong-txt.json'))) diff --git a/tests/functional/openlp_plugins/songs/test_songshowplusimport.py b/tests/functional/openlp_plugins/songs/test_songshowplusimport.py index e7dd5d354..79e8ba593 100644 --- a/tests/functional/openlp_plugins/songs/test_songshowplusimport.py +++ b/tests/functional/openlp_plugins/songs/test_songshowplusimport.py @@ -26,6 +26,7 @@ import os from unittest import TestCase from unittest.mock import patch, MagicMock +from openlp.core.common.path import Path from openlp.plugins.songs.lib import VerseType from openlp.plugins.songs.lib.importers.songshowplus import SongShowPlusImport @@ -46,13 +47,13 @@ class TestSongShowPlusFileImport(SongImportTestHelper): """ Test that loading a SongShow Plus file works correctly on various files """ - self.file_import([os.path.join(TEST_PATH, 'Amazing Grace.sbsong')], + self.file_import([Path(TEST_PATH, 'Amazing Grace.sbsong')], self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json'))) - self.file_import([os.path.join(TEST_PATH, 'Beautiful Garden Of Prayer.sbsong')], + self.file_import([Path(TEST_PATH, 'Beautiful Garden Of Prayer.sbsong')], 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.file_import([Path(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.file_import([Path(TEST_PATH, 'cleanse-me.sbsong')], self.load_external_result_data(os.path.join(TEST_PATH, 'cleanse-me.json'))) @@ -69,7 +70,7 @@ class TestSongShowPlusImport(TestCase): mocked_manager = MagicMock() # WHEN: An importer object is created - importer = SongShowPlusImport(mocked_manager, filenames=[]) + importer = SongShowPlusImport(mocked_manager, file_paths=[]) # THEN: The importer object should not be None self.assertIsNotNone(importer, 'Import should not be none') @@ -82,7 +83,7 @@ class TestSongShowPlusImport(TestCase): with patch('openlp.plugins.songs.lib.importers.songshowplus.SongImport'): mocked_manager = MagicMock() mocked_import_wizard = MagicMock() - importer = SongShowPlusImport(mocked_manager, filenames=[]) + importer = SongShowPlusImport(mocked_manager, file_paths=[]) importer.import_wizard = mocked_import_wizard importer.stop_import_flag = True @@ -103,7 +104,7 @@ class TestSongShowPlusImport(TestCase): with patch('openlp.plugins.songs.lib.importers.songshowplus.SongImport'): mocked_manager = MagicMock() mocked_import_wizard = MagicMock() - importer = SongShowPlusImport(mocked_manager, filenames=[]) + importer = SongShowPlusImport(mocked_manager, file_paths=[]) importer.import_wizard = mocked_import_wizard importer.stop_import_flag = True @@ -123,7 +124,7 @@ class TestSongShowPlusImport(TestCase): # GIVEN: A mocked out SongImport class, and a mocked out "manager" with patch('openlp.plugins.songs.lib.importers.songshowplus.SongImport'): mocked_manager = MagicMock() - importer = SongShowPlusImport(mocked_manager, filenames=[]) + importer = SongShowPlusImport(mocked_manager, file_paths=[]) # WHEN: Supplied with the following arguments replicating verses being added test_values = [ @@ -151,7 +152,7 @@ class TestSongShowPlusImport(TestCase): # GIVEN: A mocked out SongImport class, and a mocked out "manager" with patch('openlp.plugins.songs.lib.importers.songshowplus.SongImport'): mocked_manager = MagicMock() - importer = SongShowPlusImport(mocked_manager, filenames=[]) + importer = SongShowPlusImport(mocked_manager, file_paths=[]) # WHEN: Supplied with the following arguments replicating a verse order being added test_values = [ diff --git a/tests/functional/openlp_plugins/songs/test_sundayplusimport.py b/tests/functional/openlp_plugins/songs/test_sundayplusimport.py index 9c6ef1a42..5a5977943 100644 --- a/tests/functional/openlp_plugins/songs/test_sundayplusimport.py +++ b/tests/functional/openlp_plugins/songs/test_sundayplusimport.py @@ -24,6 +24,8 @@ This module contains tests for the SundayPlus song importer. import os from unittest.mock import patch +from openlp.core.common.path import Path + from tests.helpers.songfileimport import SongImportTestHelper TEST_PATH = os.path.abspath( @@ -44,5 +46,5 @@ class TestSundayPlusFileImport(SongImportTestHelper): with patch('openlp.plugins.songs.lib.importers.sundayplus.retrieve_windows_encoding') as \ mocked_retrieve_windows_encoding: mocked_retrieve_windows_encoding.return_value = 'cp1252' - self.file_import([os.path.join(TEST_PATH, 'Amazing Grace.ptf')], + self.file_import([Path(TEST_PATH, 'Amazing Grace.ptf')], self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace.json'))) diff --git a/tests/functional/openlp_plugins/songs/test_videopsalm.py b/tests/functional/openlp_plugins/songs/test_videopsalm.py index c3e2a276f..69e4d9127 100644 --- a/tests/functional/openlp_plugins/songs/test_videopsalm.py +++ b/tests/functional/openlp_plugins/songs/test_videopsalm.py @@ -21,9 +21,10 @@ """ This module contains tests for the VideoPsalm song importer. """ - import os +from openlp.core.common.path import Path + from tests.helpers.songfileimport import SongImportTestHelper from unittest.mock import patch, MagicMock @@ -48,7 +49,7 @@ class TestVideoPsalmFileImport(SongImportTestHelper): mocked_returned_settings.value.side_effect = lambda value: True if value == 'songs/enable chords' else False mocked_settings.return_value = mocked_returned_settings # Do the test import - self.file_import(os.path.join(TEST_PATH, 'videopsalm-as-safe-a-stronghold.json'), + self.file_import(Path(TEST_PATH, 'videopsalm-as-safe-a-stronghold.json'), self.load_external_result_data(os.path.join(TEST_PATH, 'as-safe-a-stronghold.json'))) - self.file_import(os.path.join(TEST_PATH, 'videopsalm-as-safe-a-stronghold2.json'), + self.file_import(Path(TEST_PATH, 'videopsalm-as-safe-a-stronghold2.json'), self.load_external_result_data(os.path.join(TEST_PATH, 'as-safe-a-stronghold2.json'))) diff --git a/tests/functional/openlp_plugins/songs/test_wordsofworshipimport.py b/tests/functional/openlp_plugins/songs/test_wordsofworshipimport.py index ececf5dbb..c0cb9b47d 100644 --- a/tests/functional/openlp_plugins/songs/test_wordsofworshipimport.py +++ b/tests/functional/openlp_plugins/songs/test_wordsofworshipimport.py @@ -22,9 +22,10 @@ """ This module contains tests for the Words of Worship song importer. """ - import os +from openlp.core.common.path import Path + from tests.helpers.songfileimport import SongImportTestHelper from openlp.plugins.songs.lib.importers.wordsofworship import WordsOfWorshipImport @@ -43,10 +44,10 @@ class TestWordsOfWorshipFileImport(SongImportTestHelper): """ Test that loading a Words of Worship file works correctly """ - self.file_import([os.path.join(TEST_PATH, 'Amazing Grace (6 Verses).wow-song')], + self.file_import([Path(TEST_PATH, 'Amazing Grace (6 Verses).wow-song')], self.load_external_result_data(os.path.join(TEST_PATH, 'Amazing Grace (6 Verses).json'))) - self.file_import([os.path.join(TEST_PATH, 'When morning gilds the skies.wsg')], + self.file_import([Path(TEST_PATH, 'When morning gilds the skies.wsg')], self.load_external_result_data(os.path.join(TEST_PATH, 'When morning gilds the skies.json'))) - self.file_import([os.path.join(TEST_PATH, 'Holy Holy Holy Lord God Almighty.wow-song')], + self.file_import([Path(TEST_PATH, 'Holy Holy Holy Lord God Almighty.wow-song')], self.load_external_result_data(os.path.join(TEST_PATH, 'Holy Holy Holy Lord God Almighty.json'))) diff --git a/tests/functional/openlp_plugins/songs/test_worshipassistantimport.py b/tests/functional/openlp_plugins/songs/test_worshipassistantimport.py index 21e5a592f..be0179a98 100644 --- a/tests/functional/openlp_plugins/songs/test_worshipassistantimport.py +++ b/tests/functional/openlp_plugins/songs/test_worshipassistantimport.py @@ -23,9 +23,10 @@ The :mod:`worshipassistantimport` module provides the functionality for importing WorshipAssistant song files into the current installation database. """ - import os +from openlp.core.common.path import Path + from tests.helpers.songfileimport import SongImportTestHelper TEST_PATH = os.path.abspath( @@ -43,9 +44,9 @@ class TestWorshipAssistantFileImport(SongImportTestHelper): """ Test that loading an Worship Assistant file works correctly """ - self.file_import(os.path.join(TEST_PATH, 'du_herr.csv'), + self.file_import(Path(TEST_PATH, 'du_herr.csv'), self.load_external_result_data(os.path.join(TEST_PATH, 'du_herr.json'))) - self.file_import(os.path.join(TEST_PATH, 'would_you_be_free.csv'), + self.file_import(Path(TEST_PATH, 'would_you_be_free.csv'), self.load_external_result_data(os.path.join(TEST_PATH, 'would_you_be_free.json'))) - self.file_import(os.path.join(TEST_PATH, 'would_you_be_free2.csv'), + self.file_import(Path(TEST_PATH, 'would_you_be_free2.csv'), self.load_external_result_data(os.path.join(TEST_PATH, 'would_you_be_free.json'))) diff --git a/tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py b/tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py index fd39b80f9..152048e24 100644 --- a/tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py +++ b/tests/functional/openlp_plugins/songs/test_worshipcenterproimport.py @@ -55,7 +55,7 @@ if CAN_RUN_TESTS: _title_assignment_list = [] def __init__(self, manager): - WorshipCenterProImport.__init__(self, manager, filenames=[]) + WorshipCenterProImport.__init__(self, manager, file_paths=[]) @property def title(self): @@ -153,7 +153,7 @@ class TestWorshipCenterProSongImport(TestCase): mocked_manager = MagicMock() # WHEN: An importer object is created - importer = WorshipCenterProImport(mocked_manager, filenames=[]) + importer = WorshipCenterProImport(mocked_manager, file_paths=[]) # THEN: The importer object should not be None self.assertIsNotNone(importer, 'Import should not be none') @@ -170,7 +170,7 @@ class TestWorshipCenterProSongImport(TestCase): mocked_manager = MagicMock() mocked_log_error = MagicMock() mocked_translate.return_value = 'Translated Text' - importer = WorshipCenterProImport(mocked_manager, filenames=[]) + importer = WorshipCenterProImport(mocked_manager, file_paths=[]) importer.log_error = mocked_log_error importer.import_source = 'import_source' pyodbc_errors = [pyodbc.DatabaseError, pyodbc.IntegrityError, pyodbc.InternalError, pyodbc.OperationalError] diff --git a/tests/functional/openlp_plugins/songs/test_zionworximport.py b/tests/functional/openlp_plugins/songs/test_zionworximport.py index 97c1e8fa2..31bfc94ad 100644 --- a/tests/functional/openlp_plugins/songs/test_zionworximport.py +++ b/tests/functional/openlp_plugins/songs/test_zionworximport.py @@ -26,9 +26,10 @@ import os from unittest import TestCase from unittest.mock import MagicMock, patch +from openlp.core.common import Registry +from openlp.core.common.path import Path from openlp.plugins.songs.lib.importers.zionworx import ZionWorxImport from openlp.plugins.songs.lib.importers.songimport import SongImport -from openlp.core.common import Registry from tests.helpers.songfileimport import SongImportTestHelper @@ -55,7 +56,7 @@ class TestZionWorxImport(TestCase): mocked_manager = MagicMock() # WHEN: An importer object is created - importer = ZionWorxImport(mocked_manager, filenames=[]) + importer = ZionWorxImport(mocked_manager, file_paths=[]) # THEN: The importer should be an instance of SongImport self.assertIsInstance(importer, SongImport) @@ -72,5 +73,5 @@ class TestZionWorxFileImport(SongImportTestHelper): """ Test that loading an ZionWorx file works correctly on various files """ - self.file_import(os.path.join(TEST_PATH, 'zionworx.csv'), + self.file_import(Path(TEST_PATH, 'zionworx.csv'), self.load_external_result_data(os.path.join(TEST_PATH, 'zionworx.json'))) diff --git a/tests/helpers/songfileimport.py b/tests/helpers/songfileimport.py index 08453e0b2..7b0f0cb14 100644 --- a/tests/helpers/songfileimport.py +++ b/tests/helpers/songfileimport.py @@ -89,7 +89,7 @@ class SongImportTestHelper(TestCase): """ Import the given file and check that it has imported correctly """ - importer = self.importer_class(self.mocked_manager, filenames=[source_file_name]) + importer = self.importer_class(self.mocked_manager, file_paths=[source_file_name]) importer.import_wizard = self.mocked_import_wizard importer.stop_import_flag = False importer.topics = [] diff --git a/tests/interfaces/openlp_core_lib/test_pluginmanager.py b/tests/interfaces/openlp_core_lib/test_pluginmanager.py index 2e9e8342f..3dbae0e03 100644 --- a/tests/interfaces/openlp_core_lib/test_pluginmanager.py +++ b/tests/interfaces/openlp_core_lib/test_pluginmanager.py @@ -94,4 +94,3 @@ class TestPluginManager(TestCase, TestMixin): self.assertIn('custom', plugin_names, 'There should be a "custom" plugin') self.assertIn('songusage', plugin_names, 'There should be a "songusage" plugin') self.assertIn('alerts', plugin_names, 'There should be a "alerts" plugin') - self.assertIn('remotes', plugin_names, 'There should be a "remotes" plugin')