Change the settings upgrade code to handle versioned upgrades

Upgrade settings to store file paths and json encoded Path objects
Enable the json encoders/decoders to work with custom objects with defined json methods
Added in automatic backup before settings upgrade on superflys request


lp:~phill-ridout/openlp/pathlib4 (revision 2769)
[SUCCESS] https://ci.openlp.io/job/Branch-01-Pull/2184/
[SUCCESS] https://ci.openlp.io/job/Branch-02-Functional-Tests/2087/
[SUCCESS] https://ci.openlp.io/job...

bzr-revno: 2764
This commit is contained in:
Phill 2017-09-04 21:28:50 -07:00 committed by Raoul Snyman
commit 28591ed04a
66 changed files with 718 additions and 505 deletions

View File

@ -33,13 +33,14 @@ import os
import shutil
import sys
import time
from pathlib import Path
from datetime import datetime
from traceback import format_exception
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import Registry, OpenLPMixin, AppLocation, LanguageManager, Settings, UiStrings, \
check_directory_exists, is_macosx, is_win, translate
from openlp.core.common.path import Path
from openlp.core.common.versionchecker import VersionThread, get_application_version
from openlp.core.lib import ScreenList
from openlp.core.resources import qInitResources
@ -347,8 +348,7 @@ def set_up_logging(log_path):
"""
Setup our logging using log_path
:param pathlib.Path log_path: The file to save the log to
:return: None
:param openlp.core.common.path.Path log_path: The file to save the log to.
:rtype: None
"""
check_directory_exists(log_path, True)
@ -406,7 +406,7 @@ def main(args=None):
# Set our data path
log.info('Data path: {name}'.format(name=data_path))
# Point to our data path
portable_settings.setValue('advanced/data path', str(data_path))
portable_settings.setValue('advanced/data path', data_path)
portable_settings.setValue('advanced/is portable', True)
portable_settings.sync()
else:
@ -423,8 +423,21 @@ def main(args=None):
if application.is_data_path_missing():
application.shared_memory.detach()
sys.exit()
# Remove/convert obsolete settings.
Settings().remove_obsolete_settings()
# Upgrade settings.
settings = Settings()
if settings.can_upgrade():
now = datetime.now()
# Only back up if OpenLP has previously run.
if settings.value('core/has run wizard'):
back_up_path = AppLocation.get_data_path() / (now.strftime('%Y-%m-%d %H-%M') + '.conf')
log.info('Settings about to be upgraded. Existing settings are being backed up to {back_up_path}'
.format(back_up_path=back_up_path))
QtWidgets.QMessageBox.information(
None, translate('OpenLP', 'Settings Upgrade'),
translate('OpenLP', 'Your settings are about to upgraded. A backup will be created at {back_up_path}')
.format(back_up_path=back_up_path))
settings.export(back_up_path)
settings.upgrade_settings()
# First time checks in settings
if not Settings().value('core/has run wizard'):
if not FirstTimeLanguageForm().exec():

View File

@ -79,8 +79,7 @@ def controller_text(request):
item['title'] = str(frame['display_title'])
if current_item.is_capable(ItemCapabilities.HasNotes):
item['slide_notes'] = str(frame['notes'])
if current_item.is_capable(ItemCapabilities.HasThumbnails) and \
Settings().value('api/thumbnails'):
if current_item.is_capable(ItemCapabilities.HasThumbnails) and Settings().value('api/thumbnails'):
# If the file is under our app directory tree send the portion after the match
data_path = str(AppLocation.get_data_path())
if frame['image'][0:len(data_path)] == data_path:

View File

@ -66,9 +66,8 @@ def check_directory_exists(directory, do_not_log=False):
"""
Check a directory exists and if not create it
:param pathlib.Path directory: The directory to make sure exists
:param openlp.core.common.path.Path directory: The directory to make sure exists
:param bool do_not_log: To not log anything. This is need for the start up, when the log isn't ready.
:return: None
:rtype: None
"""
if not do_not_log:
@ -89,7 +88,6 @@ def extension_loader(glob_pattern, excluded_files=[]):
:param str glob_pattern: A glob pattern used to find the extension(s) to be imported. Should be relative to the
application directory. i.e. plugins/*/*plugin.py
:param list[str] excluded_files: A list of file names to exclude that the glob pattern may find.
:return: None
:rtype: None
"""
app_dir = AppLocation.get_directory(AppLocation.AppDir)
@ -110,7 +108,7 @@ def path_to_module(path):
"""
Convert a path to a module name (i.e openlp.core.common)
:param pathlib.Path path: The path to convert to a module name.
:param openlp.core.common.path.Path path: The path to convert to a module name.
:return: The module name.
:rtype: str
"""
@ -377,7 +375,7 @@ def delete_file(file_path):
"""
Deletes a file from the system.
:param pathlib.Path file_path: The file, including path, to delete.
:param openlp.core.common.path.Path file_path: The file, including path, to delete.
:return: True if the deletion was successful, or the file never existed. False otherwise.
:rtype: bool
"""
@ -412,7 +410,7 @@ def is_not_image_file(file_path):
"""
Validate that the file is not an image file.
:param pathlib.Path file_path: The file to be checked.
:param openlp.core.common.path.Path file_path: The file to be checked.
:return: If the file is not an image
:rtype: bool
"""
@ -440,7 +438,7 @@ def check_binary_exists(program_path):
"""
Function that checks whether a binary exists.
:param pathlib.Path program_path: The full path to the binary to check.
:param openlp.core.common.path.Path program_path: The full path to the binary to check.
:return: program output to be parsed
:rtype: bytes
"""
@ -466,7 +464,7 @@ def get_file_encoding(file_path):
"""
Utility function to incrementally detect the file encoding.
:param pathlib.Path file_path: Filename for the file to determine the encoding for.
:param openlp.core.common.path.Path file_path: Filename for the file to determine the encoding for.
:return: A dict with the keys 'encoding' and 'confidence'
:rtype: dict[str, float]
"""

View File

@ -25,9 +25,9 @@ The :mod:`openlp.core.common.applocation` module provides an utility for OpenLP
import logging
import os
import sys
from pathlib import Path
from openlp.core.common import Settings, is_win, is_macosx
from openlp.core.common.path import Path
if not is_win() and not is_macosx():
@ -64,10 +64,8 @@ class AppLocation(object):
Return the appropriate directory according to the directory type.
:param dir_type: The directory type you want, for instance the data directory. Default *AppLocation.AppDir*
:type dir_type: AppLocation Enum
:return: The requested path
:rtype: pathlib.Path
:rtype: openlp.core.common.path.Path
"""
if dir_type == AppLocation.AppDir or dir_type == AppLocation.VersionDir:
return get_frozen_path(FROZEN_APP_PATH, APP_PATH)
@ -84,11 +82,11 @@ class AppLocation(object):
Return the path OpenLP stores all its data under.
:return: The data path to use.
:rtype: pathlib.Path
:rtype: openlp.core.common.path.Path
"""
# Check if we have a different data location.
if Settings().contains('advanced/data path'):
path = Path(Settings().value('advanced/data path'))
path = Settings().value('advanced/data path')
else:
path = AppLocation.get_directory(AppLocation.DataDir)
check_directory_exists(path)
@ -104,7 +102,7 @@ class AppLocation(object):
:param str extension: Defaults to ''. The extension to search for. For example::
'.png'
:return: List of files found.
:rtype: list[pathlib.Path]
:rtype: list[openlp.core.common.path.Path]
"""
path = AppLocation.get_data_path()
if section:
@ -120,9 +118,8 @@ class AppLocation(object):
"""
Return the path a particular module stores its data under.
:type section: str
:rtype: pathlib.Path
:param str section:
:rtype: openlp.core.common.path.Path
"""
path = AppLocation.get_data_path() / section
check_directory_exists(path)
@ -135,7 +132,7 @@ def _get_os_dir_path(dir_type):
:param dir_type: AppLocation Enum of the requested path type
:return: The requested path
:rtype: pathlib.Path
:rtype: openlp.core.common.path.Path
"""
# If running from source, return the language directory from the source directory
if dir_type == AppLocation.LanguageDir:

View File

@ -0,0 +1,86 @@
# -*- 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 #
###############################################################################
from json import JSONDecoder, JSONEncoder
from openlp.core.common.path import Path
class OpenLPJsonDecoder(JSONDecoder):
"""
Implement a custom JSONDecoder to handle Path objects
Example Usage:
object = json.loads(json_string, cls=OpenLPJsonDecoder)
"""
def __init__(self, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, strict=True,
object_pairs_hook=None, **kwargs):
"""
Re-implement __init__ so that we can pass in our object_hook method. Any additional kwargs, are stored in the
instance and are passed to custom objects upon encoding or decoding.
"""
self.kwargs = kwargs
if object_hook is None:
object_hook = self.custom_object_hook
super().__init__(object_hook, parse_float, parse_int, parse_constant, strict, object_pairs_hook)
def custom_object_hook(self, obj):
"""
Implement a custom Path object decoder.
:param dict obj: A decoded JSON object
:return: The original object literal, or a Path object if the object literal contains a key '__Path__'
:rtype: dict | openlp.core.common.path.Path
"""
if '__Path__' in obj:
obj = Path.encode_json(obj, **self.kwargs)
return obj
class OpenLPJsonEncoder(JSONEncoder):
"""
Implement a custom JSONEncoder to handle Path objects
Example Usage:
json_string = json.dumps(object, cls=OpenLPJsonEncoder)
"""
def __init__(self, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False,
indent=None, separators=None, default=None, **kwargs):
"""
Re-implement __init__ so that we can pass in additional kwargs, which are stored in the instance and are passed
to custom objects upon encoding or decoding.
"""
self.kwargs = kwargs
if default is None:
default = self.custom_default
super().__init__(skipkeys, ensure_ascii, check_circular, allow_nan, sort_keys, indent, separators, default)
def custom_default(self, obj):
"""
Convert any Path objects into a dictionary object which can be serialized.
:param object obj: The object to convert
:return: The serializable object
:rtype: dict
"""
if isinstance(obj, Path):
return obj.json_object(**self.kwargs)
return super().default(obj)

View File

@ -19,17 +19,21 @@
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from contextlib import suppress
from pathlib import Path
from openlp.core.common import is_win
if is_win():
from pathlib import WindowsPath as PathVariant
else:
from pathlib import PosixPath as PathVariant
def path_to_str(path):
def path_to_str(path=None):
"""
A utility function to convert a Path object or NoneType to a string equivalent.
:param path: The value to convert to a string
:type: pathlib.Path or None
:param openlp.core.common.path.Path | None path: The value to convert to a string
:return: An empty string if :param:`path` is None, else a string representation of the :param:`path`
:rtype: str
"""
@ -48,14 +52,49 @@ def str_to_path(string):
This function is of particular use because initating a Path object with an empty string causes the Path object to
point to the current working directory.
:param string: The string to convert
:type string: str
:param str string: The string to convert
:return: None if :param:`string` is empty, or a Path object representation of :param:`string`
:rtype: pathlib.Path or None
:rtype: openlp.core.common.path.Path | None
"""
if not isinstance(string, str):
raise TypeError('parameter \'string\' must be of type str')
if string == '':
return None
return Path(string)
class Path(PathVariant):
"""
Subclass pathlib.Path, so we can add json conversion methods
"""
@staticmethod
def encode_json(obj, base_path=None, **kwargs):
"""
Create a Path object from a dictionary representation. The dictionary has been constructed by JSON encoding of
a JSON reprensation of a Path object.
:param dict[str] obj: The dictionary representation
:param openlp.core.common.path.Path base_path: If specified, an absolute path to base the relative path off of.
:param kwargs: Contains any extra parameters. Not used!
:return: The reconstructed Path object
:rtype: openlp.core.common.path.Path
"""
path = Path(*obj['__Path__'])
if base_path and not path.is_absolute():
return base_path / path
return path
def json_object(self, base_path=None, **kwargs):
"""
Create a dictionary that can be JSON decoded.
:param openlp.core.common.path.Path base_path: If specified, an absolute path to make a relative path from.
:param kwargs: Contains any extra parameters. Not used!
:return: The dictionary representation of this Path object.
:rtype: dict[tuple]
"""
path = self
if base_path:
with suppress(ValueError):
path = path.relative_to(base_path)
return {'__Path__': path.parts}

View File

@ -24,15 +24,19 @@ This class contains the core default settings.
"""
import datetime
import logging
import json
import os
from tempfile import gettempdir
from PyQt5 import QtCore, QtGui
from openlp.core.common import ThemeLevel, SlideLimits, UiStrings, is_win, is_linux
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import SlideLimits, ThemeLevel, UiStrings, is_linux, is_win, translate
from openlp.core.common.json import OpenLPJsonDecoder, OpenLPJsonEncoder
from openlp.core.common.path import Path, str_to_path
log = logging.getLogger(__name__)
__version__ = 2
# Fix for bug #1014422.
X11_BYPASS_DEFAULT = True
@ -44,21 +48,6 @@ if is_linux():
X11_BYPASS_DEFAULT = False
def recent_files_conv(value):
"""
If the value is not a list convert it to a list
:param value: Value to convert
:return: value as a List
"""
if isinstance(value, list):
return value
elif isinstance(value, str):
return [value]
elif isinstance(value, bytes):
return [value.decode()]
return []
def media_players_conv(string):
"""
If phonon is in the setting string replace it with system
@ -73,14 +62,25 @@ def media_players_conv(string):
return string
def file_names_conv(file_names):
"""
Convert a list of file names in to a list of file paths.
:param list[str] file_names: The list of file names to convert.
:return: The list converted to file paths
:rtype: openlp.core.common.path.Path
"""
if file_names:
return [str_to_path(file_name) for file_name in file_names]
class Settings(QtCore.QSettings):
"""
Class to wrap QSettings.
* Exposes all the methods of QSettings.
* Adds functionality for OpenLP Portable. If the ``defaultFormat`` is set to
``IniFormat``, and the path to the Ini file is set using ``set_filename``,
then the Settings constructor (without any arguments) will create a Settings
* Adds functionality for OpenLP Portable. If the ``defaultFormat`` is set to ``IniFormat``, and the path to the Ini
file is set using ``set_filename``, then the Settings constructor (without any arguments) will create a Settings
object for accessing settings stored in that Ini file.
``__default_settings__``
@ -91,7 +91,7 @@ class Settings(QtCore.QSettings):
('general/enable slide loop', 'advanced/slide limits', [(SlideLimits.Wrap, True), (SlideLimits.End, False)])
The first entry is the *old key*; it will be removed.
The first entry is the *old key*; if it is different from the *new key* it will be removed.
The second entry is the *new key*; we will add it to the config. If this is just an empty string, we just remove
the old key. The last entry is a list containing two-pair tuples. If the list is empty, no conversion is made.
@ -105,11 +105,12 @@ class Settings(QtCore.QSettings):
So, if the type of the old value is bool, then there must be two rules.
"""
__default_settings__ = {
'settings/version': 0,
'advanced/add page break': False,
'advanced/alternate rows': not is_win(),
'advanced/autoscrolling': {'dist': 1, 'pos': 0},
'advanced/current media plugin': -1,
'advanced/data path': '',
'advanced/data path': None,
# 7 stands for now, 0 to 6 is Monday to Sunday.
'advanced/default service day': 7,
'advanced/default service enabled': True,
@ -143,7 +144,7 @@ class Settings(QtCore.QSettings):
'api/authentication enabled': False,
'api/ip address': '0.0.0.0',
'api/thumbnails': True,
'crashreport/last directory': '',
'crashreport/last directory': None,
'formattingTags/html_tags': '',
'core/audio repeat list': False,
'core/auto open': False,
@ -162,7 +163,7 @@ class Settings(QtCore.QSettings):
'core/screen blank': False,
'core/show splash': True,
'core/logo background color': '#ffffff',
'core/logo file': ':/graphics/openlp-splash-screen.png',
'core/logo file': Path(':/graphics/openlp-splash-screen.png'),
'core/logo hide on startup': False,
'core/songselect password': '',
'core/songselect username': '',
@ -177,17 +178,17 @@ class Settings(QtCore.QSettings):
'media/players': 'system,webkit',
'media/override player': QtCore.Qt.Unchecked,
'players/background color': '#000000',
'servicemanager/last directory': '',
'servicemanager/last file': '',
'servicemanager/service theme': '',
'servicemanager/last directory': None,
'servicemanager/last file': None,
'servicemanager/service theme': None,
'SettingsImport/file_date_created': datetime.datetime.now().strftime("%Y-%m-%d %H:%M"),
'SettingsImport/Make_Changes': 'At_Own_RISK',
'SettingsImport/type': 'OpenLP_settings_export',
'SettingsImport/version': '',
'themes/global theme': '',
'themes/last directory': '',
'themes/last directory export': '',
'themes/last directory import': '',
'themes/last directory': None,
'themes/last directory export': None,
'themes/last directory import': None,
'themes/theme level': ThemeLevel.Song,
'themes/wrap footer': False,
'user interface/live panel': True,
@ -208,22 +209,20 @@ class Settings(QtCore.QSettings):
'projector/db database': '',
'projector/enable': True,
'projector/connect on start': False,
'projector/last directory import': '',
'projector/last directory export': '',
'projector/last directory import': None,
'projector/last directory export': None,
'projector/poll time': 20, # PJLink timeout is 30 seconds
'projector/socket timeout': 5, # 5 second socket timeout
'projector/source dialog type': 0 # Source select dialog box type
}
__file_path__ = ''
__obsolete_settings__ = [
__setting_upgrade_1__ = [
# Changed during 2.2.x development.
# ('advanced/stylesheet fix', '', []),
# ('general/recent files', 'core/recent files', [(recent_files_conv, None)]),
('songs/search as type', 'advanced/search as type', []),
('media/players', 'media/players_temp', [(media_players_conv, None)]), # Convert phonon to system
('media/players_temp', 'media/players', []), # Move temp setting from above to correct setting
('advanced/default color', 'core/logo background color', []), # Default image renamed + moved to general > 2.4.
('advanced/default image', '/core/logo file', []), # Default image renamed + moved to general after 2.4.
('advanced/default image', 'core/logo file', []), # Default image renamed + moved to general after 2.4.
('remotes/https enabled', '', []),
('remotes/https port', '', []),
('remotes/twelve hour', 'api/twelve hour', []),
@ -234,7 +233,6 @@ class Settings(QtCore.QSettings):
('remotes/authentication enabled', 'api/authentication enabled', []),
('remotes/ip address', 'api/ip address', []),
('remotes/thumbnails', 'api/thumbnails', []),
('advanced/default image', 'core/logo file', []), # Default image renamed + moved to general after 2.4.
('shortcuts/escapeItem', 'shortcuts/desktopScreenEnable', []), # Escape item was removed in 2.6.
('shortcuts/offlineHelpItem', 'shortcuts/userManualItem', []), # Online and Offline help were combined in 2.6.
('shortcuts/onlineHelpItem', 'shortcuts/userManualItem', []), # Online and Offline help were combined in 2.6.
@ -243,7 +241,28 @@ class Settings(QtCore.QSettings):
# Last search type was renamed to last used search type in 2.6 since Bible search value type changed in 2.6.
('songs/last search type', 'songs/last used search type', []),
('bibles/last search type', '', []),
('custom/last search type', 'custom/last used search type', [])
('custom/last search type', 'custom/last used search type', [])]
__setting_upgrade_2__ = [
# The following changes are being made for the conversion to using Path objects made in 2.6 development
('advanced/data path', 'advanced/data path', [(str_to_path, None)]),
('crashreport/last directory', 'crashreport/last directory', [(str_to_path, None)]),
('servicemanager/last directory', 'servicemanager/last directory', [(str_to_path, None)]),
('servicemanager/last file', 'servicemanager/last file', [(str_to_path, None)]),
('themes/last directory', 'themes/last directory', [(str_to_path, None)]),
('themes/last directory export', 'themes/last directory export', [(str_to_path, None)]),
('themes/last directory import', 'themes/last directory import', [(str_to_path, None)]),
('projector/last directory import', 'projector/last directory import', [(str_to_path, None)]),
('projector/last directory export', 'projector/last directory export', [(str_to_path, None)]),
('bibles/last directory import', 'bibles/last directory import', [(str_to_path, None)]),
('presentations/pdf_program', 'presentations/pdf_program', [(str_to_path, None)]),
('songs/last directory import', 'songs/last directory import', [(str_to_path, None)]),
('songs/last directory export', 'songs/last directory export', [(str_to_path, None)]),
('songusage/last directory export', 'songusage/last directory export', [(str_to_path, None)]),
('core/recent files', 'core/recent files', [(file_names_conv, None)]),
('media/media files', 'media/media files', [(file_names_conv, None)]),
('presentations/presentations files', 'presentations/presentations files', [(file_names_conv, None)]),
('core/logo file', 'core/logo file', [(str_to_path, None)])
]
@staticmethod
@ -256,13 +275,16 @@ class Settings(QtCore.QSettings):
Settings.__default_settings__.update(default_values)
@staticmethod
def set_filename(ini_file):
def set_filename(ini_path):
"""
Sets the complete path to an Ini file to be used by Settings objects.
Does not affect existing Settings objects.
:param openlp.core.common.path.Path ini_path: ini file path
:rtype: None
"""
Settings.__file_path__ = ini_file
Settings.__file_path__ = str(ini_path)
@staticmethod
def set_up_default_values():
@ -431,14 +453,28 @@ class Settings(QtCore.QSettings):
key = self.group() + '/' + key
return Settings.__default_settings__[key]
def remove_obsolete_settings(self):
def can_upgrade(self):
"""
Can / should the settings be upgraded
:rtype: bool
"""
return __version__ != self.value('settings/version')
def upgrade_settings(self):
"""
This method is only called to clean up the config. It removes old settings and it renames settings. See
``__obsolete_settings__`` for more details.
"""
for old_key, new_key, rules in Settings.__obsolete_settings__:
# Once removed we don't have to do this again.
if self.contains(old_key):
current_version = self.value('settings/version')
for version in range(current_version, __version__):
version += 1
upgrade_list = getattr(self, '__setting_upgrade_{version}__'.format(version=version))
for old_key, new_key, rules in upgrade_list:
# Once removed we don't have to do this again. - Can be removed once fully switched to the versioning
# system.
if not self.contains(old_key):
continue
if new_key:
# Get the value of the old_key.
old_value = super(Settings, self).value(old_key)
@ -457,14 +493,17 @@ class Settings(QtCore.QSettings):
old_value = new
break
self.setValue(new_key, old_value)
self.remove(old_key)
if new_key != old_key:
self.remove(old_key)
self.setValue('settings/version', version)
def value(self, key):
"""
Returns the value for the given ``key``. The returned ``value`` is of the same type as the default value in the
*Settings.__default_settings__* dict.
:param key: The key to return the value from.
:param str key: The key to return the value from.
:return: The value stored by the setting.
"""
# if group() is not empty the group has not been specified together with the key.
if self.group():
@ -474,6 +513,18 @@ class Settings(QtCore.QSettings):
setting = super(Settings, self).value(key, default_value)
return self._convert_value(setting, default_value)
def setValue(self, key, value):
"""
Reimplement the setValue method to handle Path objects.
:param str key: The key of the setting to save
:param value: The value to save
:rtype: None
"""
if isinstance(value, Path) or (isinstance(value, list) and value and isinstance(value[0], Path)):
value = json.dumps(value, cls=OpenLPJsonEncoder)
super().setValue(key, value)
def _convert_value(self, setting, default_value):
"""
This converts the given ``setting`` to the type of the given ``default_value``.
@ -491,8 +542,11 @@ class Settings(QtCore.QSettings):
if isinstance(default_value, str):
return ''
# An empty list saved to the settings results in a None type being returned.
else:
elif isinstance(default_value, list):
return []
elif isinstance(setting, str):
if '__Path__' in setting:
return json.loads(setting, cls=OpenLPJsonDecoder)
# Convert the setting to the correct type.
if isinstance(default_value, bool):
if isinstance(setting, bool):
@ -502,3 +556,59 @@ class Settings(QtCore.QSettings):
if isinstance(default_value, int):
return int(setting)
return setting
def export(self, dest_path):
"""
Export the settings to file.
:param openlp.core.common.path.Path dest_path: The file path to create the export file.
:return: Success
:rtype: bool
"""
temp_path = Path(gettempdir(), 'openlp', 'exportConf.tmp')
# Delete old files if found.
if temp_path.exists():
temp_path.unlink()
if dest_path.exists():
dest_path.unlink()
self.remove('SettingsImport')
# Get the settings.
keys = self.allKeys()
export_settings = QtCore.QSettings(str(temp_path), Settings.IniFormat)
# Add a header section.
# This is to insure it's our conf file for import.
now = datetime.datetime.now()
# Write INI format using QSettings.
# Write our header.
export_settings.beginGroup('SettingsImport')
export_settings.setValue('Make_Changes', 'At_Own_RISK')
export_settings.setValue('type', 'OpenLP_settings_export')
export_settings.setValue('file_date_created', now.strftime("%Y-%m-%d %H:%M"))
export_settings.endGroup()
# Write all the sections and keys.
for section_key in keys:
# FIXME: We are conflicting with the standard "General" section.
if 'eneral' in section_key:
section_key = section_key.lower()
key_value = super().value(section_key)
if key_value is not None:
export_settings.setValue(section_key, key_value)
export_settings.sync()
# Temp CONF file has been written. Blanks in keys are now '%20'.
# Read the temp file and output the user's CONF file with blanks to
# make it more readable.
try:
with dest_path.open('w') as export_conf_file, temp_path.open('r') as temp_conf:
for file_record in temp_conf:
# Get rid of any invalid entries.
if file_record.find('@Invalid()') == -1:
file_record = file_record.replace('%20', ' ')
export_conf_file.write(file_record)
except OSError as ose:
QtWidgets.QMessageBox.critical(self, translate('OpenLP.MainWindow', 'Export setting error'),
translate('OpenLP.MainWindow',
'An error occurred while exporting the settings: {err}'
).format(err=ose.strerror),
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Ok))
finally:
temp_path.unlink()

View File

@ -89,7 +89,7 @@ def get_text_file_string(text_file_path):
returns False. If there is an error loading the file or the content can't be decoded then the function will return
None.
:param pathlib.Path text_file_path: The path to the file.
:param openlp.core.common.path.Path text_file_path: The path to the file.
:return: The contents of the file, False if the file does not exist, or None if there is an Error reading or
decoding the file.
:rtype: str | False | None
@ -610,17 +610,11 @@ def replace_params(args, kwargs, params):
"""
Apply a transformation function to the specified args or kwargs
:param args: Positional arguments
:type args: (,)
:param kwargs: Key Word arguments
:type kwargs: dict
:param tuple args: Positional arguments
:param dict kwargs: Key Word arguments
:param params: A tuple of tuples with the position and the key word to replace.
:type params: ((int, str, path_to_str),)
:return: The modified positional and keyword arguments
:rtype: (tuple, dict)
:rtype: tuple[tuple, dict]
Usage:

View File

@ -29,7 +29,7 @@ import re
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import Registry, RegistryProperties, Settings, UiStrings, translate
from openlp.core.common.path import path_to_str, str_to_path
from openlp.core.common.path import Path, path_to_str, str_to_path
from openlp.core.lib import ServiceItem, StringContent, ServiceItemContext
from openlp.core.lib.searchedit import SearchEdit
from openlp.core.lib.ui import create_widget_action, critical_error_message_box
@ -313,7 +313,7 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties):
"""
file_paths, selected_filter = FileDialog.getOpenFileNames(
self, self.on_new_prompt,
str_to_path(Settings().value(self.settings_section + '/last directory')),
Settings().value(self.settings_section + '/last directory'),
self.on_new_file_masks)
log.info('New files(s) {file_paths}'.format(file_paths=file_paths))
if file_paths:
@ -377,9 +377,8 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties):
self.list_view.clear()
self.load_list(full_list, target_group)
last_dir = os.path.split(files[0])[0]
Settings().setValue(self.settings_section + '/last directory', last_dir)
Settings().setValue('{section}/{section} files'.format(section=self.settings_section),
self.get_file_list())
Settings().setValue(self.settings_section + '/last directory', Path(last_dir))
Settings().setValue('{section}/{section} files'.format(section=self.settings_section), self.get_file_list())
if duplicates_found:
critical_error_message_box(UiStrings().Duplicate,
translate('OpenLP.MediaManagerItem',
@ -400,13 +399,15 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties):
def get_file_list(self):
"""
Return the current list of files
:rtype: list[openlp.core.common.path.Path]
"""
file_list = []
file_paths = []
for index in range(self.list_view.count()):
list_item = self.list_view.item(index)
filename = list_item.data(QtCore.Qt.UserRole)
file_list.append(filename)
return file_list
file_paths.append(str_to_path(filename))
return file_paths
def load_list(self, load_list, target_group):
"""

View File

@ -1,61 +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 #
###############################################################################
from pathlib import Path
def path_to_str(path):
"""
A utility function to convert a Path object or NoneType to a string equivalent.
:param path: The value to convert to a string
:type: pathlib.Path or None
:return: An empty string if :param:`path` is None, else a string representation of the :param:`path`
:rtype: str
"""
if not isinstance(path, Path) and path is not None:
raise TypeError('parameter \'path\' must be of type Path or NoneType')
if path is None:
return ''
else:
return str(path)
def str_to_path(string):
"""
A utility function to convert a str object to a Path or NoneType.
This function is of particular use because initating a Path object with an empty string causes the Path object to
point to the current working directory.
:param string: The string to convert
:type string: str
:return: None if :param:`string` is empty, or a Path object representation of :param:`string`
:rtype: pathlib.Path or None
"""
if not isinstance(string, str):
raise TypeError('parameter \'string\' must be of type str')
if string == '':
return None
return Path(string)

View File

@ -150,7 +150,7 @@ class Plugin(QtCore.QObject, RegistryProperties):
self.status = PluginStatus.Inactive
# Add the default status to the default settings.
default_settings[name + '/status'] = PluginStatus.Inactive
default_settings[name + '/last directory'] = ''
default_settings[name + '/last directory'] = None
# Append a setting for files in the mediamanager (note not all plugins
# which have a mediamanager need this).
if media_item_class is not None:

View File

@ -70,9 +70,9 @@ try:
except ImportError:
VLC_VERSION = '-'
from openlp.core.common import Settings, UiStrings, translate
from openlp.core.common import RegistryProperties, Settings, UiStrings, is_linux, translate
from openlp.core.common.versionchecker import get_application_version
from openlp.core.common import RegistryProperties, is_linux
from openlp.core.ui.lib.filedialog import FileDialog
from .exceptiondialog import Ui_ExceptionDialog
@ -139,17 +139,17 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties):
"""
Saving exception log and system information to a file.
"""
filename = QtWidgets.QFileDialog.getSaveFileName(
file_path, filter_used = FileDialog.getSaveFileName(
self,
translate('OpenLP.ExceptionForm', 'Save Crash Report'),
Settings().value(self.settings_section + '/last directory'),
translate('OpenLP.ExceptionForm', 'Text files (*.txt *.log *.text)'))[0]
if filename:
filename = str(filename).replace('/', os.path.sep)
Settings().setValue(self.settings_section + '/last directory', os.path.dirname(filename))
translate('OpenLP.ExceptionForm', 'Text files (*.txt *.log *.text)'))
if file_path:
Settings().setValue(self.settings_section + '/last directory', file_path.parent)
opts = self._create_report()
report_text = self.report_text.format(version=opts['version'], description=opts['description'],
traceback=opts['traceback'], libs=opts['libs'], system=opts['system'])
filename = str(file_path)
try:
report_file = open(filename, 'w')
try:
@ -212,17 +212,16 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties):
def on_attach_file_button_clicked(self):
"""
Attache files to the bug report e-mail.
Attach files to the bug report e-mail.
"""
files, filter_used = QtWidgets.QFileDialog.getOpenFileName(self,
translate('ImagePlugin.ExceptionDialog',
'Select Attachment'),
Settings().value(self.settings_section +
'/last directory'),
'{text} (*)'.format(text=UiStrings().AllFiles))
log.info('New files(s) {files}'.format(files=str(files)))
if files:
self.file_attachment = str(files)
file_path, filter_used = \
FileDialog.getOpenFileName(self,
translate('ImagePlugin.ExceptionDialog', 'Select Attachment'),
Settings().value(self.settings_section + '/last directory'),
'{text} (*)'.format(text=UiStrings().AllFiles))
log.info('New file {file}'.format(file=file_path))
if file_path:
self.file_attachment = str(file_path)
def __button_state(self, state):
"""

View File

@ -30,13 +30,13 @@ import urllib.request
import urllib.parse
import urllib.error
from configparser import ConfigParser, MissingSectionHeaderError, NoOptionError, NoSectionError
from pathlib import Path
from tempfile import gettempdir
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import Registry, RegistryProperties, AppLocation, Settings, check_directory_exists, \
translate, clean_button_text, trace_error_handler
from openlp.core.common.path import Path
from openlp.core.lib import PluginStatus, build_icon
from openlp.core.lib.ui import critical_error_message_box
from openlp.core.common.httputils import get_web_page, get_url_file_size, url_get_file, CONNECTION_TIMEOUT

View File

@ -23,12 +23,11 @@
The general tab of the configuration dialog.
"""
import logging
from pathlib import Path
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import Registry, Settings, UiStrings, translate, get_images_filter
from openlp.core.common.path import path_to_str, str_to_path
from openlp.core.common.path import Path, path_to_str, str_to_path
from openlp.core.lib import SettingsTab, ScreenList
from openlp.core.ui.lib import ColorButton, PathEdit
@ -294,7 +293,7 @@ class GeneralTab(SettingsTab):
self.auto_open_check_box.setChecked(settings.value('auto open'))
self.show_splash_check_box.setChecked(settings.value('show splash'))
self.logo_background_color = settings.value('logo background color')
self.logo_file_path_edit.path = str_to_path(settings.value('logo file'))
self.logo_file_path_edit.path = settings.value('logo file')
self.logo_hide_on_startup_check_box.setChecked(settings.value('logo hide on startup'))
self.logo_color_button.color = self.logo_background_color
self.check_for_updates_check_box.setChecked(settings.value('update check'))
@ -328,7 +327,7 @@ class GeneralTab(SettingsTab):
settings.setValue('auto open', self.auto_open_check_box.isChecked())
settings.setValue('show splash', self.show_splash_check_box.isChecked())
settings.setValue('logo background color', self.logo_background_color)
settings.setValue('logo file', path_to_str(self.logo_file_path_edit.path))
settings.setValue('logo file', self.logo_file_path_edit.path)
settings.setValue('logo hide on startup', self.logo_hide_on_startup_check_box.isChecked())
settings.setValue('update check', self.check_for_updates_check_box.isChecked())
settings.setValue('save prompt', self.save_check_service_check_box.isChecked())

View File

@ -20,11 +20,9 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
""" Patch the QFileDialog so it accepts and returns Path objects"""
from pathlib import Path
from PyQt5 import QtWidgets
from openlp.core.common.path import path_to_str, str_to_path
from openlp.core.common.path import Path, path_to_str, str_to_path
from openlp.core.lib import replace_params
@ -36,7 +34,7 @@ class FileDialog(QtWidgets.QFileDialog):
:type parent: QtWidgets.QWidget or None
:type caption: str
:type directory: pathlib.Path
:type directory: openlp.core.common.path.Path
:type options: QtWidgets.QFileDialog.Options
:rtype: tuple[Path, str]
"""
@ -55,7 +53,7 @@ class FileDialog(QtWidgets.QFileDialog):
:type parent: QtWidgets.QWidget or None
:type caption: str
:type directory: pathlib.Path
:type directory: openlp.core.common.path.Path
:type filter: str
:type initialFilter: str
:type options: QtWidgets.QFileDialog.Options
@ -76,7 +74,7 @@ class FileDialog(QtWidgets.QFileDialog):
:type parent: QtWidgets.QWidget or None
:type caption: str
:type directory: pathlib.Path
:type directory: openlp.core.common.path.Path
:type filter: str
:type initialFilter: str
:type options: QtWidgets.QFileDialog.Options
@ -98,7 +96,7 @@ class FileDialog(QtWidgets.QFileDialog):
:type parent: QtWidgets.QWidget or None
:type caption: str
:type directory: pathlib.Path
:type directory: openlp.core.common.path.Path
:type filter: str
:type initialFilter: str
:type options: QtWidgets.QFileDialog.Options

View File

@ -20,12 +20,11 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from enum import Enum
from pathlib import Path
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import UiStrings, translate
from openlp.core.common.path import path_to_str, str_to_path
from openlp.core.common.path import Path, path_to_str, str_to_path
from openlp.core.lib import build_icon
from openlp.core.ui.lib.filedialog import FileDialog
@ -46,19 +45,11 @@ class PathEdit(QtWidgets.QWidget):
"""
Initialise the PathEdit widget
:param parent: The parent of the widget. This is just passed to the super method.
:type parent: QWidget or None
:param dialog_caption: Used to customise the caption in the QFileDialog.
:type dialog_caption: str
:param default_path: The default path. This is set as the path when the revert button is clicked
:type default_path: pathlib.Path
:param show_revert: Used to determine if the 'revert button' should be visible.
:type show_revert: bool
:return: None
:param QtWidget.QWidget | None: The parent of the widget. This is just passed to the super method.
:param str dialog_caption: Used to customise the caption in the QFileDialog.
:param openlp.core.common.path.Path default_path: The default path. This is set as the path when the revert
button is clicked
:param bool show_revert: Used to determine if the 'revert button' should be visible.
:rtype: None
"""
super().__init__(parent)
@ -72,10 +63,7 @@ class PathEdit(QtWidgets.QWidget):
def _setup(self, show_revert):
"""
Set up the widget
:param show_revert: Show or hide the revert button
:type show_revert: bool
:return: None
:param bool show_revert: Show or hide the revert button
:rtype: None
"""
widget_layout = QtWidgets.QHBoxLayout()
@ -102,7 +90,7 @@ class PathEdit(QtWidgets.QWidget):
A property getter method to return the selected path.
:return: The selected path
:rtype: pathlib.Path
:rtype: openlp.core.common.path.Path
"""
return self._path
@ -111,10 +99,7 @@ class PathEdit(QtWidgets.QWidget):
"""
A Property setter method to set the selected path
:param path: The path to set the widget to
:type path: pathlib.Path
:return: None
:param openlp.core.common.path.Path path: The path to set the widget to
:rtype: None
"""
self._path = path
@ -138,10 +123,7 @@ class PathEdit(QtWidgets.QWidget):
"""
A Property setter method to set the path type
:param path_type: The type of path to select
:type path_type: PathType
:return: None
:param PathType path_type: The type of path to select
:rtype: None
"""
self._path_type = path_type
@ -151,7 +133,6 @@ class PathEdit(QtWidgets.QWidget):
"""
Called to update the tooltips on the buttons. This is changing path types, and when the widget is initalised
:return: None
:rtype: None
"""
if self._path_type == PathType.Directories:
@ -167,7 +148,6 @@ class PathEdit(QtWidgets.QWidget):
Show the QFileDialog and process the input from the user
:return: None
:rtype: None
"""
caption = self.dialog_caption
@ -189,7 +169,6 @@ class PathEdit(QtWidgets.QWidget):
Set the new path to the value of the default_path instance variable.
:return: None
:rtype: None
"""
self.on_new_path(self.default_path)
@ -198,7 +177,6 @@ class PathEdit(QtWidgets.QWidget):
"""
A handler to handle when the line edit has finished being edited.
:return: None
:rtype: None
"""
path = str_to_path(self.line_edit.text())
@ -210,10 +188,7 @@ class PathEdit(QtWidgets.QWidget):
Emits the pathChanged Signal
:param path: The new path
:type path: pathlib.Path
:return: None
:param openlp.core.common.path.Path path: The new path
:rtype: None
"""
if self._path != path:

View File

@ -30,6 +30,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import Registry, RegistryProperties, Settings, UiStrings, translate, is_macosx
from openlp.core.lib import build_icon
from openlp.core.lib.ui import add_welcome_page
from openlp.core.ui.lib.filedialog import FileDialog
log = logging.getLogger(__name__)
@ -278,37 +279,38 @@ class OpenLPWizard(QtWidgets.QWizard, RegistryProperties):
def get_file_name(self, title, editbox, setting_name, filters=''):
"""
Opens a QFileDialog and saves the filename to the given editbox.
Opens a FileDialog and saves the filename to the given editbox.
:param title: The title of the dialog (unicode).
:param editbox: An editbox (QLineEdit).
:param setting_name: The place where to save the last opened directory.
:param filters: The file extension filters. It should contain the file description
:param str title: The title of the dialog.
:param QtWidgets.QLineEdit editbox: An QLineEdit.
:param str setting_name: The place where to save the last opened directory.
:param str filters: The file extension filters. It should contain the file description
as well as the file extension. For example::
'OpenLP 2 Databases (*.sqlite)'
:rtype: None
"""
if filters:
filters += ';;'
filters += '%s (*)' % UiStrings().AllFiles
filename, filter_used = QtWidgets.QFileDialog.getOpenFileName(
self, title, os.path.dirname(Settings().value(self.plugin.settings_section + '/' + setting_name)),
filters)
if filename:
editbox.setText(filename)
Settings().setValue(self.plugin.settings_section + '/' + setting_name, filename)
file_path, filter_used = FileDialog.getOpenFileName(
self, title, Settings().value(self.plugin.settings_section + '/' + setting_name), filters)
if file_path:
editbox.setText(str(file_path))
Settings().setValue(self.plugin.settings_section + '/' + setting_name, file_path.parent)
def get_folder(self, title, editbox, setting_name):
"""
Opens a QFileDialog and saves the selected folder to the given editbox.
Opens a FileDialog and saves the selected folder to the given editbox.
:param title: The title of the dialog (unicode).
:param editbox: An editbox (QLineEdit).
:param setting_name: The place where to save the last opened directory.
:param str title: The title of the dialog.
:param QtWidgets.QLineEdit editbox: An QLineEditbox.
:param str setting_name: The place where to save the last opened directory.
:rtype: None
"""
folder = QtWidgets.QFileDialog.getExistingDirectory(
folder_path = FileDialog.getExistingDirectory(
self, title, Settings().value(self.plugin.settings_section + '/' + setting_name),
QtWidgets.QFileDialog.ShowDirsOnly)
if folder:
editbox.setText(folder)
Settings().setValue(self.plugin.settings_section + '/' + setting_name, folder)
if folder_path:
editbox.setText(str(folder_path))
Settings().setValue(self.plugin.settings_section + '/' + setting_name, folder_path)

View File

@ -37,6 +37,7 @@ from PyQt5 import QtCore, QtWidgets, QtWebKit, QtWebKitWidgets, QtGui, QtMultime
from openlp.core.common import AppLocation, Registry, RegistryProperties, OpenLPMixin, Settings, translate,\
is_macosx, is_win
from openlp.core.common.path import path_to_str
from openlp.core.lib import ServiceItem, ImageSource, ScreenList, build_html, expand_tags, image_to_byte
from openlp.core.lib.theme import BackgroundType
from openlp.core.ui import HideMode, AlertLocation, DisplayControllerType
@ -259,7 +260,7 @@ class MainDisplay(OpenLPMixin, Display, RegistryProperties):
background_color.setNamedColor(Settings().value('core/logo background color'))
if not background_color.isValid():
background_color = QtCore.Qt.white
image_file = Settings().value('core/logo file')
image_file = path_to_str(Settings().value('core/logo file'))
splash_image = QtGui.QImage(image_file)
self.initial_fame = QtGui.QImage(
self.screen['size'].width(),

View File

@ -30,7 +30,6 @@ import time
from datetime import datetime
from distutils import dir_util
from distutils.errors import DistutilsFileError
from pathlib import Path
from tempfile import gettempdir
from PyQt5 import QtCore, QtGui, QtWidgets
@ -40,6 +39,7 @@ from openlp.core.api.http import server
from openlp.core.common import Registry, RegistryProperties, AppLocation, LanguageManager, Settings, UiStrings, \
check_directory_exists, translate, is_win, is_macosx, add_actions
from openlp.core.common.actions import ActionList, CategoryOrder
from openlp.core.common.path import Path, path_to_str, str_to_path
from openlp.core.common.versionchecker import get_application_version
from openlp.core.lib import Renderer, PluginManager, ImageManager, PluginStatus, ScreenList, build_icon
from openlp.core.lib.ui import create_action
@ -50,6 +50,7 @@ from openlp.core.ui.media import MediaController
from openlp.core.ui.printserviceform import PrintServiceForm
from openlp.core.ui.projector.manager import ProjectorManager
from openlp.core.ui.lib.dockwidget import OpenLPDockWidget
from openlp.core.ui.lib.filedialog import FileDialog
from openlp.core.ui.lib.mediadockmanager import MediaDockManager
@ -876,11 +877,12 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, RegistryProperties):
shutil.copyfile(import_file_name, temp_config)
settings = Settings()
import_settings = Settings(temp_config, Settings.IniFormat)
# Convert image files
log.info('hook upgrade_plugin_settings')
self.plugin_manager.hook_upgrade_plugin_settings(import_settings)
# Remove/rename old settings to prepare the import.
import_settings.remove_obsolete_settings()
# Upgrade settings to prepare the import.
if import_settings.can_upgrade():
import_settings.upgrade_settings()
# Lets do a basic sanity check. If it contains this string we can assume it was created by OpenLP and so we'll
# load what we can from it, and just silently ignore anything we don't recognise.
if import_settings.value('SettingsImport/type') != 'OpenLP_settings_export':
@ -936,89 +938,17 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, RegistryProperties):
"""
Export settings to a .conf file in INI format
"""
export_file_name, filter_used = QtWidgets.QFileDialog.getSaveFileName(
export_file_path, filter_used = FileDialog.getSaveFileName(
self,
translate('OpenLP.MainWindow', 'Export Settings File'),
'',
None,
translate('OpenLP.MainWindow', 'OpenLP Settings (*.conf)'))
if not export_file_name:
if not export_file_path:
return
# Make sure it's a .conf file.
if not export_file_name.endswith('conf'):
export_file_name += '.conf'
temp_file = os.path.join(gettempdir(), 'openlp', 'exportConf.tmp')
# Make sure it's a .conf file.
export_file_path = export_file_path.with_suffix('.conf')
self.save_settings()
setting_sections = []
# Add main sections.
setting_sections.extend([self.general_settings_section])
setting_sections.extend([self.advanced_settings_section])
setting_sections.extend([self.ui_settings_section])
setting_sections.extend([self.shortcuts_settings_section])
setting_sections.extend([self.service_manager_settings_section])
setting_sections.extend([self.themes_settings_section])
setting_sections.extend([self.display_tags_section])
# Add plugin sections.
for plugin in self.plugin_manager.plugins:
setting_sections.extend([plugin.name])
# Delete old files if found.
if os.path.exists(temp_file):
os.remove(temp_file)
if os.path.exists(export_file_name):
os.remove(export_file_name)
settings = Settings()
settings.remove(self.header_section)
# Get the settings.
keys = settings.allKeys()
export_settings = Settings(temp_file, Settings.IniFormat)
# Add a header section.
# This is to insure it's our conf file for import.
now = datetime.now()
application_version = get_application_version()
# Write INI format using Qsettings.
# Write our header.
export_settings.beginGroup(self.header_section)
export_settings.setValue('Make_Changes', 'At_Own_RISK')
export_settings.setValue('type', 'OpenLP_settings_export')
export_settings.setValue('file_date_created', now.strftime("%Y-%m-%d %H:%M"))
export_settings.setValue('version', application_version['full'])
export_settings.endGroup()
# Write all the sections and keys.
for section_key in keys:
# FIXME: We are conflicting with the standard "General" section.
if 'eneral' in section_key:
section_key = section_key.lower()
try:
key_value = settings.value(section_key)
except KeyError:
QtWidgets.QMessageBox.critical(self, translate('OpenLP.MainWindow', 'Export setting error'),
translate('OpenLP.MainWindow', 'The key "{key}" does not have a default '
'value so it will be skipped in this '
'export.').format(key=section_key),
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Ok))
key_value = None
if key_value is not None:
export_settings.setValue(section_key, key_value)
export_settings.sync()
# Temp CONF file has been written. Blanks in keys are now '%20'.
# Read the temp file and output the user's CONF file with blanks to
# make it more readable.
temp_conf = open(temp_file, 'r')
try:
export_conf = open(export_file_name, 'w')
for file_record in temp_conf:
# Get rid of any invalid entries.
if file_record.find('@Invalid()') == -1:
file_record = file_record.replace('%20', ' ')
export_conf.write(file_record)
temp_conf.close()
export_conf.close()
os.remove(temp_file)
except OSError as ose:
QtWidgets.QMessageBox.critical(self, translate('OpenLP.MainWindow', 'Export setting error'),
translate('OpenLP.MainWindow',
'An error occurred while exporting the '
'settings: {err}').format(err=ose.strerror),
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Ok))
Settings().export(export_file_path)
def on_mode_default_item_clicked(self):
"""
@ -1277,7 +1207,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, RegistryProperties):
settings.remove('custom slide')
settings.remove('service')
settings.beginGroup(self.general_settings_section)
self.recent_files = settings.value('recent files')
self.recent_files = [path_to_str(file_path) for file_path in settings.value('recent files')]
settings.endGroup()
settings.beginGroup(self.ui_settings_section)
self.move(settings.value('main window position'))
@ -1301,7 +1231,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, RegistryProperties):
log.debug('Saving QSettings')
settings = Settings()
settings.beginGroup(self.general_settings_section)
settings.setValue('recent files', self.recent_files)
settings.setValue('recent files', [str_to_path(file) for file in self.recent_files])
settings.endGroup()
settings.beginGroup(self.ui_settings_section)
settings.setValue('main window position', self.pos())
@ -1443,7 +1373,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, RegistryProperties):
log.info('No data copy requested')
# Change the location of data directory in config file.
settings = QtCore.QSettings()
settings.setValue('advanced/data path', self.new_data_path)
settings.setValue('advanced/data path', Path(self.new_data_path))
# Check if the new data path is our default.
if self.new_data_path == str(AppLocation.get_directory(AppLocation.DataDir)):
settings.remove('advanced/data path')

View File

@ -28,7 +28,6 @@ import os
import shutil
import zipfile
from datetime import datetime, timedelta
from pathlib import Path
from tempfile import mkstemp
from PyQt5 import QtCore, QtGui, QtWidgets
@ -36,11 +35,13 @@ from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import Registry, RegistryProperties, AppLocation, Settings, ThemeLevel, OpenLPMixin, \
RegistryMixin, check_directory_exists, UiStrings, translate, split_filename, delete_file
from openlp.core.common.actions import ActionList, CategoryOrder
from openlp.core.common.languagemanager import format_time
from openlp.core.common.path import Path, path_to_str, str_to_path
from openlp.core.lib import ServiceItem, ItemCapabilities, PluginStatus, build_icon
from openlp.core.lib.ui import critical_error_message_box, create_widget_action, find_and_set_in_combo_box
from openlp.core.ui import ServiceNoteForm, ServiceItemEditForm, StartTimeForm
from openlp.core.ui.lib import OpenLPToolbar
from openlp.core.common.languagemanager import format_time
from openlp.core.ui.lib.filedialog import FileDialog
class ServiceManagerList(QtWidgets.QTreeWidget):
@ -373,7 +374,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
"""
self._file_name = str(file_name)
self.main_window.set_service_modified(self.is_modified(), self.short_file_name())
Settings().setValue('servicemanager/last file', file_name)
Settings().setValue('servicemanager/last file', Path(file_name))
self._save_lite = self._file_name.endswith('.oszl')
def file_name(self):
@ -435,18 +436,17 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
elif result == QtWidgets.QMessageBox.Save:
self.decide_save_method()
if not load_file:
file_name, filter_used = QtWidgets.QFileDialog.getOpenFileName(
file_path, filter_used = FileDialog.getOpenFileName(
self.main_window,
translate('OpenLP.ServiceManager', 'Open File'),
Settings().value(self.main_window.service_manager_settings_section + '/last directory'),
translate('OpenLP.ServiceManager', 'OpenLP Service Files (*.osz *.oszl)'))
if not file_name:
if not file_path:
return False
else:
file_name = load_file
Settings().setValue(self.main_window.service_manager_settings_section + '/last directory',
split_filename(file_name)[0])
self.load_file(file_name)
file_path = str_to_path(load_file)
Settings().setValue(self.main_window.service_manager_settings_section + '/last directory', file_path.parent)
self.load_file(str(file_path))
def save_modified_service(self):
"""
@ -477,7 +477,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
self.set_file_name('')
self.service_id += 1
self.set_modified(False)
Settings().setValue('servicemanager/last file', '')
Settings().setValue('servicemanager/last file', None)
self.plugin_manager.new_service_created()
def create_basic_service(self):
@ -513,7 +513,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
base_name = os.path.splitext(file_name)[0]
service_file_name = '{name}.osj'.format(name=base_name)
self.log_debug('ServiceManager.save_file - {name}'.format(name=path_file_name))
Settings().setValue(self.main_window.service_manager_settings_section + '/last directory', path)
Settings().setValue(self.main_window.service_manager_settings_section + '/last directory', Path(path))
service = self.create_basic_service()
write_list = []
missing_list = []
@ -634,7 +634,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
base_name = os.path.splitext(file_name)[0]
service_file_name = '{name}.osj'.format(name=base_name)
self.log_debug('ServiceManager.save_file - {name}'.format(name=path_file_name))
Settings().setValue(self.main_window.service_manager_settings_section + '/last directory', path)
Settings().setValue(self.main_window.service_manager_settings_section + '/last directory', Path(path))
service = self.create_basic_service()
self.application.set_busy_cursor()
# Number of items + 1 to zip it
@ -695,7 +695,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
default_file_name = format_time(default_pattern, local_time)
else:
default_file_name = ''
directory = Settings().value(self.main_window.service_manager_settings_section + '/last directory')
directory = path_to_str(Settings().value(self.main_window.service_manager_settings_section + '/last directory'))
path = os.path.join(directory, default_file_name)
# SaveAs from osz to oszl is not valid as the files will be deleted on exit which is not sensible or usable in
# the long term.
@ -778,7 +778,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
delete_file(Path(p_file))
self.main_window.add_recent_file(file_name)
self.set_modified(False)
Settings().setValue('servicemanager/last file', file_name)
Settings().setValue('servicemanager/last file', Path(file_name))
else:
critical_error_message_box(message=translate('OpenLP.ServiceManager', 'File is not a valid service.'))
self.log_error('File contains no service data')
@ -843,7 +843,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa
Load the last service item from the service manager when the service was last closed. Can be blank if there was
no service present.
"""
file_name = Settings().value('servicemanager/last file')
file_name = str_to_path(Settings().value('servicemanager/last file'))
if file_name:
self.load_file(file_name)

View File

@ -24,12 +24,11 @@ The Theme wizard
"""
import logging
import os
from pathlib import Path
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import Registry, RegistryProperties, UiStrings, translate, get_images_filter, is_not_image_file
from openlp.core.common.path import path_to_str, str_to_path
from openlp.core.common.path import Path, path_to_str, str_to_path
from openlp.core.lib.theme import BackgroundType, BackgroundGradientType
from openlp.core.lib.ui import critical_error_message_box
from openlp.core.ui import ThemeLayoutForm

View File

@ -25,14 +25,13 @@ The Theme Manager manages adding, deleteing and modifying of themes.
import os
import zipfile
import shutil
from pathlib import Path
from xml.etree.ElementTree import ElementTree, XML
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import Registry, RegistryProperties, AppLocation, Settings, OpenLPMixin, RegistryMixin, \
UiStrings, check_directory_exists, translate, is_win, get_filesystem_encoding, delete_file
from openlp.core.common.path import path_to_str, str_to_path
from openlp.core.common.path import Path, path_to_str, str_to_path
from openlp.core.lib import ImageSource, ValidationError, get_text_file_string, build_icon, \
check_item_selected, create_thumb, validate_thumb
from openlp.core.lib.theme import Theme, BackgroundType
@ -379,16 +378,16 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
critical_error_message_box(message=translate('OpenLP.ThemeManager', 'You have not selected a theme.'))
return
theme = item.data(QtCore.Qt.UserRole)
path, filter_used = \
QtWidgets.QFileDialog.getSaveFileName(self.main_window,
translate('OpenLP.ThemeManager', 'Save Theme - ({name})').
format(name=theme),
Settings().value(self.settings_section + '/last directory export'),
translate('OpenLP.ThemeManager', 'OpenLP Themes (*.otz)'))
export_path, filter_used = \
FileDialog.getSaveFileName(self.main_window,
translate('OpenLP.ThemeManager', 'Save Theme - ({name})').
format(name=theme),
Settings().value(self.settings_section + '/last directory export'),
translate('OpenLP.ThemeManager', 'OpenLP Themes (*.otz)'))
self.application.set_busy_cursor()
if path:
Settings().setValue(self.settings_section + '/last directory export', path)
if self._export_theme(path, theme):
if export_path:
Settings().setValue(self.settings_section + '/last directory export', export_path.parent)
if self._export_theme(str(export_path), theme):
QtWidgets.QMessageBox.information(self,
translate('OpenLP.ThemeManager', 'Theme Exported'),
translate('OpenLP.ThemeManager',
@ -429,16 +428,15 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
file_paths, selected_filter = FileDialog.getOpenFileNames(
self,
translate('OpenLP.ThemeManager', 'Select Theme Import File'),
str_to_path(Settings().value(self.settings_section + '/last directory import')),
Settings().value(self.settings_section + '/last directory import'),
translate('OpenLP.ThemeManager', 'OpenLP Themes (*.otz)'))
self.log_info('New Themes {file_paths}'.format(file_paths=file_paths))
if not file_paths:
return
self.application.set_busy_cursor()
for file_path in file_paths:
file_name = path_to_str(file_path)
Settings().setValue(self.settings_section + '/last directory import', str(file_name))
self.unzip_theme(file_name, self.path)
self.unzip_theme(path_to_str(file_path), self.path)
Settings().setValue(self.settings_section + '/last directory import', file_path)
self.load_themes()
self.application.set_normal_cursor()

View File

@ -22,11 +22,10 @@
"""
The Create/Edit theme wizard
"""
from pathlib import Path
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import UiStrings, translate, is_macosx
from openlp.core.common.path import Path
from openlp.core.lib import build_icon
from openlp.core.lib.theme import HorizontalType, BackgroundType, BackgroundGradientType
from openlp.core.lib.ui import add_welcome_page, create_valign_selection_widgets

View File

@ -59,7 +59,7 @@ __default_settings__ = {
'bibles/range separator': '',
'bibles/list separator': '',
'bibles/end separator': '',
'bibles/last directory import': '',
'bibles/last directory import': None,
'bibles/hide combined quick error': False,
'bibles/is search while typing enabled': True
}

View File

@ -51,9 +51,9 @@ All CSV files are expected to use a comma (',') as the delimiter and double quot
"""
import csv
from collections import namedtuple
from pathlib import Path
from openlp.core.common import get_file_encoding, translate
from openlp.core.common.path import Path
from openlp.core.lib.exceptions import ValidationError
from openlp.plugins.bibles.lib.bibleimport import BibleImport

View File

@ -21,10 +21,9 @@
###############################################################################
import logging
import os
from pathlib import Path
from openlp.core.common import AppLocation, OpenLPMixin, RegistryProperties, Settings, translate, delete_file, UiStrings
from openlp.core.common.path import Path
from openlp.plugins.bibles.lib import LanguageSelection, parse_reference
from openlp.plugins.bibles.lib.db import BibleDB, BibleMeta
from .importers.csvbible import CSVBible
@ -306,13 +305,10 @@ class BibleManager(OpenLPMixin, RegistryProperties):
"""
Does a verse search for the given bible and text.
:param bible: The bible to search
:type bible: str
:param text: The text to search for
:type text: str
:param str bible: The bible to search
:param str text: The text to search for
:return: The search results if valid, or None if the search is invalid.
:rtype: None, list
:rtype: None | list
"""
log.debug('BibleManager.verse_search("{bible}", "{text}")'.format(bible=bible, text=text))
if not text:

View File

@ -465,8 +465,7 @@ class BibleMediaItem(MediaManagerItem):
"""
Show the selected tab and set focus to it
:param index: The tab selected
:type index: int
:param int index: The tab selected
:return: None
"""
if index == SearchTabs.Search or index == SearchTabs.Select:
@ -483,7 +482,7 @@ class BibleMediaItem(MediaManagerItem):
Update list_widget with the contents of the selected list
:param index: The index of the tab that has been changed to. (int)
:return: None
:rtype: None
"""
if index == ResultsTab.Saved:
self.add_built_results_to_list_widget(self.saved_results)

View File

@ -71,14 +71,6 @@ class ImagePlugin(Plugin):
'provided by the theme.')
return about_text
def upgrade_settings(self, settings):
"""
Upgrade the settings of this plugin.
:param settings: The Settings object containing the old settings.
"""
pass
def set_plugin_text_strings(self):
"""
Called to define all translatable texts of the plugin.

View File

@ -22,12 +22,12 @@
import logging
import os
from pathlib import Path
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import Registry, AppLocation, Settings, UiStrings, check_directory_exists, translate, \
delete_file, get_images_filter
from openlp.core.common.path import Path
from openlp.core.lib import ItemCapabilities, MediaManagerItem, ServiceItemContext, StringContent, build_icon, \
check_item_selected, create_thumb, validate_thumb
from openlp.core.lib.ui import create_widget_action, critical_error_message_box
@ -390,7 +390,7 @@ class ImageMediaItem(MediaManagerItem):
self.application.set_normal_cursor()
self.load_list(files, target_group)
last_dir = os.path.split(files[0])[0]
Settings().setValue(self.settings_section + '/last directory', last_dir)
Settings().setValue(self.settings_section + '/last directory', Path(last_dir))
def load_list(self, images, target_group=None, initial_load=False):
"""

View File

@ -22,12 +22,12 @@
import logging
import os
from pathlib import Path
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import Registry, RegistryProperties, AppLocation, Settings, check_directory_exists, UiStrings,\
translate
from openlp.core.common.path import Path, path_to_str, str_to_path
from openlp.core.lib import ItemCapabilities, MediaManagerItem, MediaType, ServiceItem, ServiceItemContext, \
build_icon, check_item_selected
from openlp.core.lib.ui import create_widget_action, critical_error_message_box, create_horizontal_adjusting_combo_box
@ -303,7 +303,7 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
self.list_view.clear()
self.service_path = os.path.join(str(AppLocation.get_section_data_path(self.settings_section)), 'thumbnails')
check_directory_exists(Path(self.service_path))
self.load_list(Settings().value(self.settings_section + '/media files'))
self.load_list([path_to_str(file) for file in Settings().value(self.settings_section + '/media files')])
self.rebuild_players()
def rebuild_players(self):
@ -401,14 +401,14 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
:param media_type: Type to get, defaults to audio.
:return: The media list
"""
media = Settings().value(self.settings_section + '/media files')
media.sort(key=lambda filename: get_locale_key(os.path.split(str(filename))[1]))
media_file_paths = Settings().value(self.settings_section + '/media files')
media_file_paths.sort(key=lambda file_path: get_locale_key(file_path.name))
if media_type == MediaType.Audio:
extension = self.media_controller.audio_extensions_list
else:
extension = self.media_controller.video_extensions_list
extension = [x[1:] for x in extension]
media = [x for x in media if os.path.splitext(x)[1] in extension]
media = [x for x in media_file_paths if x.suffix in extension]
return media
def search(self, string, show_error):
@ -419,13 +419,12 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
:param show_error: Should the error be shown (True)
:return: The search result.
"""
files = Settings().value(self.settings_section + '/media files')
results = []
string = string.lower()
for file in files:
filename = os.path.split(str(file))[1]
if filename.lower().find(string) > -1:
results.append([file, filename])
for file_path in Settings().value(self.settings_section + '/media files'):
file_name = file_path.name
if file_name.lower().find(string) > -1:
results.append([str(file_path), file_name])
return results
def on_load_optical(self):
@ -446,13 +445,13 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
:param optical: The clip to add.
"""
full_list = self.get_file_list()
file_paths = self.get_file_list()
# If the clip already is in the media list it isn't added and an error message is displayed.
if optical in full_list:
if optical in file_paths:
critical_error_message_box(translate('MediaPlugin.MediaItem', 'Mediaclip already saved'),
translate('MediaPlugin.MediaItem', 'This mediaclip has already been saved'))
return
# Append the optical string to the media list
full_list.append(optical)
file_paths.append(optical)
self.load_list([optical])
Settings().setValue(self.settings_section + '/media files', self.get_file_list())
Settings().setValue(self.settings_section + '/media files', file_paths)

View File

@ -26,12 +26,11 @@ The Media plugin
import logging
import os
import re
from pathlib import Path
from PyQt5 import QtCore
from openlp.core.api.http import register_endpoint
from openlp.core.common import AppLocation, translate, check_binary_exists
from openlp.core.common.path import Path
from openlp.core.lib import Plugin, StringContent, build_icon
from openlp.plugins.media.endpoint import api_media_endpoint, media_endpoint
from openlp.plugins.media.lib import MediaMediaItem, MediaTab

View File

@ -34,9 +34,9 @@
import logging
import os
import time
from pathlib import Path
from openlp.core.common import is_win, Registry, get_uno_command, get_uno_instance, delete_file
from openlp.core.common import is_win, Registry, delete_file
from openlp.core.common.path import Path
if is_win():
from win32com.client import Dispatch

View File

@ -26,10 +26,11 @@ import os
from PyQt5 import QtCore, QtGui, QtWidgets
from openlp.core.common import Registry, Settings, UiStrings, translate
from openlp.core.common.languagemanager import get_locale_key
from openlp.core.common.path import path_to_str
from openlp.core.lib import MediaManagerItem, ItemCapabilities, ServiceItemContext,\
build_icon, check_item_selected, create_thumb, validate_thumb
from openlp.core.lib.ui import critical_error_message_box, create_horizontal_adjusting_combo_box
from openlp.core.common.languagemanager import get_locale_key
from openlp.plugins.presentations.lib import MessageListener
from openlp.plugins.presentations.lib.pdfcontroller import PDF_CONTROLLER_FILETYPES
@ -126,8 +127,8 @@ class PresentationMediaItem(MediaManagerItem):
Populate the media manager tab
"""
self.list_view.setIconSize(QtCore.QSize(88, 50))
files = Settings().value(self.settings_section + '/presentations files')
self.load_list(files, initial_load=True)
file_paths = Settings().value(self.settings_section + '/presentations files')
self.load_list([path_to_str(file) for file in file_paths], initial_load=True)
self.populate_display_types()
def populate_display_types(self):
@ -157,7 +158,7 @@ class PresentationMediaItem(MediaManagerItem):
existing files, and when the user adds new files via the media manager.
"""
current_list = self.get_file_list()
titles = [os.path.split(file)[1] for file in current_list]
titles = [file_path.name for file_path in current_list]
self.application.set_busy_cursor()
if not initial_load:
self.main_window.display_progress_bar(len(files))
@ -410,11 +411,11 @@ class PresentationMediaItem(MediaManagerItem):
:param show_error: not used
:return:
"""
files = Settings().value(self.settings_section + '/presentations files')
file_paths = Settings().value(self.settings_section + '/presentations files')
results = []
string = string.lower()
for file in files:
filename = os.path.split(str(file))[1]
if filename.lower().find(string) > -1:
results.append([file, filename])
for file_path in file_paths:
file_name = file_path.name
if file_name.lower().find(string) > -1:
results.append([path_to_str(file_path), file_name])
return results

View File

@ -23,12 +23,12 @@
import os
import logging
import re
from pathlib import Path
from shutil import which
from subprocess import check_output, CalledProcessError
from openlp.core.common import AppLocation, check_binary_exists
from openlp.core.common import Settings, is_win
from openlp.core.common.path import Path, path_to_str
from openlp.core.lib import ScreenList
from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument
@ -113,7 +113,7 @@ class PdfController(PresentationController):
self.also_supports = []
# Use the user defined program if given
if Settings().value('presentations/enable_pdf_program'):
pdf_program = Settings().value('presentations/pdf_program')
pdf_program = path_to_str(Settings().value('presentations/pdf_program'))
program_type = self.process_check_binary(pdf_program)
if program_type == 'gs':
self.gsbin = pdf_program

View File

@ -23,11 +23,11 @@
import logging
import os
import shutil
from pathlib import Path
from PyQt5 import QtCore
from openlp.core.common import Registry, AppLocation, Settings, check_directory_exists, md5_hash
from openlp.core.common.path import Path
from openlp.core.lib import create_thumb, validate_thumb
log = logging.getLogger(__name__)

View File

@ -155,9 +155,7 @@ class PresentationTab(SettingsTab):
enable_pdf_program = Settings().value(self.settings_section + '/enable_pdf_program')
self.pdf_program_check_box.setChecked(enable_pdf_program)
self.program_path_edit.setEnabled(enable_pdf_program)
pdf_program = Settings().value(self.settings_section + '/pdf_program')
if pdf_program:
self.program_path_edit.path = str_to_path(pdf_program)
self.program_path_edit.path = Settings().value(self.settings_section + '/pdf_program')
def save(self):
"""
@ -193,13 +191,13 @@ class PresentationTab(SettingsTab):
Settings().setValue(setting_key, self.ppt_window_check_box.checkState())
changed = True
# Save pdf-settings
pdf_program = path_to_str(self.program_path_edit.path)
pdf_program_path = self.program_path_edit.path
enable_pdf_program = self.pdf_program_check_box.checkState()
# If the given program is blank disable using the program
if pdf_program == '':
if not pdf_program_path:
enable_pdf_program = 0
if pdf_program != Settings().value(self.settings_section + '/pdf_program'):
Settings().setValue(self.settings_section + '/pdf_program', pdf_program)
if pdf_program_path != Settings().value(self.settings_section + '/pdf_program'):
Settings().setValue(self.settings_section + '/pdf_program', pdf_program_path)
changed = True
if enable_pdf_program != Settings().value(self.settings_section + '/enable_pdf_program'):
Settings().setValue(self.settings_section + '/enable_pdf_program', enable_pdf_program)

View File

@ -39,7 +39,7 @@ log = logging.getLogger(__name__)
__default_settings__ = {'presentations/override app': QtCore.Qt.Unchecked,
'presentations/enable_pdf_program': QtCore.Qt.Unchecked,
'presentations/pdf_program': '',
'presentations/pdf_program': None,
'presentations/Impress': QtCore.Qt.Checked,
'presentations/Powerpoint': QtCore.Qt.Checked,
'presentations/Powerpoint Viewer': QtCore.Qt.Checked,

View File

@ -28,12 +28,11 @@ import logging
import re
import os
import shutil
from pathlib import Path
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_to_str
from openlp.core.common.path import Path, path_to_str
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

View File

@ -239,13 +239,11 @@ class SongImportForm(OpenLPWizard, RegistryProperties):
filters += ';;'
filters += '{text} (*)'.format(text=UiStrings().AllFiles)
file_paths, selected_filter = FileDialog.getOpenFileNames(
self, title,
str_to_path(Settings().value(self.plugin.settings_section + '/last directory import')), filters)
self, title, Settings().value(self.plugin.settings_section + '/last directory import'), filters)
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',
os.path.split(str(file_names[0]))[0])
Settings().setValue(self.plugin.settings_section + '/last directory import', file_paths[0].parent)
def get_list_of_files(self, list_box):
"""
@ -363,14 +361,15 @@ class SongImportForm(OpenLPWizard, RegistryProperties):
def on_error_save_to_button_clicked(self):
"""
Save the error report to a file.
:rtype: None
"""
filename, filter_used = QtWidgets.QFileDialog.getSaveFileName(
file_path, filter_used = FileDialog.getSaveFileName(
self, Settings().value(self.plugin.settings_section + '/last directory import'))
if not filename:
if not file_path:
return
report_file = codecs.open(filename, 'w', 'utf-8')
report_file.write(self.error_report_text_edit.toPlainText())
report_file.close()
with file_path.open('w', encoding='utf-8') as report_file:
report_file.write(self.error_report_text_edit.toPlainText())
def add_file_select_item(self):
"""

View File

@ -27,11 +27,11 @@ import os
import re
import base64
import math
from pathlib import Path
from openlp.core.common import Settings, is_win, is_macosx, get_file_encoding
from openlp.core.common.path import Path
from openlp.plugins.songs.lib import VerseType
from openlp.plugins.songs.lib.importers.songimport import SongImport
from openlp.core.common import Settings, is_win, is_macosx, get_file_encoding
log = logging.getLogger(__name__)

View File

@ -24,11 +24,11 @@ import logging
import re
import shutil
import os
from pathlib import Path
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.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

View File

@ -23,12 +23,12 @@
import logging
import os
import shutil
from pathlib import Path
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.lib import MediaManagerItem, ItemCapabilities, PluginStatus, ServiceItemContext, \
check_item_selected, create_separated_list
from openlp.core.lib.ui import create_widget_action

View File

@ -25,11 +25,11 @@ format.
"""
import logging
import os
from pathlib import Path
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__)

View File

@ -66,8 +66,8 @@ __default_settings__ = {
'songs/display songbook': False,
'songs/display written by': True,
'songs/display copyright symbol': False,
'songs/last directory import': '',
'songs/last directory export': '',
'songs/last directory import': None,
'songs/last directory export': None,
'songs/songselect username': '',
'songs/songselect password': '',
'songs/songselect searches': '',

View File

@ -22,13 +22,12 @@
import logging
import os
from pathlib import Path
from PyQt5 import QtCore, QtWidgets
from sqlalchemy.sql import and_
from openlp.core.common import RegistryProperties, Settings, check_directory_exists, translate
from openlp.core.common.path import path_to_str, str_to_path
from openlp.core.common.path import Path, path_to_str, str_to_path
from openlp.core.lib.ui import critical_error_message_box
from openlp.plugins.songusage.lib.db import SongUsageItem
from .songusagedetaildialog import Ui_SongUsageDetailDialog
@ -57,14 +56,16 @@ class SongUsageDetailForm(QtWidgets.QDialog, Ui_SongUsageDetailDialog, RegistryP
"""
self.from_date_calendar.setSelectedDate(Settings().value(self.plugin.settings_section + '/from date'))
self.to_date_calendar.setSelectedDate(Settings().value(self.plugin.settings_section + '/to date'))
self.report_path_edit.path = str_to_path(
Settings().value(self.plugin.settings_section + '/last directory export'))
self.report_path_edit.path = Settings().value(self.plugin.settings_section + '/last directory export')
def on_report_path_edit_path_changed(self, file_path):
"""
Triggered when the Directory selection button is clicked
Called when the path in the `PathEdit` has changed
:param openlp.core.common.path.Path file_path: The new path.
:rtype: None
"""
Settings().setValue(self.plugin.settings_section + '/last directory export', path_to_str(file_path))
Settings().setValue(self.plugin.settings_section + '/last directory export', file_path)
def accept(self):
"""

View File

@ -50,7 +50,7 @@ __default_settings__ = {
'songusage/active': False,
'songusage/to date': QtCore.QDate(YEAR, 8, 31),
'songusage/from date': QtCore.QDate(YEAR - 1, 9, 1),
'songusage/last directory export': ''
'songusage/last directory export': None
}

View File

@ -22,13 +22,12 @@
"""
Functional tests to test the AppLocation class and related methods.
"""
import copy
import os
from pathlib import Path
from unittest import TestCase
from unittest.mock import MagicMock, patch
from openlp.core.common import AppLocation, get_frozen_path
from openlp.core.common.path import Path
FILE_LIST = ['file1', 'file2', 'file3.txt', 'file4.txt', 'file5.mp3', 'file6.mp3']
@ -43,12 +42,14 @@ class TestAppLocation(TestCase):
"""
with patch('openlp.core.common.applocation.Settings') as mocked_class, \
patch('openlp.core.common.AppLocation.get_directory') as mocked_get_directory, \
patch('openlp.core.common.applocation.check_directory_exists') as mocked_check_directory_exists:
patch('openlp.core.common.applocation.check_directory_exists') as mocked_check_directory_exists, \
patch('openlp.core.common.applocation.os') as mocked_os:
# GIVEN: A mocked out Settings class and a mocked out AppLocation.get_directory()
mocked_settings = mocked_class.return_value
mocked_settings.contains.return_value = False
mocked_get_directory.return_value = Path('test', 'dir')
mocked_get_directory.return_value = os.path.join('test', 'dir')
mocked_check_directory_exists.return_value = True
mocked_os.path.normpath.return_value = os.path.join('test', 'dir')
# WHEN: we call AppLocation.get_data_path()
data_path = AppLocation.get_data_path()
@ -56,8 +57,8 @@ class TestAppLocation(TestCase):
# THEN: check that all the correct methods were called, and the result is correct
mocked_settings.contains.assert_called_with('advanced/data path')
mocked_get_directory.assert_called_with(AppLocation.DataDir)
mocked_check_directory_exists.assert_called_with(Path('test', 'dir'))
self.assertEqual(Path('test', 'dir'), data_path, 'Result should be "test/dir"')
mocked_check_directory_exists.assert_called_with(os.path.join('test', 'dir'))
self.assertEqual(os.path.join('test', 'dir'), data_path, 'Result should be "test/dir"')
def test_get_data_path_with_custom_location(self):
"""

View File

@ -22,13 +22,12 @@
"""
Functional tests to test the AppLocation class and related methods.
"""
from pathlib import Path
from unittest import TestCase
from unittest.mock import MagicMock, call, patch
from openlp.core import common
from openlp.core.common import check_directory_exists, clean_button_text, de_hump, extension_loader, is_macosx, \
is_linux, is_win, path_to_module, trace_error_handler, translate
from openlp.core.common.path import Path
class TestCommonFunctions(TestCase):

View File

@ -24,12 +24,12 @@ Functional tests to test the AppLocation class and related methods.
"""
import os
from io import BytesIO
from pathlib import Path
from unittest import TestCase
from unittest.mock import MagicMock, PropertyMock, call, patch
from openlp.core.common import add_actions, clean_filename, delete_file, get_file_encoding, get_filesystem_encoding, \
get_uno_command, get_uno_instance, split_filename
from openlp.core.common.path import Path
from tests.helpers.testmixin import TestMixin

View File

@ -0,0 +1,122 @@
# -*- 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 #
###############################################################################
"""
Package to test the openlp.core.common.json package.
"""
import json
from unittest import TestCase
from unittest.mock import patch
from openlp.core.common.path import Path
from openlp.core.common.json import OpenLPJsonDecoder, OpenLPJsonEncoder
class TestOpenLPJsonDecoder(TestCase):
"""
Test the OpenLPJsonDecoder class
"""
def test_object_hook_path_object(self):
"""
Test the object_hook method when called with a decoded Path JSON object
"""
# GIVEN: An instance of OpenLPJsonDecoder
instance = OpenLPJsonDecoder()
# WHEN: Calling the object_hook method with a decoded JSON object which contains a Path
result = instance.object_hook({'__Path__': ['test', 'path']})
# THEN: A Path object should be returned
self.assertEqual(result, Path('test', 'path'))
def test_object_hook_non_path_object(self):
"""
Test the object_hook method when called with a decoded JSON object
"""
# GIVEN: An instance of OpenLPJsonDecoder
instance = OpenLPJsonDecoder()
# WHEN: Calling the object_hook method with a decoded JSON object which contains a Path
with patch('openlp.core.common.json.Path') as mocked_path:
result = instance.object_hook({'key': 'value'})
# THEN: The object should be returned unchanged and a Path object should not have been initiated
self.assertEqual(result, {'key': 'value'})
self.assertFalse(mocked_path.called)
def test_json_decode(self):
"""
Test the OpenLPJsonDecoder when decoding a JSON string
"""
# GIVEN: A JSON encoded string
json_string = '[{"__Path__": ["test", "path1"]}, {"__Path__": ["test", "path2"]}]'
# WHEN: Decoding the string using the OpenLPJsonDecoder class
obj = json.loads(json_string, cls=OpenLPJsonDecoder)
# THEN: The object returned should be a python version of the JSON string
self.assertEqual(obj, [Path('test', 'path1'), Path('test', 'path2')])
class TestOpenLPJsonEncoder(TestCase):
"""
Test the OpenLPJsonEncoder class
"""
def test_default_path_object(self):
"""
Test the default method when called with a Path object
"""
# GIVEN: An instance of OpenLPJsonEncoder
instance = OpenLPJsonEncoder()
# WHEN: Calling the default method with a Path object
result = instance.default(Path('test', 'path'))
# THEN: A dictionary object that can be JSON encoded should be returned
self.assertEqual(result, {'__Path__': ('test', 'path')})
def test_default_non_path_object(self):
"""
Test the default method when called with a object other than a Path object
"""
with patch('openlp.core.common.json.JSONEncoder.default') as mocked_super_default:
# GIVEN: An instance of OpenLPJsonEncoder
instance = OpenLPJsonEncoder()
# WHEN: Calling the default method with a object other than a Path object
instance.default('invalid object')
# THEN: default method of the super class should have been called
mocked_super_default.assert_called_once_with('invalid object')
def test_json_encode(self):
"""
Test the OpenLPJsonDEncoder when encoding an object conatining Path objects
"""
# GIVEN: A list of Path objects
obj = [Path('test', 'path1'), Path('test', 'path2')]
# WHEN: Encoding the object using the OpenLPJsonEncoder class
json_string = json.dumps(obj, cls=OpenLPJsonEncoder)
# THEN: The JSON string return should be a representation of the object encoded
self.assertEqual(json_string, '[{"__Path__": ["test", "path1"]}, {"__Path__": ["test", "path2"]}]')

View File

@ -23,10 +23,9 @@
Package to test the openlp.core.common.path package.
"""
import os
from pathlib import Path
from unittest import TestCase
from openlp.core.common.path import path_to_str, str_to_path
from openlp.core.common.path import Path, path_to_str, str_to_path
class TestPath(TestCase):
@ -86,3 +85,54 @@ class TestPath(TestCase):
# THEN: `path_to_str` should return None
self.assertEqual(result, None)
def test_path_encode_json(self):
"""
Test that `Path.encode_json` returns a Path object from a dictionary representation of a Path object decoded
from JSON
"""
# GIVEN: A Path object from openlp.core.common.path
# WHEN: Calling encode_json, with a dictionary representation
path = Path.encode_json({'__Path__': ['path', 'to', 'fi.le']}, extra=1, args=2)
# THEN: A Path object should have been returned
self.assertEqual(path, Path('path', 'to', 'fi.le'))
def test_path_encode_json_base_path(self):
"""
Test that `Path.encode_json` returns a Path object from a dictionary representation of a Path object decoded
from JSON when the base_path arg is supplied.
"""
# GIVEN: A Path object from openlp.core.common.path
# WHEN: Calling encode_json, with a dictionary representation
path = Path.encode_json({'__Path__': ['path', 'to', 'fi.le']}, base_path=Path('/base'))
# THEN: A Path object should have been returned with an absolute path
self.assertEqual(path, Path('/', 'base', 'path', 'to', 'fi.le'))
def test_path_json_object(self):
"""
Test that `Path.json_object` creates a JSON decode-able object from a Path object
"""
# GIVEN: A Path object from openlp.core.common.path
path = Path('/base', 'path', 'to', 'fi.le')
# WHEN: Calling json_object
obj = path.json_object(extra=1, args=2)
# THEN: A JSON decodable object should have been returned.
self.assertEqual(obj, {'__Path__': ('/', 'base', 'path', 'to', 'fi.le')})
def test_path_json_object_base_path(self):
"""
Test that `Path.json_object` creates a JSON decode-able object from a Path object, that is relative to the
base_path
"""
# GIVEN: A Path object from openlp.core.common.path
path = Path('/base', 'path', 'to', 'fi.le')
# WHEN: Calling json_object with a base_path
obj = path.json_object(base_path=Path('/', 'base'))
# THEN: A JSON decodable object should have been returned.
self.assertEqual(obj, {'__Path__': ('path', 'to', 'fi.le')})

View File

@ -26,7 +26,6 @@ from unittest import TestCase
from unittest.mock import patch
from openlp.core.common import Settings
from openlp.core.common.settings import recent_files_conv
from tests.helpers.testmixin import TestMixin
@ -48,25 +47,6 @@ class TestSettings(TestCase, TestMixin):
"""
self.destroy_settings()
def test_recent_files_conv(self):
"""
Test that recent_files_conv, converts various possible types of values correctly.
"""
# GIVEN: A list of possible value types and the expected results
possible_values = [(['multiple', 'values'], ['multiple', 'values']),
(['single value'], ['single value']),
('string value', ['string value']),
(b'bytes value', ['bytes value']),
([], []),
(None, [])]
# WHEN: Calling recent_files_conv with the possible values
for value, expected_result in possible_values:
actual_result = recent_files_conv(value)
# THEN: The actual result should be the same as the expected result
self.assertEqual(actual_result, expected_result)
def test_settings_basic(self):
"""
Test the Settings creation and its default usage

View File

@ -22,9 +22,7 @@
"""
Package to test the openlp.core.lib package.
"""
import os
import shutil
from pathlib import Path
from tempfile import mkdtemp
from unittest import TestCase
@ -34,6 +32,7 @@ from sqlalchemy.pool import NullPool
from sqlalchemy.orm.scoping import ScopedSession
from sqlalchemy import MetaData
from openlp.core.common.path import Path
from openlp.core.lib.db import init_db, get_upgrade_op, delete_database, upgrade_db
from openlp.core.lib.projector import upgrade as pjlink_upgrade

View File

@ -24,12 +24,12 @@ Package to test the openlp.core.lib package.
"""
import os
from datetime import datetime, timedelta
from pathlib import Path
from unittest import TestCase
from unittest.mock import MagicMock, patch
from PyQt5 import QtCore, QtGui
from openlp.core.common.path import Path
from openlp.core.lib import FormattingTags, build_icon, check_item_selected, clean_tags, compare_chord_lyric, \
create_separated_list, create_thumb, expand_chords, expand_chords_for_printing, expand_tags, find_formatting_tags, \
get_text_file_string, image_to_byte, replace_params, resize_image, str_to_bool, validate_thumb

View File

@ -23,10 +23,9 @@
Package to test the openlp.core.lib.path package.
"""
import os
from pathlib import Path
from unittest import TestCase
from openlp.core.lib.path import path_to_str, str_to_path
from openlp.core.common.path import Path, path_to_str, str_to_path
class TestPath(TestCase):

View File

@ -29,6 +29,7 @@ from unittest import TestCase
from unittest.mock import mock_open, patch
from openlp.core.common import Registry
from openlp.core.common.path import Path
from openlp.core.ui import exceptionform
from tests.helpers.testmixin import TestMixin
@ -154,7 +155,7 @@ class TestExceptionForm(TestMixin, TestCase):
# THEN: Verify strings were formatted properly
mocked_add_query_item.assert_called_with('body', MAIL_ITEM_TEXT)
@patch("openlp.core.ui.exceptionform.QtWidgets.QFileDialog.getSaveFileName")
@patch("openlp.core.ui.exceptionform.FileDialog.getSaveFileName")
@patch("openlp.core.ui.exceptionform.Qt")
def test_on_save_report_button_clicked(self,
mocked_qt,
@ -181,7 +182,7 @@ class TestExceptionForm(TestMixin, TestCase):
mocked_qt.PYQT_VERSION_STR = 'PyQt5 Test'
mocked_is_linux.return_value = False
mocked_application_version.return_value = 'Trunk Test'
mocked_save_filename.return_value = ['testfile.txt', ]
mocked_save_filename.return_value = (Path('testfile.txt'), 'filter')
test_form = exceptionform.ExceptionForm()
test_form.file_attachment = None

View File

@ -25,11 +25,11 @@ Package to test the openlp.core.ui.firsttimeform package.
import os
import tempfile
import urllib
from pathlib import Path
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.core.ui.firsttimeform import FirstTimeForm
from tests.helpers.testmixin import TestMixin

View File

@ -22,10 +22,10 @@
"""
Package to test the openlp.core.ui.themeform package.
"""
from pathlib import Path
from unittest import TestCase
from unittest.mock import MagicMock, patch
from openlp.core.common.path import Path
from openlp.core.ui import ThemeForm

View File

@ -1,10 +1,10 @@
import os
from unittest import TestCase
from unittest.mock import patch
from pathlib import Path
from PyQt5 import QtWidgets
from openlp.core.common.path import Path
from openlp.core.ui.lib.filedialog import FileDialog

View File

@ -23,10 +23,10 @@
This module contains tests for the openlp.core.ui.lib.pathedit module
"""
import os
from pathlib import Path
from unittest import TestCase
from unittest.mock import MagicMock, PropertyMock, patch
from openlp.core.common.path import Path
from openlp.core.ui.lib import PathEdit, PathType
from openlp.core.ui.lib.filedialog import FileDialog

View File

@ -22,10 +22,10 @@
"""
This module contains tests for the manager submodule of the Bibles plugin.
"""
from pathlib import Path
from unittest import TestCase
from unittest.mock import MagicMock, patch
from openlp.core.common.path import Path
from openlp.plugins.bibles.lib.manager import BibleManager

View File

@ -28,6 +28,7 @@ from unittest.mock import ANY, MagicMock, patch
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import Registry
from openlp.core.common.path import Path
from openlp.plugins.images.lib.db import ImageFilenames, ImageGroups
from openlp.plugins.images.lib.mediaitem import ImageMediaItem
@ -65,7 +66,7 @@ class TestImageMediaItem(TestCase):
# THEN: load_list should have been called with the file list and None,
# the directory should have been saved to the settings
mocked_load_list.assert_called_once_with(file_list, None)
mocked_settings().setValue.assert_called_once_with(ANY, '/path1')
mocked_settings().setValue.assert_called_once_with(ANY, Path('/', 'path1'))
@patch('openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_list')
@patch('openlp.plugins.images.lib.mediaitem.Settings')
@ -82,7 +83,7 @@ class TestImageMediaItem(TestCase):
# THEN: load_list should have been called with the file list and the group name,
# the directory should have been saved to the settings
mocked_load_list.assert_called_once_with(file_list, 'group')
mocked_settings().setValue.assert_called_once_with(ANY, '/path1')
mocked_settings().setValue.assert_called_once_with(ANY, Path('/', 'path1'))
@patch('openlp.plugins.images.lib.mediaitem.ImageMediaItem.load_full_list')
def test_save_new_images_list_empty_list(self, mocked_load_full_list):

View File

@ -28,6 +28,7 @@ from unittest.mock import MagicMock, patch
from PyQt5 import QtCore
from openlp.core import Settings
from openlp.core.common.path import Path
from openlp.plugins.media.lib.mediaitem import MediaMediaItem
from tests.helpers.testmixin import TestMixin
@ -66,7 +67,7 @@ class MediaItemTest(TestCase, TestMixin):
Media Remote Search Successful find
"""
# GIVEN: The Mediaitem set up a list of media
Settings().setValue(self.media_item.settings_section + '/media files', ['test.mp3', 'test.mp4'])
Settings().setValue(self.media_item.settings_section + '/media files', [Path('test.mp3'), Path('test.mp4')])
# WHEN: Retrieving the test file
result = self.media_item.search('test.mp4', False)
# THEN: a file should be found
@ -77,7 +78,7 @@ class MediaItemTest(TestCase, TestMixin):
Media Remote Search not find
"""
# GIVEN: The Mediaitem set up a list of media
Settings().setValue(self.media_item.settings_section + '/media files', ['test.mp3', 'test.mp4'])
Settings().setValue(self.media_item.settings_section + '/media files', [Path('test.mp3'), Path('test.mp4')])
# WHEN: Retrieving the test file
result = self.media_item.search('test.mpx', False)
# THEN: a file should be found

View File

@ -24,10 +24,10 @@ Functional tests to test the PresentationController and PresentationDocument
classes and related methods.
"""
import os
from pathlib import Path
from unittest import TestCase
from unittest.mock import MagicMock, mock_open, patch
from openlp.core.common.path import Path
from openlp.plugins.presentations.lib.presentationcontroller import PresentationController, PresentationDocument
FOLDER_TO_PATCH = 'openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument.get_thumbnail_folder'

View File

@ -22,10 +22,10 @@
"""
Functional tests to test the AppLocation class and related methods.
"""
from pathlib import Path
from unittest import TestCase
from openlp.core.common import is_not_image_file
from openlp.core.common.path import Path
from tests.utils.constants import TEST_RESOURCES_PATH
from tests.helpers.testmixin import TestMixin

View File

@ -32,6 +32,7 @@ from unittest.mock import MagicMock, patch
from PyQt5 import QtWidgets
from openlp.core.common import Registry, Settings
from openlp.core.common.path import Path
from openlp.core.lib.pluginmanager import PluginManager
from tests.helpers.testmixin import TestMixin
@ -48,7 +49,7 @@ class TestPluginManager(TestCase, TestMixin):
"""
self.setup_application()
self.build_settings()
self.temp_dir = mkdtemp('openlp')
self.temp_dir = Path(mkdtemp('openlp'))
Settings().setValue('advanced/data path', self.temp_dir)
Registry.create()
Registry().register('service_list', MagicMock())
@ -62,7 +63,7 @@ class TestPluginManager(TestCase, TestMixin):
# On windows we need to manually garbage collect to close sqlalchemy files
# to avoid errors when temporary files are deleted.
gc.collect()
shutil.rmtree(self.temp_dir)
shutil.rmtree(str(self.temp_dir))
@patch('openlp.plugins.songusage.lib.db.init_schema')
@patch('openlp.plugins.songs.lib.db.init_schema')