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')