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

Proposed by Phill
Status: Superseded
Proposed branch: lp:~phill-ridout/openlp/pathlib3
Merge into: lp:openlp
Diff against target: 1856 lines (+314/-348)
48 files modified
openlp/core/__init__.py (+16/-12)
openlp/core/api/endpoint/controller.py (+2/-2)
openlp/core/api/endpoint/pluginhelpers.py (+2/-5)
openlp/core/api/http/endpoint.py (+1/-2)
openlp/core/api/http/wsgiapp.py (+6/-2)
openlp/core/common/__init__.py (+47/-47)
openlp/core/common/applocation.py (+8/-19)
openlp/core/common/settings.py (+0/-28)
openlp/core/lib/__init__.py (+13/-15)
openlp/core/lib/db.py (+2/-2)
openlp/core/lib/pluginmanager.py (+1/-1)
openlp/core/lib/theme.py (+2/-3)
openlp/core/ui/firsttimeform.py (+3/-2)
openlp/core/ui/mainwindow.py (+2/-1)
openlp/core/ui/media/mediacontroller.py (+1/-1)
openlp/core/ui/printserviceform.py (+1/-1)
openlp/core/ui/servicemanager.py (+6/-5)
openlp/core/ui/themeform.py (+3/-1)
openlp/core/ui/thememanager.py (+13/-12)
openlp/plugins/bibles/lib/importers/csvbible.py (+2/-1)
openlp/plugins/bibles/lib/manager.py (+3/-2)
openlp/plugins/images/lib/mediaitem.py (+6/-5)
openlp/plugins/media/lib/mediaitem.py (+2/-1)
openlp/plugins/media/mediaplugin.py (+2/-2)
openlp/plugins/presentations/lib/impresscontroller.py (+2/-1)
openlp/plugins/presentations/lib/pdfcontroller.py (+2/-1)
openlp/plugins/presentations/lib/presentationcontroller.py (+4/-3)
openlp/plugins/presentations/presentationplugin.py (+1/-1)
openlp/plugins/remotes/remoteplugin.py (+10/-9)
openlp/plugins/songs/forms/editsongform.py (+1/-1)
openlp/plugins/songs/lib/importers/songbeamer.py (+2/-1)
openlp/plugins/songs/lib/importers/songimport.py (+2/-1)
openlp/plugins/songs/lib/mediaitem.py (+3/-2)
openlp/plugins/songs/lib/openlyricsexport.py (+2/-1)
openlp/plugins/songusage/forms/songusagedetailform.py (+2/-1)
scripts/appveyor.yml (+1/-1)
tests/functional/openlp_core_common/test_applocation.py (+5/-7)
tests/functional/openlp_core_common/test_common.py (+61/-35)
tests/functional/openlp_core_common/test_init.py (+36/-32)
tests/functional/openlp_core_lib/test_db.py (+5/-4)
tests/functional/openlp_core_lib/test_file_dialog.py (+0/-45)
tests/functional/openlp_core_lib/test_lib.py (+15/-15)
tests/functional/openlp_core_ui/test_firsttimeform.py (+2/-1)
tests/functional/openlp_core_ui/test_thememanager.py (+2/-2)
tests/functional/openlp_plugins/bibles/test_manager.py (+2/-2)
tests/functional/openlp_plugins/media/test_mediaplugin.py (+3/-5)
tests/functional/openlp_plugins/presentations/test_presentationcontroller.py (+4/-2)
tests/interfaces/openlp_core_common/test_utils.py (+3/-3)
To merge this branch: bzr merge lp:~phill-ridout/openlp/pathlib3
Reviewer Review Type Date Requested Status
Tomas Groth Approve
Tim Bentley Approve
Raoul Snyman Pending
Review via email: mp+329481@code.launchpad.net

This proposal supersedes a proposal from 2017-08-12.

This proposal has been superseded by a proposal from 2017-08-24.

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

See inline

review: Needs Fixing
Revision history for this message
Raoul Snyman (raoul-snyman) : Posted in a previous version of this proposal
review: Needs Information
Revision history for this message
Phill (phill-ridout) wrote : Posted in a previous version of this proposal

> See inline
See my inline reply.

Revision history for this message
Phill (phill-ridout) wrote : Posted in a previous version of this proposal

See my inline reply.

Revision history for this message
Phill (phill-ridout) wrote : Posted in a previous version of this proposal

See inline

Revision history for this message
Tomas Groth (tomasgroth) wrote : Posted in a previous version of this proposal
review: Needs Fixing
Revision history for this message
Tim Bentley (trb143) wrote :

Looks ok as part of the progression

review: Approve
lp:~phill-ridout/openlp/pathlib3 updated
2763. By Phill

Patched appveyor.yml

Revision history for this message
Tomas Groth (tomasgroth) :
review: Approve
lp:~phill-ridout/openlp/pathlib3 updated
2764. By Phill

Fixed issues with this branch and recent commits to trunk

Unmerged revisions

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-08-03 17:54:40 +0000
3+++ openlp/core/__init__.py 2017-08-24 19:54:19 +0000
4@@ -33,6 +33,7 @@
5 import shutil
6 import sys
7 import time
8+from pathlib import Path
9 from traceback import format_exception
10
11 from PyQt5 import QtCore, QtGui, QtWidgets
12@@ -346,15 +347,18 @@
13 """
14 Setup our logging using log_path
15
16- :param log_path: the path
17+ :param pathlib.Path log_path: The file to save the log to
18+ :return: None
19+ :rtype: None
20 """
21 check_directory_exists(log_path, True)
22- filename = os.path.join(log_path, 'openlp.log')
23- logfile = logging.FileHandler(filename, 'w', encoding="UTF-8")
24+ file_path = log_path / 'openlp.log'
25+ # TODO: FileHandler accepts a Path object in Py3.6
26+ logfile = logging.FileHandler(str(file_path), 'w', encoding='UTF-8')
27 logfile.setFormatter(logging.Formatter('%(asctime)s %(name)-55s %(levelname)-8s %(message)s'))
28 log.addHandler(logfile)
29 if log.isEnabledFor(logging.DEBUG):
30- print('Logging to: {name}'.format(name=filename))
31+ print('Logging to: {name}'.format(name=file_path))
32
33
34 def main(args=None):
35@@ -390,24 +394,24 @@
36 application.setApplicationName('OpenLPPortable')
37 Settings.setDefaultFormat(Settings.IniFormat)
38 # Get location OpenLPPortable.ini
39- application_path = str(AppLocation.get_directory(AppLocation.AppDir))
40- set_up_logging(os.path.abspath(os.path.join(application_path, '..', '..', 'Other')))
41+ portable_path = (AppLocation.get_directory(AppLocation.AppDir) / '..' / '..').resolve()
42+ data_path = portable_path / 'Data'
43+ set_up_logging(portable_path / 'Other')
44 log.info('Running portable')
45- portable_settings_file = os.path.abspath(os.path.join(application_path, '..', '..', 'Data', 'OpenLP.ini'))
46+ portable_settings_path = data_path / 'OpenLP.ini'
47 # Make this our settings file
48- log.info('INI file: {name}'.format(name=portable_settings_file))
49- Settings.set_filename(portable_settings_file)
50+ log.info('INI file: {name}'.format(name=portable_settings_path))
51+ Settings.set_filename(str(portable_settings_path))
52 portable_settings = Settings()
53 # Set our data path
54- data_path = os.path.abspath(os.path.join(application_path, '..', '..', 'Data',))
55 log.info('Data path: {name}'.format(name=data_path))
56 # Point to our data path
57- portable_settings.setValue('advanced/data path', data_path)
58+ portable_settings.setValue('advanced/data path', str(data_path))
59 portable_settings.setValue('advanced/is portable', True)
60 portable_settings.sync()
61 else:
62 application.setApplicationName('OpenLP')
63- set_up_logging(str(AppLocation.get_directory(AppLocation.CacheDir)))
64+ set_up_logging(AppLocation.get_directory(AppLocation.CacheDir))
65 Registry.create()
66 Registry().register('application', application)
67 Registry().set_flag('no_web_server', args.no_web_server)
68
69=== modified file 'openlp/core/api/endpoint/controller.py'
70--- openlp/core/api/endpoint/controller.py 2017-08-13 05:50:44 +0000
71+++ openlp/core/api/endpoint/controller.py 2017-08-24 19:54:19 +0000
72@@ -64,7 +64,7 @@
73 elif current_item.is_image() and not frame.get('image', '') and Settings().value('api/thumbnails'):
74 item['tag'] = str(index + 1)
75 thumbnail_path = os.path.join('images', 'thumbnails', frame['title'])
76- full_thumbnail_path = os.path.join(AppLocation.get_data_path(), thumbnail_path)
77+ full_thumbnail_path = str(AppLocation.get_data_path() / thumbnail_path)
78 # Create thumbnail if it doesn't exists
79 if not os.path.exists(full_thumbnail_path):
80 create_thumb(current_item.get_frame_path(index), full_thumbnail_path, False)
81@@ -82,7 +82,7 @@
82 if current_item.is_capable(ItemCapabilities.HasThumbnails) and \
83 Settings().value('api/thumbnails'):
84 # If the file is under our app directory tree send the portion after the match
85- data_path = AppLocation.get_data_path()
86+ data_path = str(AppLocation.get_data_path())
87 if frame['image'][0:len(data_path)] == data_path:
88 item['img'] = urllib.request.pathname2url(frame['image'][len(data_path):])
89 Registry().get('image_manager').add_image(frame['image'], frame['title'], None, 88, 88)
90
91=== modified file 'openlp/core/api/endpoint/pluginhelpers.py'
92--- openlp/core/api/endpoint/pluginhelpers.py 2017-06-10 10:53:52 +0000
93+++ openlp/core/api/endpoint/pluginhelpers.py 2017-08-24 19:54:19 +0000
94@@ -125,12 +125,9 @@
95 file_name = urllib.parse.unquote(file_name)
96 if '..' not in file_name: # no hacking please
97 if slide:
98- full_path = os.path.normpath(os.path.join(AppLocation.get_section_data_path(controller_name),
99- 'thumbnails', file_name, slide))
100+ full_path = str(AppLocation.get_section_data_path(controller_name) / 'thumbnails' / file_name / slide)
101 else:
102- full_path = os.path.normpath(os.path.join(AppLocation.get_section_data_path(controller_name),
103-
104- 'thumbnails', file_name))
105+ full_path = str(AppLocation.get_section_data_path(controller_name) / 'thumbnails' / file_name)
106 if os.path.exists(full_path):
107 path, just_file_name = os.path.split(full_path)
108 Registry().get('image_manager').add_image(full_path, just_file_name, None, width, height)
109
110=== modified file 'openlp/core/api/http/endpoint.py'
111--- openlp/core/api/http/endpoint.py 2017-08-13 05:28:25 +0000
112+++ openlp/core/api/http/endpoint.py 2017-08-24 19:54:19 +0000
113@@ -68,11 +68,10 @@
114 """
115 Render a mako template
116 """
117- root = os.path.join(str(AppLocation.get_section_data_path('remotes')))
118+ root = str(AppLocation.get_section_data_path('remotes'))
119 if not self.template_dir:
120 raise Exception('No template directory specified')
121 path = os.path.join(root, self.template_dir, filename)
122- # path = os.path.abspath(os.path.join(self.template_dir, filename))
123 if self.static_dir:
124 kwargs['static_url'] = '/{prefix}/static'.format(prefix=self.url_prefix)
125 kwargs['static_url'] = kwargs['static_url'].replace('//', '/')
126
127=== modified file 'openlp/core/api/http/wsgiapp.py'
128--- openlp/core/api/http/wsgiapp.py 2017-08-12 20:26:39 +0000
129+++ openlp/core/api/http/wsgiapp.py 2017-08-24 19:54:19 +0000
130@@ -138,8 +138,12 @@
131 Add a static directory as a route
132 """
133 if route not in self.static_routes:
134- root = os.path.join(str(AppLocation.get_section_data_path('remotes')))
135- self.static_routes[route] = DirectoryApp(os.path.abspath(os.path.join(root, static_dir)))
136+ root = str(AppLocation.get_section_data_path('remotes'))
137+ static_path = os.path.abspath(os.path.join(root, static_dir))
138+ if not os.path.exists(static_path):
139+ log.error('Static path "%s" does not exist. Skipping creating static route/', static_path)
140+ return
141+ self.static_routes[route] = DirectoryApp(static_path)
142
143 def dispatch(self, request):
144 """
145
146=== modified file 'openlp/core/common/__init__.py'
147--- openlp/core/common/__init__.py 2017-08-01 20:59:41 +0000
148+++ openlp/core/common/__init__.py 2017-08-24 19:54:19 +0000
149@@ -32,7 +32,6 @@
150 import traceback
151 from chardet.universaldetector import UniversalDetector
152 from ipaddress import IPv4Address, IPv6Address, AddressValueError
153-from pathlib import Path
154 from shutil import which
155 from subprocess import check_output, CalledProcessError, STDOUT
156
157@@ -65,17 +64,19 @@
158
159 def check_directory_exists(directory, do_not_log=False):
160 """
161- Check a theme directory exists and if not create it
162+ Check a directory exists and if not create it
163
164- :param directory: The directory to make sure exists
165- :param do_not_log: To not log anything. This is need for the start up, when the log isn't ready.
166+ :param pathlib.Path directory: The directory to make sure exists
167+ :param bool do_not_log: To not log anything. This is need for the start up, when the log isn't ready.
168+ :return: None
169+ :rtype: None
170 """
171 if not do_not_log:
172 log.debug('check_directory_exists {text}'.format(text=directory))
173 try:
174- if not os.path.exists(directory):
175- os.makedirs(directory)
176- except IOError as e:
177+ if not directory.exists():
178+ directory.mkdir(parents=True)
179+ except IOError:
180 if not do_not_log:
181 log.exception('failed to check if directory exists or create directory')
182
183@@ -85,19 +86,15 @@
184 A utility function to find and load OpenLP extensions, such as plugins, presentation and media controllers and
185 importers.
186
187- :param glob_pattern: A glob pattern used to find the extension(s) to be imported. Should be relative to the
188- application directory. i.e. openlp/plugins/*/*plugin.py
189- :type glob_pattern: str
190-
191- :param excluded_files: A list of file names to exclude that the glob pattern may find.
192- :type excluded_files: list of strings
193-
194+ :param str glob_pattern: A glob pattern used to find the extension(s) to be imported. Should be relative to the
195+ application directory. i.e. plugins/*/*plugin.py
196+ :param list[str] excluded_files: A list of file names to exclude that the glob pattern may find.
197 :return: None
198 :rtype: None
199 """
200- base_dir_path = AppLocation.get_directory(AppLocation.AppDir).parent
201- for extension_path in base_dir_path.glob(glob_pattern):
202- extension_path = extension_path.relative_to(base_dir_path)
203+ app_dir = AppLocation.get_directory(AppLocation.AppDir)
204+ for extension_path in app_dir.glob(glob_pattern):
205+ extension_path = extension_path.relative_to(app_dir)
206 if extension_path.name in excluded_files:
207 continue
208 module_name = path_to_module(extension_path)
209@@ -106,21 +103,19 @@
210 except (ImportError, OSError):
211 # On some platforms importing vlc.py might cause OSError exceptions. (e.g. Mac OS X)
212 log.warning('Failed to import {module_name} on path {extension_path}'
213- .format(module_name=module_name, extension_path=str(extension_path)))
214+ .format(module_name=module_name, extension_path=extension_path))
215
216
217 def path_to_module(path):
218 """
219 Convert a path to a module name (i.e openlp.core.common)
220
221- :param path: The path to convert to a module name.
222- :type path: Path
223-
224+ :param pathlib.Path path: The path to convert to a module name.
225 :return: The module name.
226 :rtype: str
227 """
228 module_path = path.with_suffix('')
229- return '.'.join(module_path.parts)
230+ return 'openlp.' + '.'.join(module_path.parts)
231
232
233 def get_frozen_path(frozen_option, non_frozen_option):
234@@ -378,20 +373,22 @@
235 return os.path.split(path)
236
237
238-def delete_file(file_path_name):
239+def delete_file(file_path):
240 """
241 Deletes a file from the system.
242
243- :param file_path_name: The file, including path, to delete.
244+ :param pathlib.Path file_path: The file, including path, to delete.
245+ :return: True if the deletion was successful, or the file never existed. False otherwise.
246+ :rtype: bool
247 """
248- if not file_path_name:
249+ if not file_path:
250 return False
251 try:
252- if os.path.exists(file_path_name):
253- os.remove(file_path_name)
254+ if file_path.exists():
255+ file_path.unlink()
256 return True
257 except (IOError, OSError):
258- log.exception("Unable to delete file {text}".format(text=file_path_name))
259+ log.exception('Unable to delete file {file_path}'.format(file_path=file_path))
260 return False
261
262
263@@ -411,18 +408,19 @@
264 return IMAGES_FILTER
265
266
267-def is_not_image_file(file_name):
268+def is_not_image_file(file_path):
269 """
270 Validate that the file is not an image file.
271
272- :param file_name: File name to be checked.
273+ :param pathlib.Path file_path: The file to be checked.
274+ :return: If the file is not an image
275+ :rtype: bool
276 """
277- if not file_name:
278+ if not (file_path and file_path.exists()):
279 return True
280 else:
281 formats = [bytes(fmt).decode().lower() for fmt in QtGui.QImageReader.supportedImageFormats()]
282- file_part, file_extension = os.path.splitext(str(file_name))
283- if file_extension[1:].lower() in formats and os.path.exists(file_name):
284+ if file_path.suffix[1:].lower() in formats:
285 return False
286 return True
287
288@@ -431,10 +429,10 @@
289 """
290 Removes invalid characters from the given ``filename``.
291
292- :param filename: The "dirty" file name to clean.
293+ :param str filename: The "dirty" file name to clean.
294+ :return: The cleaned string
295+ :rtype: str
296 """
297- if not isinstance(filename, str):
298- filename = str(filename, 'utf-8')
299 return INVALID_FILE_CHARS.sub('_', CONTROL_CHARS.sub('', filename))
300
301
302@@ -442,8 +440,9 @@
303 """
304 Function that checks whether a binary exists.
305
306- :param program_path: The full path to the binary to check.
307+ :param pathlib.Path program_path: The full path to the binary to check.
308 :return: program output to be parsed
309+ :rtype: bytes
310 """
311 log.debug('testing program_path: {text}'.format(text=program_path))
312 try:
313@@ -453,26 +452,27 @@
314 startupinfo.dwFlags |= STARTF_USESHOWWINDOW
315 else:
316 startupinfo = None
317- runlog = check_output([program_path, '--help'], stderr=STDOUT, startupinfo=startupinfo)
318+ run_log = check_output([str(program_path), '--help'], stderr=STDOUT, startupinfo=startupinfo)
319 except CalledProcessError as e:
320- runlog = e.output
321+ run_log = e.output
322 except Exception:
323 trace_error_handler(log)
324- runlog = ''
325- log.debug('check_output returned: {text}'.format(text=runlog))
326- return runlog
327-
328-
329-def get_file_encoding(filename):
330+ run_log = ''
331+ log.debug('check_output returned: {text}'.format(text=run_log))
332+ return run_log
333+
334+
335+def get_file_encoding(file_path):
336 """
337 Utility function to incrementally detect the file encoding.
338
339- :param filename: Filename for the file to determine the encoding for. Str
340+ :param pathlib.Path file_path: Filename for the file to determine the encoding for.
341 :return: A dict with the keys 'encoding' and 'confidence'
342+ :rtype: dict[str, float]
343 """
344 detector = UniversalDetector()
345 try:
346- with open(filename, 'rb') as detect_file:
347+ with file_path.open('rb') as detect_file:
348 while not detector.done:
349 chunk = detect_file.read(1024)
350 if not chunk:
351
352=== modified file 'openlp/core/common/applocation.py'
353--- openlp/core/common/applocation.py 2017-08-02 06:09:38 +0000
354+++ openlp/core/common/applocation.py 2017-08-24 19:54:19 +0000
355@@ -58,9 +58,6 @@
356 CacheDir = 5
357 LanguageDir = 6
358
359- # Base path where data/config/cache dir is located
360- BaseDir = None
361-
362 @staticmethod
363 def get_directory(dir_type=AppDir):
364 """
365@@ -78,8 +75,6 @@
366 return get_frozen_path(FROZEN_APP_PATH, APP_PATH) / 'plugins'
367 elif dir_type == AppLocation.LanguageDir:
368 return get_frozen_path(FROZEN_APP_PATH, _get_os_dir_path(dir_type)) / 'i18n'
369- elif dir_type == AppLocation.DataDir and AppLocation.BaseDir:
370- return Path(AppLocation.BaseDir, 'data')
371 else:
372 return _get_os_dir_path(dir_type)
373
374@@ -96,7 +91,7 @@
375 path = Path(Settings().value('advanced/data path'))
376 else:
377 path = AppLocation.get_directory(AppLocation.DataDir)
378- check_directory_exists(str(path))
379+ check_directory_exists(path)
380 return path
381
382 @staticmethod
383@@ -104,14 +99,10 @@
384 """
385 Get a list of files from the data files path.
386
387- :param section: Defaults to *None*. The section of code getting the files - used to load from a section's data
388- subdirectory.
389- :type section: None | str
390-
391- :param extension: Defaults to ''. The extension to search for. For example::
392+ :param None | str section: Defaults to *None*. The section of code getting the files - used to load from a
393+ section's data subdirectory.
394+ :param str extension: Defaults to ''. The extension to search for. For example::
395 '.png'
396- :type extension: str
397-
398 :return: List of files found.
399 :rtype: list[pathlib.Path]
400 """
401@@ -134,7 +125,7 @@
402 :rtype: pathlib.Path
403 """
404 path = AppLocation.get_data_path() / section
405- check_directory_exists(str(path))
406+ check_directory_exists(path)
407 return path
408
409
410@@ -143,14 +134,12 @@
411 Return a path based on which OS and environment we are running in.
412
413 :param dir_type: AppLocation Enum of the requested path type
414- :type dir_type: AppLocation Enum
415-
416 :return: The requested path
417 :rtype: pathlib.Path
418 """
419 # If running from source, return the language directory from the source directory
420 if dir_type == AppLocation.LanguageDir:
421- directory = Path(os.path.abspath(os.path.join(os.path.dirname(openlp.__file__), '..', 'resources')))
422+ directory = Path(openlp.__file__, '..', '..').resolve() / 'resources'
423 if directory.exists():
424 return directory
425 if is_win():
426@@ -158,14 +147,14 @@
427 if dir_type == AppLocation.DataDir:
428 return openlp_folder_path / 'data'
429 elif dir_type == AppLocation.LanguageDir:
430- return os.path.dirname(openlp.__file__)
431+ return Path(openlp.__file__).parent
432 return openlp_folder_path
433 elif is_macosx():
434 openlp_folder_path = Path(os.getenv('HOME'), 'Library', 'Application Support', 'openlp')
435 if dir_type == AppLocation.DataDir:
436 return openlp_folder_path / 'Data'
437 elif dir_type == AppLocation.LanguageDir:
438- return os.path.dirname(openlp.__file__)
439+ return Path(openlp.__file__).parent
440 return openlp_folder_path
441 else:
442 if dir_type == AppLocation.LanguageDir:
443
444=== modified file 'openlp/core/common/settings.py'
445--- openlp/core/common/settings.py 2017-08-23 20:21:11 +0000
446+++ openlp/core/common/settings.py 2017-08-24 19:54:19 +0000
447@@ -502,31 +502,3 @@
448 if isinstance(default_value, int):
449 return int(setting)
450 return setting
451-
452- def get_files_from_config(self, plugin):
453- """
454- This removes the settings needed for old way we saved files (e. g. the image paths for the image plugin). A list
455- of file paths are returned.
456-
457- **Note**: Only a list of paths is returned; this does not convert anything!
458-
459- :param plugin: The Plugin object.The caller has to convert/save the list himself; o
460- """
461- files_list = []
462- # We need QSettings instead of Settings here to bypass our central settings dict.
463- # Do NOT do this anywhere else!
464- settings = QtCore.QSettings(self.fileName(), Settings.IniFormat)
465- settings.beginGroup(plugin.settings_section)
466- if settings.contains('{name} count'.format(name=plugin.name)):
467- # Get the count.
468- list_count = int(settings.value('{name} count'.format(name=plugin.name), 0))
469- if list_count:
470- for counter in range(list_count):
471- # The keys were named e. g.: "image 0"
472- item = settings.value('{name} {counter:d}'.format(name=plugin.name, counter=counter), '')
473- if item:
474- files_list.append(item)
475- settings.remove('{name} {counter:d}'.format(name=plugin.name, counter=counter))
476- settings.remove('{name} count'.format(name=plugin.name))
477- settings.endGroup()
478- return files_list
479
480=== modified file 'openlp/core/lib/__init__.py'
481--- openlp/core/lib/__init__.py 2017-08-23 20:21:11 +0000
482+++ openlp/core/lib/__init__.py 2017-08-24 19:54:19 +0000
483@@ -83,30 +83,28 @@
484 Next = 3
485
486
487-def get_text_file_string(text_file):
488+def get_text_file_string(text_file_path):
489 """
490- Open a file and return its content as unicode string. If the supplied file name is not a file then the function
491+ Open a file and return its content as a string. If the supplied file path is not a file then the function
492 returns False. If there is an error loading the file or the content can't be decoded then the function will return
493 None.
494
495- :param text_file: The name of the file.
496- :return: The file as a single string
497+ :param pathlib.Path text_file_path: The path to the file.
498+ :return: The contents of the file, False if the file does not exist, or None if there is an Error reading or
499+ decoding the file.
500+ :rtype: str | False | None
501 """
502- if not os.path.isfile(text_file):
503+ if not text_file_path.is_file():
504 return False
505- file_handle = None
506 content = None
507 try:
508- file_handle = open(text_file, 'r', encoding='utf-8')
509- if file_handle.read(3) != '\xEF\xBB\xBF':
510- # no BOM was found
511- file_handle.seek(0)
512- content = file_handle.read()
513+ with text_file_path.open('r', encoding='utf-8') as file_handle:
514+ if file_handle.read(3) != '\xEF\xBB\xBF':
515+ # no BOM was found
516+ file_handle.seek(0)
517+ content = file_handle.read()
518 except (IOError, UnicodeError):
519- log.exception('Failed to open text file {text}'.format(text=text_file))
520- finally:
521- if file_handle:
522- file_handle.close()
523+ log.exception('Failed to open text file {text}'.format(text=text_file_path))
524 return content
525
526
527
528=== modified file 'openlp/core/lib/db.py'
529--- openlp/core/lib/db.py 2017-08-01 20:59:41 +0000
530+++ openlp/core/lib/db.py 2017-08-24 19:54:19 +0000
531@@ -274,9 +274,9 @@
532 :param db_file_name: The database file name. Defaults to None resulting in the plugin_name being used.
533 """
534 if db_file_name:
535- db_file_path = os.path.join(str(AppLocation.get_section_data_path(plugin_name)), db_file_name)
536+ db_file_path = AppLocation.get_section_data_path(plugin_name) / db_file_name
537 else:
538- db_file_path = os.path.join(str(AppLocation.get_section_data_path(plugin_name)), plugin_name)
539+ db_file_path = AppLocation.get_section_data_path(plugin_name) / plugin_name
540 return delete_file(db_file_path)
541
542
543
544=== modified file 'openlp/core/lib/pluginmanager.py'
545--- openlp/core/lib/pluginmanager.py 2017-08-01 20:59:41 +0000
546+++ openlp/core/lib/pluginmanager.py 2017-08-24 19:54:19 +0000
547@@ -69,7 +69,7 @@
548 """
549 Scan a directory for objects inheriting from the ``Plugin`` class.
550 """
551- glob_pattern = os.path.join('openlp', 'plugins', '*', '*plugin.py')
552+ glob_pattern = os.path.join('plugins', '*', '*plugin.py')
553 extension_loader(glob_pattern)
554 plugin_classes = Plugin.__subclasses__()
555 plugin_objects = []
556
557=== modified file 'openlp/core/lib/theme.py'
558--- openlp/core/lib/theme.py 2017-08-01 20:59:41 +0000
559+++ openlp/core/lib/theme.py 2017-08-24 19:54:19 +0000
560@@ -158,9 +158,8 @@
561 Initialise the theme object.
562 """
563 # basic theme object with defaults
564- json_dir = os.path.join(str(AppLocation.get_directory(AppLocation.AppDir)), 'core', 'lib', 'json')
565- json_file = os.path.join(json_dir, 'theme.json')
566- jsn = get_text_file_string(json_file)
567+ json_path = AppLocation.get_directory(AppLocation.AppDir) / 'core' / 'lib' / 'json' / 'theme.json'
568+ jsn = get_text_file_string(json_path)
569 jsn = json.loads(jsn)
570 self.expand_json(jsn)
571 self.background_filename = ''
572
573=== modified file 'openlp/core/ui/firsttimeform.py'
574--- openlp/core/ui/firsttimeform.py 2017-08-03 17:54:40 +0000
575+++ openlp/core/ui/firsttimeform.py 2017-08-24 19:54:19 +0000
576@@ -29,8 +29,9 @@
577 import urllib.request
578 import urllib.parse
579 import urllib.error
580+from configparser import ConfigParser, MissingSectionHeaderError, NoOptionError, NoSectionError
581+from pathlib import Path
582 from tempfile import gettempdir
583-from configparser import ConfigParser, MissingSectionHeaderError, NoSectionError, NoOptionError
584
585 from PyQt5 import QtCore, QtWidgets
586
587@@ -282,7 +283,7 @@
588 self.no_internet_cancel_button.setVisible(False)
589 # Check if this is a re-run of the wizard.
590 self.has_run_wizard = Settings().value('core/has run wizard')
591- check_directory_exists(os.path.join(gettempdir(), 'openlp'))
592+ check_directory_exists(Path(gettempdir(), 'openlp'))
593
594 def update_screen_list_combo(self):
595 """
596
597=== modified file 'openlp/core/ui/mainwindow.py'
598--- openlp/core/ui/mainwindow.py 2017-08-03 17:54:40 +0000
599+++ openlp/core/ui/mainwindow.py 2017-08-24 19:54:19 +0000
600@@ -30,6 +30,7 @@
601 from datetime import datetime
602 from distutils import dir_util
603 from distutils.errors import DistutilsFileError
604+from pathlib import Path
605 from tempfile import gettempdir
606
607 from PyQt5 import QtCore, QtGui, QtWidgets
608@@ -870,7 +871,7 @@
609 setting_sections.extend([plugin.name for plugin in self.plugin_manager.plugins])
610 # Copy the settings file to the tmp dir, because we do not want to change the original one.
611 temp_directory = os.path.join(str(gettempdir()), 'openlp')
612- check_directory_exists(temp_directory)
613+ check_directory_exists(Path(temp_directory))
614 temp_config = os.path.join(temp_directory, os.path.basename(import_file_name))
615 shutil.copyfile(import_file_name, temp_config)
616 settings = Settings()
617
618=== modified file 'openlp/core/ui/media/mediacontroller.py'
619--- openlp/core/ui/media/mediacontroller.py 2017-06-25 17:03:31 +0000
620+++ openlp/core/ui/media/mediacontroller.py 2017-08-24 19:54:19 +0000
621@@ -177,7 +177,7 @@
622 Check to see if we have any media Player's available.
623 """
624 log.debug('_check_available_media_players')
625- controller_dir = os.path.join('openlp', 'core', 'ui', 'media')
626+ controller_dir = os.path.join('core', 'ui', 'media')
627 glob_pattern = os.path.join(controller_dir, '*player.py')
628 extension_loader(glob_pattern, ['mediaplayer.py'])
629 player_classes = MediaPlayer.__subclasses__()
630
631=== modified file 'openlp/core/ui/printserviceform.py'
632--- openlp/core/ui/printserviceform.py 2017-08-01 20:59:41 +0000
633+++ openlp/core/ui/printserviceform.py 2017-08-24 19:54:19 +0000
634@@ -176,7 +176,7 @@
635 html_data = self._add_element('html')
636 self._add_element('head', parent=html_data)
637 self._add_element('title', self.title_line_edit.text(), html_data.head)
638- css_path = os.path.join(str(AppLocation.get_data_path()), 'serviceprint', 'service_print.css')
639+ css_path = AppLocation.get_data_path() / 'serviceprint' / 'service_print.css'
640 custom_css = get_text_file_string(css_path)
641 if not custom_css:
642 custom_css = DEFAULT_CSS
643
644=== modified file 'openlp/core/ui/servicemanager.py'
645--- openlp/core/ui/servicemanager.py 2017-08-03 17:54:40 +0000
646+++ openlp/core/ui/servicemanager.py 2017-08-24 19:54:19 +0000
647@@ -28,6 +28,7 @@
648 import shutil
649 import zipfile
650 from datetime import datetime, timedelta
651+from pathlib import Path
652 from tempfile import mkstemp
653
654 from PyQt5 import QtCore, QtGui, QtWidgets
655@@ -587,7 +588,7 @@
656 audio_from = os.path.join(self.service_path, audio_from)
657 save_file = os.path.join(self.service_path, audio_to)
658 save_path = os.path.split(save_file)[0]
659- check_directory_exists(save_path)
660+ check_directory_exists(Path(save_path))
661 if not os.path.exists(save_file):
662 shutil.copy(audio_from, save_file)
663 zip_file.write(audio_from, audio_to)
664@@ -614,7 +615,7 @@
665 success = False
666 self.main_window.add_recent_file(path_file_name)
667 self.set_modified(False)
668- delete_file(temp_file_name)
669+ delete_file(Path(temp_file_name))
670 return success
671
672 def save_local_file(self):
673@@ -669,7 +670,7 @@
674 return self.save_file_as()
675 self.main_window.add_recent_file(path_file_name)
676 self.set_modified(False)
677- delete_file(temp_file_name)
678+ delete_file(Path(temp_file_name))
679 return success
680
681 def save_file_as(self, field=None):
682@@ -774,7 +775,7 @@
683 self.set_file_name(file_name)
684 self.main_window.display_progress_bar(len(items))
685 self.process_service_items(items)
686- delete_file(p_file)
687+ delete_file(Path(p_file))
688 self.main_window.add_recent_file(file_name)
689 self.set_modified(False)
690 Settings().setValue('servicemanager/last file', file_name)
691@@ -1343,7 +1344,7 @@
692 Empties the service_path of temporary files on system exit.
693 """
694 for file_name in os.listdir(self.service_path):
695- file_path = os.path.join(self.service_path, file_name)
696+ file_path = Path(self.service_path, file_name)
697 delete_file(file_path)
698 if os.path.exists(os.path.join(self.service_path, 'audio')):
699 shutil.rmtree(os.path.join(self.service_path, 'audio'), True)
700
701=== modified file 'openlp/core/ui/themeform.py'
702--- openlp/core/ui/themeform.py 2017-08-07 20:50:01 +0000
703+++ openlp/core/ui/themeform.py 2017-08-24 19:54:19 +0000
704@@ -24,6 +24,7 @@
705 """
706 import logging
707 import os
708+from pathlib import Path
709
710 from PyQt5 import QtCore, QtGui, QtWidgets
711
712@@ -188,7 +189,8 @@
713 """
714 background_image = BackgroundType.to_string(BackgroundType.Image)
715 if self.page(self.currentId()) == self.background_page and \
716- self.theme.background_type == background_image and is_not_image_file(self.theme.background_filename):
717+ self.theme.background_type == background_image and \
718+ is_not_image_file(Path(self.theme.background_filename)):
719 QtWidgets.QMessageBox.critical(self, translate('OpenLP.ThemeWizard', 'Background Image Empty'),
720 translate('OpenLP.ThemeWizard', 'You have not selected a '
721 'background image. Please select one before continuing.'))
722
723=== modified file 'openlp/core/ui/thememanager.py'
724--- openlp/core/ui/thememanager.py 2017-08-07 20:50:01 +0000
725+++ openlp/core/ui/thememanager.py 2017-08-24 19:54:19 +0000
726@@ -25,6 +25,7 @@
727 import os
728 import zipfile
729 import shutil
730+from pathlib import Path
731
732 from xml.etree.ElementTree import ElementTree, XML
733 from PyQt5 import QtCore, QtGui, QtWidgets
734@@ -161,9 +162,9 @@
735 Set up the theme path variables
736 """
737 self.path = str(AppLocation.get_section_data_path(self.settings_section))
738- check_directory_exists(self.path)
739+ check_directory_exists(Path(self.path))
740 self.thumb_path = os.path.join(self.path, 'thumbnails')
741- check_directory_exists(self.thumb_path)
742+ check_directory_exists(Path(self.thumb_path))
743
744 def check_list_state(self, item, field=None):
745 """
746@@ -355,8 +356,8 @@
747 """
748 self.theme_list.remove(theme)
749 thumb = '{name}.png'.format(name=theme)
750- delete_file(os.path.join(self.path, thumb))
751- delete_file(os.path.join(self.thumb_path, thumb))
752+ delete_file(Path(self.path, thumb))
753+ delete_file(Path(self.thumb_path, thumb))
754 try:
755 # Windows is always unicode, so no need to encode filenames
756 if is_win():
757@@ -450,7 +451,7 @@
758 for theme_file in files:
759 theme_file = os.path.join(self.path, str(theme_file))
760 self.unzip_theme(theme_file, self.path)
761- delete_file(theme_file)
762+ delete_file(Path(theme_file))
763 files = AppLocation.get_files(self.settings_section, '.png')
764 # No themes have been found so create one
765 if not files:
766@@ -514,12 +515,12 @@
767 :return: The theme object.
768 """
769 self.log_debug('get theme data for theme {name}'.format(name=theme_name))
770- theme_file = os.path.join(self.path, str(theme_name), str(theme_name) + '.json')
771- theme_data = get_text_file_string(theme_file)
772+ theme_file_path = Path(self.path, str(theme_name), '{file_name}.json'.format(file_name=theme_name))
773+ theme_data = get_text_file_string(theme_file_path)
774 jsn = True
775 if not theme_data:
776- theme_file = os.path.join(self.path, str(theme_name), str(theme_name) + '.xml')
777- theme_data = get_text_file_string(theme_file)
778+ theme_file_path = theme_file_path.with_suffix('.xml')
779+ theme_data = get_text_file_string(theme_file_path)
780 jsn = False
781 if not theme_data:
782 self.log_debug('No theme data - using default theme')
783@@ -592,7 +593,7 @@
784 # is directory or preview file
785 continue
786 full_name = os.path.join(directory, out_name)
787- check_directory_exists(os.path.dirname(full_name))
788+ check_directory_exists(Path(os.path.dirname(full_name)))
789 if os.path.splitext(name)[1].lower() == '.xml' or os.path.splitext(name)[1].lower() == '.json':
790 file_xml = str(theme_zip.read(name), 'utf-8')
791 out_file = open(full_name, 'w', encoding='utf-8')
792@@ -670,10 +671,10 @@
793 name = theme.theme_name
794 theme_pretty = theme.export_theme()
795 theme_dir = os.path.join(self.path, name)
796- check_directory_exists(theme_dir)
797+ check_directory_exists(Path(theme_dir))
798 theme_file = os.path.join(theme_dir, name + '.json')
799 if self.old_background_image and image_to != self.old_background_image:
800- delete_file(self.old_background_image)
801+ delete_file(Path(self.old_background_image))
802 out_file = None
803 try:
804 out_file = open(theme_file, 'w', encoding='utf-8')
805
806=== modified file 'openlp/plugins/bibles/lib/importers/csvbible.py'
807--- openlp/plugins/bibles/lib/importers/csvbible.py 2016-12-31 11:01:36 +0000
808+++ openlp/plugins/bibles/lib/importers/csvbible.py 2017-08-24 19:54:19 +0000
809@@ -51,6 +51,7 @@
810 """
811 import csv
812 from collections import namedtuple
813+from pathlib import Path
814
815 from openlp.core.common import get_file_encoding, translate
816 from openlp.core.lib.exceptions import ValidationError
817@@ -100,7 +101,7 @@
818 :return: An iterable yielding namedtuples of type results_tuple
819 """
820 try:
821- encoding = get_file_encoding(filename)['encoding']
822+ encoding = get_file_encoding(Path(filename))['encoding']
823 with open(filename, 'r', encoding=encoding, newline='') as csv_file:
824 csv_reader = csv.reader(csv_file, delimiter=',', quotechar='"')
825 return [results_tuple(*line) for line in csv_reader]
826
827=== modified file 'openlp/plugins/bibles/lib/manager.py'
828--- openlp/plugins/bibles/lib/manager.py 2017-08-01 20:59:41 +0000
829+++ openlp/plugins/bibles/lib/manager.py 2017-08-24 19:54:19 +0000
830@@ -22,6 +22,7 @@
831
832 import logging
833 import os
834+from pathlib import Path
835
836 from openlp.core.common import AppLocation, OpenLPMixin, RegistryProperties, Settings, translate, delete_file, UiStrings
837 from openlp.plugins.bibles.lib import LanguageSelection, parse_reference
838@@ -137,7 +138,7 @@
839 # Remove corrupted files.
840 if name is None:
841 bible.session.close_all()
842- delete_file(os.path.join(self.path, filename))
843+ delete_file(Path(self.path, filename))
844 continue
845 log.debug('Bible Name: "{name}"'.format(name=name))
846 self.db_cache[name] = bible
847@@ -185,7 +186,7 @@
848 bible = self.db_cache[name]
849 bible.session.close_all()
850 bible.session = None
851- return delete_file(os.path.join(bible.path, bible.file))
852+ return delete_file(Path(bible.path, bible.file))
853
854 def get_bibles(self):
855 """
856
857=== modified file 'openlp/plugins/images/lib/mediaitem.py'
858--- openlp/plugins/images/lib/mediaitem.py 2017-08-03 17:54:40 +0000
859+++ openlp/plugins/images/lib/mediaitem.py 2017-08-24 19:54:19 +0000
860@@ -22,6 +22,7 @@
861
862 import logging
863 import os
864+from pathlib import Path
865
866 from PyQt5 import QtCore, QtGui, QtWidgets
867
868@@ -99,7 +100,7 @@
869 self.list_view.setIndentation(self.list_view.default_indentation)
870 self.list_view.allow_internal_dnd = True
871 self.service_path = os.path.join(str(AppLocation.get_section_data_path(self.settings_section)), 'thumbnails')
872- check_directory_exists(self.service_path)
873+ check_directory_exists(Path(self.service_path))
874 # Load images from the database
875 self.load_full_list(
876 self.manager.get_all_objects(ImageFilenames, order_by_ref=ImageFilenames.filename), initial_load=True)
877@@ -210,8 +211,8 @@
878 """
879 images = self.manager.get_all_objects(ImageFilenames, ImageFilenames.group_id == image_group.id)
880 for image in images:
881- delete_file(os.path.join(self.service_path, os.path.split(image.filename)[1]))
882- delete_file(self.generate_thumbnail_path(image))
883+ delete_file(Path(self.service_path, os.path.split(image.filename)[1]))
884+ delete_file(Path(self.generate_thumbnail_path(image)))
885 self.manager.delete_object(ImageFilenames, image.id)
886 image_groups = self.manager.get_all_objects(ImageGroups, ImageGroups.parent_id == image_group.id)
887 for group in image_groups:
888@@ -233,8 +234,8 @@
889 if row_item:
890 item_data = row_item.data(0, QtCore.Qt.UserRole)
891 if isinstance(item_data, ImageFilenames):
892- delete_file(os.path.join(self.service_path, row_item.text(0)))
893- delete_file(self.generate_thumbnail_path(item_data))
894+ delete_file(Path(self.service_path, row_item.text(0)))
895+ delete_file(Path(self.generate_thumbnail_path(item_data)))
896 if item_data.group_id == 0:
897 self.list_view.takeTopLevelItem(self.list_view.indexOfTopLevelItem(row_item))
898 else:
899
900=== modified file 'openlp/plugins/media/lib/mediaitem.py'
901--- openlp/plugins/media/lib/mediaitem.py 2017-08-03 17:54:40 +0000
902+++ openlp/plugins/media/lib/mediaitem.py 2017-08-24 19:54:19 +0000
903@@ -22,6 +22,7 @@
904
905 import logging
906 import os
907+from pathlib import Path
908
909 from PyQt5 import QtCore, QtWidgets
910
911@@ -301,7 +302,7 @@
912 """
913 self.list_view.clear()
914 self.service_path = os.path.join(str(AppLocation.get_section_data_path(self.settings_section)), 'thumbnails')
915- check_directory_exists(self.service_path)
916+ check_directory_exists(Path(self.service_path))
917 self.load_list(Settings().value(self.settings_section + '/media files'))
918 self.rebuild_players()
919
920
921=== modified file 'openlp/plugins/media/mediaplugin.py'
922--- openlp/plugins/media/mediaplugin.py 2017-08-03 17:54:40 +0000
923+++ openlp/plugins/media/mediaplugin.py 2017-08-24 19:54:19 +0000
924@@ -26,6 +26,7 @@
925 import logging
926 import os
927 import re
928+from pathlib import Path
929
930 from PyQt5 import QtCore
931
932@@ -165,8 +166,7 @@
933 :param program_path:The full path to the binary to check.
934 :return: If exists or not
935 """
936- program_type = None
937- runlog = check_binary_exists(program_path)
938+ runlog = check_binary_exists(Path(program_path))
939 # Analyse the output to see it the program is mediainfo
940 for line in runlog.splitlines():
941 decoded_line = line.decode()
942
943=== modified file 'openlp/plugins/presentations/lib/impresscontroller.py'
944--- openlp/plugins/presentations/lib/impresscontroller.py 2017-05-14 10:11:10 +0000
945+++ openlp/plugins/presentations/lib/impresscontroller.py 2017-08-24 19:54:19 +0000
946@@ -34,6 +34,7 @@
947 import logging
948 import os
949 import time
950+from pathlib import Path
951
952 from openlp.core.common import is_win, Registry, get_uno_command, get_uno_instance, delete_file
953
954@@ -275,7 +276,7 @@
955 try:
956 doc.storeToURL(url_path, properties)
957 self.convert_thumbnail(path, index + 1)
958- delete_file(path)
959+ delete_file(Path(path))
960 except ErrorCodeIOException as exception:
961 log.exception('ERROR! ErrorCodeIOException {error:d}'.format(error=exception.ErrCode))
962 except:
963
964=== modified file 'openlp/plugins/presentations/lib/pdfcontroller.py'
965--- openlp/plugins/presentations/lib/pdfcontroller.py 2017-08-01 20:59:41 +0000
966+++ openlp/plugins/presentations/lib/pdfcontroller.py 2017-08-24 19:54:19 +0000
967@@ -23,6 +23,7 @@
968 import os
969 import logging
970 import re
971+from pathlib import Path
972 from shutil import which
973 from subprocess import check_output, CalledProcessError
974
975@@ -69,7 +70,7 @@
976 :return: Type of the binary, 'gs' if ghostscript, 'mudraw' if mudraw, None if invalid.
977 """
978 program_type = None
979- runlog = check_binary_exists(program_path)
980+ runlog = check_binary_exists(Path(program_path))
981 # Analyse the output to see it the program is mudraw, ghostscript or neither
982 for line in runlog.splitlines():
983 decoded_line = line.decode()
984
985=== modified file 'openlp/plugins/presentations/lib/presentationcontroller.py'
986--- openlp/plugins/presentations/lib/presentationcontroller.py 2017-08-01 20:59:41 +0000
987+++ openlp/plugins/presentations/lib/presentationcontroller.py 2017-08-24 19:54:19 +0000
988@@ -23,6 +23,7 @@
989 import logging
990 import os
991 import shutil
992+from pathlib import Path
993
994 from PyQt5 import QtCore
995
996@@ -98,7 +99,7 @@
997 """
998 self.slide_number = 0
999 self.file_path = name
1000- check_directory_exists(self.get_thumbnail_folder())
1001+ check_directory_exists(Path(self.get_thumbnail_folder()))
1002
1003 def load_presentation(self):
1004 """
1005@@ -419,8 +420,8 @@
1006 self.thumbnail_folder = os.path.join(
1007 str(AppLocation.get_section_data_path(self.settings_section)), 'thumbnails')
1008 self.thumbnail_prefix = 'slide'
1009- check_directory_exists(self.thumbnail_folder)
1010- check_directory_exists(self.temp_folder)
1011+ check_directory_exists(Path(self.thumbnail_folder))
1012+ check_directory_exists(Path(self.temp_folder))
1013
1014 def enabled(self):
1015 """
1016
1017=== modified file 'openlp/plugins/presentations/presentationplugin.py'
1018--- openlp/plugins/presentations/presentationplugin.py 2017-06-09 15:56:40 +0000
1019+++ openlp/plugins/presentations/presentationplugin.py 2017-08-24 19:54:19 +0000
1020@@ -125,7 +125,7 @@
1021 Check to see if we have any presentation software available. If not do not install the plugin.
1022 """
1023 log.debug('check_pre_conditions')
1024- controller_dir = os.path.join('openlp', 'plugins', 'presentations', 'lib')
1025+ controller_dir = os.path.join('plugins', 'presentations', 'lib')
1026 glob_pattern = os.path.join(controller_dir, '*controller.py')
1027 extension_loader(glob_pattern, ['presentationcontroller.py'])
1028 controller_classes = PresentationController.__subclasses__()
1029
1030=== modified file 'openlp/plugins/remotes/remoteplugin.py'
1031--- openlp/plugins/remotes/remoteplugin.py 2017-06-18 06:03:42 +0000
1032+++ openlp/plugins/remotes/remoteplugin.py 2017-08-24 19:54:19 +0000
1033@@ -59,21 +59,22 @@
1034 Create the internal file structure if it does not exist
1035 :return:
1036 """
1037- check_directory_exists(os.path.join(AppLocation.get_section_data_path('remotes'), 'assets'))
1038- check_directory_exists(os.path.join(AppLocation.get_section_data_path('remotes'), 'images'))
1039- check_directory_exists(os.path.join(AppLocation.get_section_data_path('remotes'), 'static'))
1040- check_directory_exists(os.path.join(AppLocation.get_section_data_path('remotes'), 'static', 'index'))
1041- check_directory_exists(os.path.join(AppLocation.get_section_data_path('remotes'), 'templates'))
1042+ check_directory_exists(AppLocation.get_section_data_path('remotes') / 'assets')
1043+ check_directory_exists(AppLocation.get_section_data_path('remotes') / 'images')
1044+ check_directory_exists(AppLocation.get_section_data_path('remotes') / 'static')
1045+ check_directory_exists(AppLocation.get_section_data_path('remotes') / 'static', 'index')
1046+ check_directory_exists(AppLocation.get_section_data_path('remotes') / 'templates')
1047
1048 @staticmethod
1049 def about():
1050 """
1051 Information about this plugin
1052 """
1053- about_text = translate('RemotePlugin', '<strong>Web Interface</strong>'
1054- '<br />The web interface plugin provides the ability develop web based '
1055- 'interfaces using openlp web services. \nPredefined interfaces can be '
1056- 'download as well as custom developed interfaces')
1057+ about_text = translate(
1058+ 'RemotePlugin',
1059+ '<strong>Web Interface</strong>'
1060+ '<br />The web interface plugin provides the ability to develop web based interfaces using OpenLP web '
1061+ 'services.\nPredefined interfaces can be download as well as custom developed interfaces.')
1062 return about_text
1063
1064 def set_plugin_text_strings(self):
1065
1066=== modified file 'openlp/plugins/songs/forms/editsongform.py'
1067--- openlp/plugins/songs/forms/editsongform.py 2017-08-11 20:47:52 +0000
1068+++ openlp/plugins/songs/forms/editsongform.py 2017-08-24 19:54:19 +0000
1069@@ -1071,7 +1071,7 @@
1070 log.debug(audio_files)
1071 save_path = os.path.join(str(AppLocation.get_section_data_path(self.media_item.plugin.name)), 'audio',
1072 str(self.song.id))
1073- check_directory_exists(save_path)
1074+ check_directory_exists(Path(save_path))
1075 self.song.media_files = []
1076 files = []
1077 for row in range(self.audio_list_widget.count()):
1078
1079=== modified file 'openlp/plugins/songs/lib/importers/songbeamer.py'
1080--- openlp/plugins/songs/lib/importers/songbeamer.py 2017-05-11 19:53:47 +0000
1081+++ openlp/plugins/songs/lib/importers/songbeamer.py 2017-08-24 19:54:19 +0000
1082@@ -27,6 +27,7 @@
1083 import re
1084 import base64
1085 import math
1086+from pathlib import Path
1087
1088 from openlp.plugins.songs.lib import VerseType
1089 from openlp.plugins.songs.lib.importers.songimport import SongImport
1090@@ -122,7 +123,7 @@
1091 file_name = os.path.split(import_file)[1]
1092 if os.path.isfile(import_file):
1093 # Detect the encoding
1094- self.input_file_encoding = get_file_encoding(import_file)['encoding']
1095+ self.input_file_encoding = get_file_encoding(Path(import_file))['encoding']
1096 # The encoding should only be ANSI (cp1252), UTF-8, Unicode, Big-Endian-Unicode.
1097 # So if it doesn't start with 'u' we default to cp1252. See:
1098 # https://forum.songbeamer.com/viewtopic.php?p=419&sid=ca4814924e37c11e4438b7272a98b6f2
1099
1100=== modified file 'openlp/plugins/songs/lib/importers/songimport.py'
1101--- openlp/plugins/songs/lib/importers/songimport.py 2017-08-01 20:59:41 +0000
1102+++ openlp/plugins/songs/lib/importers/songimport.py 2017-08-24 19:54:19 +0000
1103@@ -24,6 +24,7 @@
1104 import re
1105 import shutil
1106 import os
1107+from pathlib import Path
1108
1109 from PyQt5 import QtCore
1110
1111@@ -423,7 +424,7 @@
1112 if not hasattr(self, 'save_path'):
1113 self.save_path = os.path.join(str(AppLocation.get_section_data_path(self.import_wizard.plugin.name)),
1114 'audio', str(song_id))
1115- check_directory_exists(self.save_path)
1116+ check_directory_exists(Path(self.save_path))
1117 if not filename.startswith(self.save_path):
1118 old_file, filename = filename, os.path.join(self.save_path, os.path.split(filename)[1])
1119 shutil.copyfile(old_file, filename)
1120
1121=== modified file 'openlp/plugins/songs/lib/mediaitem.py'
1122--- openlp/plugins/songs/lib/mediaitem.py 2017-08-03 17:54:40 +0000
1123+++ openlp/plugins/songs/lib/mediaitem.py 2017-08-24 19:54:19 +0000
1124@@ -23,6 +23,7 @@
1125 import logging
1126 import os
1127 import shutil
1128+from pathlib import Path
1129
1130 from PyQt5 import QtCore, QtWidgets
1131 from sqlalchemy.sql import and_, or_
1132@@ -89,7 +90,7 @@
1133 for i, bga in enumerate(item.background_audio):
1134 dest_file = os.path.join(
1135 str(AppLocation.get_section_data_path(self.plugin.name)), 'audio', str(song.id), os.path.split(bga)[1])
1136- check_directory_exists(os.path.split(dest_file)[0])
1137+ check_directory_exists(Path(os.path.split(dest_file)[0]))
1138 shutil.copyfile(os.path.join(str(AppLocation.get_section_data_path('servicemanager')), bga), dest_file)
1139 song.media_files.append(MediaFile.populate(weight=i, file_name=dest_file))
1140 self.plugin.manager.save_object(song, True)
1141@@ -535,7 +536,7 @@
1142 if len(old_song.media_files) > 0:
1143 save_path = os.path.join(
1144 str(AppLocation.get_section_data_path(self.plugin.name)), 'audio', str(new_song.id))
1145- check_directory_exists(save_path)
1146+ check_directory_exists(Path(save_path))
1147 for media_file in old_song.media_files:
1148 new_media_file_name = os.path.join(save_path, os.path.basename(media_file.file_name))
1149 shutil.copyfile(media_file.file_name, new_media_file_name)
1150
1151=== modified file 'openlp/plugins/songs/lib/openlyricsexport.py'
1152--- openlp/plugins/songs/lib/openlyricsexport.py 2016-12-31 11:01:36 +0000
1153+++ openlp/plugins/songs/lib/openlyricsexport.py 2017-08-24 19:54:19 +0000
1154@@ -25,6 +25,7 @@
1155 """
1156 import logging
1157 import os
1158+from pathlib import Path
1159
1160 from lxml import etree
1161
1162@@ -47,7 +48,7 @@
1163 self.manager = parent.plugin.manager
1164 self.songs = songs
1165 self.save_path = save_path
1166- check_directory_exists(self.save_path)
1167+ check_directory_exists(Path(self.save_path))
1168
1169 def do_export(self):
1170 """
1171
1172=== modified file 'openlp/plugins/songusage/forms/songusagedetailform.py'
1173--- openlp/plugins/songusage/forms/songusagedetailform.py 2017-08-04 17:40:57 +0000
1174+++ openlp/plugins/songusage/forms/songusagedetailform.py 2017-08-24 19:54:19 +0000
1175@@ -22,6 +22,7 @@
1176
1177 import logging
1178 import os
1179+from pathlib import Path
1180
1181 from PyQt5 import QtCore, QtWidgets
1182 from sqlalchemy.sql import and_
1183@@ -78,7 +79,7 @@
1184 ' song usage report. \nPlease select an existing path on your computer.')
1185 )
1186 return
1187- check_directory_exists(path)
1188+ check_directory_exists(Path(path))
1189 file_name = translate('SongUsagePlugin.SongUsageDetailForm',
1190 'usage_detail_{old}_{new}.txt'
1191 ).format(old=self.from_date_calendar.selectedDate().toString('ddMMyyyy'),
1192
1193=== modified file 'scripts/appveyor.yml'
1194--- scripts/appveyor.yml 2017-05-11 20:24:20 +0000
1195+++ scripts/appveyor.yml 2017-08-24 19:54:19 +0000
1196@@ -12,7 +12,7 @@
1197
1198 install:
1199 # Install dependencies from pypi
1200- - "%PYTHON%\\python.exe -m pip install sqlalchemy alembic chardet beautifulsoup4 Mako nose mock pyodbc==4.0.8 psycopg2 pypiwin32 pyenchant"
1201+ - "%PYTHON%\\python.exe -m pip install sqlalchemy alembic chardet beautifulsoup4 Mako nose mock pyodbc==4.0.8 psycopg2 pypiwin32 pyenchant websockets asyncio waitress six webob"
1202 # Install mysql dependency
1203 - "%PYTHON%\\python.exe -m pip install http://cdn.mysql.com/Downloads/Connector-Python/mysql-connector-python-2.0.4.zip#md5=3df394d89300db95163f17c843ef49df"
1204 # Download and install lxml and pyicu (originally from http://www.lfd.uci.edu/~gohlke/pythonlibs/)
1205
1206=== modified file 'tests/functional/openlp_core_common/test_applocation.py'
1207--- tests/functional/openlp_core_common/test_applocation.py 2017-08-01 20:59:41 +0000
1208+++ tests/functional/openlp_core_common/test_applocation.py 2017-08-24 19:54:19 +0000
1209@@ -43,14 +43,12 @@
1210 """
1211 with patch('openlp.core.common.applocation.Settings') as mocked_class, \
1212 patch('openlp.core.common.AppLocation.get_directory') as mocked_get_directory, \
1213- patch('openlp.core.common.applocation.check_directory_exists') as mocked_check_directory_exists, \
1214- patch('openlp.core.common.applocation.os') as mocked_os:
1215+ patch('openlp.core.common.applocation.check_directory_exists') as mocked_check_directory_exists:
1216 # GIVEN: A mocked out Settings class and a mocked out AppLocation.get_directory()
1217 mocked_settings = mocked_class.return_value
1218 mocked_settings.contains.return_value = False
1219- mocked_get_directory.return_value = os.path.join('test', 'dir')
1220+ mocked_get_directory.return_value = Path('test', 'dir')
1221 mocked_check_directory_exists.return_value = True
1222- mocked_os.path.normpath.return_value = os.path.join('test', 'dir')
1223
1224 # WHEN: we call AppLocation.get_data_path()
1225 data_path = AppLocation.get_data_path()
1226@@ -58,8 +56,8 @@
1227 # THEN: check that all the correct methods were called, and the result is correct
1228 mocked_settings.contains.assert_called_with('advanced/data path')
1229 mocked_get_directory.assert_called_with(AppLocation.DataDir)
1230- mocked_check_directory_exists.assert_called_with(os.path.join('test', 'dir'))
1231- self.assertEqual(os.path.join('test', 'dir'), data_path, 'Result should be "test/dir"')
1232+ mocked_check_directory_exists.assert_called_with(Path('test', 'dir'))
1233+ self.assertEqual(Path('test', 'dir'), data_path, 'Result should be "test/dir"')
1234
1235 def test_get_data_path_with_custom_location(self):
1236 """
1237@@ -125,7 +123,7 @@
1238 data_path = AppLocation.get_section_data_path('section')
1239
1240 # THEN: check that all the correct methods were called, and the result is correct
1241- mocked_check_directory_exists.assert_called_with(os.path.join('test', 'dir', 'section'))
1242+ mocked_check_directory_exists.assert_called_with(Path('test', 'dir', 'section'))
1243 self.assertEqual(Path('test', 'dir', 'section'), data_path, 'Result should be "test/dir/section"')
1244
1245 def test_get_directory_for_app_dir(self):
1246
1247=== modified file 'tests/functional/openlp_core_common/test_common.py'
1248--- tests/functional/openlp_core_common/test_common.py 2017-08-01 20:59:41 +0000
1249+++ tests/functional/openlp_core_common/test_common.py 2017-08-24 19:54:19 +0000
1250@@ -35,44 +35,70 @@
1251 """
1252 A test suite to test out various functions in the openlp.core.common module.
1253 """
1254- def test_check_directory_exists(self):
1255- """
1256- Test the check_directory_exists() function
1257- """
1258- with patch('openlp.core.lib.os.path.exists') as mocked_exists, \
1259- patch('openlp.core.lib.os.makedirs') as mocked_makedirs:
1260- # GIVEN: A directory to check and a mocked out os.makedirs and os.path.exists
1261- directory_to_check = 'existing/directory'
1262+ def test_check_directory_exists_dir_exists(self):
1263+ """
1264+ Test the check_directory_exists() function when the path already exists
1265+ """
1266+ # GIVEN: A `Path` to check with patched out mkdir and exists methods
1267+ with patch.object(Path, 'exists') as mocked_exists, \
1268+ patch.object(Path, 'mkdir') as mocked_mkdir, \
1269+ patch('openlp.core.common.log'):
1270
1271- # WHEN: os.path.exists returns True and we check to see if the directory exists
1272+ # WHEN: `check_directory_exists` is called and the path exists
1273 mocked_exists.return_value = True
1274- check_directory_exists(directory_to_check)
1275-
1276- # THEN: Only os.path.exists should have been called
1277- mocked_exists.assert_called_with(directory_to_check)
1278- self.assertIsNot(mocked_makedirs.called, 'os.makedirs should not have been called')
1279-
1280- # WHEN: os.path.exists returns False and we check the directory exists
1281+ check_directory_exists(Path('existing', 'directory'))
1282+
1283+ # THEN: The function should not attempt to create the directory
1284+ mocked_exists.assert_called_with()
1285+ self.assertFalse(mocked_mkdir.called)
1286+
1287+ def test_check_directory_exists_dir_doesnt_exists(self):
1288+ """
1289+ Test the check_directory_exists() function when the path does not already exist
1290+ """
1291+ # GIVEN: A `Path` to check with patched out mkdir and exists methods
1292+ with patch.object(Path, 'exists') as mocked_exists, \
1293+ patch.object(Path, 'mkdir') as mocked_mkdir, \
1294+ patch('openlp.core.common.log'):
1295+
1296+ # WHEN: `check_directory_exists` is called and the path does not exist
1297 mocked_exists.return_value = False
1298- check_directory_exists(directory_to_check)
1299-
1300- # THEN: Both the mocked functions should have been called
1301- mocked_exists.assert_called_with(directory_to_check)
1302- mocked_makedirs.assert_called_with(directory_to_check)
1303-
1304- # WHEN: os.path.exists raises an IOError
1305+ check_directory_exists(Path('existing', 'directory'))
1306+
1307+ # THEN: The directory should have been created
1308+ mocked_exists.assert_called_with()
1309+ mocked_mkdir.assert_called_with(parents=True)
1310+
1311+ def test_check_directory_exists_dir_io_error(self):
1312+ """
1313+ Test the check_directory_exists() when an IOError is raised
1314+ """
1315+ # GIVEN: A `Path` to check with patched out mkdir and exists methods
1316+ with patch.object(Path, 'exists') as mocked_exists, \
1317+ patch.object(Path, 'mkdir'), \
1318+ patch('openlp.core.common.log') as mocked_logger:
1319+
1320+ # WHEN: An IOError is raised when checking the if the path exists.
1321 mocked_exists.side_effect = IOError()
1322- check_directory_exists(directory_to_check)
1323-
1324- # THEN: We shouldn't get an exception though the mocked exists has been called
1325- mocked_exists.assert_called_with(directory_to_check)
1326+ check_directory_exists(Path('existing', 'directory'))
1327+
1328+ # THEN: The Error should have been logged
1329+ mocked_logger.exception.assert_called_once_with('failed to check if directory exists or create directory')
1330+
1331+ def test_check_directory_exists_dir_value_error(self):
1332+ """
1333+ Test the check_directory_exists() when an error other than IOError is raised
1334+ """
1335+ # GIVEN: A `Path` to check with patched out mkdir and exists methods
1336+ with patch.object(Path, 'exists') as mocked_exists, \
1337+ patch.object(Path, 'mkdir'), \
1338+ patch('openlp.core.common.log'):
1339
1340 # WHEN: Some other exception is raised
1341 mocked_exists.side_effect = ValueError()
1342
1343- # THEN: check_directory_exists raises an exception
1344- mocked_exists.assert_called_with(directory_to_check)
1345- self.assertRaises(ValueError, check_directory_exists, directory_to_check)
1346+ # THEN: `check_directory_exists` raises an exception
1347+ self.assertRaises(ValueError, check_directory_exists, Path('existing', 'directory'))
1348
1349 def test_extension_loader_no_files_found(self):
1350 """
1351@@ -80,7 +106,7 @@
1352 """
1353 # GIVEN: A mocked `Path.glob` method which does not match any files
1354 with patch('openlp.core.common.AppLocation.get_directory', return_value=Path('/', 'app', 'dir', 'openlp')), \
1355- patch.object(common.Path, 'glob', return_value=[]), \
1356+ patch.object(Path, 'glob', return_value=[]), \
1357 patch('openlp.core.common.importlib.import_module') as mocked_import_module:
1358
1359 # WHEN: Calling `extension_loader`
1360@@ -95,7 +121,7 @@
1361 """
1362 # GIVEN: A mocked `Path.glob` method which returns a list of files
1363 with patch('openlp.core.common.AppLocation.get_directory', return_value=Path('/', 'app', 'dir', 'openlp')), \
1364- patch.object(common.Path, 'glob', return_value=[
1365+ patch.object(Path, 'glob', return_value=[
1366 Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file1.py'),
1367 Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file2.py'),
1368 Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file3.py'),
1369@@ -115,7 +141,7 @@
1370 """
1371 # GIVEN: A mocked `import_module` which raises an `ImportError`
1372 with patch('openlp.core.common.AppLocation.get_directory', return_value=Path('/', 'app', 'dir', 'openlp')), \
1373- patch.object(common.Path, 'glob', return_value=[
1374+ patch.object(Path, 'glob', return_value=[
1375 Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file1.py')]), \
1376 patch('openlp.core.common.importlib.import_module', side_effect=ImportError()), \
1377 patch('openlp.core.common.log') as mocked_logger:
1378@@ -132,7 +158,7 @@
1379 """
1380 # GIVEN: A mocked `SourceFileLoader` which raises an `OSError`
1381 with patch('openlp.core.common.AppLocation.get_directory', return_value=Path('/', 'app', 'dir', 'openlp')), \
1382- patch.object(common.Path, 'glob', return_value=[
1383+ patch.object(Path, 'glob', return_value=[
1384 Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file1.py')]), \
1385 patch('openlp.core.common.importlib.import_module', side_effect=OSError()), \
1386 patch('openlp.core.common.log') as mocked_logger:
1387@@ -174,7 +200,7 @@
1388 Test `path_to_module` when supplied with a `Path` object
1389 """
1390 # GIVEN: A `Path` object
1391- path = Path('openlp/core/ui/media/webkitplayer.py')
1392+ path = Path('core', 'ui', 'media', 'webkitplayer.py')
1393
1394 # WHEN: Calling path_to_module with the `Path` object
1395 result = path_to_module(path)
1396
1397=== modified file 'tests/functional/openlp_core_common/test_init.py'
1398--- tests/functional/openlp_core_common/test_init.py 2017-04-24 05:17:55 +0000
1399+++ tests/functional/openlp_core_common/test_init.py 2017-08-24 19:54:19 +0000
1400@@ -24,6 +24,7 @@
1401 """
1402 import os
1403 from io import BytesIO
1404+from pathlib import Path
1405 from unittest import TestCase
1406 from unittest.mock import MagicMock, PropertyMock, call, patch
1407
1408@@ -296,10 +297,10 @@
1409 """
1410 # GIVEN: A blank path
1411 # WEHN: Calling delete_file
1412- result = delete_file('')
1413+ result = delete_file(None)
1414
1415 # THEN: delete_file should return False
1416- self.assertFalse(result, "delete_file should return False when called with ''")
1417+ self.assertFalse(result, "delete_file should return False when called with None")
1418
1419 def test_delete_file_path_success(self):
1420 """
1421@@ -309,84 +310,87 @@
1422 with patch('openlp.core.common.os', **{'path.exists.return_value': False}):
1423
1424 # WHEN: Calling delete_file with a file path
1425- result = delete_file('path/file.ext')
1426+ result = delete_file(Path('path', 'file.ext'))
1427
1428 # THEN: delete_file should return True
1429 self.assertTrue(result, 'delete_file should return True when it successfully deletes a file')
1430
1431 def test_delete_file_path_no_file_exists(self):
1432 """
1433- Test the delete_file function when the file to remove does not exist
1434+ Test the `delete_file` function when the file to remove does not exist
1435 """
1436- # GIVEN: A mocked os which returns False when os.path.exists is called
1437- with patch('openlp.core.common.os', **{'path.exists.return_value': False}):
1438-
1439- # WHEN: Calling delete_file with a file path
1440- result = delete_file('path/file.ext')
1441-
1442- # THEN: delete_file should return True
1443+ # GIVEN: A patched `exists` methods on the Path object, which returns False
1444+ with patch.object(Path, 'exists', return_value=False), \
1445+ patch.object(Path, 'unlink') as mocked_unlink:
1446+
1447+ # WHEN: Calling `delete_file with` a file path
1448+ result = delete_file(Path('path', 'file.ext'))
1449+
1450+ # THEN: The function should not attempt to delete the file and it should return True
1451+ self.assertFalse(mocked_unlink.called)
1452 self.assertTrue(result, 'delete_file should return True when the file doesnt exist')
1453
1454 def test_delete_file_path_exception(self):
1455 """
1456- Test the delete_file function when os.remove raises an exception
1457+ Test the delete_file function when an exception is raised
1458 """
1459- # GIVEN: A mocked os which returns True when os.path.exists is called and raises an OSError when os.remove is
1460+ # GIVEN: A test `Path` object with a patched exists method which raises an OSError
1461 # called.
1462- with patch('openlp.core.common.os', **{'path.exists.return_value': True, 'path.exists.side_effect': OSError}), \
1463+ with patch.object(Path, 'exists') as mocked_exists, \
1464 patch('openlp.core.common.log') as mocked_log:
1465-
1466- # WHEN: Calling delete_file with a file path
1467- result = delete_file('path/file.ext')
1468-
1469- # THEN: delete_file should log and exception and return False
1470- self.assertEqual(mocked_log.exception.call_count, 1)
1471- self.assertFalse(result, 'delete_file should return False when os.remove raises an OSError')
1472-
1473- def test_get_file_name_encoding_done_test(self):
1474+ mocked_exists.side_effect = OSError
1475+
1476+ # WHEN: Calling delete_file with a the test Path object
1477+ result = delete_file(Path('path', 'file.ext'))
1478+
1479+ # THEN: The exception should be logged and `delete_file` should return False
1480+ self.assertTrue(mocked_log.exception.called)
1481+ self.assertFalse(result, 'delete_file should return False when an OSError is raised')
1482+
1483+ def test_get_file_encoding_done_test(self):
1484 """
1485 Test get_file_encoding when the detector sets done to True
1486 """
1487 # GIVEN: A mocked UniversalDetector instance with done attribute set to True after first iteration
1488 with patch('openlp.core.common.UniversalDetector') as mocked_universal_detector, \
1489- patch('builtins.open', return_value=BytesIO(b"data" * 260)) as mocked_open:
1490+ patch.object(Path, 'open', return_value=BytesIO(b"data" * 260)) as mocked_open:
1491 encoding_result = {'encoding': 'UTF-8', 'confidence': 0.99}
1492 mocked_universal_detector_inst = MagicMock(result=encoding_result)
1493 type(mocked_universal_detector_inst).done = PropertyMock(side_effect=[False, True])
1494 mocked_universal_detector.return_value = mocked_universal_detector_inst
1495
1496 # WHEN: Calling get_file_encoding
1497- result = get_file_encoding('file name')
1498+ result = get_file_encoding(Path('file name'))
1499
1500 # THEN: The feed method of UniversalDetector should only br called once before returning a result
1501- mocked_open.assert_called_once_with('file name', 'rb')
1502+ mocked_open.assert_called_once_with('rb')
1503 self.assertEqual(mocked_universal_detector_inst.feed.mock_calls, [call(b"data" * 256)])
1504 mocked_universal_detector_inst.close.assert_called_once_with()
1505 self.assertEqual(result, encoding_result)
1506
1507- def test_get_file_name_encoding_eof_test(self):
1508+ def test_get_file_encoding_eof_test(self):
1509 """
1510 Test get_file_encoding when the end of the file is reached
1511 """
1512 # GIVEN: A mocked UniversalDetector instance which isn't set to done and a mocked open, with 1040 bytes of test
1513 # data (enough to run the iterator twice)
1514 with patch('openlp.core.common.UniversalDetector') as mocked_universal_detector, \
1515- patch('builtins.open', return_value=BytesIO(b"data" * 260)) as mocked_open:
1516+ patch.object(Path, 'open', return_value=BytesIO(b"data" * 260)) as mocked_open:
1517 encoding_result = {'encoding': 'UTF-8', 'confidence': 0.99}
1518 mocked_universal_detector_inst = MagicMock(mock=mocked_universal_detector,
1519 **{'done': False, 'result': encoding_result})
1520 mocked_universal_detector.return_value = mocked_universal_detector_inst
1521
1522 # WHEN: Calling get_file_encoding
1523- result = get_file_encoding('file name')
1524+ result = get_file_encoding(Path('file name'))
1525
1526 # THEN: The feed method of UniversalDetector should have been called twice before returning a result
1527- mocked_open.assert_called_once_with('file name', 'rb')
1528+ mocked_open.assert_called_once_with('rb')
1529 self.assertEqual(mocked_universal_detector_inst.feed.mock_calls, [call(b"data" * 256), call(b"data" * 4)])
1530 mocked_universal_detector_inst.close.assert_called_once_with()
1531 self.assertEqual(result, encoding_result)
1532
1533- def test_get_file_name_encoding_oserror_test(self):
1534+ def test_get_file_encoding_oserror_test(self):
1535 """
1536 Test get_file_encoding when the end of the file is reached
1537 """
1538@@ -397,7 +401,7 @@
1539 patch('openlp.core.common.log') as mocked_log:
1540
1541 # WHEN: Calling get_file_encoding
1542- result = get_file_encoding('file name')
1543+ result = get_file_encoding(Path('file name'))
1544
1545 # THEN: log.exception should be called and get_file_encoding should return None
1546 mocked_log.exception.assert_called_once_with('Error detecting file encoding')
1547
1548=== modified file 'tests/functional/openlp_core_lib/test_db.py'
1549--- tests/functional/openlp_core_lib/test_db.py 2017-06-09 13:45:18 +0000
1550+++ tests/functional/openlp_core_lib/test_db.py 2017-08-24 19:54:19 +0000
1551@@ -24,6 +24,7 @@
1552 """
1553 import os
1554 import shutil
1555+from pathlib import Path
1556
1557 from tempfile import mkdtemp
1558 from unittest import TestCase
1559@@ -129,10 +130,10 @@
1560 # GIVEN: Mocked out AppLocation class and delete_file method, a test plugin name and a db location
1561 with patch('openlp.core.lib.db.AppLocation') as MockedAppLocation, \
1562 patch('openlp.core.lib.db.delete_file') as mocked_delete_file:
1563- MockedAppLocation.get_section_data_path.return_value = 'test-dir'
1564+ MockedAppLocation.get_section_data_path.return_value = Path('test-dir')
1565 mocked_delete_file.return_value = True
1566 test_plugin = 'test'
1567- test_location = os.path.join('test-dir', test_plugin)
1568+ test_location = Path('test-dir', test_plugin)
1569
1570 # WHEN: delete_database is run without a database file
1571 result = delete_database(test_plugin)
1572@@ -149,11 +150,11 @@
1573 # GIVEN: Mocked out AppLocation class and delete_file method, a test plugin name and a db location
1574 with patch('openlp.core.lib.db.AppLocation') as MockedAppLocation, \
1575 patch('openlp.core.lib.db.delete_file') as mocked_delete_file:
1576- MockedAppLocation.get_section_data_path.return_value = 'test-dir'
1577+ MockedAppLocation.get_section_data_path.return_value = Path('test-dir')
1578 mocked_delete_file.return_value = False
1579 test_plugin = 'test'
1580 test_db_file = 'mydb.sqlite'
1581- test_location = os.path.join('test-dir', test_db_file)
1582+ test_location = Path('test-dir', test_db_file)
1583
1584 # WHEN: delete_database is run without a database file
1585 result = delete_database(test_plugin, test_db_file)
1586
1587=== removed file 'tests/functional/openlp_core_lib/test_file_dialog.py'
1588--- tests/functional/openlp_core_lib/test_file_dialog.py 2017-08-07 21:12:42 +0000
1589+++ tests/functional/openlp_core_lib/test_file_dialog.py 1970-01-01 00:00:00 +0000
1590@@ -1,45 +0,0 @@
1591-# -*- coding: utf-8 -*-
1592-# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
1593-
1594-###############################################################################
1595-# OpenLP - Open Source Lyrics Projection #
1596-# --------------------------------------------------------------------------- #
1597-# Copyright (c) 2008-2017 OpenLP Developers #
1598-# --------------------------------------------------------------------------- #
1599-# This program is free software; you can redistribute it and/or modify it #
1600-# under the terms of the GNU General Public License as published by the Free #
1601-# Software Foundation; version 2 of the License. #
1602-# #
1603-# This program is distributed in the hope that it will be useful, but WITHOUT #
1604-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
1605-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
1606-# more details. #
1607-# #
1608-# You should have received a copy of the GNU General Public License along #
1609-# with this program; if not, write to the Free Software Foundation, Inc., 59 #
1610-# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
1611-###############################################################################
1612-"""
1613-Package to test the openlp.core.ui.lib.filedialog package.
1614-"""
1615-from unittest import TestCase
1616-from unittest.mock import MagicMock, patch
1617-
1618-
1619-class TestFileDialog(TestCase):
1620- """
1621- Test the functions in the :mod:`filedialog` module.
1622- """
1623- def setUp(self):
1624- self.os_patcher = patch('openlp.core.ui.lib.filedialog.os')
1625- self.qt_gui_patcher = patch('openlp.core.ui.lib.filedialog.QtWidgets')
1626- self.ui_strings_patcher = patch('openlp.core.ui.lib.filedialog.UiStrings')
1627- self.mocked_os = self.os_patcher.start()
1628- self.mocked_qt_gui = self.qt_gui_patcher.start()
1629- self.mocked_ui_strings = self.ui_strings_patcher.start()
1630- self.mocked_parent = MagicMock()
1631-
1632- def tearDown(self):
1633- self.os_patcher.stop()
1634- self.qt_gui_patcher.stop()
1635- self.ui_strings_patcher.stop()
1636
1637=== modified file 'tests/functional/openlp_core_lib/test_lib.py'
1638--- tests/functional/openlp_core_lib/test_lib.py 2017-08-23 20:21:11 +0000
1639+++ tests/functional/openlp_core_lib/test_lib.py 2017-08-24 19:54:19 +0000
1640@@ -24,6 +24,7 @@
1641 """
1642 import os
1643 from datetime import datetime, timedelta
1644+from pathlib import Path
1645 from unittest import TestCase
1646 from unittest.mock import MagicMock, patch
1647
1648@@ -148,35 +149,34 @@
1649 """
1650 Test the get_text_file_string() function when a file does not exist
1651 """
1652- with patch('openlp.core.lib.os.path.isfile') as mocked_isfile:
1653- # GIVEN: A mocked out isfile which returns true, and a text file name
1654- filename = 'testfile.txt'
1655- mocked_isfile.return_value = False
1656+ # GIVEN: A patched is_file which returns False, and a file path
1657+ with patch.object(Path, 'is_file', return_value=False):
1658+ file_path = Path('testfile.txt')
1659
1660 # WHEN: get_text_file_string is called
1661- result = get_text_file_string(filename)
1662+ result = get_text_file_string(file_path)
1663
1664 # THEN: The result should be False
1665- mocked_isfile.assert_called_with(filename)
1666+ file_path.is_file.assert_called_with()
1667 self.assertFalse(result, 'False should be returned if no file exists')
1668
1669 def test_get_text_file_string_read_error(self):
1670 """
1671 Test the get_text_file_string() method when a read error happens
1672 """
1673- with patch('openlp.core.lib.os.path.isfile') as mocked_isfile, \
1674- patch('openlp.core.lib.open', create=True) as mocked_open:
1675- # GIVEN: A mocked-out open() which raises an exception and isfile returns True
1676- filename = 'testfile.txt'
1677- mocked_isfile.return_value = True
1678- mocked_open.side_effect = IOError()
1679+ # GIVEN: A patched open which raises an exception and is_file which returns True
1680+ with patch.object(Path, 'is_file'), \
1681+ patch.object(Path, 'open'):
1682+ file_path = Path('testfile.txt')
1683+ file_path.is_file.return_value = True
1684+ file_path.open.side_effect = IOError()
1685
1686 # WHEN: get_text_file_string is called
1687- result = get_text_file_string(filename)
1688+ result = get_text_file_string(file_path)
1689
1690 # THEN: None should be returned
1691- mocked_isfile.assert_called_with(filename)
1692- mocked_open.assert_called_with(filename, 'r', encoding='utf-8')
1693+ file_path.is_file.assert_called_once_with()
1694+ file_path.open.assert_called_once_with('r', encoding='utf-8')
1695 self.assertIsNone(result, 'None should be returned if the file cannot be opened')
1696
1697 def test_get_text_file_string_decode_error(self):
1698
1699=== modified file 'tests/functional/openlp_core_ui/test_firsttimeform.py'
1700--- tests/functional/openlp_core_ui/test_firsttimeform.py 2017-04-24 05:17:55 +0000
1701+++ tests/functional/openlp_core_ui/test_firsttimeform.py 2017-08-24 19:54:19 +0000
1702@@ -25,6 +25,7 @@
1703 import os
1704 import tempfile
1705 import urllib
1706+from pathlib import Path
1707 from unittest import TestCase
1708 from unittest.mock import MagicMock, patch
1709
1710@@ -116,7 +117,7 @@
1711 mocked_settings.value.return_value = True
1712 MockedSettings.return_value = mocked_settings
1713 mocked_gettempdir.return_value = 'temp'
1714- expected_temp_path = os.path.join('temp', 'openlp')
1715+ expected_temp_path = Path('temp', 'openlp')
1716
1717 # WHEN: The set_defaults() method is run
1718 frw.set_defaults()
1719
1720=== modified file 'tests/functional/openlp_core_ui/test_thememanager.py'
1721--- tests/functional/openlp_core_ui/test_thememanager.py 2017-06-01 06:18:47 +0000
1722+++ tests/functional/openlp_core_ui/test_thememanager.py 2017-08-24 19:54:19 +0000
1723@@ -90,7 +90,7 @@
1724 # theme, check_directory_exists and thememanager-attributes.
1725 with patch('builtins.open') as mocked_open, \
1726 patch('openlp.core.ui.thememanager.shutil.copyfile') as mocked_copyfile, \
1727- patch('openlp.core.ui.thememanager.check_directory_exists') as mocked_check_directory_exists:
1728+ patch('openlp.core.ui.thememanager.check_directory_exists'):
1729 mocked_open.return_value = MagicMock()
1730 theme_manager = ThemeManager(None)
1731 theme_manager.old_background_image = None
1732@@ -118,7 +118,7 @@
1733 # theme, check_directory_exists and thememanager-attributes.
1734 with patch('builtins.open') as mocked_open, \
1735 patch('openlp.core.ui.thememanager.shutil.copyfile') as mocked_copyfile, \
1736- patch('openlp.core.ui.thememanager.check_directory_exists') as mocked_check_directory_exists:
1737+ patch('openlp.core.ui.thememanager.check_directory_exists'):
1738 mocked_open.return_value = MagicMock()
1739 theme_manager = ThemeManager(None)
1740 theme_manager.old_background_image = None
1741
1742=== modified file 'tests/functional/openlp_plugins/bibles/test_manager.py'
1743--- tests/functional/openlp_plugins/bibles/test_manager.py 2016-12-31 11:01:36 +0000
1744+++ tests/functional/openlp_plugins/bibles/test_manager.py 2017-08-24 19:54:19 +0000
1745@@ -22,6 +22,7 @@
1746 """
1747 This module contains tests for the manager submodule of the Bibles plugin.
1748 """
1749+from pathlib import Path
1750 from unittest import TestCase
1751 from unittest.mock import MagicMock, patch
1752
1753@@ -50,7 +51,6 @@
1754 """
1755 # GIVEN: An instance of BibleManager and a mocked bible
1756 with patch.object(BibleManager, 'reload_bibles'), \
1757- patch('openlp.plugins.bibles.lib.manager.os.path.join', side_effect=lambda x, y: '{}/{}'.format(x, y)),\
1758 patch('openlp.plugins.bibles.lib.manager.delete_file', return_value=True) as mocked_delete_file:
1759 instance = BibleManager(MagicMock())
1760 # We need to keep a reference to the mock for close_all as it gets set to None later on!
1761@@ -66,4 +66,4 @@
1762 self.assertTrue(result)
1763 mocked_close_all.assert_called_once_with()
1764 self.assertIsNone(mocked_bible.session)
1765- mocked_delete_file.assert_called_once_with('bibles/KJV.sqlite')
1766+ mocked_delete_file.assert_called_once_with(Path('bibles', 'KJV.sqlite'))
1767
1768=== modified file 'tests/functional/openlp_plugins/media/test_mediaplugin.py'
1769--- tests/functional/openlp_plugins/media/test_mediaplugin.py 2017-06-06 20:58:12 +0000
1770+++ tests/functional/openlp_plugins/media/test_mediaplugin.py 2017-08-24 19:54:19 +0000
1771@@ -38,20 +38,18 @@
1772 def setUp(self):
1773 Registry.create()
1774
1775- @patch(u'openlp.plugins.media.mediaplugin.Plugin.initialise')
1776+ @patch('openlp.plugins.media.mediaplugin.Plugin.initialise')
1777 def test_initialise(self, mocked_initialise):
1778 """
1779 Test that the initialise() method overwrites the built-in one, but still calls it
1780 """
1781- # GIVEN: A media plugin instance and a mocked settings object
1782+ # GIVEN: A media plugin instance
1783 media_plugin = MediaPlugin()
1784- mocked_settings = MagicMock()
1785- mocked_settings.get_files_from_config.return_value = True # Not the real value, just need something "true-ish"
1786
1787 # WHEN: initialise() is called
1788 media_plugin.initialise()
1789
1790- # THEN: The settings should be upgraded and the base initialise() method should be called
1791+ # THEN: The the base initialise() method should be called
1792 mocked_initialise.assert_called_with()
1793
1794 def test_about_text(self):
1795
1796=== modified file 'tests/functional/openlp_plugins/presentations/test_presentationcontroller.py'
1797--- tests/functional/openlp_plugins/presentations/test_presentationcontroller.py 2017-05-30 18:42:35 +0000
1798+++ tests/functional/openlp_plugins/presentations/test_presentationcontroller.py 2017-08-24 19:54:19 +0000
1799@@ -24,6 +24,7 @@
1800 classes and related methods.
1801 """
1802 import os
1803+from pathlib import Path
1804 from unittest import TestCase
1805 from unittest.mock import MagicMock, mock_open, patch
1806
1807@@ -38,7 +39,8 @@
1808 """
1809 def setUp(self):
1810 self.get_thumbnail_folder_patcher = \
1811- patch('openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument.get_thumbnail_folder')
1812+ patch('openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument.get_thumbnail_folder',
1813+ return_value=Path())
1814 self.get_thumbnail_folder_patcher.start()
1815 mocked_plugin = MagicMock()
1816 mocked_plugin.settings_section = 'presentations'
1817@@ -225,7 +227,7 @@
1818 PresentationDocument(self.mock_controller, 'Name')
1819
1820 # THEN: check_directory_exists should have been called with 'returned/path/'
1821- self.mock_check_directory_exists.assert_called_once_with('returned/path/')
1822+ self.mock_check_directory_exists.assert_called_once_with(Path('returned', 'path'))
1823
1824 self._setup_patcher.start()
1825
1826
1827=== modified file 'tests/interfaces/openlp_core_common/test_utils.py'
1828--- tests/interfaces/openlp_core_common/test_utils.py 2016-12-31 11:01:36 +0000
1829+++ tests/interfaces/openlp_core_common/test_utils.py 2017-08-24 19:54:19 +0000
1830@@ -22,7 +22,7 @@
1831 """
1832 Functional tests to test the AppLocation class and related methods.
1833 """
1834-import os
1835+from pathlib import Path
1836 from unittest import TestCase
1837
1838 from openlp.core.common import is_not_image_file
1839@@ -59,7 +59,7 @@
1840 Test the method handles an image file
1841 """
1842 # Given and empty string
1843- file_name = os.path.join(TEST_RESOURCES_PATH, 'church.jpg')
1844+ file_name = Path(TEST_RESOURCES_PATH, 'church.jpg')
1845
1846 # WHEN testing for it
1847 result = is_not_image_file(file_name)
1848@@ -72,7 +72,7 @@
1849 Test the method handles a non image file
1850 """
1851 # Given and empty string
1852- file_name = os.path.join(TEST_RESOURCES_PATH, 'serviceitem_custom_1.osj')
1853+ file_name = Path(TEST_RESOURCES_PATH, 'serviceitem_custom_1.osj')
1854
1855 # WHEN testing for it
1856 result = is_not_image_file(file_name)