openlp-core team mailing list archive
-
openlp-core team
-
Mailing list archive
-
Message #31931
[Merge] lp:~phill-ridout/openlp/pathlib2 into lp:openlp
Phill has proposed merging lp:~phill-ridout/openlp/pathlib2 into lp:openlp.
Requested reviews:
Tim Bentley (trb143)
For more details, see:
https://code.launchpad.net/~phill-ridout/openlp/pathlib2/+merge/328616
Part 2
Changed the pathedit widget over to using pathlib
Added a 'patched' file dialog
Added a few utility methods
lp:~phill-ridout/openlp/pathlib2 (revision 2759)
[SUCCESS] https://ci.openlp.io/job/Branch-01-Pull/2115/
[SUCCESS] https://ci.openlp.io/job/Branch-02-Functional-Tests/2025/
[SUCCESS] https://ci.openlp.io/job/Branch-03-Interface-Tests/1933/
[SUCCESS] https://ci.openlp.io/job/Branch-04a-Code_Analysis/1310/
[SUCCESS] https://ci.openlp.io/job/Branch-04b-Test_Coverage/1153/
[SUCCESS] https://ci.openlp.io/job/Branch-04c-Code_Analysis2/283/
[FAILURE] https://ci.openlp.io/job/Branch-05-AppVeyor-Tests/128/
Stopping after failure
--
Your team OpenLP Core is subscribed to branch lp:openlp.
=== added file 'openlp/core/common/path.py'
--- openlp/core/common/path.py 1970-01-01 00:00:00 +0000
+++ openlp/core/common/path.py 2017-08-04 22:00:43 +0000
@@ -0,0 +1,61 @@
+# -*- 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)
=== modified file 'openlp/core/lib/__init__.py'
--- openlp/core/lib/__init__.py 2017-05-20 05:51:58 +0000
+++ openlp/core/lib/__init__.py 2017-08-04 22:00:43 +0000
@@ -608,6 +608,41 @@
return list_to_string
+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 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)
+
+
+ Usage:
+ Take a method with the following signature, and assume we which to apply the str function to arg2:
+ def method(arg1=None, arg2=None, arg3=None)
+
+ As arg2 can be specified postitionally as the second argument (1 with a zero index) or as a keyword, the we
+ would call this function as follows:
+
+ replace_params(args, kwargs, ((1, 'arg2', str),))
+ """
+ args = list(args)
+ for position, key_word, transform in params:
+ if len(args) > position:
+ args[position] = transform(args[position])
+ elif key_word in kwargs:
+ kwargs[key_word] = transform(kwargs[key_word])
+ return tuple(args), kwargs
+
+
from .exceptions import ValidationError
from .filedialog import FileDialog
from .screen import ScreenList
=== modified file 'openlp/core/ui/advancedtab.py'
--- openlp/core/ui/advancedtab.py 2017-08-01 20:59:41 +0000
+++ openlp/core/ui/advancedtab.py 2017-08-04 22:00:43 +0000
@@ -30,6 +30,7 @@
from openlp.core.common import AppLocation, Settings, SlideLimits, UiStrings, translate
from openlp.core.common.languagemanager import format_time
+from openlp.core.common.path import path_to_str
from openlp.core.lib import SettingsTab, build_icon
from openlp.core.ui.lib import PathEdit, PathType
@@ -156,7 +157,7 @@
self.data_directory_new_label = QtWidgets.QLabel(self.data_directory_group_box)
self.data_directory_new_label.setObjectName('data_directory_current_label')
self.data_directory_path_edit = PathEdit(self.data_directory_group_box, path_type=PathType.Directories,
- default_path=str(AppLocation.get_directory(AppLocation.DataDir)))
+ default_path=AppLocation.get_directory(AppLocation.DataDir))
self.data_directory_layout.addRow(self.data_directory_new_label, self.data_directory_path_edit)
self.new_data_directory_has_files_label = QtWidgets.QLabel(self.data_directory_group_box)
self.new_data_directory_has_files_label.setObjectName('new_data_directory_has_files_label')
@@ -373,7 +374,7 @@
self.new_data_directory_has_files_label.hide()
self.data_directory_cancel_button.hide()
# Since data location can be changed, make sure the path is present.
- self.data_directory_path_edit.path = str(AppLocation.get_data_path())
+ self.data_directory_path_edit.path = AppLocation.get_data_path()
# Don't allow data directory move if running portable.
if settings.value('advanced/is portable'):
self.data_directory_group_box.hide()
@@ -497,12 +498,12 @@
'closed.').format(path=new_data_path),
defaultButton=QtWidgets.QMessageBox.No)
if answer != QtWidgets.QMessageBox.Yes:
- self.data_directory_path_edit.path = str(AppLocation.get_data_path())
+ self.data_directory_path_edit.path = AppLocation.get_data_path()
return
# Check if data already exists here.
- self.check_data_overwrite(new_data_path)
+ self.check_data_overwrite(path_to_str(new_data_path))
# Save the new location.
- self.main_window.set_new_data_path(new_data_path)
+ self.main_window.set_new_data_path(path_to_str(new_data_path))
self.data_directory_cancel_button.show()
def on_data_directory_copy_check_box_toggled(self):
@@ -550,7 +551,7 @@
"""
Cancel the data directory location change
"""
- self.data_directory_path_edit.path = str(AppLocation.get_data_path())
+ self.data_directory_path_edit.path = AppLocation.get_data_path()
self.data_directory_copy_check_box.setChecked(False)
self.main_window.set_new_data_path(None)
self.main_window.set_copy_data(False)
=== modified file 'openlp/core/ui/generaltab.py'
--- openlp/core/ui/generaltab.py 2017-05-22 19:56:54 +0000
+++ openlp/core/ui/generaltab.py 2017-08-04 22:00:43 +0000
@@ -23,10 +23,12 @@
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.lib import SettingsTab, ScreenList
from openlp.core.ui.lib import ColorButton, PathEdit
@@ -172,7 +174,8 @@
self.logo_layout.setObjectName('logo_layout')
self.logo_file_label = QtWidgets.QLabel(self.logo_group_box)
self.logo_file_label.setObjectName('logo_file_label')
- self.logo_file_path_edit = PathEdit(self.logo_group_box, default_path=':/graphics/openlp-splash-screen.png')
+ self.logo_file_path_edit = PathEdit(self.logo_group_box,
+ default_path=Path(':/graphics/openlp-splash-screen.png'))
self.logo_layout.addRow(self.logo_file_label, self.logo_file_path_edit)
self.logo_color_label = QtWidgets.QLabel(self.logo_group_box)
self.logo_color_label.setObjectName('logo_color_label')
@@ -266,7 +269,7 @@
self.audio_group_box.setTitle(translate('OpenLP.GeneralTab', 'Background Audio'))
self.start_paused_check_box.setText(translate('OpenLP.GeneralTab', 'Start background audio paused'))
self.repeat_list_check_box.setText(translate('OpenLP.GeneralTab', 'Repeat track list'))
- self.logo_file_path_edit.dialog_caption = dialog_caption = translate('OpenLP.AdvancedTab', 'Select Logo File')
+ self.logo_file_path_edit.dialog_caption = translate('OpenLP.AdvancedTab', 'Select Logo File')
self.logo_file_path_edit.filters = '{text};;{names} (*)'.format(
text=get_images_filter(), names=UiStrings().AllFiles)
@@ -291,7 +294,7 @@
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 = settings.value('logo file')
+ self.logo_file_path_edit.path = str_to_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'))
@@ -325,7 +328,7 @@
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', self.logo_file_path_edit.path)
+ settings.setValue('logo file', path_to_str(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())
=== added file 'openlp/core/ui/lib/filedialogpatches.py'
--- openlp/core/ui/lib/filedialogpatches.py 1970-01-01 00:00:00 +0000
+++ openlp/core/ui/lib/filedialogpatches.py 2017-08-04 22:00:43 +0000
@@ -0,0 +1,118 @@
+# -*- 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 #
+###############################################################################
+""" Patch the QFileDialog so it accepts and returns Path objects"""
+from functools import wraps
+from pathlib import Path
+
+from PyQt5 import QtWidgets
+
+from openlp.core.common.path import path_to_str, str_to_path
+from openlp.core.lib import replace_params
+
+
+class PQFileDialog(QtWidgets.QFileDialog):
+ @classmethod
+ @wraps(QtWidgets.QFileDialog.getExistingDirectory)
+ def getExistingDirectory(cls, *args, **kwargs):
+ """
+ Reimplement `getExistingDirectory` so that it can be called with, and return Path objects
+
+ :type parent: QtWidgets.QWidget or None
+ :type caption: str
+ :type directory: pathlib.Path
+ :type options: QtWidgets.QFileDialog.Options
+ :rtype: tuple[Path, str]
+ """
+
+ args, kwargs = replace_params(args, kwargs, ((2, 'directory', path_to_str),))
+
+ return_value = super().getExistingDirectory(*args, **kwargs)
+
+ # getExistingDirectory returns a str that represents the path. The string is empty if the user cancels the
+ # dialog.
+ return str_to_path(return_value)
+
+ @classmethod
+ @wraps(QtWidgets.QFileDialog.getOpenFileName)
+ def getOpenFileName(cls, *args, **kwargs):
+ """
+ Reimplement `getOpenFileName` so that it can be called with, and return Path objects
+
+ :type parent: QtWidgets.QWidget or None
+ :type caption: str
+ :type directory: pathlib.Path
+ :type filter: str
+ :type initialFilter: str
+ :type options: QtWidgets.QFileDialog.Options
+ :rtype: tuple[Path, str]
+ """
+
+ args, kwargs = replace_params(args, kwargs, ((2, 'directory', path_to_str),))
+
+ return_value = super().getOpenFileName(*args, **kwargs)
+
+ # getOpenFileName returns a tuple. The first item is a of str's that represents the path. The string is empty if
+ # the user cancels the dialog.
+ return str_to_path(return_value[0]), return_value[1]
+
+ @classmethod
+ def getOpenFileNames(cls, *args, **kwargs):
+ """
+ Reimplement `getOpenFileNames` so that it can be called with, and return Path objects
+
+ :type parent: QtWidgets.QWidget or None
+ :type caption: str
+ :type directory: pathlib.Path
+ :type filter: str
+ :type initialFilter: str
+ :type options: QtWidgets.QFileDialog.Options
+ :rtype: tuple[list[Path], str]
+ """
+ args, kwargs = replace_params(args, kwargs, ((2, 'directory', path_to_str),))
+
+ return_value = super().getOpenFileNames(*args, **kwargs)
+
+ # getSaveFileName returns a tuple. The first item is a list of str's that represents the path. The list is
+ # empty if the user cancels the dialog.
+ paths = [str_to_path(path) for path in return_value[0]]
+ return paths, return_value[1]
+
+ @classmethod
+ def getSaveFileName(cls, *args, **kwargs):
+ """
+ Reimplement `getSaveFileName` so that it can be called with, and return Path objects
+
+ :type parent: QtWidgets.QWidget or None
+ :type caption: str
+ :type directory: pathlib.Path
+ :type filter: str
+ :type initialFilter: str
+ :type options: QtWidgets.QFileDialog.Options
+ :rtype: tuple[Path or None, str]
+ """
+ args, kwargs = replace_params(args, kwargs, ((2, 'directory', path_to_str),))
+
+ return_value = super().getSaveFileName(*args, **kwargs)
+
+ # getSaveFileName returns a tuple. The first item represents the path as a str. The string is empty if the user
+ # cancels the dialog.
+ return str_to_path(return_value[0]), return_value[1]
=== modified file 'openlp/core/ui/lib/pathedit.py' (properties changed: +x to -x)
--- openlp/core/ui/lib/pathedit.py 2017-07-04 23:13:51 +0000
+++ openlp/core/ui/lib/pathedit.py 2017-08-04 22:00:43 +0000
@@ -20,12 +20,14 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from enum import Enum
-import os.path
+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.lib import build_icon
+from openlp.core.ui.lib.filedialogpatches import PQFileDialog
class PathType(Enum):
@@ -38,11 +40,12 @@
The :class:`~openlp.core.ui.lib.pathedit.PathEdit` class subclasses QWidget to create a custom widget for use when
a file or directory needs to be selected.
"""
- pathChanged = QtCore.pyqtSignal(str)
+
+ pathChanged = QtCore.pyqtSignal(Path)
def __init__(self, parent=None, path_type=PathType.Files, default_path=None, dialog_caption=None, show_revert=True):
"""
- Initalise the PathEdit widget
+ Initialise the PathEdit widget
:param parent: The parent of the widget. This is just passed to the super method.
:type parent: QWidget or None
@@ -51,9 +54,9 @@
: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: str
+ :type default_path: pathlib.Path
- :param show_revert: Used to determin if the 'revert button' should be visible.
+ :param show_revert: Used to determine if the 'revert button' should be visible.
:type show_revert: bool
:return: None
@@ -79,7 +82,6 @@
widget_layout = QtWidgets.QHBoxLayout()
widget_layout.setContentsMargins(0, 0, 0, 0)
self.line_edit = QtWidgets.QLineEdit(self)
- self.line_edit.setText(self._path)
widget_layout.addWidget(self.line_edit)
self.browse_button = QtWidgets.QToolButton(self)
self.browse_button.setIcon(build_icon(':/general/general_open.png'))
@@ -101,7 +103,7 @@
A property getter method to return the selected path.
:return: The selected path
- :rtype: str
+ :rtype: pathlib.Path
"""
return self._path
@@ -111,11 +113,15 @@
A Property setter method to set the selected path
:param path: The path to set the widget to
- :type path: str
+ :type path: pathlib.Path
+
+ :return: None
+ :rtype: None
"""
self._path = path
- self.line_edit.setText(path)
- self.line_edit.setToolTip(path)
+ text = path_to_str(path)
+ self.line_edit.setText(text)
+ self.line_edit.setToolTip(text)
@property
def path_type(self):
@@ -124,7 +130,7 @@
selecting a file or directory.
:return: The type selected
- :rtype: Enum of PathEdit
+ :rtype: PathType
"""
return self._path_type
@@ -133,8 +139,11 @@
"""
A Property setter method to set the path type
- :param path: The type of path to select
- :type path: Enum of PathEdit
+ :param path_type: The type of path to select
+ :type path_type: PathType
+
+ :return: None
+ :rtype: None
"""
self._path_type = path_type
self.update_button_tool_tips()
@@ -142,7 +151,9 @@
def update_button_tool_tips(self):
"""
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:
self.browse_button.setToolTip(translate('OpenLP.PathEdit', 'Browse for directory.'))
@@ -156,21 +167,21 @@
A handler to handle a click on the browse button.
Show the QFileDialog and process the input from the user
+
:return: None
+ :rtype: None
"""
caption = self.dialog_caption
- path = ''
+ path = None
if self._path_type == PathType.Directories:
if not caption:
caption = translate('OpenLP.PathEdit', 'Select Directory')
- path = QtWidgets.QFileDialog.getExistingDirectory(self, caption,
- self._path, QtWidgets.QFileDialog.ShowDirsOnly)
+ path = PQFileDialog.getExistingDirectory(self, caption, self._path, PQFileDialog.ShowDirsOnly)
elif self._path_type == PathType.Files:
if not caption:
caption = self.dialog_caption = translate('OpenLP.PathEdit', 'Select File')
- path, filter_used = QtWidgets.QFileDialog.getOpenFileName(self, caption, self._path, self.filters)
+ path, filter_used = PQFileDialog.getOpenFileName(self, caption, self._path, self.filters)
if path:
- path = os.path.normpath(path)
self.on_new_path(path)
def on_revert_button_clicked(self):
@@ -178,16 +189,21 @@
A handler to handle a click on the revert button.
Set the new path to the value of the default_path instance variable.
+
:return: None
+ :rtype: None
"""
self.on_new_path(self.default_path)
def on_line_edit_editing_finished(self):
"""
A handler to handle when the line edit has finished being edited.
+
:return: None
+ :rtype: None
"""
- self.on_new_path(self.line_edit.text())
+ path = str_to_path(self.line_edit.text())
+ self.on_new_path(path)
def on_new_path(self, path):
"""
@@ -196,9 +212,10 @@
Emits the pathChanged Signal
:param path: The new path
- :type path: str
+ :type path: pathlib.Path
:return: None
+ :rtype: None
"""
if self._path != path:
self.path = path
=== modified file 'openlp/core/ui/themeform.py'
--- openlp/core/ui/themeform.py 2017-05-30 18:50:39 +0000
+++ openlp/core/ui/themeform.py 2017-08-04 22:00:43 +0000
@@ -28,12 +28,14 @@
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.lib.theme import BackgroundType, BackgroundGradientType
from openlp.core.lib.ui import critical_error_message_box
from openlp.core.ui import ThemeLayoutForm
from openlp.core.ui.media.webkitplayer import VIDEO_EXT
from .themewizard import Ui_ThemeWizard
+
log = logging.getLogger(__name__)
@@ -316,11 +318,11 @@
self.setField('background_type', 1)
elif self.theme.background_type == BackgroundType.to_string(BackgroundType.Image):
self.image_color_button.color = self.theme.background_border_color
- self.image_path_edit.path = self.theme.background_filename
+ self.image_path_edit.path = str_to_path(self.theme.background_filename)
self.setField('background_type', 2)
elif self.theme.background_type == BackgroundType.to_string(BackgroundType.Video):
self.video_color_button.color = self.theme.background_border_color
- self.video_path_edit.path = self.theme.background_filename
+ self.video_path_edit.path = str_to_path(self.theme.background_filename)
self.setField('background_type', 4)
elif self.theme.background_type == BackgroundType.to_string(BackgroundType.Transparent):
self.setField('background_type', 3)
@@ -448,18 +450,18 @@
"""
self.theme.background_end_color = color
- def on_image_path_edit_path_changed(self, filename):
+ def on_image_path_edit_path_changed(self, file_path):
"""
Background Image button pushed.
"""
- self.theme.background_filename = filename
+ self.theme.background_filename = path_to_str(file_path)
self.set_background_page_values()
- def on_video_path_edit_path_changed(self, filename):
+ def on_video_path_edit_path_changed(self, file_path):
"""
Background video button pushed.
"""
- self.theme.background_filename = filename
+ self.theme.background_filename = path_to_str(file_path)
self.set_background_page_values()
def on_main_color_changed(self, color):
=== modified file 'openlp/core/ui/themewizard.py'
--- openlp/core/ui/themewizard.py 2017-05-22 18:22:43 +0000
+++ openlp/core/ui/themewizard.py 2017-08-04 22:00:43 +0000
@@ -30,6 +30,8 @@
from openlp.core.lib.ui import add_welcome_page, create_valign_selection_widgets
from openlp.core.ui.lib import ColorButton, PathEdit
+from pathlib import Path
+
class Ui_ThemeWizard(object):
"""
=== modified file 'openlp/plugins/bibles/lib/importers/http.py'
--- openlp/plugins/bibles/lib/importers/http.py 2017-08-02 06:10:26 +0000
+++ openlp/plugins/bibles/lib/importers/http.py 2017-08-04 22:00:43 +0000
@@ -255,7 +255,7 @@
chapter=chapter,
version=version)
soup = get_soup_for_bible_ref(
- 'http://biblegateway.com/passage/?{url}'.format(url=url_params),
+ 'http://www.biblegateway.com/passage/?{url}'.format(url=url_params),
pre_parse_regex=r'<meta name.*?/>', pre_parse_substitute='')
if not soup:
return None
@@ -284,7 +284,7 @@
"""
log.debug('BGExtract.get_books_from_http("{version}")'.format(version=version))
url_params = urllib.parse.urlencode({'action': 'getVersionInfo', 'vid': '{version}'.format(version=version)})
- reference_url = 'http://biblegateway.com/versions/?{url}#books'.format(url=url_params)
+ reference_url = 'http://www.biblegateway.com/versions/?{url}#books'.format(url=url_params)
page = get_web_page(reference_url)
if not page:
send_error_message('download')
=== modified file 'openlp/plugins/presentations/lib/presentationtab.py'
--- openlp/plugins/presentations/lib/presentationtab.py 2017-05-22 18:27:40 +0000
+++ openlp/plugins/presentations/lib/presentationtab.py 2017-08-04 22:00:43 +0000
@@ -20,10 +20,11 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
-from PyQt5 import QtGui, QtWidgets
+from PyQt5 import QtWidgets
from openlp.core.common import Settings, UiStrings, translate
-from openlp.core.lib import SettingsTab, build_icon
+from openlp.core.common.path import path_to_str, str_to_path
+from openlp.core.lib import SettingsTab
from openlp.core.lib.ui import critical_error_message_box
from openlp.core.ui.lib import PathEdit
from openlp.plugins.presentations.lib.pdfcontroller import PdfController
@@ -156,7 +157,7 @@
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 = pdf_program
+ self.program_path_edit.path = str_to_path(pdf_program)
def save(self):
"""
@@ -192,7 +193,7 @@
Settings().setValue(setting_key, self.ppt_window_check_box.checkState())
changed = True
# Save pdf-settings
- pdf_program = self.program_path_edit.path
+ pdf_program = path_to_str(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 == '':
@@ -219,12 +220,13 @@
checkbox.setEnabled(controller.is_available())
self.set_controller_text(checkbox, controller)
- def on_program_path_edit_path_changed(self, filename):
+ def on_program_path_edit_path_changed(self, new_path):
"""
Select the mudraw or ghostscript binary that should be used.
"""
- if filename:
- if not PdfController.process_check_binary(filename):
+ new_path = path_to_str(new_path)
+ if new_path:
+ if not PdfController.process_check_binary(new_path):
critical_error_message_box(UiStrings().Error,
translate('PresentationPlugin.PresentationTab',
'The program is not ghostscript or mudraw which is required.'))
=== modified file 'openlp/plugins/songusage/forms/songusagedetailform.py'
--- openlp/plugins/songusage/forms/songusagedetailform.py 2017-06-04 12:14:23 +0000
+++ openlp/plugins/songusage/forms/songusagedetailform.py 2017-08-04 22:00:43 +0000
@@ -27,6 +27,7 @@
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.lib.ui import critical_error_message_box
from openlp.plugins.songusage.lib.db import SongUsageItem
from .songusagedetaildialog import Ui_SongUsageDetailDialog
@@ -55,20 +56,21 @@
"""
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 = Settings().value(self.plugin.settings_section + '/last directory export')
+ self.report_path_edit.path = str_to_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
"""
- Settings().setValue(self.plugin.settings_section + '/last directory export', file_path)
+ Settings().setValue(self.plugin.settings_section + '/last directory export', path_to_str(file_path))
def accept(self):
"""
Ok was triggered so lets save the data and run the report
"""
log.debug('accept')
- path = self.report_path_edit.path
+ path = path_to_str(self.report_path_edit.path)
if not path:
self.main_window.error_message(
translate('SongUsagePlugin.SongUsageDetailForm', 'Output Path Not Selected'),
=== added file 'tests/functional/openlp_core_common/test_path.py'
--- tests/functional/openlp_core_common/test_path.py 1970-01-01 00:00:00 +0000
+++ tests/functional/openlp_core_common/test_path.py 2017-08-04 22:00:43 +0000
@@ -0,0 +1,88 @@
+# -*- 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.path package.
+"""
+import os
+from pathlib import Path
+from unittest import TestCase
+
+from openlp.core.common.path import path_to_str, str_to_path
+
+
+class TestPath(TestCase):
+ """
+ Tests for the :mod:`openlp.core.common.path` module
+ """
+
+ def test_path_to_str_type_error(self):
+ """
+ Test that `path_to_str` raises a type error when called with an invalid type
+ """
+ # GIVEN: The `path_to_str` function
+ # WHEN: Calling `path_to_str` with an invalid Type
+ # THEN: A TypeError should have been raised
+ with self.assertRaises(TypeError):
+ path_to_str(str())
+
+ def test_path_to_str_none(self):
+ """
+ Test that `path_to_str` correctly converts the path parameter when passed with None
+ """
+ # GIVEN: The `path_to_str` function
+ # WHEN: Calling the `path_to_str` function with None
+ result = path_to_str(None)
+
+ # THEN: `path_to_str` should return an empty string
+ self.assertEqual(result, '')
+
+ def test_path_to_str_path_object(self):
+ """
+ Test that `path_to_str` correctly converts the path parameter when passed a Path object
+ """
+ # GIVEN: The `path_to_str` function
+ # WHEN: Calling the `path_to_str` function with a Path object
+ result = path_to_str(Path('test/path'))
+
+ # THEN: `path_to_str` should return a string representation of the Path object
+ self.assertEqual(result, os.path.join('test', 'path'))
+
+ def test_str_to_path_type_error(self):
+ """
+ Test that `str_to_path` raises a type error when called with an invalid type
+ """
+ # GIVEN: The `str_to_path` function
+ # WHEN: Calling `str_to_path` with an invalid Type
+ # THEN: A TypeError should have been raised
+ with self.assertRaises(TypeError):
+ str_to_path(Path())
+
+ def test_str_to_path_empty_str(self):
+ """
+ Test that `str_to_path` correctly converts the string parameter when passed with and empty string
+ """
+ # GIVEN: The `str_to_path` function
+ # WHEN: Calling the `str_to_path` function with None
+ result = str_to_path('')
+
+ # THEN: `path_to_str` should return None
+ self.assertEqual(result, None)
=== modified file 'tests/functional/openlp_core_lib/test_lib.py'
--- tests/functional/openlp_core_lib/test_lib.py 2017-05-17 20:06:45 +0000
+++ tests/functional/openlp_core_lib/test_lib.py 2017-08-04 22:00:43 +0000
@@ -29,10 +29,9 @@
from PyQt5 import QtCore, QtGui
-from openlp.core.lib import FormattingTags, expand_chords_for_printing
-from openlp.core.lib import build_icon, check_item_selected, clean_tags, create_thumb, create_separated_list, \
- expand_tags, get_text_file_string, image_to_byte, resize_image, str_to_bool, validate_thumb, expand_chords, \
- compare_chord_lyric, find_formatting_tags
+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
TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'resources'))
@@ -652,6 +651,38 @@
mocked_os.stat.assert_any_call(thumb_path)
assert result is False, 'The result should be False'
+ def test_replace_params_no_params(self):
+ """
+ Test replace_params when called with and empty tuple instead of parameters to replace
+ """
+ # GIVEN: Some test data
+ test_args = (1, 2)
+ test_kwargs = {'arg3': 3, 'arg4': 4}
+ test_params = tuple()
+
+ # WHEN: Calling replace_params
+ result_args, result_kwargs = replace_params(test_args, test_kwargs, test_params)
+
+ # THEN: The positional and keyword args should not have changed
+ self.assertEqual(test_args, result_args)
+ self.assertEqual(test_kwargs, result_kwargs)
+
+ def test_replace_params_params(self):
+ """
+ Test replace_params when given a positional and a keyword argument to change
+ """
+ # GIVEN: Some test data
+ test_args = (1, 2)
+ test_kwargs = {'arg3': 3, 'arg4': 4}
+ test_params = ((1, 'arg2', str), (2, 'arg3', str))
+
+ # WHEN: Calling replace_params
+ result_args, result_kwargs = replace_params(test_args, test_kwargs, test_params)
+
+ # THEN: The positional and keyword args should have have changed
+ self.assertEqual(result_args, (1, '2'))
+ self.assertEqual(result_kwargs, {'arg3': '3', 'arg4': 4})
+
def test_resize_thumb(self):
"""
Test the resize_thumb() function
=== modified file 'tests/functional/openlp_core_ui/test_themeform.py'
--- tests/functional/openlp_core_ui/test_themeform.py 2017-05-14 07:15:29 +0000
+++ tests/functional/openlp_core_ui/test_themeform.py 2017-08-04 22:00:43 +0000
@@ -22,6 +22,7 @@
"""
Package to test the openlp.core.ui.themeform package.
"""
+from pathlib import Path
from unittest import TestCase
from unittest.mock import MagicMock, patch
@@ -45,7 +46,7 @@
self.instance.theme = MagicMock()
# WHEN: `on_image_path_edit_path_changed` is clicked
- self.instance.on_image_path_edit_path_changed('/new/pat.h')
+ self.instance.on_image_path_edit_path_changed(Path('/', 'new', 'pat.h'))
# THEN: The theme background file should be set and `set_background_page_values` should have been called
self.assertEqual(self.instance.theme.background_filename, '/new/pat.h')
=== renamed file 'tests/functional/openlp_core_ui_lib/test_color_button.py' => 'tests/functional/openlp_core_ui_lib/test_colorbutton.py'
=== added file 'tests/functional/openlp_core_ui_lib/test_filedialogpatches.py'
--- tests/functional/openlp_core_ui_lib/test_filedialogpatches.py 1970-01-01 00:00:00 +0000
+++ tests/functional/openlp_core_ui_lib/test_filedialogpatches.py 2017-08-04 22:00:43 +0000
@@ -0,0 +1,189 @@
+import os
+import sys
+from unittest import TestCase
+from unittest.mock import patch
+from pathlib import Path
+
+from PyQt5 import QtWidgets
+
+from openlp.core.ui.lib.filedialogpatches import PQFileDialog
+
+
+class TestFileDialogPatches(TestCase):
+ """
+ Tests for the :mod:`openlp.core.ui.lib.filedialogpatches` module
+ """
+
+ def test_pq_file_dialog(self):
+ """
+ Test that the :class:`PQFileDialog` instantiates correctly
+ """
+ # GIVEN: The PQFileDialog class
+ # WHEN: Creating an instance
+ instance = PQFileDialog()
+
+ # THEN: The instance should be an instance of QFileDialog
+ self.assertIsInstance(instance, QtWidgets.QFileDialog)
+
+ def test_get_existing_directory_user_abort(self):
+ """
+ Test that `getExistingDirectory` handles the case when the user cancels the dialog
+ """
+ # GIVEN: PQFileDialog with a mocked QDialog.getExistingDirectory method
+ # WHEN: Calling PQFileDialog.getExistingDirectory and the user cancels the dialog returns a empty string
+ with patch('PyQt5.QtWidgets.QFileDialog.getExistingDirectory', return_value=''):
+ result = PQFileDialog.getExistingDirectory()
+
+ # THEN: The result should be None
+ self.assertEqual(result, None)
+
+ def test_get_existing_directory_user_accepts(self):
+ """
+ Test that `getExistingDirectory` handles the case when the user accepts the dialog
+ """
+ # GIVEN: PQFileDialog with a mocked QDialog.getExistingDirectory method
+ # WHEN: Calling PQFileDialog.getExistingDirectory, the user chooses a file and accepts the dialog (it returns a
+ # string pointing to the directory)
+ with patch('PyQt5.QtWidgets.QFileDialog.getExistingDirectory', return_value=os.path.join('test', 'dir')):
+ result = PQFileDialog.getExistingDirectory()
+
+ # THEN: getExistingDirectory() should return a Path object pointing to the chosen file
+ self.assertEqual(result, Path('test', 'dir'))
+
+ def test_get_existing_directory_param_order(self):
+ """
+ Test that `getExistingDirectory` passes the parameters to `QFileDialog.getExistingDirectory` in the correct
+ order
+ """
+ # GIVEN: PQFileDialog
+ with patch('openlp.core.ui.lib.filedialogpatches.QtWidgets.QFileDialog.getExistingDirectory', return_value='') \
+ as mocked_get_existing_directory:
+
+ # WHEN: Calling the getExistingDirectory method with all parameters set
+ PQFileDialog.getExistingDirectory('Parent', 'Caption', Path('test', 'dir'), 'Options')
+
+ # THEN: The `QFileDialog.getExistingDirectory` should have been called with the parameters in the correct
+ # order
+ mocked_get_existing_directory.assert_called_once_with('Parent', 'Caption', os.path.join('test', 'dir'),
+ 'Options')
+
+ def test_get_open_file_name_user_abort(self):
+ """
+ Test that `getOpenFileName` handles the case when the user cancels the dialog
+ """
+ # GIVEN: PQFileDialog with a mocked QDialog.getOpenFileName method
+ # WHEN: Calling PQFileDialog.getOpenFileName and the user cancels the dialog (it returns a tuple with the first
+ # value set as an empty string)
+ with patch('PyQt5.QtWidgets.QFileDialog.getOpenFileName', return_value=('', '')):
+ result = PQFileDialog.getOpenFileName()
+
+ # THEN: First value should be None
+ self.assertEqual(result[0], None)
+
+ def test_get_open_file_name_user_accepts(self):
+ """
+ Test that `getOpenFileName` handles the case when the user accepts the dialog
+ """
+ # GIVEN: PQFileDialog with a mocked QDialog.getOpenFileName method
+ # WHEN: Calling PQFileDialog.getOpenFileName, the user chooses a file and accepts the dialog (it returns a
+ # tuple with the first value set as an string pointing to the file)
+ with patch('PyQt5.QtWidgets.QFileDialog.getOpenFileName',
+ return_value=(os.path.join('test', 'chosen.file'), '')):
+ result = PQFileDialog.getOpenFileName()
+
+ # THEN: getOpenFileName() should return a tuple with the first value set to a Path object pointing to the
+ # chosen file
+ self.assertEqual(result[0], Path('test', 'chosen.file'))
+
+ def test_get_open_file_name_selected_filter(self):
+ """
+ Test that `getOpenFileName` does not modify the selectedFilter as returned by `QFileDialog.getOpenFileName`
+ """
+ # GIVEN: PQFileDialog with a mocked QDialog.get_save_file_name method
+ # WHEN: Calling PQFileDialog.getOpenFileName, and `QFileDialog.getOpenFileName` returns a known `selectedFilter`
+ with patch('PyQt5.QtWidgets.QFileDialog.getOpenFileName', return_value=('', 'selected filter')):
+ result = PQFileDialog.getOpenFileName()
+
+ # THEN: getOpenFileName() should return a tuple with the second value set to a the selected filter
+ self.assertEqual(result[1], 'selected filter')
+
+ def test_get_open_file_names_user_abort(self):
+ """
+ Test that `getOpenFileNames` handles the case when the user cancels the dialog
+ """
+ # GIVEN: PQFileDialog with a mocked QDialog.getOpenFileNames method
+ # WHEN: Calling PQFileDialog.getOpenFileNames and the user cancels the dialog (it returns a tuple with the first
+ # value set as an empty list)
+ with patch('PyQt5.QtWidgets.QFileDialog.getOpenFileNames', return_value=([], '')):
+ result = PQFileDialog.getOpenFileNames()
+
+ # THEN: First value should be an empty list
+ self.assertEqual(result[0], [])
+
+ def test_get_open_file_names_user_accepts(self):
+ """
+ Test that `getOpenFileNames` handles the case when the user accepts the dialog
+ """
+ # GIVEN: PQFileDialog with a mocked QDialog.getOpenFileNames method
+ # WHEN: Calling PQFileDialog.getOpenFileNames, the user chooses some files and accepts the dialog (it returns a
+ # tuple with the first value set as a list of strings pointing to the file)
+ with patch('PyQt5.QtWidgets.QFileDialog.getOpenFileNames',
+ return_value=([os.path.join('test', 'chosen.file1'), os.path.join('test', 'chosen.file2')], '')):
+ result = PQFileDialog.getOpenFileNames()
+
+ # THEN: getOpenFileNames() should return a tuple with the first value set to a list of Path objects pointing
+ # to the chosen file
+ self.assertEqual(result[0], [Path('test', 'chosen.file1'), Path('test', 'chosen.file2')])
+
+ def test_get_open_file_names_selected_filter(self):
+ """
+ Test that `getOpenFileNames` does not modify the selectedFilter as returned by `QFileDialog.getOpenFileNames`
+ """
+ # GIVEN: PQFileDialog with a mocked QDialog.getOpenFileNames method
+ # WHEN: Calling PQFileDialog.getOpenFileNames, and `QFileDialog.getOpenFileNames` returns a known
+ # `selectedFilter`
+ with patch('PyQt5.QtWidgets.QFileDialog.getOpenFileNames', return_value=([], 'selected filter')):
+ result = PQFileDialog.getOpenFileNames()
+
+ # THEN: getOpenFileNames() should return a tuple with the second value set to a the selected filter
+ self.assertEqual(result[1], 'selected filter')
+
+ def test_get_save_file_name_user_abort(self):
+ """
+ Test that `getSaveFileName` handles the case when the user cancels the dialog
+ """
+ # GIVEN: PQFileDialog with a mocked QDialog.get_save_file_name method
+ # WHEN: Calling PQFileDialog.getSaveFileName and the user cancels the dialog (it returns a tuple with the first
+ # value set as an empty string)
+ with patch('PyQt5.QtWidgets.QFileDialog.getSaveFileName', return_value=('', '')):
+ result = PQFileDialog.getSaveFileName()
+
+ # THEN: First value should be None
+ self.assertEqual(result[0], None)
+
+ def test_get_save_file_name_user_accepts(self):
+ """
+ Test that `getSaveFileName` handles the case when the user accepts the dialog
+ """
+ # GIVEN: PQFileDialog with a mocked QDialog.getSaveFileName method
+ # WHEN: Calling PQFileDialog.getSaveFileName, the user chooses a file and accepts the dialog (it returns a
+ # tuple with the first value set as an string pointing to the file)
+ with patch('PyQt5.QtWidgets.QFileDialog.getSaveFileName',
+ return_value=(os.path.join('test', 'chosen.file'), '')):
+ result = PQFileDialog.getSaveFileName()
+
+ # THEN: getSaveFileName() should return a tuple with the first value set to a Path object pointing to the
+ # chosen file
+ self.assertEqual(result[0], Path('test', 'chosen.file'))
+
+ def test_get_save_file_name_selected_filter(self):
+ """
+ Test that `getSaveFileName` does not modify the selectedFilter as returned by `QFileDialog.getSaveFileName`
+ """
+ # GIVEN: PQFileDialog with a mocked QDialog.get_save_file_name method
+ # WHEN: Calling PQFileDialog.getSaveFileName, and `QFileDialog.getSaveFileName` returns a known `selectedFilter`
+ with patch('PyQt5.QtWidgets.QFileDialog.getSaveFileName', return_value=('', 'selected filter')):
+ result = PQFileDialog.getSaveFileName()
+
+ # THEN: getSaveFileName() should return a tuple with the second value set to a the selected filter
+ self.assertEqual(result[1], 'selected filter')
=== renamed file 'tests/functional/openlp_core_ui_lib/test_path_edit.py' => 'tests/functional/openlp_core_ui_lib/test_pathedit.py'
--- tests/functional/openlp_core_ui_lib/test_path_edit.py 2017-05-13 07:35:39 +0000
+++ tests/functional/openlp_core_ui_lib/test_pathedit.py 2017-08-04 22:00:43 +0000
@@ -22,12 +22,13 @@
"""
This module contains tests for the openlp.core.ui.lib.pathedit module
"""
+import os
+from pathlib import Path
from unittest import TestCase
-
-from PyQt5 import QtWidgets
+from unittest.mock import MagicMock, PropertyMock, patch
from openlp.core.ui.lib import PathEdit, PathType
-from unittest.mock import MagicMock, PropertyMock, patch
+from openlp.core.ui.lib.filedialogpatches import PQFileDialog
class TestPathEdit(TestCase):
@@ -43,11 +44,11 @@
Test the `path` property getter.
"""
# GIVEN: An instance of PathEdit with the `_path` instance variable set
- self.widget._path = 'getter/test/pat.h'
+ self.widget._path = Path('getter', 'test', 'pat.h')
# WHEN: Reading the `path` property
# THEN: The value that we set should be returned
- self.assertEqual(self.widget.path, 'getter/test/pat.h')
+ self.assertEqual(self.widget.path, Path('getter', 'test', 'pat.h'))
def test_path_setter(self):
"""
@@ -57,13 +58,13 @@
self.widget.line_edit = MagicMock()
# WHEN: Writing to the `path` property
- self.widget.path = 'setter/test/pat.h'
+ self.widget.path = Path('setter', 'test', 'pat.h')
# THEN: The `_path` instance variable should be set with the test data. The `line_edit` text and tooltip
# should have also been set.
- self.assertEqual(self.widget._path, 'setter/test/pat.h')
- self.widget.line_edit.setToolTip.assert_called_once_with('setter/test/pat.h')
- self.widget.line_edit.setText.assert_called_once_with('setter/test/pat.h')
+ self.assertEqual(self.widget._path, Path('setter', 'test', 'pat.h'))
+ self.widget.line_edit.setToolTip.assert_called_once_with(os.path.join('setter', 'test', 'pat.h'))
+ self.widget.line_edit.setText.assert_called_once_with(os.path.join('setter', 'test', 'pat.h'))
def test_path_type_getter(self):
"""
@@ -125,22 +126,20 @@
"""
# GIVEN: An instance of PathEdit with the `path_type` set to `Directories` and a mocked
# QFileDialog.getExistingDirectory
- with patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getExistingDirectory', return_value='') as \
+ with patch('openlp.core.ui.lib.pathedit.PQFileDialog.getExistingDirectory', return_value=None) as \
mocked_get_existing_directory, \
- patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getOpenFileName') as \
- mocked_get_open_file_name, \
- patch('openlp.core.ui.lib.pathedit.os.path.normpath') as mocked_normpath:
+ patch('openlp.core.ui.lib.pathedit.PQFileDialog.getOpenFileName') as mocked_get_open_file_name:
self.widget._path_type = PathType.Directories
- self.widget._path = 'test/path/'
+ self.widget._path = Path('test', 'path')
# WHEN: Calling on_browse_button_clicked
self.widget.on_browse_button_clicked()
# THEN: The FileDialog.getExistingDirectory should have been called with the default caption
- mocked_get_existing_directory.assert_called_once_with(self.widget, 'Select Directory', 'test/path/',
- QtWidgets.QFileDialog.ShowDirsOnly)
+ mocked_get_existing_directory.assert_called_once_with(self.widget, 'Select Directory',
+ Path('test', 'path'),
+ PQFileDialog.ShowDirsOnly)
self.assertFalse(mocked_get_open_file_name.called)
- self.assertFalse(mocked_normpath.called)
def test_on_browse_button_clicked_directory_custom_caption(self):
"""
@@ -149,45 +148,40 @@
"""
# GIVEN: An instance of PathEdit with the `path_type` set to `Directories` and a mocked
# QFileDialog.getExistingDirectory with `default_caption` set.
- with patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getExistingDirectory', return_value='') as \
+ with patch('openlp.core.ui.lib.pathedit.PQFileDialog.getExistingDirectory', return_value=None) as \
mocked_get_existing_directory, \
- patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getOpenFileName') as \
- mocked_get_open_file_name, \
- patch('openlp.core.ui.lib.pathedit.os.path.normpath') as mocked_normpath:
+ patch('openlp.core.ui.lib.pathedit.PQFileDialog.getOpenFileName') as mocked_get_open_file_name:
self.widget._path_type = PathType.Directories
- self.widget._path = 'test/path/'
+ self.widget._path = Path('test', 'path')
self.widget.dialog_caption = 'Directory Caption'
# WHEN: Calling on_browse_button_clicked
self.widget.on_browse_button_clicked()
# THEN: The FileDialog.getExistingDirectory should have been called with the custom caption
- mocked_get_existing_directory.assert_called_once_with(self.widget, 'Directory Caption', 'test/path/',
- QtWidgets.QFileDialog.ShowDirsOnly)
+ mocked_get_existing_directory.assert_called_once_with(self.widget, 'Directory Caption',
+ Path('test', 'path'),
+ PQFileDialog.ShowDirsOnly)
self.assertFalse(mocked_get_open_file_name.called)
- self.assertFalse(mocked_normpath.called)
def test_on_browse_button_clicked_file(self):
"""
Test the `browse_button` `clicked` handler on_browse_button_clicked when the `path_type` is set to Files.
"""
# GIVEN: An instance of PathEdit with the `path_type` set to `Files` and a mocked QFileDialog.getOpenFileName
- with patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getExistingDirectory') as \
- mocked_get_existing_directory, \
- patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getOpenFileName', return_value=('', '')) as \
- mocked_get_open_file_name, \
- patch('openlp.core.ui.lib.pathedit.os.path.normpath') as mocked_normpath:
+ with patch('openlp.core.ui.lib.pathedit.PQFileDialog.getExistingDirectory') as mocked_get_existing_directory, \
+ patch('openlp.core.ui.lib.pathedit.PQFileDialog.getOpenFileName', return_value=(None, '')) as \
+ mocked_get_open_file_name:
self.widget._path_type = PathType.Files
- self.widget._path = 'test/pat.h'
+ self.widget._path = Path('test', 'pat.h')
# WHEN: Calling on_browse_button_clicked
self.widget.on_browse_button_clicked()
# THEN: The FileDialog.getOpenFileName should have been called with the default caption
- mocked_get_open_file_name.assert_called_once_with(self.widget, 'Select File', 'test/pat.h',
+ mocked_get_open_file_name.assert_called_once_with(self.widget, 'Select File', Path('test', 'pat.h'),
self.widget.filters)
self.assertFalse(mocked_get_existing_directory.called)
- self.assertFalse(mocked_normpath.called)
def test_on_browse_button_clicked_file_custom_caption(self):
"""
@@ -196,23 +190,20 @@
"""
# GIVEN: An instance of PathEdit with the `path_type` set to `Files` and a mocked QFileDialog.getOpenFileName
# with `default_caption` set.
- with patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getExistingDirectory') as \
- mocked_get_existing_directory, \
- patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getOpenFileName', return_value=('', '')) as \
- mocked_get_open_file_name, \
- patch('openlp.core.ui.lib.pathedit.os.path.normpath') as mocked_normpath:
+ with patch('openlp.core.ui.lib.pathedit.PQFileDialog.getExistingDirectory') as mocked_get_existing_directory, \
+ patch('openlp.core.ui.lib.pathedit.PQFileDialog.getOpenFileName', return_value=(None, '')) as \
+ mocked_get_open_file_name:
self.widget._path_type = PathType.Files
- self.widget._path = 'test/pat.h'
+ self.widget._path = Path('test', 'pat.h')
self.widget.dialog_caption = 'File Caption'
# WHEN: Calling on_browse_button_clicked
self.widget.on_browse_button_clicked()
# THEN: The FileDialog.getOpenFileName should have been called with the custom caption
- mocked_get_open_file_name.assert_called_once_with(self.widget, 'File Caption', 'test/pat.h',
+ mocked_get_open_file_name.assert_called_once_with(self.widget, 'File Caption', Path('test', 'pat.h'),
self.widget.filters)
self.assertFalse(mocked_get_existing_directory.called)
- self.assertFalse(mocked_normpath.called)
def test_on_browse_button_clicked_user_cancels(self):
"""
@@ -221,16 +212,14 @@
"""
# GIVEN: An instance of PathEdit with a mocked QFileDialog.getOpenFileName which returns an empty str for the
# file path.
- with patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getOpenFileName', return_value=('', '')) as \
- mocked_get_open_file_name, \
- patch('openlp.core.ui.lib.pathedit.os.path.normpath') as mocked_normpath:
+ with patch('openlp.core.ui.lib.pathedit.PQFileDialog.getOpenFileName', return_value=(None, '')) as \
+ mocked_get_open_file_name:
# WHEN: Calling on_browse_button_clicked
self.widget.on_browse_button_clicked()
# THEN: normpath should not have been called
self.assertTrue(mocked_get_open_file_name.called)
- self.assertFalse(mocked_normpath.called)
def test_on_browse_button_clicked_user_accepts(self):
"""
@@ -239,9 +228,8 @@
"""
# GIVEN: An instance of PathEdit with a mocked QFileDialog.getOpenFileName which returns a str for the file
# path.
- with patch('openlp.core.ui.lib.pathedit.QtWidgets.QFileDialog.getOpenFileName',
- return_value=('/test/pat.h', '')) as mocked_get_open_file_name, \
- patch('openlp.core.ui.lib.pathedit.os.path.normpath') as mocked_normpath, \
+ with patch('openlp.core.ui.lib.pathedit.PQFileDialog.getOpenFileName',
+ return_value=(Path('test', 'pat.h'), '')) as mocked_get_open_file_name, \
patch.object(self.widget, 'on_new_path'):
# WHEN: Calling on_browse_button_clicked
@@ -249,7 +237,6 @@
# THEN: normpath and `on_new_path` should have been called
self.assertTrue(mocked_get_open_file_name.called)
- mocked_normpath.assert_called_once_with('/test/pat.h')
self.assertTrue(self.widget.on_new_path.called)
def test_on_revert_button_clicked(self):
@@ -258,13 +245,13 @@
"""
# GIVEN: An instance of PathEdit with a mocked `on_new_path`, and the `default_path` set.
with patch.object(self.widget, 'on_new_path') as mocked_on_new_path:
- self.widget.default_path = '/default/pat.h'
+ self.widget.default_path = Path('default', 'pat.h')
# WHEN: Calling `on_revert_button_clicked`
self.widget.on_revert_button_clicked()
# THEN: on_new_path should have been called with the default path
- mocked_on_new_path.assert_called_once_with('/default/pat.h')
+ mocked_on_new_path.assert_called_once_with(Path('default', 'pat.h'))
def test_on_line_edit_editing_finished(self):
"""
@@ -272,13 +259,13 @@
"""
# GIVEN: An instance of PathEdit with a mocked `line_edit` and `on_new_path`.
with patch.object(self.widget, 'on_new_path') as mocked_on_new_path:
- self.widget.line_edit = MagicMock(**{'text.return_value': '/test/pat.h'})
+ self.widget.line_edit = MagicMock(**{'text.return_value': 'test/pat.h'})
# WHEN: Calling `on_line_edit_editing_finished`
self.widget.on_line_edit_editing_finished()
# THEN: on_new_path should have been called with the path enetered in `line_edit`
- mocked_on_new_path.assert_called_once_with('/test/pat.h')
+ mocked_on_new_path.assert_called_once_with(Path('test', 'pat.h'))
def test_on_new_path_no_change(self):
"""
@@ -286,11 +273,11 @@
"""
# GIVEN: An instance of PathEdit with a test path and mocked `pathChanged` signal
with patch('openlp.core.ui.lib.pathedit.PathEdit.path', new_callable=PropertyMock):
- self.widget._path = '/old/test/pat.h'
+ self.widget._path = Path('/old', 'test', 'pat.h')
self.widget.pathChanged = MagicMock()
# WHEN: Calling `on_new_path` with the same path as the existing path
- self.widget.on_new_path('/old/test/pat.h')
+ self.widget.on_new_path(Path('/old', 'test', 'pat.h'))
# THEN: The `pathChanged` signal should not be emitted
self.assertFalse(self.widget.pathChanged.emit.called)
@@ -301,11 +288,11 @@
"""
# GIVEN: An instance of PathEdit with a test path and mocked `pathChanged` signal
with patch('openlp.core.ui.lib.pathedit.PathEdit.path', new_callable=PropertyMock):
- self.widget._path = '/old/test/pat.h'
+ self.widget._path = Path('/old', 'test', 'pat.h')
self.widget.pathChanged = MagicMock()
# WHEN: Calling `on_new_path` with the a new path
- self.widget.on_new_path('/new/test/pat.h')
+ self.widget.on_new_path(Path('/new', 'test', 'pat.h'))
# THEN: The `pathChanged` signal should be emitted
- self.widget.pathChanged.emit.assert_called_once_with('/new/test/pat.h')
+ self.widget.pathChanged.emit.assert_called_once_with(Path('/new', 'test', 'pat.h'))
Follow ups