Merge lp:~phill-ridout/openlp/pathlib1 into lp:openlp

Proposed by Phill
Status: Merged
Approved by: Raoul Snyman
Approved revision: 2757
Merged at revision: 2754
Proposed branch: lp:~phill-ridout/openlp/pathlib1
Merge into: lp:openlp
Diff against target: 1140 lines (+315/-148)
35 files modified
openlp/core/__init__.py (+4/-4)
openlp/core/common/__init__.py (+3/-3)
openlp/core/common/applocation.py (+62/-46)
openlp/core/common/languagemanager.py (+2/-2)
openlp/core/common/versionchecker.py (+1/-1)
openlp/core/lib/db.py (+2/-2)
openlp/core/lib/path.py (+61/-0)
openlp/core/lib/pluginmanager.py (+1/-1)
openlp/core/lib/serviceitem.py (+1/-1)
openlp/core/lib/theme.py (+1/-1)
openlp/core/ui/advancedtab.py (+4/-4)
openlp/core/ui/firsttimeform.py (+2/-2)
openlp/core/ui/maindisplay.py (+1/-1)
openlp/core/ui/mainwindow.py (+4/-4)
openlp/core/ui/printserviceform.py (+1/-1)
openlp/core/ui/servicemanager.py (+1/-1)
openlp/core/ui/thememanager.py (+3/-2)
openlp/plugins/bibles/forms/bibleimportform.py (+1/-1)
openlp/plugins/bibles/lib/db.py (+2/-2)
openlp/plugins/bibles/lib/importers/http.py (+2/-2)
openlp/plugins/bibles/lib/manager.py (+2/-2)
openlp/plugins/images/lib/mediaitem.py (+1/-1)
openlp/plugins/media/lib/mediaitem.py (+1/-1)
openlp/plugins/media/mediaplugin.py (+1/-1)
openlp/plugins/presentations/lib/pdfcontroller.py (+5/-5)
openlp/plugins/presentations/lib/pptviewcontroller.py (+1/-1)
openlp/plugins/presentations/lib/presentationcontroller.py (+3/-2)
openlp/plugins/remotes/lib/httprouter.py (+5/-5)
openlp/plugins/songs/forms/editsongform.py (+1/-1)
openlp/plugins/songs/lib/__init__.py (+1/-1)
openlp/plugins/songs/lib/importers/songimport.py (+1/-1)
openlp/plugins/songs/lib/mediaitem.py (+4/-3)
tests/functional/openlp_core_common/test_applocation.py (+29/-33)
tests/functional/openlp_core_common/test_common.py (+13/-10)
tests/functional/openlp_core_lib/test_path.py (+88/-0)
To merge this branch: bzr merge lp:~phill-ridout/openlp/pathlib1
Reviewer Review Type Date Requested Status
Raoul Snyman Approve
Tim Bentley Approve
Tomas Groth Pending
Review via email: mp+328435@code.launchpad.net

Description of the change

This is the first in a series of merges to switch to the pathlib module. As per tgc's request I am splitting this down into smaller parts for merging. As such, this merge works in itself, but is incomplete.

Please bear this in mind when reviewing

Also contains a fix for bible gateway

lp:~phill-ridout/openlp/pathlib1 (revision 2757)
[SUCCESS] https://ci.openlp.io/job/Branch-01-Pull/2108/
[SUCCESS] https://ci.openlp.io/job/Branch-02-Functional-Tests/2018/
[SUCCESS] https://ci.openlp.io/job/Branch-03-Interface-Tests/1929/
[SUCCESS] https://ci.openlp.io/job/Branch-04a-Code_Analysis/1306/
[SUCCESS] https://ci.openlp.io/job/Branch-04b-Test_Coverage/1150/
[SUCCESS] https://ci.openlp.io/job/Branch-04c-Code_Analysis2/280/
[SUCCESS] https://ci.openlp.io/job/Branch-05-AppVeyor-Tests/125/

To post a comment you must log in.
Revision history for this message
Tim Bentley (trb143) wrote :

See below

If we need to keep adding str to things should Application methods be internally wrapped with str not adding str all over the code.

review: Needs Fixing
Revision history for this message
Phill (phill-ridout) wrote :

> See below
>
> If we need to keep adding str to things should Application methods be
> internally wrapped with str not adding str all over the code.

This is only a temporary measure. Eventually, those strs will be removed and the rest of the code will changed to using Path objects. Just tgc asked me to break it up as the diff on my other branch was 15,000 lines and growing!

(https://code.launchpad.net/~phill-ridout/openlp/pathlib/+merge/326416/comments/855627)

Revision history for this message
Tim Bentley (trb143) wrote :

Now I understand this looks OK for a first phase.

review: Approve
Revision history for this message
Raoul Snyman (raoul-snyman) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'openlp/core/__init__.py'
2--- openlp/core/__init__.py 2017-05-30 18:42:35 +0000
3+++ openlp/core/__init__.py 2017-08-02 06:25:28 +0000
4@@ -181,7 +181,7 @@
5 """
6 Check if the data folder path exists.
7 """
8- data_folder_path = AppLocation.get_data_path()
9+ data_folder_path = str(AppLocation.get_data_path())
10 if not os.path.exists(data_folder_path):
11 log.critical('Database was not found in: ' + data_folder_path)
12 status = QtWidgets.QMessageBox.critical(None, translate('OpenLP', 'Data Directory Error'),
13@@ -253,7 +253,7 @@
14 'a backup of the old data folder?'),
15 defaultButton=QtWidgets.QMessageBox.Yes) == QtWidgets.QMessageBox.Yes:
16 # Create copy of data folder
17- data_folder_path = AppLocation.get_data_path()
18+ data_folder_path = str(AppLocation.get_data_path())
19 timestamp = time.strftime("%Y%m%d-%H%M%S")
20 data_folder_backup_path = data_folder_path + '-' + timestamp
21 try:
22@@ -390,7 +390,7 @@
23 application.setApplicationName('OpenLPPortable')
24 Settings.setDefaultFormat(Settings.IniFormat)
25 # Get location OpenLPPortable.ini
26- application_path = AppLocation.get_directory(AppLocation.AppDir)
27+ application_path = str(AppLocation.get_directory(AppLocation.AppDir))
28 set_up_logging(os.path.abspath(os.path.join(application_path, '..', '..', 'Other')))
29 log.info('Running portable')
30 portable_settings_file = os.path.abspath(os.path.join(application_path, '..', '..', 'Data', 'OpenLP.ini'))
31@@ -407,7 +407,7 @@
32 portable_settings.sync()
33 else:
34 application.setApplicationName('OpenLP')
35- set_up_logging(AppLocation.get_directory(AppLocation.CacheDir))
36+ set_up_logging(str(AppLocation.get_directory(AppLocation.CacheDir)))
37 Registry.create()
38 Registry().register('application', application)
39 application.setApplicationVersion(get_application_version()['version'])
40
41=== modified file 'openlp/core/common/__init__.py'
42--- openlp/core/common/__init__.py 2017-05-24 20:01:46 +0000
43+++ openlp/core/common/__init__.py 2017-08-02 06:25:28 +0000
44@@ -95,9 +95,9 @@
45 :return: None
46 :rtype: None
47 """
48- app_dir = Path(AppLocation.get_directory(AppLocation.AppDir)).parent
49- for extension_path in app_dir.glob(glob_pattern):
50- extension_path = extension_path.relative_to(app_dir)
51+ base_dir_path = AppLocation.get_directory(AppLocation.AppDir).parent
52+ for extension_path in base_dir_path.glob(glob_pattern):
53+ extension_path = extension_path.relative_to(base_dir_path)
54 if extension_path.name in excluded_files:
55 continue
56 module_name = path_to_module(extension_path)
57
58=== modified file 'openlp/core/common/applocation.py'
59--- openlp/core/common/applocation.py 2016-12-31 11:01:36 +0000
60+++ openlp/core/common/applocation.py 2017-08-02 06:25:28 +0000
61@@ -25,6 +25,7 @@
62 import logging
63 import os
64 import sys
65+from pathlib import Path
66
67 from openlp.core.common import Settings, is_win, is_macosx
68
69@@ -42,6 +43,9 @@
70
71 log = logging.getLogger(__name__)
72
73+FROZEN_APP_PATH = Path(sys.argv[0]).parent
74+APP_PATH = Path(openlp.__file__).parent
75+
76
77 class AppLocation(object):
78 """
79@@ -63,20 +67,19 @@
80 Return the appropriate directory according to the directory type.
81
82 :param dir_type: The directory type you want, for instance the data directory. Default *AppLocation.AppDir*
83+ :type dir_type: AppLocation Enum
84+
85+ :return: The requested path
86+ :rtype: pathlib.Path
87 """
88- if dir_type == AppLocation.AppDir:
89- return get_frozen_path(os.path.abspath(os.path.dirname(sys.argv[0])), os.path.dirname(openlp.__file__))
90+ if dir_type == AppLocation.AppDir or dir_type == AppLocation.VersionDir:
91+ return get_frozen_path(FROZEN_APP_PATH, APP_PATH)
92 elif dir_type == AppLocation.PluginsDir:
93- app_path = os.path.abspath(os.path.dirname(sys.argv[0]))
94- return get_frozen_path(os.path.join(app_path, 'plugins'),
95- os.path.join(os.path.dirname(openlp.__file__), 'plugins'))
96- elif dir_type == AppLocation.VersionDir:
97- return get_frozen_path(os.path.abspath(os.path.dirname(sys.argv[0])), os.path.dirname(openlp.__file__))
98+ return get_frozen_path(FROZEN_APP_PATH, APP_PATH) / 'plugins'
99 elif dir_type == AppLocation.LanguageDir:
100- app_path = get_frozen_path(os.path.abspath(os.path.dirname(sys.argv[0])), _get_os_dir_path(dir_type))
101- return os.path.join(app_path, 'i18n')
102+ return get_frozen_path(FROZEN_APP_PATH, _get_os_dir_path(dir_type)) / 'i18n'
103 elif dir_type == AppLocation.DataDir and AppLocation.BaseDir:
104- return os.path.join(AppLocation.BaseDir, 'data')
105+ return Path(AppLocation.BaseDir, 'data')
106 else:
107 return _get_os_dir_path(dir_type)
108
109@@ -84,84 +87,97 @@
110 def get_data_path():
111 """
112 Return the path OpenLP stores all its data under.
113+
114+ :return: The data path to use.
115+ :rtype: pathlib.Path
116 """
117 # Check if we have a different data location.
118 if Settings().contains('advanced/data path'):
119- path = Settings().value('advanced/data path')
120+ path = Path(Settings().value('advanced/data path'))
121 else:
122 path = AppLocation.get_directory(AppLocation.DataDir)
123- check_directory_exists(path)
124- return os.path.normpath(path)
125+ check_directory_exists(str(path))
126+ return path
127
128 @staticmethod
129- def get_files(section=None, extension=None):
130+ def get_files(section=None, extension=''):
131 """
132 Get a list of files from the data files path.
133
134- :param section: Defaults to *None*. The section of code getting the files - used to load from a section's
135- data subdirectory.
136- :param extension:
137- Defaults to *None*. The extension to search for. For example::
138-
139- '.png'
140+ :param section: Defaults to *None*. The section of code getting the files - used to load from a section's data
141+ subdirectory.
142+ :type section: None | str
143+
144+ :param extension: Defaults to ''. The extension to search for. For example::
145+ '.png'
146+ :type extension: str
147+
148+ :return: List of files found.
149+ :rtype: list[pathlib.Path]
150 """
151 path = AppLocation.get_data_path()
152 if section:
153- path = os.path.join(path, section)
154+ path = path / section
155 try:
156- files = os.listdir(path)
157+ file_paths = path.glob('*' + extension)
158+ return [file_path.relative_to(path) for file_path in file_paths]
159 except OSError:
160 return []
161- if extension:
162- return [filename for filename in files if extension == os.path.splitext(filename)[1]]
163- else:
164- # no filtering required
165- return files
166
167 @staticmethod
168 def get_section_data_path(section):
169 """
170 Return the path a particular module stores its data under.
171+
172+ :type section: str
173+
174+ :rtype: pathlib.Path
175 """
176- data_path = AppLocation.get_data_path()
177- path = os.path.join(data_path, section)
178- check_directory_exists(path)
179+ path = AppLocation.get_data_path() / section
180+ check_directory_exists(str(path))
181 return path
182
183
184 def _get_os_dir_path(dir_type):
185 """
186 Return a path based on which OS and environment we are running in.
187+
188+ :param dir_type: AppLocation Enum of the requested path type
189+ :type dir_type: AppLocation Enum
190+
191+ :return: The requested path
192+ :rtype: pathlib.Path
193 """
194 # If running from source, return the language directory from the source directory
195 if dir_type == AppLocation.LanguageDir:
196- directory = os.path.abspath(os.path.join(os.path.dirname(openlp.__file__), '..', 'resources'))
197- if os.path.exists(directory):
198+ directory = Path(os.path.abspath(os.path.join(os.path.dirname(openlp.__file__), '..', 'resources')))
199+ if directory.exists():
200 return directory
201 if is_win():
202+ openlp_folder_path = Path(os.getenv('APPDATA'), 'openlp')
203 if dir_type == AppLocation.DataDir:
204- return os.path.join(str(os.getenv('APPDATA')), 'openlp', 'data')
205+ return openlp_folder_path / 'data'
206 elif dir_type == AppLocation.LanguageDir:
207 return os.path.dirname(openlp.__file__)
208- return os.path.join(str(os.getenv('APPDATA')), 'openlp')
209+ return openlp_folder_path
210 elif is_macosx():
211+ openlp_folder_path = Path(os.getenv('HOME'), 'Library', 'Application Support', 'openlp')
212 if dir_type == AppLocation.DataDir:
213- return os.path.join(str(os.getenv('HOME')), 'Library', 'Application Support', 'openlp', 'Data')
214+ return openlp_folder_path / 'Data'
215 elif dir_type == AppLocation.LanguageDir:
216 return os.path.dirname(openlp.__file__)
217- return os.path.join(str(os.getenv('HOME')), 'Library', 'Application Support', 'openlp')
218+ return openlp_folder_path
219 else:
220 if dir_type == AppLocation.LanguageDir:
221- for prefix in ['/usr/local', '/usr']:
222- directory = os.path.join(prefix, 'share', 'openlp')
223- if os.path.exists(directory):
224- return directory
225- return os.path.join('/usr', 'share', 'openlp')
226+ directory = Path('/usr', 'local', 'share', 'openlp')
227+ if directory.exists():
228+ return directory
229+ return Path('/usr', 'share', 'openlp')
230 if XDG_BASE_AVAILABLE:
231- if dir_type == AppLocation.DataDir:
232- return os.path.join(str(BaseDirectory.xdg_data_home), 'openlp')
233+ if dir_type == AppLocation.DataDir or dir_type == AppLocation.CacheDir:
234+ return Path(BaseDirectory.xdg_data_home, 'openlp')
235 elif dir_type == AppLocation.CacheDir:
236- return os.path.join(str(BaseDirectory.xdg_cache_home), 'openlp')
237+ return Path(BaseDirectory.xdg_cache_home, 'openlp')
238 if dir_type == AppLocation.DataDir:
239- return os.path.join(str(os.getenv('HOME')), '.openlp', 'data')
240- return os.path.join(str(os.getenv('HOME')), '.openlp')
241+ return Path(os.getenv('HOME'), '.openlp', 'data')
242+ return Path(os.getenv('HOME'), '.openlp')
243
244=== modified file 'openlp/core/common/languagemanager.py'
245--- openlp/core/common/languagemanager.py 2017-05-30 18:42:35 +0000
246+++ openlp/core/common/languagemanager.py 2017-08-02 06:25:28 +0000
247@@ -53,7 +53,7 @@
248 """
249 if LanguageManager.auto_language:
250 language = QtCore.QLocale.system().name()
251- lang_path = AppLocation.get_directory(AppLocation.LanguageDir)
252+ lang_path = str(AppLocation.get_directory(AppLocation.LanguageDir))
253 app_translator = QtCore.QTranslator()
254 app_translator.load(language, lang_path)
255 # A translator for buttons and other default strings provided by Qt.
256@@ -72,7 +72,7 @@
257 Find all available language files in this OpenLP install
258 """
259 log.debug('Translation files: {files}'.format(files=AppLocation.get_directory(AppLocation.LanguageDir)))
260- trans_dir = QtCore.QDir(AppLocation.get_directory(AppLocation.LanguageDir))
261+ trans_dir = QtCore.QDir(str(AppLocation.get_directory(AppLocation.LanguageDir)))
262 file_names = trans_dir.entryList(['*.qm'], QtCore.QDir.Files, QtCore.QDir.Name)
263 # Remove qm files from the list which start with "qt".
264 file_names = [file_ for file_ in file_names if not file_.startswith('qt')]
265
266=== modified file 'openlp/core/common/versionchecker.py'
267--- openlp/core/common/versionchecker.py 2016-07-01 21:17:20 +0000
268+++ openlp/core/common/versionchecker.py 2017-08-02 06:25:28 +0000
269@@ -95,7 +95,7 @@
270 full_version = '{tag}-bzr{tree}'.format(tag=tag_version.strip(), tree=tree_revision.strip())
271 else:
272 # We're not running the development version, let's use the file.
273- file_path = AppLocation.get_directory(AppLocation.VersionDir)
274+ file_path = str(AppLocation.get_directory(AppLocation.VersionDir))
275 file_path = os.path.join(file_path, '.version')
276 version_file = None
277 try:
278
279=== modified file 'openlp/core/lib/db.py'
280--- openlp/core/lib/db.py 2017-06-09 14:04:52 +0000
281+++ openlp/core/lib/db.py 2017-08-02 06:25:28 +0000
282@@ -274,9 +274,9 @@
283 :param db_file_name: The database file name. Defaults to None resulting in the plugin_name being used.
284 """
285 if db_file_name:
286- db_file_path = os.path.join(AppLocation.get_section_data_path(plugin_name), db_file_name)
287+ db_file_path = os.path.join(str(AppLocation.get_section_data_path(plugin_name)), db_file_name)
288 else:
289- db_file_path = os.path.join(AppLocation.get_section_data_path(plugin_name), plugin_name)
290+ db_file_path = os.path.join(str(AppLocation.get_section_data_path(plugin_name)), plugin_name)
291 return delete_file(db_file_path)
292
293
294
295=== added file 'openlp/core/lib/path.py'
296--- openlp/core/lib/path.py 1970-01-01 00:00:00 +0000
297+++ openlp/core/lib/path.py 2017-08-02 06:25:28 +0000
298@@ -0,0 +1,61 @@
299+# -*- coding: utf-8 -*-
300+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
301+
302+###############################################################################
303+# OpenLP - Open Source Lyrics Projection #
304+# --------------------------------------------------------------------------- #
305+# Copyright (c) 2008-2017 OpenLP Developers #
306+# --------------------------------------------------------------------------- #
307+# This program is free software; you can redistribute it and/or modify it #
308+# under the terms of the GNU General Public License as published by the Free #
309+# Software Foundation; version 2 of the License. #
310+# #
311+# This program is distributed in the hope that it will be useful, but WITHOUT #
312+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
313+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
314+# more details. #
315+# #
316+# You should have received a copy of the GNU General Public License along #
317+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
318+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
319+###############################################################################
320+
321+from pathlib import Path
322+
323+
324+def path_to_str(path):
325+ """
326+ A utility function to convert a Path object or NoneType to a string equivalent.
327+
328+ :param path: The value to convert to a string
329+ :type: pathlib.Path or None
330+
331+ :return: An empty string if :param:`path` is None, else a string representation of the :param:`path`
332+ :rtype: str
333+ """
334+ if not isinstance(path, Path) and path is not None:
335+ raise TypeError('parameter \'path\' must be of type Path or NoneType')
336+ if path is None:
337+ return ''
338+ else:
339+ return str(path)
340+
341+
342+def str_to_path(string):
343+ """
344+ A utility function to convert a str object to a Path or NoneType.
345+
346+ This function is of particular use because initating a Path object with an empty string causes the Path object to
347+ point to the current working directory.
348+
349+ :param string: The string to convert
350+ :type string: str
351+
352+ :return: None if :param:`string` is empty, or a Path object representation of :param:`string`
353+ :rtype: pathlib.Path or None
354+ """
355+ if not isinstance(string, str):
356+ raise TypeError('parameter \'string\' must be of type str')
357+ if string == '':
358+ return None
359+ return Path(string)
360
361=== modified file 'openlp/core/lib/pluginmanager.py'
362--- openlp/core/lib/pluginmanager.py 2017-05-15 10:09:59 +0000
363+++ openlp/core/lib/pluginmanager.py 2017-08-02 06:25:28 +0000
364@@ -40,7 +40,7 @@
365 """
366 super(PluginManager, self).__init__(parent)
367 self.log_info('Plugin manager Initialising')
368- self.base_path = os.path.abspath(AppLocation.get_directory(AppLocation.PluginsDir))
369+ self.base_path = os.path.abspath(str(AppLocation.get_directory(AppLocation.PluginsDir)))
370 self.log_debug('Base path {path}'.format(path=self.base_path))
371 self.plugins = []
372 self.log_info('Plugin manager Initialised')
373
374=== modified file 'openlp/core/lib/serviceitem.py'
375--- openlp/core/lib/serviceitem.py 2017-05-17 20:06:45 +0000
376+++ openlp/core/lib/serviceitem.py 2017-08-02 06:25:28 +0000
377@@ -335,7 +335,7 @@
378 if image and not self.has_original_files and self.name == 'presentations':
379 file_location = os.path.join(path, file_name)
380 file_location_hash = md5_hash(file_location.encode('utf-8'))
381- image = os.path.join(AppLocation.get_section_data_path(self.name), 'thumbnails',
382+ image = os.path.join(str(AppLocation.get_section_data_path(self.name)), 'thumbnails',
383 file_location_hash, ntpath.basename(image))
384 self._raw_frames.append({'title': file_name, 'image': image, 'path': path,
385 'display_title': display_title, 'notes': notes})
386
387=== modified file 'openlp/core/lib/theme.py'
388--- openlp/core/lib/theme.py 2017-05-24 19:55:30 +0000
389+++ openlp/core/lib/theme.py 2017-08-02 06:25:28 +0000
390@@ -158,7 +158,7 @@
391 Initialise the theme object.
392 """
393 # basic theme object with defaults
394- json_dir = os.path.join(AppLocation.get_directory(AppLocation.AppDir), 'core', 'lib', 'json')
395+ json_dir = os.path.join(str(AppLocation.get_directory(AppLocation.AppDir)), 'core', 'lib', 'json')
396 json_file = os.path.join(json_dir, 'theme.json')
397 jsn = get_text_file_string(json_file)
398 jsn = json.loads(jsn)
399
400=== modified file 'openlp/core/ui/advancedtab.py'
401--- openlp/core/ui/advancedtab.py 2017-05-30 18:50:39 +0000
402+++ openlp/core/ui/advancedtab.py 2017-08-02 06:25:28 +0000
403@@ -156,7 +156,7 @@
404 self.data_directory_new_label = QtWidgets.QLabel(self.data_directory_group_box)
405 self.data_directory_new_label.setObjectName('data_directory_current_label')
406 self.data_directory_path_edit = PathEdit(self.data_directory_group_box, path_type=PathType.Directories,
407- default_path=AppLocation.get_directory(AppLocation.DataDir))
408+ default_path=str(AppLocation.get_directory(AppLocation.DataDir)))
409 self.data_directory_layout.addRow(self.data_directory_new_label, self.data_directory_path_edit)
410 self.new_data_directory_has_files_label = QtWidgets.QLabel(self.data_directory_group_box)
411 self.new_data_directory_has_files_label.setObjectName('new_data_directory_has_files_label')
412@@ -373,7 +373,7 @@
413 self.new_data_directory_has_files_label.hide()
414 self.data_directory_cancel_button.hide()
415 # Since data location can be changed, make sure the path is present.
416- self.data_directory_path_edit.path = AppLocation.get_data_path()
417+ self.data_directory_path_edit.path = str(AppLocation.get_data_path())
418 # Don't allow data directory move if running portable.
419 if settings.value('advanced/is portable'):
420 self.data_directory_group_box.hide()
421@@ -497,7 +497,7 @@
422 'closed.').format(path=new_data_path),
423 defaultButton=QtWidgets.QMessageBox.No)
424 if answer != QtWidgets.QMessageBox.Yes:
425- self.data_directory_path_edit.path = AppLocation.get_data_path()
426+ self.data_directory_path_edit.path = str(AppLocation.get_data_path())
427 return
428 # Check if data already exists here.
429 self.check_data_overwrite(new_data_path)
430@@ -550,7 +550,7 @@
431 """
432 Cancel the data directory location change
433 """
434- self.data_directory_path_edit.path = AppLocation.get_data_path()
435+ self.data_directory_path_edit.path = str(AppLocation.get_data_path())
436 self.data_directory_copy_check_box.setChecked(False)
437 self.main_window.set_new_data_path(None)
438 self.main_window.set_copy_data(False)
439
440=== modified file 'openlp/core/ui/firsttimeform.py'
441--- openlp/core/ui/firsttimeform.py 2017-05-30 18:42:35 +0000
442+++ openlp/core/ui/firsttimeform.py 2017-08-02 06:25:28 +0000
443@@ -554,8 +554,8 @@
444 """
445 # Build directories for downloads
446 songs_destination = os.path.join(gettempdir(), 'openlp')
447- bibles_destination = AppLocation.get_section_data_path('bibles')
448- themes_destination = AppLocation.get_section_data_path('themes')
449+ bibles_destination = str(AppLocation.get_section_data_path('bibles'))
450+ themes_destination = str(AppLocation.get_section_data_path('themes'))
451 missed_files = []
452 # Download songs
453 for i in range(self.songs_list_widget.count()):
454
455=== modified file 'openlp/core/ui/maindisplay.py'
456--- openlp/core/ui/maindisplay.py 2017-06-04 12:26:50 +0000
457+++ openlp/core/ui/maindisplay.py 2017-08-02 06:25:28 +0000
458@@ -484,7 +484,7 @@
459 service_item = ServiceItem()
460 service_item.title = 'webkit'
461 service_item.processor = 'webkit'
462- path = os.path.join(AppLocation.get_section_data_path('themes'),
463+ path = os.path.join(str(AppLocation.get_section_data_path('themes')),
464 self.service_item.theme_data.theme_name)
465 service_item.add_from_command(path,
466 self.service_item.theme_data.background_filename,
467
468=== modified file 'openlp/core/ui/mainwindow.py'
469--- openlp/core/ui/mainwindow.py 2017-05-30 18:42:35 +0000
470+++ openlp/core/ui/mainwindow.py 2017-08-02 06:25:28 +0000
471@@ -305,9 +305,9 @@
472 # Give QT Extra Hint that this is an About Menu Item
473 self.about_item.setMenuRole(QtWidgets.QAction.AboutRole)
474 if is_win():
475- self.local_help_file = os.path.join(AppLocation.get_directory(AppLocation.AppDir), 'OpenLP.chm')
476+ self.local_help_file = os.path.join(str(AppLocation.get_directory(AppLocation.AppDir)), 'OpenLP.chm')
477 elif is_macosx():
478- self.local_help_file = os.path.join(AppLocation.get_directory(AppLocation.AppDir),
479+ self.local_help_file = os.path.join(str(AppLocation.get_directory(AppLocation.AppDir)),
480 '..', 'Resources', 'OpenLP.help')
481 self.user_manual_item = create_action(main_window, 'userManualItem', icon=':/system/system_help_contents.png',
482 can_shortcuts=True, category=UiStrings().Help,
483@@ -788,7 +788,7 @@
484 """
485 Open data folder
486 """
487- path = AppLocation.get_data_path()
488+ path = str(AppLocation.get_data_path())
489 QtGui.QDesktopServices.openUrl(QtCore.QUrl.fromLocalFile(path))
490
491 def on_update_theme_images(self):
492@@ -1438,7 +1438,7 @@
493 settings = QtCore.QSettings()
494 settings.setValue('advanced/data path', self.new_data_path)
495 # Check if the new data path is our default.
496- if self.new_data_path == AppLocation.get_directory(AppLocation.DataDir):
497+ if self.new_data_path == str(AppLocation.get_directory(AppLocation.DataDir)):
498 settings.remove('advanced/data path')
499 self.application.set_normal_cursor()
500
501
502=== modified file 'openlp/core/ui/printserviceform.py'
503--- openlp/core/ui/printserviceform.py 2017-06-04 12:14:23 +0000
504+++ openlp/core/ui/printserviceform.py 2017-08-02 06:25:28 +0000
505@@ -176,7 +176,7 @@
506 html_data = self._add_element('html')
507 self._add_element('head', parent=html_data)
508 self._add_element('title', self.title_line_edit.text(), html_data.head)
509- css_path = os.path.join(AppLocation.get_data_path(), 'serviceprint', 'service_print.css')
510+ css_path = os.path.join(str(AppLocation.get_data_path()), 'serviceprint', 'service_print.css')
511 custom_css = get_text_file_string(css_path)
512 if not custom_css:
513 custom_css = DEFAULT_CSS
514
515=== modified file 'openlp/core/ui/servicemanager.py'
516--- openlp/core/ui/servicemanager.py 2017-06-27 17:42:54 +0000
517+++ openlp/core/ui/servicemanager.py 2017-08-02 06:25:28 +0000
518@@ -223,7 +223,7 @@
519 self.service_manager_list.itemExpanded.connect(self.expanded)
520 # Last little bits of setting up
521 self.service_theme = Settings().value(self.main_window.service_manager_settings_section + '/service theme')
522- self.service_path = AppLocation.get_section_data_path('servicemanager')
523+ self.service_path = str(AppLocation.get_section_data_path('servicemanager'))
524 # build the drag and drop context menu
525 self.dnd_menu = QtWidgets.QMenu()
526 self.new_action = self.dnd_menu.addAction(translate('OpenLP.ServiceManager', '&Add New Item'))
527
528=== modified file 'openlp/core/ui/thememanager.py'
529--- openlp/core/ui/thememanager.py 2017-06-01 06:18:47 +0000
530+++ openlp/core/ui/thememanager.py 2017-08-02 06:25:28 +0000
531@@ -159,7 +159,7 @@
532 """
533 Set up the theme path variables
534 """
535- self.path = AppLocation.get_section_data_path(self.settings_section)
536+ self.path = str(AppLocation.get_section_data_path(self.settings_section))
537 check_directory_exists(self.path)
538 self.thumb_path = os.path.join(self.path, 'thumbnails')
539 check_directory_exists(self.thumb_path)
540@@ -445,7 +445,7 @@
541 self.application.set_busy_cursor()
542 files = AppLocation.get_files(self.settings_section, '.otz')
543 for theme_file in files:
544- theme_file = os.path.join(self.path, theme_file)
545+ theme_file = os.path.join(self.path, str(theme_file))
546 self.unzip_theme(theme_file, self.path)
547 delete_file(theme_file)
548 files = AppLocation.get_files(self.settings_section, '.png')
549@@ -470,6 +470,7 @@
550 files.sort(key=lambda file_name: get_locale_key(str(file_name)))
551 # now process the file list of png files
552 for name in files:
553+ name = str(name)
554 # check to see file is in theme root directory
555 theme = os.path.join(self.path, name)
556 if os.path.exists(theme):
557
558=== modified file 'openlp/plugins/bibles/forms/bibleimportform.py'
559--- openlp/plugins/bibles/forms/bibleimportform.py 2017-05-30 18:50:39 +0000
560+++ openlp/plugins/bibles/forms/bibleimportform.py 2017-08-02 06:25:28 +0000
561@@ -584,7 +584,7 @@
562 elif self.currentPage() == self.license_details_page:
563 license_version = self.field('license_version')
564 license_copyright = self.field('license_copyright')
565- path = AppLocation.get_section_data_path('bibles')
566+ path = str(AppLocation.get_section_data_path('bibles'))
567 if not license_version:
568 critical_error_message_box(
569 UiStrings().EmptyField,
570
571=== modified file 'openlp/plugins/bibles/lib/db.py'
572--- openlp/plugins/bibles/lib/db.py 2017-06-01 06:18:47 +0000
573+++ openlp/plugins/bibles/lib/db.py 2017-08-02 06:25:28 +0000
574@@ -470,7 +470,7 @@
575 Return the cursor object. Instantiate one if it doesn't exist yet.
576 """
577 if BiblesResourcesDB.cursor is None:
578- file_path = os.path.join(AppLocation.get_directory(AppLocation.PluginsDir),
579+ file_path = os.path.join(str(AppLocation.get_directory(AppLocation.PluginsDir)),
580 'bibles', 'resources', 'bibles_resources.sqlite')
581 conn = sqlite3.connect(file_path)
582 BiblesResourcesDB.cursor = conn.cursor()
583@@ -759,7 +759,7 @@
584 """
585 if AlternativeBookNamesDB.cursor is None:
586 file_path = os.path.join(
587- AppLocation.get_directory(AppLocation.DataDir), 'bibles', 'alternative_book_names.sqlite')
588+ str(AppLocation.get_directory(AppLocation.DataDir)), 'bibles', 'alternative_book_names.sqlite')
589 if not os.path.exists(file_path):
590 # create new DB, create table alternative_book_names
591 AlternativeBookNamesDB.conn = sqlite3.connect(file_path)
592
593=== modified file 'openlp/plugins/bibles/lib/importers/http.py'
594--- openlp/plugins/bibles/lib/importers/http.py 2017-05-30 18:42:35 +0000
595+++ openlp/plugins/bibles/lib/importers/http.py 2017-08-02 06:25:28 +0000
596@@ -325,7 +325,7 @@
597 returns a list in the form [(biblename, biblekey, language_code)]
598 """
599 log.debug('BGExtract.get_bibles_from_http')
600- bible_url = 'https://biblegateway.com/versions/'
601+ bible_url = 'https://www.biblegateway.com/versions/'
602 soup = get_soup_for_bible_ref(bible_url)
603 if not soup:
604 return None
605@@ -773,7 +773,7 @@
606 return None
607 try:
608 page = get_web_page(reference_url, header, True)
609- except:
610+ except Exception as e:
611 page = None
612 if not page:
613 send_error_message('download')
614
615=== modified file 'openlp/plugins/bibles/lib/manager.py'
616--- openlp/plugins/bibles/lib/manager.py 2017-05-26 13:30:54 +0000
617+++ openlp/plugins/bibles/lib/manager.py 2017-08-02 06:25:28 +0000
618@@ -111,7 +111,7 @@
619 self.settings_section = 'bibles'
620 self.web = 'Web'
621 self.db_cache = None
622- self.path = AppLocation.get_section_data_path(self.settings_section)
623+ self.path = str(AppLocation.get_section_data_path(self.settings_section))
624 self.proxy_name = Settings().value(self.settings_section + '/proxy name')
625 self.suffix = '.sqlite'
626 self.import_wizard = None
627@@ -124,7 +124,7 @@
628 of HTTPBible is loaded instead of the BibleDB class.
629 """
630 log.debug('Reload bibles')
631- files = AppLocation.get_files(self.settings_section, self.suffix)
632+ files = [str(file) for file in AppLocation.get_files(self.settings_section, self.suffix)]
633 if 'alternative_book_names.sqlite' in files:
634 files.remove('alternative_book_names.sqlite')
635 log.debug('Bible Files {text}'.format(text=files))
636
637=== modified file 'openlp/plugins/images/lib/mediaitem.py'
638--- openlp/plugins/images/lib/mediaitem.py 2017-05-30 18:42:35 +0000
639+++ openlp/plugins/images/lib/mediaitem.py 2017-08-02 06:25:28 +0000
640@@ -98,7 +98,7 @@
641 self.list_view.setIconSize(QtCore.QSize(88, 50))
642 self.list_view.setIndentation(self.list_view.default_indentation)
643 self.list_view.allow_internal_dnd = True
644- self.service_path = os.path.join(AppLocation.get_section_data_path(self.settings_section), 'thumbnails')
645+ self.service_path = os.path.join(str(AppLocation.get_section_data_path(self.settings_section)), 'thumbnails')
646 check_directory_exists(self.service_path)
647 # Load images from the database
648 self.load_full_list(
649
650=== modified file 'openlp/plugins/media/lib/mediaitem.py'
651--- openlp/plugins/media/lib/mediaitem.py 2016-12-31 11:01:36 +0000
652+++ openlp/plugins/media/lib/mediaitem.py 2017-08-02 06:25:28 +0000
653@@ -300,7 +300,7 @@
654 Initialize media item.
655 """
656 self.list_view.clear()
657- self.service_path = os.path.join(AppLocation.get_section_data_path(self.settings_section), 'thumbnails')
658+ self.service_path = os.path.join(str(AppLocation.get_section_data_path(self.settings_section)), 'thumbnails')
659 check_directory_exists(self.service_path)
660 self.load_list(Settings().value(self.settings_section + '/media files'))
661 self.rebuild_players()
662
663=== modified file 'openlp/plugins/media/mediaplugin.py'
664--- openlp/plugins/media/mediaplugin.py 2016-12-31 11:01:36 +0000
665+++ openlp/plugins/media/mediaplugin.py 2017-08-02 06:25:28 +0000
666@@ -75,7 +75,7 @@
667 exists = process_check_binary('mediainfo')
668 # If mediainfo is not in the path, try to find it in the application folder
669 if not exists:
670- exists = process_check_binary(os.path.join(AppLocation.get_directory(AppLocation.AppDir), 'mediainfo'))
671+ exists = process_check_binary(os.path.join(str(AppLocation.get_directory(AppLocation.AppDir)), 'mediainfo'))
672 return exists
673
674 def app_startup(self):
675
676=== modified file 'openlp/plugins/presentations/lib/pdfcontroller.py'
677--- openlp/plugins/presentations/lib/pdfcontroller.py 2017-05-30 18:50:39 +0000
678+++ openlp/plugins/presentations/lib/pdfcontroller.py 2017-08-02 06:25:28 +0000
679@@ -122,10 +122,10 @@
680 self.mutoolbin = pdf_program
681 else:
682 # Fallback to autodetection
683- application_path = AppLocation.get_directory(AppLocation.AppDir)
684+ application_path = str(AppLocation.get_directory(AppLocation.AppDir))
685 if is_win():
686 # for windows we only accept mudraw.exe or mutool.exe in the base folder
687- application_path = AppLocation.get_directory(AppLocation.AppDir)
688+ application_path = str(AppLocation.get_directory(AppLocation.AppDir))
689 if os.path.isfile(os.path.join(application_path, 'mudraw.exe')):
690 self.mudrawbin = os.path.join(application_path, 'mudraw.exe')
691 elif os.path.isfile(os.path.join(application_path, 'mutool.exe')):
692@@ -142,7 +142,7 @@
693 self.gsbin = which('gs')
694 # Last option: check if mudraw or mutool is placed in OpenLP base folder
695 if not self.mudrawbin and not self.mutoolbin and not self.gsbin:
696- application_path = AppLocation.get_directory(AppLocation.AppDir)
697+ application_path = str(AppLocation.get_directory(AppLocation.AppDir))
698 if os.path.isfile(os.path.join(application_path, 'mudraw')):
699 self.mudrawbin = os.path.join(application_path, 'mudraw')
700 elif os.path.isfile(os.path.join(application_path, 'mutool')):
701@@ -199,8 +199,8 @@
702 :return: The resolution dpi to be used.
703 """
704 # Use a postscript script to get size of the pdf. It is assumed that all pages have same size
705- gs_resolution_script = AppLocation.get_directory(
706- AppLocation.PluginsDir) + '/presentations/lib/ghostscript_get_resolution.ps'
707+ gs_resolution_script = str(AppLocation.get_directory(
708+ AppLocation.PluginsDir)) + '/presentations/lib/ghostscript_get_resolution.ps'
709 # Run the script on the pdf to get the size
710 runlog = []
711 try:
712
713=== modified file 'openlp/plugins/presentations/lib/pptviewcontroller.py'
714--- openlp/plugins/presentations/lib/pptviewcontroller.py 2017-05-14 10:11:10 +0000
715+++ openlp/plugins/presentations/lib/pptviewcontroller.py 2017-08-02 06:25:28 +0000
716@@ -85,7 +85,7 @@
717 if self.process:
718 return
719 log.debug('start PPTView')
720- dll_path = os.path.join(AppLocation.get_directory(AppLocation.AppDir),
721+ dll_path = os.path.join(str(AppLocation.get_directory(AppLocation.AppDir)),
722 'plugins', 'presentations', 'lib', 'pptviewlib', 'pptviewlib.dll')
723 self.process = cdll.LoadLibrary(dll_path)
724 if log.isEnabledFor(logging.DEBUG):
725
726=== modified file 'openlp/plugins/presentations/lib/presentationcontroller.py'
727--- openlp/plugins/presentations/lib/presentationcontroller.py 2016-12-31 11:01:36 +0000
728+++ openlp/plugins/presentations/lib/presentationcontroller.py 2017-08-02 06:25:28 +0000
729@@ -415,8 +415,9 @@
730 self.document_class = document_class
731 self.settings_section = self.plugin.settings_section
732 self.available = None
733- self.temp_folder = os.path.join(AppLocation.get_section_data_path(self.settings_section), name)
734- self.thumbnail_folder = os.path.join(AppLocation.get_section_data_path(self.settings_section), 'thumbnails')
735+ self.temp_folder = os.path.join(str(AppLocation.get_section_data_path(self.settings_section)), name)
736+ self.thumbnail_folder = os.path.join(
737+ str(AppLocation.get_section_data_path(self.settings_section)), 'thumbnails')
738 self.thumbnail_prefix = 'slide'
739 check_directory_exists(self.thumbnail_folder)
740 check_directory_exists(self.temp_folder)
741
742=== modified file 'openlp/plugins/remotes/lib/httprouter.py'
743--- openlp/plugins/remotes/lib/httprouter.py 2017-01-25 21:17:27 +0000
744+++ openlp/plugins/remotes/lib/httprouter.py 2017-08-02 06:25:28 +0000
745@@ -171,8 +171,8 @@
746 ]
747 self.settings_section = 'remotes'
748 self.translate()
749- self.html_dir = os.path.join(AppLocation.get_directory(AppLocation.PluginsDir), 'remotes', 'html')
750- self.config_dir = os.path.join(AppLocation.get_data_path(), 'stages')
751+ self.html_dir = os.path.join(str(AppLocation.get_directory(AppLocation.PluginsDir)), 'remotes', 'html')
752+ self.config_dir = os.path.join(str(AppLocation.get_data_path()), 'stages')
753
754 def do_post_processor(self):
755 """
756@@ -456,7 +456,7 @@
757 if controller_name in supported_controllers:
758 full_path = urllib.parse.unquote(file_name)
759 if '..' not in full_path: # no hacking please
760- full_path = os.path.normpath(os.path.join(AppLocation.get_section_data_path(controller_name),
761+ full_path = os.path.normpath(os.path.join(str(AppLocation.get_section_data_path(controller_name)),
762 'thumbnails/' + full_path))
763 if os.path.exists(full_path):
764 path, just_file_name = os.path.split(full_path)
765@@ -565,7 +565,7 @@
766 elif current_item.is_image() and not frame.get('image', '') and Settings().value('remotes/thumbnails'):
767 item['tag'] = str(index + 1)
768 thumbnail_path = os.path.join('images', 'thumbnails', frame['title'])
769- full_thumbnail_path = os.path.join(AppLocation.get_data_path(), thumbnail_path)
770+ full_thumbnail_path = os.path.join(str(AppLocation.get_data_path()), thumbnail_path)
771 # Create thumbnail if it doesn't exists
772 if not os.path.exists(full_thumbnail_path):
773 create_thumb(current_item.get_frame_path(index), full_thumbnail_path, False)
774@@ -582,7 +582,7 @@
775 if current_item.is_capable(ItemCapabilities.HasThumbnails) and \
776 Settings().value('remotes/thumbnails'):
777 # If the file is under our app directory tree send the portion after the match
778- data_path = AppLocation.get_data_path()
779+ data_path = str(AppLocation.get_data_path())
780 if frame['image'][0:len(data_path)] == data_path:
781 item['img'] = urllib.request.pathname2url(frame['image'][len(data_path):])
782 item['text'] = str(frame['title'])
783
784=== modified file 'openlp/plugins/songs/forms/editsongform.py'
785--- openlp/plugins/songs/forms/editsongform.py 2017-06-09 06:06:49 +0000
786+++ openlp/plugins/songs/forms/editsongform.py 2017-08-02 06:25:28 +0000
787@@ -1065,7 +1065,7 @@
788 self.manager.save_object(self.song)
789 audio_files = [a.file_name for a in self.song.media_files]
790 log.debug(audio_files)
791- save_path = os.path.join(AppLocation.get_section_data_path(self.media_item.plugin.name), 'audio',
792+ save_path = os.path.join(str(AppLocation.get_section_data_path(self.media_item.plugin.name)), 'audio',
793 str(self.song.id))
794 check_directory_exists(save_path)
795 self.song.media_files = []
796
797=== modified file 'openlp/plugins/songs/lib/__init__.py'
798--- openlp/plugins/songs/lib/__init__.py 2017-05-22 19:07:07 +0000
799+++ openlp/plugins/songs/lib/__init__.py 2017-08-02 06:25:28 +0000
800@@ -538,7 +538,7 @@
801 except OSError:
802 log.exception('Could not remove file: {name}'.format(name=media_file.file_name))
803 try:
804- save_path = os.path.join(AppLocation.get_section_data_path(song_plugin.name), 'audio', str(song_id))
805+ save_path = os.path.join(str(AppLocation.get_section_data_path(song_plugin.name)), 'audio', str(song_id))
806 if os.path.exists(save_path):
807 os.rmdir(save_path)
808 except OSError:
809
810=== modified file 'openlp/plugins/songs/lib/importers/songimport.py'
811--- openlp/plugins/songs/lib/importers/songimport.py 2017-05-30 18:42:35 +0000
812+++ openlp/plugins/songs/lib/importers/songimport.py 2017-08-02 06:25:28 +0000
813@@ -421,7 +421,7 @@
814 :param filename: The file to copy.
815 """
816 if not hasattr(self, 'save_path'):
817- self.save_path = os.path.join(AppLocation.get_section_data_path(self.import_wizard.plugin.name),
818+ self.save_path = os.path.join(str(AppLocation.get_section_data_path(self.import_wizard.plugin.name)),
819 'audio', str(song_id))
820 check_directory_exists(self.save_path)
821 if not filename.startswith(self.save_path):
822
823=== modified file 'openlp/plugins/songs/lib/mediaitem.py'
824--- openlp/plugins/songs/lib/mediaitem.py 2017-06-09 06:06:49 +0000
825+++ openlp/plugins/songs/lib/mediaitem.py 2017-08-02 06:25:28 +0000
826@@ -88,9 +88,9 @@
827 song.media_files = []
828 for i, bga in enumerate(item.background_audio):
829 dest_file = os.path.join(
830- AppLocation.get_section_data_path(self.plugin.name), 'audio', str(song.id), os.path.split(bga)[1])
831+ str(AppLocation.get_section_data_path(self.plugin.name)), 'audio', str(song.id), os.path.split(bga)[1])
832 check_directory_exists(os.path.split(dest_file)[0])
833- shutil.copyfile(os.path.join(AppLocation.get_section_data_path('servicemanager'), bga), dest_file)
834+ shutil.copyfile(os.path.join(str(AppLocation.get_section_data_path('servicemanager')), bga), dest_file)
835 song.media_files.append(MediaFile.populate(weight=i, file_name=dest_file))
836 self.plugin.manager.save_object(song, True)
837
838@@ -533,7 +533,8 @@
839 'copy', 'For song cloning'))
840 # Copy audio files from the old to the new song
841 if len(old_song.media_files) > 0:
842- save_path = os.path.join(AppLocation.get_section_data_path(self.plugin.name), 'audio', str(new_song.id))
843+ save_path = os.path.join(
844+ str(AppLocation.get_section_data_path(self.plugin.name)), 'audio', str(new_song.id))
845 check_directory_exists(save_path)
846 for media_file in old_song.media_files:
847 new_media_file_name = os.path.join(save_path, os.path.basename(media_file.file_name))
848
849=== modified file 'tests/functional/openlp_core_common/test_applocation.py'
850--- tests/functional/openlp_core_common/test_applocation.py 2017-04-24 05:17:55 +0000
851+++ tests/functional/openlp_core_common/test_applocation.py 2017-08-02 06:25:28 +0000
852@@ -24,8 +24,9 @@
853 """
854 import copy
855 import os
856+from pathlib import Path
857 from unittest import TestCase
858-from unittest.mock import patch
859+from unittest.mock import MagicMock, patch
860
861 from openlp.core.common import AppLocation, get_frozen_path
862
863@@ -64,56 +65,51 @@
864 """
865 Test the AppLocation.get_data_path() method when a custom location is set in the settings
866 """
867- with patch('openlp.core.common.applocation.Settings') as mocked_class,\
868- patch('openlp.core.common.applocation.os') as mocked_os:
869- # GIVEN: A mocked out Settings class which returns a custom data location
870- mocked_settings = mocked_class.return_value
871- mocked_settings.contains.return_value = True
872- mocked_settings.value.return_value.toString.return_value = 'custom/dir'
873- mocked_os.path.normpath.return_value = 'custom/dir'
874+ # GIVEN: A mocked out Settings class which returns a custom data location
875+ mocked_settings_instance = MagicMock(
876+ **{'contains.return_value': True, 'value.return_value': Path('custom', 'dir')})
877+ with patch('openlp.core.common.applocation.Settings', return_value=mocked_settings_instance):
878
879 # WHEN: we call AppLocation.get_data_path()
880 data_path = AppLocation.get_data_path()
881
882 # THEN: the mocked Settings methods were called and the value returned was our set up value
883- mocked_settings.contains.assert_called_with('advanced/data path')
884- mocked_settings.value.assert_called_with('advanced/data path')
885- self.assertEqual('custom/dir', data_path, 'Result should be "custom/dir"')
886+ mocked_settings_instance.contains.assert_called_with('advanced/data path')
887+ mocked_settings_instance.value.assert_called_with('advanced/data path')
888+ self.assertEqual(Path('custom', 'dir'), data_path, 'Result should be "custom/dir"')
889
890 def test_get_files_no_section_no_extension(self):
891 """
892 Test the AppLocation.get_files() method with no parameters passed.
893 """
894- with patch('openlp.core.common.AppLocation.get_data_path') as mocked_get_data_path, \
895- patch('openlp.core.common.applocation.os.listdir') as mocked_listdir:
896- # GIVEN: Our mocked modules/methods.
897- mocked_get_data_path.return_value = 'test/dir'
898- mocked_listdir.return_value = copy.deepcopy(FILE_LIST)
899+ # GIVEN: Our mocked modules/methods.
900+ with patch.object(Path, 'glob', return_value=[Path('/dir/file5.mp3'), Path('/dir/file6.mp3')]) as mocked_glob, \
901+ patch('openlp.core.common.AppLocation.get_data_path', return_value=Path('/dir')):
902
903 # When: Get the list of files.
904 result = AppLocation.get_files()
905
906+ # Then: Check if the section parameter was used correctly, and the glob argument was passed.
907+ mocked_glob.assert_called_once_with('*')
908+
909 # Then: check if the file lists are identical.
910- self.assertListEqual(FILE_LIST, result, 'The file lists should be identical.')
911+ self.assertListEqual([Path('file5.mp3'), Path('file6.mp3')], result, 'The file lists should be identical.')
912
913 def test_get_files(self):
914 """
915 Test the AppLocation.get_files() method with all parameters passed.
916 """
917- with patch('openlp.core.common.AppLocation.get_data_path') as mocked_get_data_path, \
918- patch('openlp.core.common.applocation.os.listdir') as mocked_listdir:
919- # GIVEN: Our mocked modules/methods.
920- mocked_get_data_path.return_value = os.path.join('test', 'dir')
921- mocked_listdir.return_value = copy.deepcopy(FILE_LIST)
922+ # GIVEN: Our mocked modules/methods.
923+ with patch.object(Path, 'glob', return_value=[Path('/dir/section/file5.mp3'), Path('/dir/section/file6.mp3')]) \
924+ as mocked_glob, \
925+ patch('openlp.core.common.AppLocation.get_data_path', return_value=Path('/dir')):
926
927 # When: Get the list of files.
928 result = AppLocation.get_files('section', '.mp3')
929
930- # Then: Check if the section parameter was used correctly.
931- mocked_listdir.assert_called_with(os.path.join('test', 'dir', 'section'))
932-
933- # Then: check if the file lists are identical.
934- self.assertListEqual(['file5.mp3', 'file6.mp3'], result, 'The file lists should be identical.')
935+ # Then: The section parameter was used correctly, and the glob argument was passed..
936+ mocked_glob.assert_called_once_with('*.mp3')
937+ self.assertListEqual([Path('file5.mp3'), Path('file6.mp3')], result, 'The file lists should be identical.')
938
939 def test_get_section_data_path(self):
940 """
941@@ -122,7 +118,7 @@
942 with patch('openlp.core.common.AppLocation.get_data_path') as mocked_get_data_path, \
943 patch('openlp.core.common.applocation.check_directory_exists') as mocked_check_directory_exists:
944 # GIVEN: A mocked out AppLocation.get_data_path()
945- mocked_get_data_path.return_value = os.path.join('test', 'dir')
946+ mocked_get_data_path.return_value = Path('test', 'dir')
947 mocked_check_directory_exists.return_value = True
948
949 # WHEN: we call AppLocation.get_data_path()
950@@ -130,7 +126,7 @@
951
952 # THEN: check that all the correct methods were called, and the result is correct
953 mocked_check_directory_exists.assert_called_with(os.path.join('test', 'dir', 'section'))
954- self.assertEqual(os.path.join('test', 'dir', 'section'), data_path, 'Result should be "test/dir/section"')
955+ self.assertEqual(Path('test', 'dir', 'section'), data_path, 'Result should be "test/dir/section"')
956
957 def test_get_directory_for_app_dir(self):
958 """
959@@ -138,13 +134,13 @@
960 """
961 # GIVEN: A mocked out _get_frozen_path function
962 with patch('openlp.core.common.applocation.get_frozen_path') as mocked_get_frozen_path:
963- mocked_get_frozen_path.return_value = os.path.join('app', 'dir')
964+ mocked_get_frozen_path.return_value = Path('app', 'dir')
965
966 # WHEN: We call AppLocation.get_directory
967 directory = AppLocation.get_directory(AppLocation.AppDir)
968
969 # THEN: check that the correct directory is returned
970- self.assertEqual(os.path.join('app', 'dir'), directory, 'Directory should be "app/dir"')
971+ self.assertEqual(Path('app', 'dir'), directory, 'Directory should be "app/dir"')
972
973 def test_get_directory_for_plugins_dir(self):
974 """
975@@ -157,7 +153,7 @@
976 patch('openlp.core.common.applocation.sys') as mocked_sys:
977 mocked_abspath.return_value = os.path.join('plugins', 'dir')
978 mocked_split.return_value = ['openlp']
979- mocked_get_frozen_path.return_value = os.path.join('plugins', 'dir')
980+ mocked_get_frozen_path.return_value = Path('dir')
981 mocked_sys.frozen = 1
982 mocked_sys.argv = ['openlp']
983
984@@ -165,7 +161,7 @@
985 directory = AppLocation.get_directory(AppLocation.PluginsDir)
986
987 # THEN: The correct directory should be returned
988- self.assertEqual(os.path.join('plugins', 'dir'), directory, 'Directory should be "plugins/dir"')
989+ self.assertEqual(Path('dir', 'plugins'), directory, 'Directory should be "dir/plugins"')
990
991 def test_get_frozen_path_in_unfrozen_app(self):
992 """
993
994=== modified file 'tests/functional/openlp_core_common/test_common.py'
995--- tests/functional/openlp_core_common/test_common.py 2017-05-15 10:15:32 +0000
996+++ tests/functional/openlp_core_common/test_common.py 2017-08-02 06:25:28 +0000
997@@ -79,7 +79,7 @@
998 Test the `extension_loader` function when no files are found
999 """
1000 # GIVEN: A mocked `Path.glob` method which does not match any files
1001- with patch('openlp.core.common.AppLocation.get_directory', return_value='/app/dir/openlp'), \
1002+ with patch('openlp.core.common.AppLocation.get_directory', return_value=Path('/', 'app', 'dir', 'openlp')), \
1003 patch.object(common.Path, 'glob', return_value=[]), \
1004 patch('openlp.core.common.importlib.import_module') as mocked_import_module:
1005
1006@@ -94,11 +94,12 @@
1007 Test the `extension_loader` function when it successfully finds and loads some files
1008 """
1009 # GIVEN: A mocked `Path.glob` method which returns a list of files
1010- with patch('openlp.core.common.AppLocation.get_directory', return_value='/app/dir/openlp'), \
1011- patch.object(common.Path, 'glob', return_value=[Path('/app/dir/openlp/import_dir/file1.py'),
1012- Path('/app/dir/openlp/import_dir/file2.py'),
1013- Path('/app/dir/openlp/import_dir/file3.py'),
1014- Path('/app/dir/openlp/import_dir/file4.py')]), \
1015+ with patch('openlp.core.common.AppLocation.get_directory', return_value=Path('/', 'app', 'dir', 'openlp')), \
1016+ patch.object(common.Path, 'glob', return_value=[
1017+ Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file1.py'),
1018+ Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file2.py'),
1019+ Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file3.py'),
1020+ Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file4.py')]), \
1021 patch('openlp.core.common.importlib.import_module') as mocked_import_module:
1022
1023 # WHEN: Calling `extension_loader` with a list of files to exclude
1024@@ -113,8 +114,9 @@
1025 Test the `extension_loader` function when `SourceFileLoader` raises a `ImportError`
1026 """
1027 # GIVEN: A mocked `import_module` which raises an `ImportError`
1028- with patch('openlp.core.common.AppLocation.get_directory', return_value='/app/dir/openlp'), \
1029- patch.object(common.Path, 'glob', return_value=[Path('/app/dir/openlp/import_dir/file1.py')]), \
1030+ with patch('openlp.core.common.AppLocation.get_directory', return_value=Path('/', 'app', 'dir', 'openlp')), \
1031+ patch.object(common.Path, 'glob', return_value=[
1032+ Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file1.py')]), \
1033 patch('openlp.core.common.importlib.import_module', side_effect=ImportError()), \
1034 patch('openlp.core.common.log') as mocked_logger:
1035
1036@@ -129,8 +131,9 @@
1037 Test the `extension_loader` function when `import_module` raises a `ImportError`
1038 """
1039 # GIVEN: A mocked `SourceFileLoader` which raises an `OSError`
1040- with patch('openlp.core.common.AppLocation.get_directory', return_value='/app/dir/openlp'), \
1041- patch.object(common.Path, 'glob', return_value=[Path('/app/dir/openlp/import_dir/file1.py')]), \
1042+ with patch('openlp.core.common.AppLocation.get_directory', return_value=Path('/', 'app', 'dir', 'openlp')), \
1043+ patch.object(common.Path, 'glob', return_value=[
1044+ Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file1.py')]), \
1045 patch('openlp.core.common.importlib.import_module', side_effect=OSError()), \
1046 patch('openlp.core.common.log') as mocked_logger:
1047
1048
1049=== added file 'tests/functional/openlp_core_lib/test_path.py'
1050--- tests/functional/openlp_core_lib/test_path.py 1970-01-01 00:00:00 +0000
1051+++ tests/functional/openlp_core_lib/test_path.py 2017-08-02 06:25:28 +0000
1052@@ -0,0 +1,88 @@
1053+# -*- coding: utf-8 -*-
1054+# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
1055+
1056+###############################################################################
1057+# OpenLP - Open Source Lyrics Projection #
1058+# --------------------------------------------------------------------------- #
1059+# Copyright (c) 2008-2017 OpenLP Developers #
1060+# --------------------------------------------------------------------------- #
1061+# This program is free software; you can redistribute it and/or modify it #
1062+# under the terms of the GNU General Public License as published by the Free #
1063+# Software Foundation; version 2 of the License. #
1064+# #
1065+# This program is distributed in the hope that it will be useful, but WITHOUT #
1066+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
1067+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
1068+# more details. #
1069+# #
1070+# You should have received a copy of the GNU General Public License along #
1071+# with this program; if not, write to the Free Software Foundation, Inc., 59 #
1072+# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
1073+###############################################################################
1074+"""
1075+Package to test the openlp.core.lib.path package.
1076+"""
1077+import os
1078+from pathlib import Path
1079+from unittest import TestCase
1080+
1081+from openlp.core.lib.path import path_to_str, str_to_path
1082+
1083+
1084+class TestPath(TestCase):
1085+ """
1086+ Tests for the :mod:`openlp.core.lib.path` module
1087+ """
1088+
1089+ def test_path_to_str_type_error(self):
1090+ """
1091+ Test that `path_to_str` raises a type error when called with an invalid type
1092+ """
1093+ # GIVEN: The `path_to_str` function
1094+ # WHEN: Calling `path_to_str` with an invalid Type
1095+ # THEN: A TypeError should have been raised
1096+ with self.assertRaises(TypeError):
1097+ path_to_str(str())
1098+
1099+ def test_path_to_str_none(self):
1100+ """
1101+ Test that `path_to_str` correctly converts the path parameter when passed with None
1102+ """
1103+ # GIVEN: The `path_to_str` function
1104+ # WHEN: Calling the `path_to_str` function with None
1105+ result = path_to_str(None)
1106+
1107+ # THEN: `path_to_str` should return an empty string
1108+ self.assertEqual(result, '')
1109+
1110+ def test_path_to_str_path_object(self):
1111+ """
1112+ Test that `path_to_str` correctly converts the path parameter when passed a Path object
1113+ """
1114+ # GIVEN: The `path_to_str` function
1115+ # WHEN: Calling the `path_to_str` function with a Path object
1116+ result = path_to_str(Path('test/path'))
1117+
1118+ # THEN: `path_to_str` should return a string representation of the Path object
1119+ self.assertEqual(result, os.path.join('test', 'path'))
1120+
1121+ def test_str_to_path_type_error(self):
1122+ """
1123+ Test that `str_to_path` raises a type error when called with an invalid type
1124+ """
1125+ # GIVEN: The `str_to_path` function
1126+ # WHEN: Calling `str_to_path` with an invalid Type
1127+ # THEN: A TypeError should have been raised
1128+ with self.assertRaises(TypeError):
1129+ str_to_path(Path())
1130+
1131+ def test_str_to_path_empty_str(self):
1132+ """
1133+ Test that `str_to_path` correctly converts the string parameter when passed with and empty string
1134+ """
1135+ # GIVEN: The `str_to_path` function
1136+ # WHEN: Calling the `str_to_path` function with None
1137+ result = str_to_path('')
1138+
1139+ # THEN: `path_to_str` should return None
1140+ self.assertEqual(result, None)