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
=== modified file 'openlp/core/__init__.py'
--- openlp/core/__init__.py 2017-08-03 17:54:40 +0000
+++ openlp/core/__init__.py 2017-08-24 19:54:19 +0000
@@ -33,6 +33,7 @@
33import shutil33import shutil
34import sys34import sys
35import time35import time
36from pathlib import Path
36from traceback import format_exception37from traceback import format_exception
3738
38from PyQt5 import QtCore, QtGui, QtWidgets39from PyQt5 import QtCore, QtGui, QtWidgets
@@ -346,15 +347,18 @@
346 """347 """
347 Setup our logging using log_path348 Setup our logging using log_path
348349
349 :param log_path: the path350 :param pathlib.Path log_path: The file to save the log to
351 :return: None
352 :rtype: None
350 """353 """
351 check_directory_exists(log_path, True)354 check_directory_exists(log_path, True)
352 filename = os.path.join(log_path, 'openlp.log')355 file_path = log_path / 'openlp.log'
353 logfile = logging.FileHandler(filename, 'w', encoding="UTF-8")356 # TODO: FileHandler accepts a Path object in Py3.6
357 logfile = logging.FileHandler(str(file_path), 'w', encoding='UTF-8')
354 logfile.setFormatter(logging.Formatter('%(asctime)s %(name)-55s %(levelname)-8s %(message)s'))358 logfile.setFormatter(logging.Formatter('%(asctime)s %(name)-55s %(levelname)-8s %(message)s'))
355 log.addHandler(logfile)359 log.addHandler(logfile)
356 if log.isEnabledFor(logging.DEBUG):360 if log.isEnabledFor(logging.DEBUG):
357 print('Logging to: {name}'.format(name=filename))361 print('Logging to: {name}'.format(name=file_path))
358362
359363
360def main(args=None):364def main(args=None):
@@ -390,24 +394,24 @@
390 application.setApplicationName('OpenLPPortable')394 application.setApplicationName('OpenLPPortable')
391 Settings.setDefaultFormat(Settings.IniFormat)395 Settings.setDefaultFormat(Settings.IniFormat)
392 # Get location OpenLPPortable.ini396 # Get location OpenLPPortable.ini
393 application_path = str(AppLocation.get_directory(AppLocation.AppDir))397 portable_path = (AppLocation.get_directory(AppLocation.AppDir) / '..' / '..').resolve()
394 set_up_logging(os.path.abspath(os.path.join(application_path, '..', '..', 'Other')))398 data_path = portable_path / 'Data'
399 set_up_logging(portable_path / 'Other')
395 log.info('Running portable')400 log.info('Running portable')
396 portable_settings_file = os.path.abspath(os.path.join(application_path, '..', '..', 'Data', 'OpenLP.ini'))401 portable_settings_path = data_path / 'OpenLP.ini'
397 # Make this our settings file402 # Make this our settings file
398 log.info('INI file: {name}'.format(name=portable_settings_file))403 log.info('INI file: {name}'.format(name=portable_settings_path))
399 Settings.set_filename(portable_settings_file)404 Settings.set_filename(str(portable_settings_path))
400 portable_settings = Settings()405 portable_settings = Settings()
401 # Set our data path406 # Set our data path
402 data_path = os.path.abspath(os.path.join(application_path, '..', '..', 'Data',))
403 log.info('Data path: {name}'.format(name=data_path))407 log.info('Data path: {name}'.format(name=data_path))
404 # Point to our data path408 # Point to our data path
405 portable_settings.setValue('advanced/data path', data_path)409 portable_settings.setValue('advanced/data path', str(data_path))
406 portable_settings.setValue('advanced/is portable', True)410 portable_settings.setValue('advanced/is portable', True)
407 portable_settings.sync()411 portable_settings.sync()
408 else:412 else:
409 application.setApplicationName('OpenLP')413 application.setApplicationName('OpenLP')
410 set_up_logging(str(AppLocation.get_directory(AppLocation.CacheDir)))414 set_up_logging(AppLocation.get_directory(AppLocation.CacheDir))
411 Registry.create()415 Registry.create()
412 Registry().register('application', application)416 Registry().register('application', application)
413 Registry().set_flag('no_web_server', args.no_web_server)417 Registry().set_flag('no_web_server', args.no_web_server)
414418
=== modified file 'openlp/core/api/endpoint/controller.py'
--- openlp/core/api/endpoint/controller.py 2017-08-13 05:50:44 +0000
+++ openlp/core/api/endpoint/controller.py 2017-08-24 19:54:19 +0000
@@ -64,7 +64,7 @@
64 elif current_item.is_image() and not frame.get('image', '') and Settings().value('api/thumbnails'):64 elif current_item.is_image() and not frame.get('image', '') and Settings().value('api/thumbnails'):
65 item['tag'] = str(index + 1)65 item['tag'] = str(index + 1)
66 thumbnail_path = os.path.join('images', 'thumbnails', frame['title'])66 thumbnail_path = os.path.join('images', 'thumbnails', frame['title'])
67 full_thumbnail_path = os.path.join(AppLocation.get_data_path(), thumbnail_path)67 full_thumbnail_path = str(AppLocation.get_data_path() / thumbnail_path)
68 # Create thumbnail if it doesn't exists68 # Create thumbnail if it doesn't exists
69 if not os.path.exists(full_thumbnail_path):69 if not os.path.exists(full_thumbnail_path):
70 create_thumb(current_item.get_frame_path(index), full_thumbnail_path, False)70 create_thumb(current_item.get_frame_path(index), full_thumbnail_path, False)
@@ -82,7 +82,7 @@
82 if current_item.is_capable(ItemCapabilities.HasThumbnails) and \82 if current_item.is_capable(ItemCapabilities.HasThumbnails) and \
83 Settings().value('api/thumbnails'):83 Settings().value('api/thumbnails'):
84 # If the file is under our app directory tree send the portion after the match84 # If the file is under our app directory tree send the portion after the match
85 data_path = AppLocation.get_data_path()85 data_path = str(AppLocation.get_data_path())
86 if frame['image'][0:len(data_path)] == data_path:86 if frame['image'][0:len(data_path)] == data_path:
87 item['img'] = urllib.request.pathname2url(frame['image'][len(data_path):])87 item['img'] = urllib.request.pathname2url(frame['image'][len(data_path):])
88 Registry().get('image_manager').add_image(frame['image'], frame['title'], None, 88, 88)88 Registry().get('image_manager').add_image(frame['image'], frame['title'], None, 88, 88)
8989
=== modified file 'openlp/core/api/endpoint/pluginhelpers.py'
--- openlp/core/api/endpoint/pluginhelpers.py 2017-06-10 10:53:52 +0000
+++ openlp/core/api/endpoint/pluginhelpers.py 2017-08-24 19:54:19 +0000
@@ -125,12 +125,9 @@
125 file_name = urllib.parse.unquote(file_name)125 file_name = urllib.parse.unquote(file_name)
126 if '..' not in file_name: # no hacking please126 if '..' not in file_name: # no hacking please
127 if slide:127 if slide:
128 full_path = os.path.normpath(os.path.join(AppLocation.get_section_data_path(controller_name),128 full_path = str(AppLocation.get_section_data_path(controller_name) / 'thumbnails' / file_name / slide)
129 'thumbnails', file_name, slide))
130 else:129 else:
131 full_path = os.path.normpath(os.path.join(AppLocation.get_section_data_path(controller_name),130 full_path = str(AppLocation.get_section_data_path(controller_name) / 'thumbnails' / file_name)
132
133 'thumbnails', file_name))
134 if os.path.exists(full_path):131 if os.path.exists(full_path):
135 path, just_file_name = os.path.split(full_path)132 path, just_file_name = os.path.split(full_path)
136 Registry().get('image_manager').add_image(full_path, just_file_name, None, width, height)133 Registry().get('image_manager').add_image(full_path, just_file_name, None, width, height)
137134
=== modified file 'openlp/core/api/http/endpoint.py'
--- openlp/core/api/http/endpoint.py 2017-08-13 05:28:25 +0000
+++ openlp/core/api/http/endpoint.py 2017-08-24 19:54:19 +0000
@@ -68,11 +68,10 @@
68 """68 """
69 Render a mako template69 Render a mako template
70 """70 """
71 root = os.path.join(str(AppLocation.get_section_data_path('remotes')))71 root = str(AppLocation.get_section_data_path('remotes'))
72 if not self.template_dir:72 if not self.template_dir:
73 raise Exception('No template directory specified')73 raise Exception('No template directory specified')
74 path = os.path.join(root, self.template_dir, filename)74 path = os.path.join(root, self.template_dir, filename)
75 # path = os.path.abspath(os.path.join(self.template_dir, filename))
76 if self.static_dir:75 if self.static_dir:
77 kwargs['static_url'] = '/{prefix}/static'.format(prefix=self.url_prefix)76 kwargs['static_url'] = '/{prefix}/static'.format(prefix=self.url_prefix)
78 kwargs['static_url'] = kwargs['static_url'].replace('//', '/')77 kwargs['static_url'] = kwargs['static_url'].replace('//', '/')
7978
=== modified file 'openlp/core/api/http/wsgiapp.py'
--- openlp/core/api/http/wsgiapp.py 2017-08-12 20:26:39 +0000
+++ openlp/core/api/http/wsgiapp.py 2017-08-24 19:54:19 +0000
@@ -138,8 +138,12 @@
138 Add a static directory as a route138 Add a static directory as a route
139 """139 """
140 if route not in self.static_routes:140 if route not in self.static_routes:
141 root = os.path.join(str(AppLocation.get_section_data_path('remotes')))141 root = str(AppLocation.get_section_data_path('remotes'))
142 self.static_routes[route] = DirectoryApp(os.path.abspath(os.path.join(root, static_dir)))142 static_path = os.path.abspath(os.path.join(root, static_dir))
143 if not os.path.exists(static_path):
144 log.error('Static path "%s" does not exist. Skipping creating static route/', static_path)
145 return
146 self.static_routes[route] = DirectoryApp(static_path)
143147
144 def dispatch(self, request):148 def dispatch(self, request):
145 """149 """
146150
=== modified file 'openlp/core/common/__init__.py'
--- openlp/core/common/__init__.py 2017-08-01 20:59:41 +0000
+++ openlp/core/common/__init__.py 2017-08-24 19:54:19 +0000
@@ -32,7 +32,6 @@
32import traceback32import traceback
33from chardet.universaldetector import UniversalDetector33from chardet.universaldetector import UniversalDetector
34from ipaddress import IPv4Address, IPv6Address, AddressValueError34from ipaddress import IPv4Address, IPv6Address, AddressValueError
35from pathlib import Path
36from shutil import which35from shutil import which
37from subprocess import check_output, CalledProcessError, STDOUT36from subprocess import check_output, CalledProcessError, STDOUT
3837
@@ -65,17 +64,19 @@
6564
66def check_directory_exists(directory, do_not_log=False):65def check_directory_exists(directory, do_not_log=False):
67 """66 """
68 Check a theme directory exists and if not create it67 Check a directory exists and if not create it
6968
70 :param directory: The directory to make sure exists69 :param pathlib.Path directory: The directory to make sure exists
71 :param do_not_log: To not log anything. This is need for the start up, when the log isn't ready.70 :param bool do_not_log: To not log anything. This is need for the start up, when the log isn't ready.
71 :return: None
72 :rtype: None
72 """73 """
73 if not do_not_log:74 if not do_not_log:
74 log.debug('check_directory_exists {text}'.format(text=directory))75 log.debug('check_directory_exists {text}'.format(text=directory))
75 try:76 try:
76 if not os.path.exists(directory):77 if not directory.exists():
77 os.makedirs(directory)78 directory.mkdir(parents=True)
78 except IOError as e:79 except IOError:
79 if not do_not_log:80 if not do_not_log:
80 log.exception('failed to check if directory exists or create directory')81 log.exception('failed to check if directory exists or create directory')
8182
@@ -85,19 +86,15 @@
85 A utility function to find and load OpenLP extensions, such as plugins, presentation and media controllers and86 A utility function to find and load OpenLP extensions, such as plugins, presentation and media controllers and
86 importers.87 importers.
8788
88 :param glob_pattern: A glob pattern used to find the extension(s) to be imported. Should be relative to the89 :param str glob_pattern: A glob pattern used to find the extension(s) to be imported. Should be relative to the
89 application directory. i.e. openlp/plugins/*/*plugin.py90 application directory. i.e. plugins/*/*plugin.py
90 :type glob_pattern: str91 :param list[str] excluded_files: A list of file names to exclude that the glob pattern may find.
91
92 :param excluded_files: A list of file names to exclude that the glob pattern may find.
93 :type excluded_files: list of strings
94
95 :return: None92 :return: None
96 :rtype: None93 :rtype: None
97 """94 """
98 base_dir_path = AppLocation.get_directory(AppLocation.AppDir).parent95 app_dir = AppLocation.get_directory(AppLocation.AppDir)
99 for extension_path in base_dir_path.glob(glob_pattern):96 for extension_path in app_dir.glob(glob_pattern):
100 extension_path = extension_path.relative_to(base_dir_path)97 extension_path = extension_path.relative_to(app_dir)
101 if extension_path.name in excluded_files:98 if extension_path.name in excluded_files:
102 continue99 continue
103 module_name = path_to_module(extension_path)100 module_name = path_to_module(extension_path)
@@ -106,21 +103,19 @@
106 except (ImportError, OSError):103 except (ImportError, OSError):
107 # On some platforms importing vlc.py might cause OSError exceptions. (e.g. Mac OS X)104 # On some platforms importing vlc.py might cause OSError exceptions. (e.g. Mac OS X)
108 log.warning('Failed to import {module_name} on path {extension_path}'105 log.warning('Failed to import {module_name} on path {extension_path}'
109 .format(module_name=module_name, extension_path=str(extension_path)))106 .format(module_name=module_name, extension_path=extension_path))
110107
111108
112def path_to_module(path):109def path_to_module(path):
113 """110 """
114 Convert a path to a module name (i.e openlp.core.common)111 Convert a path to a module name (i.e openlp.core.common)
115112
116 :param path: The path to convert to a module name.113 :param pathlib.Path path: The path to convert to a module name.
117 :type path: Path
118
119 :return: The module name.114 :return: The module name.
120 :rtype: str115 :rtype: str
121 """116 """
122 module_path = path.with_suffix('')117 module_path = path.with_suffix('')
123 return '.'.join(module_path.parts)118 return 'openlp.' + '.'.join(module_path.parts)
124119
125120
126def get_frozen_path(frozen_option, non_frozen_option):121def get_frozen_path(frozen_option, non_frozen_option):
@@ -378,20 +373,22 @@
378 return os.path.split(path)373 return os.path.split(path)
379374
380375
381def delete_file(file_path_name):376def delete_file(file_path):
382 """377 """
383 Deletes a file from the system.378 Deletes a file from the system.
384379
385 :param file_path_name: The file, including path, to delete.380 :param pathlib.Path file_path: The file, including path, to delete.
381 :return: True if the deletion was successful, or the file never existed. False otherwise.
382 :rtype: bool
386 """383 """
387 if not file_path_name:384 if not file_path:
388 return False385 return False
389 try:386 try:
390 if os.path.exists(file_path_name):387 if file_path.exists():
391 os.remove(file_path_name)388 file_path.unlink()
392 return True389 return True
393 except (IOError, OSError):390 except (IOError, OSError):
394 log.exception("Unable to delete file {text}".format(text=file_path_name))391 log.exception('Unable to delete file {file_path}'.format(file_path=file_path))
395 return False392 return False
396393
397394
@@ -411,18 +408,19 @@
411 return IMAGES_FILTER408 return IMAGES_FILTER
412409
413410
414def is_not_image_file(file_name):411def is_not_image_file(file_path):
415 """412 """
416 Validate that the file is not an image file.413 Validate that the file is not an image file.
417414
418 :param file_name: File name to be checked.415 :param pathlib.Path file_path: The file to be checked.
416 :return: If the file is not an image
417 :rtype: bool
419 """418 """
420 if not file_name:419 if not (file_path and file_path.exists()):
421 return True420 return True
422 else:421 else:
423 formats = [bytes(fmt).decode().lower() for fmt in QtGui.QImageReader.supportedImageFormats()]422 formats = [bytes(fmt).decode().lower() for fmt in QtGui.QImageReader.supportedImageFormats()]
424 file_part, file_extension = os.path.splitext(str(file_name))423 if file_path.suffix[1:].lower() in formats:
425 if file_extension[1:].lower() in formats and os.path.exists(file_name):
426 return False424 return False
427 return True425 return True
428426
@@ -431,10 +429,10 @@
431 """429 """
432 Removes invalid characters from the given ``filename``.430 Removes invalid characters from the given ``filename``.
433431
434 :param filename: The "dirty" file name to clean.432 :param str filename: The "dirty" file name to clean.
433 :return: The cleaned string
434 :rtype: str
435 """435 """
436 if not isinstance(filename, str):
437 filename = str(filename, 'utf-8')
438 return INVALID_FILE_CHARS.sub('_', CONTROL_CHARS.sub('', filename))436 return INVALID_FILE_CHARS.sub('_', CONTROL_CHARS.sub('', filename))
439437
440438
@@ -442,8 +440,9 @@
442 """440 """
443 Function that checks whether a binary exists.441 Function that checks whether a binary exists.
444442
445 :param program_path: The full path to the binary to check.443 :param pathlib.Path program_path: The full path to the binary to check.
446 :return: program output to be parsed444 :return: program output to be parsed
445 :rtype: bytes
447 """446 """
448 log.debug('testing program_path: {text}'.format(text=program_path))447 log.debug('testing program_path: {text}'.format(text=program_path))
449 try:448 try:
@@ -453,26 +452,27 @@
453 startupinfo.dwFlags |= STARTF_USESHOWWINDOW452 startupinfo.dwFlags |= STARTF_USESHOWWINDOW
454 else:453 else:
455 startupinfo = None454 startupinfo = None
456 runlog = check_output([program_path, '--help'], stderr=STDOUT, startupinfo=startupinfo)455 run_log = check_output([str(program_path), '--help'], stderr=STDOUT, startupinfo=startupinfo)
457 except CalledProcessError as e:456 except CalledProcessError as e:
458 runlog = e.output457 run_log = e.output
459 except Exception:458 except Exception:
460 trace_error_handler(log)459 trace_error_handler(log)
461 runlog = ''460 run_log = ''
462 log.debug('check_output returned: {text}'.format(text=runlog))461 log.debug('check_output returned: {text}'.format(text=run_log))
463 return runlog462 return run_log
464463
465464
466def get_file_encoding(filename):465def get_file_encoding(file_path):
467 """466 """
468 Utility function to incrementally detect the file encoding.467 Utility function to incrementally detect the file encoding.
469468
470 :param filename: Filename for the file to determine the encoding for. Str469 :param pathlib.Path file_path: Filename for the file to determine the encoding for.
471 :return: A dict with the keys 'encoding' and 'confidence'470 :return: A dict with the keys 'encoding' and 'confidence'
471 :rtype: dict[str, float]
472 """472 """
473 detector = UniversalDetector()473 detector = UniversalDetector()
474 try:474 try:
475 with open(filename, 'rb') as detect_file:475 with file_path.open('rb') as detect_file:
476 while not detector.done:476 while not detector.done:
477 chunk = detect_file.read(1024)477 chunk = detect_file.read(1024)
478 if not chunk:478 if not chunk:
479479
=== modified file 'openlp/core/common/applocation.py'
--- openlp/core/common/applocation.py 2017-08-02 06:09:38 +0000
+++ openlp/core/common/applocation.py 2017-08-24 19:54:19 +0000
@@ -58,9 +58,6 @@
58 CacheDir = 558 CacheDir = 5
59 LanguageDir = 659 LanguageDir = 6
6060
61 # Base path where data/config/cache dir is located
62 BaseDir = None
63
64 @staticmethod61 @staticmethod
65 def get_directory(dir_type=AppDir):62 def get_directory(dir_type=AppDir):
66 """63 """
@@ -78,8 +75,6 @@
78 return get_frozen_path(FROZEN_APP_PATH, APP_PATH) / 'plugins'75 return get_frozen_path(FROZEN_APP_PATH, APP_PATH) / 'plugins'
79 elif dir_type == AppLocation.LanguageDir:76 elif dir_type == AppLocation.LanguageDir:
80 return get_frozen_path(FROZEN_APP_PATH, _get_os_dir_path(dir_type)) / 'i18n'77 return get_frozen_path(FROZEN_APP_PATH, _get_os_dir_path(dir_type)) / 'i18n'
81 elif dir_type == AppLocation.DataDir and AppLocation.BaseDir:
82 return Path(AppLocation.BaseDir, 'data')
83 else:78 else:
84 return _get_os_dir_path(dir_type)79 return _get_os_dir_path(dir_type)
8580
@@ -96,7 +91,7 @@
96 path = Path(Settings().value('advanced/data path'))91 path = Path(Settings().value('advanced/data path'))
97 else:92 else:
98 path = AppLocation.get_directory(AppLocation.DataDir)93 path = AppLocation.get_directory(AppLocation.DataDir)
99 check_directory_exists(str(path))94 check_directory_exists(path)
100 return path95 return path
10196
102 @staticmethod97 @staticmethod
@@ -104,14 +99,10 @@
104 """99 """
105 Get a list of files from the data files path.100 Get a list of files from the data files path.
106101
107 :param section: Defaults to *None*. The section of code getting the files - used to load from a section's data102 :param None | str section: Defaults to *None*. The section of code getting the files - used to load from a
108 subdirectory.103 section's data subdirectory.
109 :type section: None | str104 :param str extension: Defaults to ''. The extension to search for. For example::
110
111 :param extension: Defaults to ''. The extension to search for. For example::
112 '.png'105 '.png'
113 :type extension: str
114
115 :return: List of files found.106 :return: List of files found.
116 :rtype: list[pathlib.Path]107 :rtype: list[pathlib.Path]
117 """108 """
@@ -134,7 +125,7 @@
134 :rtype: pathlib.Path125 :rtype: pathlib.Path
135 """126 """
136 path = AppLocation.get_data_path() / section127 path = AppLocation.get_data_path() / section
137 check_directory_exists(str(path))128 check_directory_exists(path)
138 return path129 return path
139130
140131
@@ -143,14 +134,12 @@
143 Return a path based on which OS and environment we are running in.134 Return a path based on which OS and environment we are running in.
144135
145 :param dir_type: AppLocation Enum of the requested path type136 :param dir_type: AppLocation Enum of the requested path type
146 :type dir_type: AppLocation Enum
147
148 :return: The requested path137 :return: The requested path
149 :rtype: pathlib.Path138 :rtype: pathlib.Path
150 """139 """
151 # If running from source, return the language directory from the source directory140 # If running from source, return the language directory from the source directory
152 if dir_type == AppLocation.LanguageDir:141 if dir_type == AppLocation.LanguageDir:
153 directory = Path(os.path.abspath(os.path.join(os.path.dirname(openlp.__file__), '..', 'resources')))142 directory = Path(openlp.__file__, '..', '..').resolve() / 'resources'
154 if directory.exists():143 if directory.exists():
155 return directory144 return directory
156 if is_win():145 if is_win():
@@ -158,14 +147,14 @@
158 if dir_type == AppLocation.DataDir:147 if dir_type == AppLocation.DataDir:
159 return openlp_folder_path / 'data'148 return openlp_folder_path / 'data'
160 elif dir_type == AppLocation.LanguageDir:149 elif dir_type == AppLocation.LanguageDir:
161 return os.path.dirname(openlp.__file__)150 return Path(openlp.__file__).parent
162 return openlp_folder_path151 return openlp_folder_path
163 elif is_macosx():152 elif is_macosx():
164 openlp_folder_path = Path(os.getenv('HOME'), 'Library', 'Application Support', 'openlp')153 openlp_folder_path = Path(os.getenv('HOME'), 'Library', 'Application Support', 'openlp')
165 if dir_type == AppLocation.DataDir:154 if dir_type == AppLocation.DataDir:
166 return openlp_folder_path / 'Data'155 return openlp_folder_path / 'Data'
167 elif dir_type == AppLocation.LanguageDir:156 elif dir_type == AppLocation.LanguageDir:
168 return os.path.dirname(openlp.__file__)157 return Path(openlp.__file__).parent
169 return openlp_folder_path158 return openlp_folder_path
170 else:159 else:
171 if dir_type == AppLocation.LanguageDir:160 if dir_type == AppLocation.LanguageDir:
172161
=== modified file 'openlp/core/common/settings.py'
--- openlp/core/common/settings.py 2017-08-23 20:21:11 +0000
+++ openlp/core/common/settings.py 2017-08-24 19:54:19 +0000
@@ -502,31 +502,3 @@
502 if isinstance(default_value, int):502 if isinstance(default_value, int):
503 return int(setting)503 return int(setting)
504 return setting504 return setting
505
506 def get_files_from_config(self, plugin):
507 """
508 This removes the settings needed for old way we saved files (e. g. the image paths for the image plugin). A list
509 of file paths are returned.
510
511 **Note**: Only a list of paths is returned; this does not convert anything!
512
513 :param plugin: The Plugin object.The caller has to convert/save the list himself; o
514 """
515 files_list = []
516 # We need QSettings instead of Settings here to bypass our central settings dict.
517 # Do NOT do this anywhere else!
518 settings = QtCore.QSettings(self.fileName(), Settings.IniFormat)
519 settings.beginGroup(plugin.settings_section)
520 if settings.contains('{name} count'.format(name=plugin.name)):
521 # Get the count.
522 list_count = int(settings.value('{name} count'.format(name=plugin.name), 0))
523 if list_count:
524 for counter in range(list_count):
525 # The keys were named e. g.: "image 0"
526 item = settings.value('{name} {counter:d}'.format(name=plugin.name, counter=counter), '')
527 if item:
528 files_list.append(item)
529 settings.remove('{name} {counter:d}'.format(name=plugin.name, counter=counter))
530 settings.remove('{name} count'.format(name=plugin.name))
531 settings.endGroup()
532 return files_list
533505
=== modified file 'openlp/core/lib/__init__.py'
--- openlp/core/lib/__init__.py 2017-08-23 20:21:11 +0000
+++ openlp/core/lib/__init__.py 2017-08-24 19:54:19 +0000
@@ -83,30 +83,28 @@
83 Next = 383 Next = 3
8484
8585
86def get_text_file_string(text_file):86def get_text_file_string(text_file_path):
87 """87 """
88 Open a file and return its content as unicode string. If the supplied file name is not a file then the function88 Open a file and return its content as a string. If the supplied file path is not a file then the function
89 returns False. If there is an error loading the file or the content can't be decoded then the function will return89 returns False. If there is an error loading the file or the content can't be decoded then the function will return
90 None.90 None.
9191
92 :param text_file: The name of the file.92 :param pathlib.Path text_file_path: The path to the file.
93 :return: The file as a single string93 :return: The contents of the file, False if the file does not exist, or None if there is an Error reading or
94 decoding the file.
95 :rtype: str | False | None
94 """96 """
95 if not os.path.isfile(text_file):97 if not text_file_path.is_file():
96 return False98 return False
97 file_handle = None
98 content = None99 content = None
99 try:100 try:
100 file_handle = open(text_file, 'r', encoding='utf-8')101 with text_file_path.open('r', encoding='utf-8') as file_handle:
101 if file_handle.read(3) != '\xEF\xBB\xBF':102 if file_handle.read(3) != '\xEF\xBB\xBF':
102 # no BOM was found103 # no BOM was found
103 file_handle.seek(0)104 file_handle.seek(0)
104 content = file_handle.read()105 content = file_handle.read()
105 except (IOError, UnicodeError):106 except (IOError, UnicodeError):
106 log.exception('Failed to open text file {text}'.format(text=text_file))107 log.exception('Failed to open text file {text}'.format(text=text_file_path))
107 finally:
108 if file_handle:
109 file_handle.close()
110 return content108 return content
111109
112110
113111
=== modified file 'openlp/core/lib/db.py'
--- openlp/core/lib/db.py 2017-08-01 20:59:41 +0000
+++ openlp/core/lib/db.py 2017-08-24 19:54:19 +0000
@@ -274,9 +274,9 @@
274 :param db_file_name: The database file name. Defaults to None resulting in the plugin_name being used.274 :param db_file_name: The database file name. Defaults to None resulting in the plugin_name being used.
275 """275 """
276 if db_file_name:276 if db_file_name:
277 db_file_path = os.path.join(str(AppLocation.get_section_data_path(plugin_name)), db_file_name)277 db_file_path = AppLocation.get_section_data_path(plugin_name) / db_file_name
278 else:278 else:
279 db_file_path = os.path.join(str(AppLocation.get_section_data_path(plugin_name)), plugin_name)279 db_file_path = AppLocation.get_section_data_path(plugin_name) / plugin_name
280 return delete_file(db_file_path)280 return delete_file(db_file_path)
281281
282282
283283
=== modified file 'openlp/core/lib/pluginmanager.py'
--- openlp/core/lib/pluginmanager.py 2017-08-01 20:59:41 +0000
+++ openlp/core/lib/pluginmanager.py 2017-08-24 19:54:19 +0000
@@ -69,7 +69,7 @@
69 """69 """
70 Scan a directory for objects inheriting from the ``Plugin`` class.70 Scan a directory for objects inheriting from the ``Plugin`` class.
71 """71 """
72 glob_pattern = os.path.join('openlp', 'plugins', '*', '*plugin.py')72 glob_pattern = os.path.join('plugins', '*', '*plugin.py')
73 extension_loader(glob_pattern)73 extension_loader(glob_pattern)
74 plugin_classes = Plugin.__subclasses__()74 plugin_classes = Plugin.__subclasses__()
75 plugin_objects = []75 plugin_objects = []
7676
=== modified file 'openlp/core/lib/theme.py'
--- openlp/core/lib/theme.py 2017-08-01 20:59:41 +0000
+++ openlp/core/lib/theme.py 2017-08-24 19:54:19 +0000
@@ -158,9 +158,8 @@
158 Initialise the theme object.158 Initialise the theme object.
159 """159 """
160 # basic theme object with defaults160 # basic theme object with defaults
161 json_dir = os.path.join(str(AppLocation.get_directory(AppLocation.AppDir)), 'core', 'lib', 'json')161 json_path = AppLocation.get_directory(AppLocation.AppDir) / 'core' / 'lib' / 'json' / 'theme.json'
162 json_file = os.path.join(json_dir, 'theme.json')162 jsn = get_text_file_string(json_path)
163 jsn = get_text_file_string(json_file)
164 jsn = json.loads(jsn)163 jsn = json.loads(jsn)
165 self.expand_json(jsn)164 self.expand_json(jsn)
166 self.background_filename = ''165 self.background_filename = ''
167166
=== modified file 'openlp/core/ui/firsttimeform.py'
--- openlp/core/ui/firsttimeform.py 2017-08-03 17:54:40 +0000
+++ openlp/core/ui/firsttimeform.py 2017-08-24 19:54:19 +0000
@@ -29,8 +29,9 @@
29import urllib.request29import urllib.request
30import urllib.parse30import urllib.parse
31import urllib.error31import urllib.error
32from configparser import ConfigParser, MissingSectionHeaderError, NoOptionError, NoSectionError
33from pathlib import Path
32from tempfile import gettempdir34from tempfile import gettempdir
33from configparser import ConfigParser, MissingSectionHeaderError, NoSectionError, NoOptionError
3435
35from PyQt5 import QtCore, QtWidgets36from PyQt5 import QtCore, QtWidgets
3637
@@ -282,7 +283,7 @@
282 self.no_internet_cancel_button.setVisible(False)283 self.no_internet_cancel_button.setVisible(False)
283 # Check if this is a re-run of the wizard.284 # Check if this is a re-run of the wizard.
284 self.has_run_wizard = Settings().value('core/has run wizard')285 self.has_run_wizard = Settings().value('core/has run wizard')
285 check_directory_exists(os.path.join(gettempdir(), 'openlp'))286 check_directory_exists(Path(gettempdir(), 'openlp'))
286287
287 def update_screen_list_combo(self):288 def update_screen_list_combo(self):
288 """289 """
289290
=== modified file 'openlp/core/ui/mainwindow.py'
--- openlp/core/ui/mainwindow.py 2017-08-03 17:54:40 +0000
+++ openlp/core/ui/mainwindow.py 2017-08-24 19:54:19 +0000
@@ -30,6 +30,7 @@
30from datetime import datetime30from datetime import datetime
31from distutils import dir_util31from distutils import dir_util
32from distutils.errors import DistutilsFileError32from distutils.errors import DistutilsFileError
33from pathlib import Path
33from tempfile import gettempdir34from tempfile import gettempdir
3435
35from PyQt5 import QtCore, QtGui, QtWidgets36from PyQt5 import QtCore, QtGui, QtWidgets
@@ -870,7 +871,7 @@
870 setting_sections.extend([plugin.name for plugin in self.plugin_manager.plugins])871 setting_sections.extend([plugin.name for plugin in self.plugin_manager.plugins])
871 # Copy the settings file to the tmp dir, because we do not want to change the original one.872 # Copy the settings file to the tmp dir, because we do not want to change the original one.
872 temp_directory = os.path.join(str(gettempdir()), 'openlp')873 temp_directory = os.path.join(str(gettempdir()), 'openlp')
873 check_directory_exists(temp_directory)874 check_directory_exists(Path(temp_directory))
874 temp_config = os.path.join(temp_directory, os.path.basename(import_file_name))875 temp_config = os.path.join(temp_directory, os.path.basename(import_file_name))
875 shutil.copyfile(import_file_name, temp_config)876 shutil.copyfile(import_file_name, temp_config)
876 settings = Settings()877 settings = Settings()
877878
=== modified file 'openlp/core/ui/media/mediacontroller.py'
--- openlp/core/ui/media/mediacontroller.py 2017-06-25 17:03:31 +0000
+++ openlp/core/ui/media/mediacontroller.py 2017-08-24 19:54:19 +0000
@@ -177,7 +177,7 @@
177 Check to see if we have any media Player's available.177 Check to see if we have any media Player's available.
178 """178 """
179 log.debug('_check_available_media_players')179 log.debug('_check_available_media_players')
180 controller_dir = os.path.join('openlp', 'core', 'ui', 'media')180 controller_dir = os.path.join('core', 'ui', 'media')
181 glob_pattern = os.path.join(controller_dir, '*player.py')181 glob_pattern = os.path.join(controller_dir, '*player.py')
182 extension_loader(glob_pattern, ['mediaplayer.py'])182 extension_loader(glob_pattern, ['mediaplayer.py'])
183 player_classes = MediaPlayer.__subclasses__()183 player_classes = MediaPlayer.__subclasses__()
184184
=== modified file 'openlp/core/ui/printserviceform.py'
--- openlp/core/ui/printserviceform.py 2017-08-01 20:59:41 +0000
+++ openlp/core/ui/printserviceform.py 2017-08-24 19:54:19 +0000
@@ -176,7 +176,7 @@
176 html_data = self._add_element('html')176 html_data = self._add_element('html')
177 self._add_element('head', parent=html_data)177 self._add_element('head', parent=html_data)
178 self._add_element('title', self.title_line_edit.text(), html_data.head)178 self._add_element('title', self.title_line_edit.text(), html_data.head)
179 css_path = os.path.join(str(AppLocation.get_data_path()), 'serviceprint', 'service_print.css')179 css_path = AppLocation.get_data_path() / 'serviceprint' / 'service_print.css'
180 custom_css = get_text_file_string(css_path)180 custom_css = get_text_file_string(css_path)
181 if not custom_css:181 if not custom_css:
182 custom_css = DEFAULT_CSS182 custom_css = DEFAULT_CSS
183183
=== modified file 'openlp/core/ui/servicemanager.py'
--- openlp/core/ui/servicemanager.py 2017-08-03 17:54:40 +0000
+++ openlp/core/ui/servicemanager.py 2017-08-24 19:54:19 +0000
@@ -28,6 +28,7 @@
28import shutil28import shutil
29import zipfile29import zipfile
30from datetime import datetime, timedelta30from datetime import datetime, timedelta
31from pathlib import Path
31from tempfile import mkstemp32from tempfile import mkstemp
3233
33from PyQt5 import QtCore, QtGui, QtWidgets34from PyQt5 import QtCore, QtGui, QtWidgets
@@ -587,7 +588,7 @@
587 audio_from = os.path.join(self.service_path, audio_from)588 audio_from = os.path.join(self.service_path, audio_from)
588 save_file = os.path.join(self.service_path, audio_to)589 save_file = os.path.join(self.service_path, audio_to)
589 save_path = os.path.split(save_file)[0]590 save_path = os.path.split(save_file)[0]
590 check_directory_exists(save_path)591 check_directory_exists(Path(save_path))
591 if not os.path.exists(save_file):592 if not os.path.exists(save_file):
592 shutil.copy(audio_from, save_file)593 shutil.copy(audio_from, save_file)
593 zip_file.write(audio_from, audio_to)594 zip_file.write(audio_from, audio_to)
@@ -614,7 +615,7 @@
614 success = False615 success = False
615 self.main_window.add_recent_file(path_file_name)616 self.main_window.add_recent_file(path_file_name)
616 self.set_modified(False)617 self.set_modified(False)
617 delete_file(temp_file_name)618 delete_file(Path(temp_file_name))
618 return success619 return success
619620
620 def save_local_file(self):621 def save_local_file(self):
@@ -669,7 +670,7 @@
669 return self.save_file_as()670 return self.save_file_as()
670 self.main_window.add_recent_file(path_file_name)671 self.main_window.add_recent_file(path_file_name)
671 self.set_modified(False)672 self.set_modified(False)
672 delete_file(temp_file_name)673 delete_file(Path(temp_file_name))
673 return success674 return success
674675
675 def save_file_as(self, field=None):676 def save_file_as(self, field=None):
@@ -774,7 +775,7 @@
774 self.set_file_name(file_name)775 self.set_file_name(file_name)
775 self.main_window.display_progress_bar(len(items))776 self.main_window.display_progress_bar(len(items))
776 self.process_service_items(items)777 self.process_service_items(items)
777 delete_file(p_file)778 delete_file(Path(p_file))
778 self.main_window.add_recent_file(file_name)779 self.main_window.add_recent_file(file_name)
779 self.set_modified(False)780 self.set_modified(False)
780 Settings().setValue('servicemanager/last file', file_name)781 Settings().setValue('servicemanager/last file', file_name)
@@ -1343,7 +1344,7 @@
1343 Empties the service_path of temporary files on system exit.1344 Empties the service_path of temporary files on system exit.
1344 """1345 """
1345 for file_name in os.listdir(self.service_path):1346 for file_name in os.listdir(self.service_path):
1346 file_path = os.path.join(self.service_path, file_name)1347 file_path = Path(self.service_path, file_name)
1347 delete_file(file_path)1348 delete_file(file_path)
1348 if os.path.exists(os.path.join(self.service_path, 'audio')):1349 if os.path.exists(os.path.join(self.service_path, 'audio')):
1349 shutil.rmtree(os.path.join(self.service_path, 'audio'), True)1350 shutil.rmtree(os.path.join(self.service_path, 'audio'), True)
13501351
=== modified file 'openlp/core/ui/themeform.py'
--- openlp/core/ui/themeform.py 2017-08-07 20:50:01 +0000
+++ openlp/core/ui/themeform.py 2017-08-24 19:54:19 +0000
@@ -24,6 +24,7 @@
24"""24"""
25import logging25import logging
26import os26import os
27from pathlib import Path
2728
28from PyQt5 import QtCore, QtGui, QtWidgets29from PyQt5 import QtCore, QtGui, QtWidgets
2930
@@ -188,7 +189,8 @@
188 """189 """
189 background_image = BackgroundType.to_string(BackgroundType.Image)190 background_image = BackgroundType.to_string(BackgroundType.Image)
190 if self.page(self.currentId()) == self.background_page and \191 if self.page(self.currentId()) == self.background_page and \
191 self.theme.background_type == background_image and is_not_image_file(self.theme.background_filename):192 self.theme.background_type == background_image and \
193 is_not_image_file(Path(self.theme.background_filename)):
192 QtWidgets.QMessageBox.critical(self, translate('OpenLP.ThemeWizard', 'Background Image Empty'),194 QtWidgets.QMessageBox.critical(self, translate('OpenLP.ThemeWizard', 'Background Image Empty'),
193 translate('OpenLP.ThemeWizard', 'You have not selected a '195 translate('OpenLP.ThemeWizard', 'You have not selected a '
194 'background image. Please select one before continuing.'))196 'background image. Please select one before continuing.'))
195197
=== modified file 'openlp/core/ui/thememanager.py'
--- openlp/core/ui/thememanager.py 2017-08-07 20:50:01 +0000
+++ openlp/core/ui/thememanager.py 2017-08-24 19:54:19 +0000
@@ -25,6 +25,7 @@
25import os25import os
26import zipfile26import zipfile
27import shutil27import shutil
28from pathlib import Path
2829
29from xml.etree.ElementTree import ElementTree, XML30from xml.etree.ElementTree import ElementTree, XML
30from PyQt5 import QtCore, QtGui, QtWidgets31from PyQt5 import QtCore, QtGui, QtWidgets
@@ -161,9 +162,9 @@
161 Set up the theme path variables162 Set up the theme path variables
162 """163 """
163 self.path = str(AppLocation.get_section_data_path(self.settings_section))164 self.path = str(AppLocation.get_section_data_path(self.settings_section))
164 check_directory_exists(self.path)165 check_directory_exists(Path(self.path))
165 self.thumb_path = os.path.join(self.path, 'thumbnails')166 self.thumb_path = os.path.join(self.path, 'thumbnails')
166 check_directory_exists(self.thumb_path)167 check_directory_exists(Path(self.thumb_path))
167168
168 def check_list_state(self, item, field=None):169 def check_list_state(self, item, field=None):
169 """170 """
@@ -355,8 +356,8 @@
355 """356 """
356 self.theme_list.remove(theme)357 self.theme_list.remove(theme)
357 thumb = '{name}.png'.format(name=theme)358 thumb = '{name}.png'.format(name=theme)
358 delete_file(os.path.join(self.path, thumb))359 delete_file(Path(self.path, thumb))
359 delete_file(os.path.join(self.thumb_path, thumb))360 delete_file(Path(self.thumb_path, thumb))
360 try:361 try:
361 # Windows is always unicode, so no need to encode filenames362 # Windows is always unicode, so no need to encode filenames
362 if is_win():363 if is_win():
@@ -450,7 +451,7 @@
450 for theme_file in files:451 for theme_file in files:
451 theme_file = os.path.join(self.path, str(theme_file))452 theme_file = os.path.join(self.path, str(theme_file))
452 self.unzip_theme(theme_file, self.path)453 self.unzip_theme(theme_file, self.path)
453 delete_file(theme_file)454 delete_file(Path(theme_file))
454 files = AppLocation.get_files(self.settings_section, '.png')455 files = AppLocation.get_files(self.settings_section, '.png')
455 # No themes have been found so create one456 # No themes have been found so create one
456 if not files:457 if not files:
@@ -514,12 +515,12 @@
514 :return: The theme object.515 :return: The theme object.
515 """516 """
516 self.log_debug('get theme data for theme {name}'.format(name=theme_name))517 self.log_debug('get theme data for theme {name}'.format(name=theme_name))
517 theme_file = os.path.join(self.path, str(theme_name), str(theme_name) + '.json')518 theme_file_path = Path(self.path, str(theme_name), '{file_name}.json'.format(file_name=theme_name))
518 theme_data = get_text_file_string(theme_file)519 theme_data = get_text_file_string(theme_file_path)
519 jsn = True520 jsn = True
520 if not theme_data:521 if not theme_data:
521 theme_file = os.path.join(self.path, str(theme_name), str(theme_name) + '.xml')522 theme_file_path = theme_file_path.with_suffix('.xml')
522 theme_data = get_text_file_string(theme_file)523 theme_data = get_text_file_string(theme_file_path)
523 jsn = False524 jsn = False
524 if not theme_data:525 if not theme_data:
525 self.log_debug('No theme data - using default theme')526 self.log_debug('No theme data - using default theme')
@@ -592,7 +593,7 @@
592 # is directory or preview file593 # is directory or preview file
593 continue594 continue
594 full_name = os.path.join(directory, out_name)595 full_name = os.path.join(directory, out_name)
595 check_directory_exists(os.path.dirname(full_name))596 check_directory_exists(Path(os.path.dirname(full_name)))
596 if os.path.splitext(name)[1].lower() == '.xml' or os.path.splitext(name)[1].lower() == '.json':597 if os.path.splitext(name)[1].lower() == '.xml' or os.path.splitext(name)[1].lower() == '.json':
597 file_xml = str(theme_zip.read(name), 'utf-8')598 file_xml = str(theme_zip.read(name), 'utf-8')
598 out_file = open(full_name, 'w', encoding='utf-8')599 out_file = open(full_name, 'w', encoding='utf-8')
@@ -670,10 +671,10 @@
670 name = theme.theme_name671 name = theme.theme_name
671 theme_pretty = theme.export_theme()672 theme_pretty = theme.export_theme()
672 theme_dir = os.path.join(self.path, name)673 theme_dir = os.path.join(self.path, name)
673 check_directory_exists(theme_dir)674 check_directory_exists(Path(theme_dir))
674 theme_file = os.path.join(theme_dir, name + '.json')675 theme_file = os.path.join(theme_dir, name + '.json')
675 if self.old_background_image and image_to != self.old_background_image:676 if self.old_background_image and image_to != self.old_background_image:
676 delete_file(self.old_background_image)677 delete_file(Path(self.old_background_image))
677 out_file = None678 out_file = None
678 try:679 try:
679 out_file = open(theme_file, 'w', encoding='utf-8')680 out_file = open(theme_file, 'w', encoding='utf-8')
680681
=== modified file 'openlp/plugins/bibles/lib/importers/csvbible.py'
--- openlp/plugins/bibles/lib/importers/csvbible.py 2016-12-31 11:01:36 +0000
+++ openlp/plugins/bibles/lib/importers/csvbible.py 2017-08-24 19:54:19 +0000
@@ -51,6 +51,7 @@
51"""51"""
52import csv52import csv
53from collections import namedtuple53from collections import namedtuple
54from pathlib import Path
5455
55from openlp.core.common import get_file_encoding, translate56from openlp.core.common import get_file_encoding, translate
56from openlp.core.lib.exceptions import ValidationError57from openlp.core.lib.exceptions import ValidationError
@@ -100,7 +101,7 @@
100 :return: An iterable yielding namedtuples of type results_tuple101 :return: An iterable yielding namedtuples of type results_tuple
101 """102 """
102 try:103 try:
103 encoding = get_file_encoding(filename)['encoding']104 encoding = get_file_encoding(Path(filename))['encoding']
104 with open(filename, 'r', encoding=encoding, newline='') as csv_file:105 with open(filename, 'r', encoding=encoding, newline='') as csv_file:
105 csv_reader = csv.reader(csv_file, delimiter=',', quotechar='"')106 csv_reader = csv.reader(csv_file, delimiter=',', quotechar='"')
106 return [results_tuple(*line) for line in csv_reader]107 return [results_tuple(*line) for line in csv_reader]
107108
=== modified file 'openlp/plugins/bibles/lib/manager.py'
--- openlp/plugins/bibles/lib/manager.py 2017-08-01 20:59:41 +0000
+++ openlp/plugins/bibles/lib/manager.py 2017-08-24 19:54:19 +0000
@@ -22,6 +22,7 @@
2222
23import logging23import logging
24import os24import os
25from pathlib import Path
2526
26from openlp.core.common import AppLocation, OpenLPMixin, RegistryProperties, Settings, translate, delete_file, UiStrings27from openlp.core.common import AppLocation, OpenLPMixin, RegistryProperties, Settings, translate, delete_file, UiStrings
27from openlp.plugins.bibles.lib import LanguageSelection, parse_reference28from openlp.plugins.bibles.lib import LanguageSelection, parse_reference
@@ -137,7 +138,7 @@
137 # Remove corrupted files.138 # Remove corrupted files.
138 if name is None:139 if name is None:
139 bible.session.close_all()140 bible.session.close_all()
140 delete_file(os.path.join(self.path, filename))141 delete_file(Path(self.path, filename))
141 continue142 continue
142 log.debug('Bible Name: "{name}"'.format(name=name))143 log.debug('Bible Name: "{name}"'.format(name=name))
143 self.db_cache[name] = bible144 self.db_cache[name] = bible
@@ -185,7 +186,7 @@
185 bible = self.db_cache[name]186 bible = self.db_cache[name]
186 bible.session.close_all()187 bible.session.close_all()
187 bible.session = None188 bible.session = None
188 return delete_file(os.path.join(bible.path, bible.file))189 return delete_file(Path(bible.path, bible.file))
189190
190 def get_bibles(self):191 def get_bibles(self):
191 """192 """
192193
=== modified file 'openlp/plugins/images/lib/mediaitem.py'
--- openlp/plugins/images/lib/mediaitem.py 2017-08-03 17:54:40 +0000
+++ openlp/plugins/images/lib/mediaitem.py 2017-08-24 19:54:19 +0000
@@ -22,6 +22,7 @@
2222
23import logging23import logging
24import os24import os
25from pathlib import Path
2526
26from PyQt5 import QtCore, QtGui, QtWidgets27from PyQt5 import QtCore, QtGui, QtWidgets
2728
@@ -99,7 +100,7 @@
99 self.list_view.setIndentation(self.list_view.default_indentation)100 self.list_view.setIndentation(self.list_view.default_indentation)
100 self.list_view.allow_internal_dnd = True101 self.list_view.allow_internal_dnd = True
101 self.service_path = os.path.join(str(AppLocation.get_section_data_path(self.settings_section)), 'thumbnails')102 self.service_path = os.path.join(str(AppLocation.get_section_data_path(self.settings_section)), 'thumbnails')
102 check_directory_exists(self.service_path)103 check_directory_exists(Path(self.service_path))
103 # Load images from the database104 # Load images from the database
104 self.load_full_list(105 self.load_full_list(
105 self.manager.get_all_objects(ImageFilenames, order_by_ref=ImageFilenames.filename), initial_load=True)106 self.manager.get_all_objects(ImageFilenames, order_by_ref=ImageFilenames.filename), initial_load=True)
@@ -210,8 +211,8 @@
210 """211 """
211 images = self.manager.get_all_objects(ImageFilenames, ImageFilenames.group_id == image_group.id)212 images = self.manager.get_all_objects(ImageFilenames, ImageFilenames.group_id == image_group.id)
212 for image in images:213 for image in images:
213 delete_file(os.path.join(self.service_path, os.path.split(image.filename)[1]))214 delete_file(Path(self.service_path, os.path.split(image.filename)[1]))
214 delete_file(self.generate_thumbnail_path(image))215 delete_file(Path(self.generate_thumbnail_path(image)))
215 self.manager.delete_object(ImageFilenames, image.id)216 self.manager.delete_object(ImageFilenames, image.id)
216 image_groups = self.manager.get_all_objects(ImageGroups, ImageGroups.parent_id == image_group.id)217 image_groups = self.manager.get_all_objects(ImageGroups, ImageGroups.parent_id == image_group.id)
217 for group in image_groups:218 for group in image_groups:
@@ -233,8 +234,8 @@
233 if row_item:234 if row_item:
234 item_data = row_item.data(0, QtCore.Qt.UserRole)235 item_data = row_item.data(0, QtCore.Qt.UserRole)
235 if isinstance(item_data, ImageFilenames):236 if isinstance(item_data, ImageFilenames):
236 delete_file(os.path.join(self.service_path, row_item.text(0)))237 delete_file(Path(self.service_path, row_item.text(0)))
237 delete_file(self.generate_thumbnail_path(item_data))238 delete_file(Path(self.generate_thumbnail_path(item_data)))
238 if item_data.group_id == 0:239 if item_data.group_id == 0:
239 self.list_view.takeTopLevelItem(self.list_view.indexOfTopLevelItem(row_item))240 self.list_view.takeTopLevelItem(self.list_view.indexOfTopLevelItem(row_item))
240 else:241 else:
241242
=== modified file 'openlp/plugins/media/lib/mediaitem.py'
--- openlp/plugins/media/lib/mediaitem.py 2017-08-03 17:54:40 +0000
+++ openlp/plugins/media/lib/mediaitem.py 2017-08-24 19:54:19 +0000
@@ -22,6 +22,7 @@
2222
23import logging23import logging
24import os24import os
25from pathlib import Path
2526
26from PyQt5 import QtCore, QtWidgets27from PyQt5 import QtCore, QtWidgets
2728
@@ -301,7 +302,7 @@
301 """302 """
302 self.list_view.clear()303 self.list_view.clear()
303 self.service_path = os.path.join(str(AppLocation.get_section_data_path(self.settings_section)), 'thumbnails')304 self.service_path = os.path.join(str(AppLocation.get_section_data_path(self.settings_section)), 'thumbnails')
304 check_directory_exists(self.service_path)305 check_directory_exists(Path(self.service_path))
305 self.load_list(Settings().value(self.settings_section + '/media files'))306 self.load_list(Settings().value(self.settings_section + '/media files'))
306 self.rebuild_players()307 self.rebuild_players()
307308
308309
=== modified file 'openlp/plugins/media/mediaplugin.py'
--- openlp/plugins/media/mediaplugin.py 2017-08-03 17:54:40 +0000
+++ openlp/plugins/media/mediaplugin.py 2017-08-24 19:54:19 +0000
@@ -26,6 +26,7 @@
26import logging26import logging
27import os27import os
28import re28import re
29from pathlib import Path
2930
30from PyQt5 import QtCore31from PyQt5 import QtCore
3132
@@ -165,8 +166,7 @@
165 :param program_path:The full path to the binary to check.166 :param program_path:The full path to the binary to check.
166 :return: If exists or not167 :return: If exists or not
167 """168 """
168 program_type = None169 runlog = check_binary_exists(Path(program_path))
169 runlog = check_binary_exists(program_path)
170 # Analyse the output to see it the program is mediainfo170 # Analyse the output to see it the program is mediainfo
171 for line in runlog.splitlines():171 for line in runlog.splitlines():
172 decoded_line = line.decode()172 decoded_line = line.decode()
173173
=== modified file 'openlp/plugins/presentations/lib/impresscontroller.py'
--- openlp/plugins/presentations/lib/impresscontroller.py 2017-05-14 10:11:10 +0000
+++ openlp/plugins/presentations/lib/impresscontroller.py 2017-08-24 19:54:19 +0000
@@ -34,6 +34,7 @@
34import logging34import logging
35import os35import os
36import time36import time
37from pathlib import Path
3738
38from openlp.core.common import is_win, Registry, get_uno_command, get_uno_instance, delete_file39from openlp.core.common import is_win, Registry, get_uno_command, get_uno_instance, delete_file
3940
@@ -275,7 +276,7 @@
275 try:276 try:
276 doc.storeToURL(url_path, properties)277 doc.storeToURL(url_path, properties)
277 self.convert_thumbnail(path, index + 1)278 self.convert_thumbnail(path, index + 1)
278 delete_file(path)279 delete_file(Path(path))
279 except ErrorCodeIOException as exception:280 except ErrorCodeIOException as exception:
280 log.exception('ERROR! ErrorCodeIOException {error:d}'.format(error=exception.ErrCode))281 log.exception('ERROR! ErrorCodeIOException {error:d}'.format(error=exception.ErrCode))
281 except:282 except:
282283
=== modified file 'openlp/plugins/presentations/lib/pdfcontroller.py'
--- openlp/plugins/presentations/lib/pdfcontroller.py 2017-08-01 20:59:41 +0000
+++ openlp/plugins/presentations/lib/pdfcontroller.py 2017-08-24 19:54:19 +0000
@@ -23,6 +23,7 @@
23import os23import os
24import logging24import logging
25import re25import re
26from pathlib import Path
26from shutil import which27from shutil import which
27from subprocess import check_output, CalledProcessError28from subprocess import check_output, CalledProcessError
2829
@@ -69,7 +70,7 @@
69 :return: Type of the binary, 'gs' if ghostscript, 'mudraw' if mudraw, None if invalid.70 :return: Type of the binary, 'gs' if ghostscript, 'mudraw' if mudraw, None if invalid.
70 """71 """
71 program_type = None72 program_type = None
72 runlog = check_binary_exists(program_path)73 runlog = check_binary_exists(Path(program_path))
73 # Analyse the output to see it the program is mudraw, ghostscript or neither74 # Analyse the output to see it the program is mudraw, ghostscript or neither
74 for line in runlog.splitlines():75 for line in runlog.splitlines():
75 decoded_line = line.decode()76 decoded_line = line.decode()
7677
=== modified file 'openlp/plugins/presentations/lib/presentationcontroller.py'
--- openlp/plugins/presentations/lib/presentationcontroller.py 2017-08-01 20:59:41 +0000
+++ openlp/plugins/presentations/lib/presentationcontroller.py 2017-08-24 19:54:19 +0000
@@ -23,6 +23,7 @@
23import logging23import logging
24import os24import os
25import shutil25import shutil
26from pathlib import Path
2627
27from PyQt5 import QtCore28from PyQt5 import QtCore
2829
@@ -98,7 +99,7 @@
98 """99 """
99 self.slide_number = 0100 self.slide_number = 0
100 self.file_path = name101 self.file_path = name
101 check_directory_exists(self.get_thumbnail_folder())102 check_directory_exists(Path(self.get_thumbnail_folder()))
102103
103 def load_presentation(self):104 def load_presentation(self):
104 """105 """
@@ -419,8 +420,8 @@
419 self.thumbnail_folder = os.path.join(420 self.thumbnail_folder = os.path.join(
420 str(AppLocation.get_section_data_path(self.settings_section)), 'thumbnails')421 str(AppLocation.get_section_data_path(self.settings_section)), 'thumbnails')
421 self.thumbnail_prefix = 'slide'422 self.thumbnail_prefix = 'slide'
422 check_directory_exists(self.thumbnail_folder)423 check_directory_exists(Path(self.thumbnail_folder))
423 check_directory_exists(self.temp_folder)424 check_directory_exists(Path(self.temp_folder))
424425
425 def enabled(self):426 def enabled(self):
426 """427 """
427428
=== modified file 'openlp/plugins/presentations/presentationplugin.py'
--- openlp/plugins/presentations/presentationplugin.py 2017-06-09 15:56:40 +0000
+++ openlp/plugins/presentations/presentationplugin.py 2017-08-24 19:54:19 +0000
@@ -125,7 +125,7 @@
125 Check to see if we have any presentation software available. If not do not install the plugin.125 Check to see if we have any presentation software available. If not do not install the plugin.
126 """126 """
127 log.debug('check_pre_conditions')127 log.debug('check_pre_conditions')
128 controller_dir = os.path.join('openlp', 'plugins', 'presentations', 'lib')128 controller_dir = os.path.join('plugins', 'presentations', 'lib')
129 glob_pattern = os.path.join(controller_dir, '*controller.py')129 glob_pattern = os.path.join(controller_dir, '*controller.py')
130 extension_loader(glob_pattern, ['presentationcontroller.py'])130 extension_loader(glob_pattern, ['presentationcontroller.py'])
131 controller_classes = PresentationController.__subclasses__()131 controller_classes = PresentationController.__subclasses__()
132132
=== modified file 'openlp/plugins/remotes/remoteplugin.py'
--- openlp/plugins/remotes/remoteplugin.py 2017-06-18 06:03:42 +0000
+++ openlp/plugins/remotes/remoteplugin.py 2017-08-24 19:54:19 +0000
@@ -59,21 +59,22 @@
59 Create the internal file structure if it does not exist59 Create the internal file structure if it does not exist
60 :return:60 :return:
61 """61 """
62 check_directory_exists(os.path.join(AppLocation.get_section_data_path('remotes'), 'assets'))62 check_directory_exists(AppLocation.get_section_data_path('remotes') / 'assets')
63 check_directory_exists(os.path.join(AppLocation.get_section_data_path('remotes'), 'images'))63 check_directory_exists(AppLocation.get_section_data_path('remotes') / 'images')
64 check_directory_exists(os.path.join(AppLocation.get_section_data_path('remotes'), 'static'))64 check_directory_exists(AppLocation.get_section_data_path('remotes') / 'static')
65 check_directory_exists(os.path.join(AppLocation.get_section_data_path('remotes'), 'static', 'index'))65 check_directory_exists(AppLocation.get_section_data_path('remotes') / 'static', 'index')
66 check_directory_exists(os.path.join(AppLocation.get_section_data_path('remotes'), 'templates'))66 check_directory_exists(AppLocation.get_section_data_path('remotes') / 'templates')
6767
68 @staticmethod68 @staticmethod
69 def about():69 def about():
70 """70 """
71 Information about this plugin71 Information about this plugin
72 """72 """
73 about_text = translate('RemotePlugin', '<strong>Web Interface</strong>'73 about_text = translate(
74 '<br />The web interface plugin provides the ability develop web based '74 'RemotePlugin',
75 'interfaces using openlp web services. \nPredefined interfaces can be '75 '<strong>Web Interface</strong>'
76 'download as well as custom developed interfaces')76 '<br />The web interface plugin provides the ability to develop web based interfaces using OpenLP web '
77 'services.\nPredefined interfaces can be download as well as custom developed interfaces.')
77 return about_text78 return about_text
7879
79 def set_plugin_text_strings(self):80 def set_plugin_text_strings(self):
8081
=== modified file 'openlp/plugins/songs/forms/editsongform.py'
--- openlp/plugins/songs/forms/editsongform.py 2017-08-11 20:47:52 +0000
+++ openlp/plugins/songs/forms/editsongform.py 2017-08-24 19:54:19 +0000
@@ -1071,7 +1071,7 @@
1071 log.debug(audio_files)1071 log.debug(audio_files)
1072 save_path = os.path.join(str(AppLocation.get_section_data_path(self.media_item.plugin.name)), 'audio',1072 save_path = os.path.join(str(AppLocation.get_section_data_path(self.media_item.plugin.name)), 'audio',
1073 str(self.song.id))1073 str(self.song.id))
1074 check_directory_exists(save_path)1074 check_directory_exists(Path(save_path))
1075 self.song.media_files = []1075 self.song.media_files = []
1076 files = []1076 files = []
1077 for row in range(self.audio_list_widget.count()):1077 for row in range(self.audio_list_widget.count()):
10781078
=== modified file 'openlp/plugins/songs/lib/importers/songbeamer.py'
--- openlp/plugins/songs/lib/importers/songbeamer.py 2017-05-11 19:53:47 +0000
+++ openlp/plugins/songs/lib/importers/songbeamer.py 2017-08-24 19:54:19 +0000
@@ -27,6 +27,7 @@
27import re27import re
28import base6428import base64
29import math29import math
30from pathlib import Path
3031
31from openlp.plugins.songs.lib import VerseType32from openlp.plugins.songs.lib import VerseType
32from openlp.plugins.songs.lib.importers.songimport import SongImport33from openlp.plugins.songs.lib.importers.songimport import SongImport
@@ -122,7 +123,7 @@
122 file_name = os.path.split(import_file)[1]123 file_name = os.path.split(import_file)[1]
123 if os.path.isfile(import_file):124 if os.path.isfile(import_file):
124 # Detect the encoding125 # Detect the encoding
125 self.input_file_encoding = get_file_encoding(import_file)['encoding']126 self.input_file_encoding = get_file_encoding(Path(import_file))['encoding']
126 # The encoding should only be ANSI (cp1252), UTF-8, Unicode, Big-Endian-Unicode.127 # The encoding should only be ANSI (cp1252), UTF-8, Unicode, Big-Endian-Unicode.
127 # So if it doesn't start with 'u' we default to cp1252. See:128 # So if it doesn't start with 'u' we default to cp1252. See:
128 # https://forum.songbeamer.com/viewtopic.php?p=419&sid=ca4814924e37c11e4438b7272a98b6f2129 # https://forum.songbeamer.com/viewtopic.php?p=419&sid=ca4814924e37c11e4438b7272a98b6f2
129130
=== modified file 'openlp/plugins/songs/lib/importers/songimport.py'
--- openlp/plugins/songs/lib/importers/songimport.py 2017-08-01 20:59:41 +0000
+++ openlp/plugins/songs/lib/importers/songimport.py 2017-08-24 19:54:19 +0000
@@ -24,6 +24,7 @@
24import re24import re
25import shutil25import shutil
26import os26import os
27from pathlib import Path
2728
28from PyQt5 import QtCore29from PyQt5 import QtCore
2930
@@ -423,7 +424,7 @@
423 if not hasattr(self, 'save_path'):424 if not hasattr(self, 'save_path'):
424 self.save_path = os.path.join(str(AppLocation.get_section_data_path(self.import_wizard.plugin.name)),425 self.save_path = os.path.join(str(AppLocation.get_section_data_path(self.import_wizard.plugin.name)),
425 'audio', str(song_id))426 'audio', str(song_id))
426 check_directory_exists(self.save_path)427 check_directory_exists(Path(self.save_path))
427 if not filename.startswith(self.save_path):428 if not filename.startswith(self.save_path):
428 old_file, filename = filename, os.path.join(self.save_path, os.path.split(filename)[1])429 old_file, filename = filename, os.path.join(self.save_path, os.path.split(filename)[1])
429 shutil.copyfile(old_file, filename)430 shutil.copyfile(old_file, filename)
430431
=== modified file 'openlp/plugins/songs/lib/mediaitem.py'
--- openlp/plugins/songs/lib/mediaitem.py 2017-08-03 17:54:40 +0000
+++ openlp/plugins/songs/lib/mediaitem.py 2017-08-24 19:54:19 +0000
@@ -23,6 +23,7 @@
23import logging23import logging
24import os24import os
25import shutil25import shutil
26from pathlib import Path
2627
27from PyQt5 import QtCore, QtWidgets28from PyQt5 import QtCore, QtWidgets
28from sqlalchemy.sql import and_, or_29from sqlalchemy.sql import and_, or_
@@ -89,7 +90,7 @@
89 for i, bga in enumerate(item.background_audio):90 for i, bga in enumerate(item.background_audio):
90 dest_file = os.path.join(91 dest_file = os.path.join(
91 str(AppLocation.get_section_data_path(self.plugin.name)), 'audio', str(song.id), os.path.split(bga)[1])92 str(AppLocation.get_section_data_path(self.plugin.name)), 'audio', str(song.id), os.path.split(bga)[1])
92 check_directory_exists(os.path.split(dest_file)[0])93 check_directory_exists(Path(os.path.split(dest_file)[0]))
93 shutil.copyfile(os.path.join(str(AppLocation.get_section_data_path('servicemanager')), bga), dest_file)94 shutil.copyfile(os.path.join(str(AppLocation.get_section_data_path('servicemanager')), bga), dest_file)
94 song.media_files.append(MediaFile.populate(weight=i, file_name=dest_file))95 song.media_files.append(MediaFile.populate(weight=i, file_name=dest_file))
95 self.plugin.manager.save_object(song, True)96 self.plugin.manager.save_object(song, True)
@@ -535,7 +536,7 @@
535 if len(old_song.media_files) > 0:536 if len(old_song.media_files) > 0:
536 save_path = os.path.join(537 save_path = os.path.join(
537 str(AppLocation.get_section_data_path(self.plugin.name)), 'audio', str(new_song.id))538 str(AppLocation.get_section_data_path(self.plugin.name)), 'audio', str(new_song.id))
538 check_directory_exists(save_path)539 check_directory_exists(Path(save_path))
539 for media_file in old_song.media_files:540 for media_file in old_song.media_files:
540 new_media_file_name = os.path.join(save_path, os.path.basename(media_file.file_name))541 new_media_file_name = os.path.join(save_path, os.path.basename(media_file.file_name))
541 shutil.copyfile(media_file.file_name, new_media_file_name)542 shutil.copyfile(media_file.file_name, new_media_file_name)
542543
=== modified file 'openlp/plugins/songs/lib/openlyricsexport.py'
--- openlp/plugins/songs/lib/openlyricsexport.py 2016-12-31 11:01:36 +0000
+++ openlp/plugins/songs/lib/openlyricsexport.py 2017-08-24 19:54:19 +0000
@@ -25,6 +25,7 @@
25"""25"""
26import logging26import logging
27import os27import os
28from pathlib import Path
2829
29from lxml import etree30from lxml import etree
3031
@@ -47,7 +48,7 @@
47 self.manager = parent.plugin.manager48 self.manager = parent.plugin.manager
48 self.songs = songs49 self.songs = songs
49 self.save_path = save_path50 self.save_path = save_path
50 check_directory_exists(self.save_path)51 check_directory_exists(Path(self.save_path))
5152
52 def do_export(self):53 def do_export(self):
53 """54 """
5455
=== modified file 'openlp/plugins/songusage/forms/songusagedetailform.py'
--- openlp/plugins/songusage/forms/songusagedetailform.py 2017-08-04 17:40:57 +0000
+++ openlp/plugins/songusage/forms/songusagedetailform.py 2017-08-24 19:54:19 +0000
@@ -22,6 +22,7 @@
2222
23import logging23import logging
24import os24import os
25from pathlib import Path
2526
26from PyQt5 import QtCore, QtWidgets27from PyQt5 import QtCore, QtWidgets
27from sqlalchemy.sql import and_28from sqlalchemy.sql import and_
@@ -78,7 +79,7 @@
78 ' song usage report. \nPlease select an existing path on your computer.')79 ' song usage report. \nPlease select an existing path on your computer.')
79 )80 )
80 return81 return
81 check_directory_exists(path)82 check_directory_exists(Path(path))
82 file_name = translate('SongUsagePlugin.SongUsageDetailForm',83 file_name = translate('SongUsagePlugin.SongUsageDetailForm',
83 'usage_detail_{old}_{new}.txt'84 'usage_detail_{old}_{new}.txt'
84 ).format(old=self.from_date_calendar.selectedDate().toString('ddMMyyyy'),85 ).format(old=self.from_date_calendar.selectedDate().toString('ddMMyyyy'),
8586
=== modified file 'scripts/appveyor.yml'
--- scripts/appveyor.yml 2017-05-11 20:24:20 +0000
+++ scripts/appveyor.yml 2017-08-24 19:54:19 +0000
@@ -12,7 +12,7 @@
1212
13install:13install:
14 # Install dependencies from pypi14 # Install dependencies from pypi
15 - "%PYTHON%\\python.exe -m pip install sqlalchemy alembic chardet beautifulsoup4 Mako nose mock pyodbc==4.0.8 psycopg2 pypiwin32 pyenchant"15 - "%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"
16 # Install mysql dependency16 # Install mysql dependency
17 - "%PYTHON%\\python.exe -m pip install http://cdn.mysql.com/Downloads/Connector-Python/mysql-connector-python-2.0.4.zip#md5=3df394d89300db95163f17c843ef49df"17 - "%PYTHON%\\python.exe -m pip install http://cdn.mysql.com/Downloads/Connector-Python/mysql-connector-python-2.0.4.zip#md5=3df394d89300db95163f17c843ef49df"
18 # Download and install lxml and pyicu (originally from http://www.lfd.uci.edu/~gohlke/pythonlibs/)18 # Download and install lxml and pyicu (originally from http://www.lfd.uci.edu/~gohlke/pythonlibs/)
1919
=== modified file 'tests/functional/openlp_core_common/test_applocation.py'
--- tests/functional/openlp_core_common/test_applocation.py 2017-08-01 20:59:41 +0000
+++ tests/functional/openlp_core_common/test_applocation.py 2017-08-24 19:54:19 +0000
@@ -43,14 +43,12 @@
43 """43 """
44 with patch('openlp.core.common.applocation.Settings') as mocked_class, \44 with patch('openlp.core.common.applocation.Settings') as mocked_class, \
45 patch('openlp.core.common.AppLocation.get_directory') as mocked_get_directory, \45 patch('openlp.core.common.AppLocation.get_directory') as mocked_get_directory, \
46 patch('openlp.core.common.applocation.check_directory_exists') as mocked_check_directory_exists, \46 patch('openlp.core.common.applocation.check_directory_exists') as mocked_check_directory_exists:
47 patch('openlp.core.common.applocation.os') as mocked_os:
48 # GIVEN: A mocked out Settings class and a mocked out AppLocation.get_directory()47 # GIVEN: A mocked out Settings class and a mocked out AppLocation.get_directory()
49 mocked_settings = mocked_class.return_value48 mocked_settings = mocked_class.return_value
50 mocked_settings.contains.return_value = False49 mocked_settings.contains.return_value = False
51 mocked_get_directory.return_value = os.path.join('test', 'dir')50 mocked_get_directory.return_value = Path('test', 'dir')
52 mocked_check_directory_exists.return_value = True51 mocked_check_directory_exists.return_value = True
53 mocked_os.path.normpath.return_value = os.path.join('test', 'dir')
5452
55 # WHEN: we call AppLocation.get_data_path()53 # WHEN: we call AppLocation.get_data_path()
56 data_path = AppLocation.get_data_path()54 data_path = AppLocation.get_data_path()
@@ -58,8 +56,8 @@
58 # THEN: check that all the correct methods were called, and the result is correct56 # THEN: check that all the correct methods were called, and the result is correct
59 mocked_settings.contains.assert_called_with('advanced/data path')57 mocked_settings.contains.assert_called_with('advanced/data path')
60 mocked_get_directory.assert_called_with(AppLocation.DataDir)58 mocked_get_directory.assert_called_with(AppLocation.DataDir)
61 mocked_check_directory_exists.assert_called_with(os.path.join('test', 'dir'))59 mocked_check_directory_exists.assert_called_with(Path('test', 'dir'))
62 self.assertEqual(os.path.join('test', 'dir'), data_path, 'Result should be "test/dir"')60 self.assertEqual(Path('test', 'dir'), data_path, 'Result should be "test/dir"')
6361
64 def test_get_data_path_with_custom_location(self):62 def test_get_data_path_with_custom_location(self):
65 """63 """
@@ -125,7 +123,7 @@
125 data_path = AppLocation.get_section_data_path('section')123 data_path = AppLocation.get_section_data_path('section')
126124
127 # THEN: check that all the correct methods were called, and the result is correct125 # THEN: check that all the correct methods were called, and the result is correct
128 mocked_check_directory_exists.assert_called_with(os.path.join('test', 'dir', 'section'))126 mocked_check_directory_exists.assert_called_with(Path('test', 'dir', 'section'))
129 self.assertEqual(Path('test', 'dir', 'section'), data_path, 'Result should be "test/dir/section"')127 self.assertEqual(Path('test', 'dir', 'section'), data_path, 'Result should be "test/dir/section"')
130128
131 def test_get_directory_for_app_dir(self):129 def test_get_directory_for_app_dir(self):
132130
=== modified file 'tests/functional/openlp_core_common/test_common.py'
--- tests/functional/openlp_core_common/test_common.py 2017-08-01 20:59:41 +0000
+++ tests/functional/openlp_core_common/test_common.py 2017-08-24 19:54:19 +0000
@@ -35,44 +35,70 @@
35 """35 """
36 A test suite to test out various functions in the openlp.core.common module.36 A test suite to test out various functions in the openlp.core.common module.
37 """37 """
38 def test_check_directory_exists(self):38 def test_check_directory_exists_dir_exists(self):
39 """39 """
40 Test the check_directory_exists() function40 Test the check_directory_exists() function when the path already exists
41 """41 """
42 with patch('openlp.core.lib.os.path.exists') as mocked_exists, \42 # GIVEN: A `Path` to check with patched out mkdir and exists methods
43 patch('openlp.core.lib.os.makedirs') as mocked_makedirs:43 with patch.object(Path, 'exists') as mocked_exists, \
44 # GIVEN: A directory to check and a mocked out os.makedirs and os.path.exists44 patch.object(Path, 'mkdir') as mocked_mkdir, \
45 directory_to_check = 'existing/directory'45 patch('openlp.core.common.log'):
4646
47 # WHEN: os.path.exists returns True and we check to see if the directory exists47 # WHEN: `check_directory_exists` is called and the path exists
48 mocked_exists.return_value = True48 mocked_exists.return_value = True
49 check_directory_exists(directory_to_check)49 check_directory_exists(Path('existing', 'directory'))
5050
51 # THEN: Only os.path.exists should have been called51 # THEN: The function should not attempt to create the directory
52 mocked_exists.assert_called_with(directory_to_check)52 mocked_exists.assert_called_with()
53 self.assertIsNot(mocked_makedirs.called, 'os.makedirs should not have been called')53 self.assertFalse(mocked_mkdir.called)
5454
55 # WHEN: os.path.exists returns False and we check the directory exists55 def test_check_directory_exists_dir_doesnt_exists(self):
56 """
57 Test the check_directory_exists() function when the path does not already exist
58 """
59 # GIVEN: A `Path` to check with patched out mkdir and exists methods
60 with patch.object(Path, 'exists') as mocked_exists, \
61 patch.object(Path, 'mkdir') as mocked_mkdir, \
62 patch('openlp.core.common.log'):
63
64 # WHEN: `check_directory_exists` is called and the path does not exist
56 mocked_exists.return_value = False65 mocked_exists.return_value = False
57 check_directory_exists(directory_to_check)66 check_directory_exists(Path('existing', 'directory'))
5867
59 # THEN: Both the mocked functions should have been called68 # THEN: The directory should have been created
60 mocked_exists.assert_called_with(directory_to_check)69 mocked_exists.assert_called_with()
61 mocked_makedirs.assert_called_with(directory_to_check)70 mocked_mkdir.assert_called_with(parents=True)
6271
63 # WHEN: os.path.exists raises an IOError72 def test_check_directory_exists_dir_io_error(self):
73 """
74 Test the check_directory_exists() when an IOError is raised
75 """
76 # GIVEN: A `Path` to check with patched out mkdir and exists methods
77 with patch.object(Path, 'exists') as mocked_exists, \
78 patch.object(Path, 'mkdir'), \
79 patch('openlp.core.common.log') as mocked_logger:
80
81 # WHEN: An IOError is raised when checking the if the path exists.
64 mocked_exists.side_effect = IOError()82 mocked_exists.side_effect = IOError()
65 check_directory_exists(directory_to_check)83 check_directory_exists(Path('existing', 'directory'))
6684
67 # THEN: We shouldn't get an exception though the mocked exists has been called85 # THEN: The Error should have been logged
68 mocked_exists.assert_called_with(directory_to_check)86 mocked_logger.exception.assert_called_once_with('failed to check if directory exists or create directory')
87
88 def test_check_directory_exists_dir_value_error(self):
89 """
90 Test the check_directory_exists() when an error other than IOError is raised
91 """
92 # GIVEN: A `Path` to check with patched out mkdir and exists methods
93 with patch.object(Path, 'exists') as mocked_exists, \
94 patch.object(Path, 'mkdir'), \
95 patch('openlp.core.common.log'):
6996
70 # WHEN: Some other exception is raised97 # WHEN: Some other exception is raised
71 mocked_exists.side_effect = ValueError()98 mocked_exists.side_effect = ValueError()
7299
73 # THEN: check_directory_exists raises an exception100 # THEN: `check_directory_exists` raises an exception
74 mocked_exists.assert_called_with(directory_to_check)101 self.assertRaises(ValueError, check_directory_exists, Path('existing', 'directory'))
75 self.assertRaises(ValueError, check_directory_exists, directory_to_check)
76102
77 def test_extension_loader_no_files_found(self):103 def test_extension_loader_no_files_found(self):
78 """104 """
@@ -80,7 +106,7 @@
80 """106 """
81 # GIVEN: A mocked `Path.glob` method which does not match any files107 # GIVEN: A mocked `Path.glob` method which does not match any files
82 with patch('openlp.core.common.AppLocation.get_directory', return_value=Path('/', 'app', 'dir', 'openlp')), \108 with patch('openlp.core.common.AppLocation.get_directory', return_value=Path('/', 'app', 'dir', 'openlp')), \
83 patch.object(common.Path, 'glob', return_value=[]), \109 patch.object(Path, 'glob', return_value=[]), \
84 patch('openlp.core.common.importlib.import_module') as mocked_import_module:110 patch('openlp.core.common.importlib.import_module') as mocked_import_module:
85111
86 # WHEN: Calling `extension_loader`112 # WHEN: Calling `extension_loader`
@@ -95,7 +121,7 @@
95 """121 """
96 # GIVEN: A mocked `Path.glob` method which returns a list of files122 # GIVEN: A mocked `Path.glob` method which returns a list of files
97 with patch('openlp.core.common.AppLocation.get_directory', return_value=Path('/', 'app', 'dir', 'openlp')), \123 with patch('openlp.core.common.AppLocation.get_directory', return_value=Path('/', 'app', 'dir', 'openlp')), \
98 patch.object(common.Path, 'glob', return_value=[124 patch.object(Path, 'glob', return_value=[
99 Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file1.py'),125 Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file1.py'),
100 Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file2.py'),126 Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file2.py'),
101 Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file3.py'),127 Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file3.py'),
@@ -115,7 +141,7 @@
115 """141 """
116 # GIVEN: A mocked `import_module` which raises an `ImportError`142 # GIVEN: A mocked `import_module` which raises an `ImportError`
117 with patch('openlp.core.common.AppLocation.get_directory', return_value=Path('/', 'app', 'dir', 'openlp')), \143 with patch('openlp.core.common.AppLocation.get_directory', return_value=Path('/', 'app', 'dir', 'openlp')), \
118 patch.object(common.Path, 'glob', return_value=[144 patch.object(Path, 'glob', return_value=[
119 Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file1.py')]), \145 Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file1.py')]), \
120 patch('openlp.core.common.importlib.import_module', side_effect=ImportError()), \146 patch('openlp.core.common.importlib.import_module', side_effect=ImportError()), \
121 patch('openlp.core.common.log') as mocked_logger:147 patch('openlp.core.common.log') as mocked_logger:
@@ -132,7 +158,7 @@
132 """158 """
133 # GIVEN: A mocked `SourceFileLoader` which raises an `OSError`159 # GIVEN: A mocked `SourceFileLoader` which raises an `OSError`
134 with patch('openlp.core.common.AppLocation.get_directory', return_value=Path('/', 'app', 'dir', 'openlp')), \160 with patch('openlp.core.common.AppLocation.get_directory', return_value=Path('/', 'app', 'dir', 'openlp')), \
135 patch.object(common.Path, 'glob', return_value=[161 patch.object(Path, 'glob', return_value=[
136 Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file1.py')]), \162 Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file1.py')]), \
137 patch('openlp.core.common.importlib.import_module', side_effect=OSError()), \163 patch('openlp.core.common.importlib.import_module', side_effect=OSError()), \
138 patch('openlp.core.common.log') as mocked_logger:164 patch('openlp.core.common.log') as mocked_logger:
@@ -174,7 +200,7 @@
174 Test `path_to_module` when supplied with a `Path` object200 Test `path_to_module` when supplied with a `Path` object
175 """201 """
176 # GIVEN: A `Path` object202 # GIVEN: A `Path` object
177 path = Path('openlp/core/ui/media/webkitplayer.py')203 path = Path('core', 'ui', 'media', 'webkitplayer.py')
178204
179 # WHEN: Calling path_to_module with the `Path` object205 # WHEN: Calling path_to_module with the `Path` object
180 result = path_to_module(path)206 result = path_to_module(path)
181207
=== modified file 'tests/functional/openlp_core_common/test_init.py'
--- tests/functional/openlp_core_common/test_init.py 2017-04-24 05:17:55 +0000
+++ tests/functional/openlp_core_common/test_init.py 2017-08-24 19:54:19 +0000
@@ -24,6 +24,7 @@
24"""24"""
25import os25import os
26from io import BytesIO26from io import BytesIO
27from pathlib import Path
27from unittest import TestCase28from unittest import TestCase
28from unittest.mock import MagicMock, PropertyMock, call, patch29from unittest.mock import MagicMock, PropertyMock, call, patch
2930
@@ -296,10 +297,10 @@
296 """297 """
297 # GIVEN: A blank path298 # GIVEN: A blank path
298 # WEHN: Calling delete_file299 # WEHN: Calling delete_file
299 result = delete_file('')300 result = delete_file(None)
300301
301 # THEN: delete_file should return False302 # THEN: delete_file should return False
302 self.assertFalse(result, "delete_file should return False when called with ''")303 self.assertFalse(result, "delete_file should return False when called with None")
303304
304 def test_delete_file_path_success(self):305 def test_delete_file_path_success(self):
305 """306 """
@@ -309,84 +310,87 @@
309 with patch('openlp.core.common.os', **{'path.exists.return_value': False}):310 with patch('openlp.core.common.os', **{'path.exists.return_value': False}):
310311
311 # WHEN: Calling delete_file with a file path312 # WHEN: Calling delete_file with a file path
312 result = delete_file('path/file.ext')313 result = delete_file(Path('path', 'file.ext'))
313314
314 # THEN: delete_file should return True315 # THEN: delete_file should return True
315 self.assertTrue(result, 'delete_file should return True when it successfully deletes a file')316 self.assertTrue(result, 'delete_file should return True when it successfully deletes a file')
316317
317 def test_delete_file_path_no_file_exists(self):318 def test_delete_file_path_no_file_exists(self):
318 """319 """
319 Test the delete_file function when the file to remove does not exist320 Test the `delete_file` function when the file to remove does not exist
320 """321 """
321 # GIVEN: A mocked os which returns False when os.path.exists is called322 # GIVEN: A patched `exists` methods on the Path object, which returns False
322 with patch('openlp.core.common.os', **{'path.exists.return_value': False}):323 with patch.object(Path, 'exists', return_value=False), \
323324 patch.object(Path, 'unlink') as mocked_unlink:
324 # WHEN: Calling delete_file with a file path325
325 result = delete_file('path/file.ext')326 # WHEN: Calling `delete_file with` a file path
326327 result = delete_file(Path('path', 'file.ext'))
327 # THEN: delete_file should return True328
329 # THEN: The function should not attempt to delete the file and it should return True
330 self.assertFalse(mocked_unlink.called)
328 self.assertTrue(result, 'delete_file should return True when the file doesnt exist')331 self.assertTrue(result, 'delete_file should return True when the file doesnt exist')
329332
330 def test_delete_file_path_exception(self):333 def test_delete_file_path_exception(self):
331 """334 """
332 Test the delete_file function when os.remove raises an exception335 Test the delete_file function when an exception is raised
333 """336 """
334 # GIVEN: A mocked os which returns True when os.path.exists is called and raises an OSError when os.remove is337 # GIVEN: A test `Path` object with a patched exists method which raises an OSError
335 # called.338 # called.
336 with patch('openlp.core.common.os', **{'path.exists.return_value': True, 'path.exists.side_effect': OSError}), \339 with patch.object(Path, 'exists') as mocked_exists, \
337 patch('openlp.core.common.log') as mocked_log:340 patch('openlp.core.common.log') as mocked_log:
338341 mocked_exists.side_effect = OSError
339 # WHEN: Calling delete_file with a file path342
340 result = delete_file('path/file.ext')343 # WHEN: Calling delete_file with a the test Path object
341344 result = delete_file(Path('path', 'file.ext'))
342 # THEN: delete_file should log and exception and return False345
343 self.assertEqual(mocked_log.exception.call_count, 1)346 # THEN: The exception should be logged and `delete_file` should return False
344 self.assertFalse(result, 'delete_file should return False when os.remove raises an OSError')347 self.assertTrue(mocked_log.exception.called)
345348 self.assertFalse(result, 'delete_file should return False when an OSError is raised')
346 def test_get_file_name_encoding_done_test(self):349
350 def test_get_file_encoding_done_test(self):
347 """351 """
348 Test get_file_encoding when the detector sets done to True352 Test get_file_encoding when the detector sets done to True
349 """353 """
350 # GIVEN: A mocked UniversalDetector instance with done attribute set to True after first iteration354 # GIVEN: A mocked UniversalDetector instance with done attribute set to True after first iteration
351 with patch('openlp.core.common.UniversalDetector') as mocked_universal_detector, \355 with patch('openlp.core.common.UniversalDetector') as mocked_universal_detector, \
352 patch('builtins.open', return_value=BytesIO(b"data" * 260)) as mocked_open:356 patch.object(Path, 'open', return_value=BytesIO(b"data" * 260)) as mocked_open:
353 encoding_result = {'encoding': 'UTF-8', 'confidence': 0.99}357 encoding_result = {'encoding': 'UTF-8', 'confidence': 0.99}
354 mocked_universal_detector_inst = MagicMock(result=encoding_result)358 mocked_universal_detector_inst = MagicMock(result=encoding_result)
355 type(mocked_universal_detector_inst).done = PropertyMock(side_effect=[False, True])359 type(mocked_universal_detector_inst).done = PropertyMock(side_effect=[False, True])
356 mocked_universal_detector.return_value = mocked_universal_detector_inst360 mocked_universal_detector.return_value = mocked_universal_detector_inst
357361
358 # WHEN: Calling get_file_encoding362 # WHEN: Calling get_file_encoding
359 result = get_file_encoding('file name')363 result = get_file_encoding(Path('file name'))
360364
361 # THEN: The feed method of UniversalDetector should only br called once before returning a result365 # THEN: The feed method of UniversalDetector should only br called once before returning a result
362 mocked_open.assert_called_once_with('file name', 'rb')366 mocked_open.assert_called_once_with('rb')
363 self.assertEqual(mocked_universal_detector_inst.feed.mock_calls, [call(b"data" * 256)])367 self.assertEqual(mocked_universal_detector_inst.feed.mock_calls, [call(b"data" * 256)])
364 mocked_universal_detector_inst.close.assert_called_once_with()368 mocked_universal_detector_inst.close.assert_called_once_with()
365 self.assertEqual(result, encoding_result)369 self.assertEqual(result, encoding_result)
366370
367 def test_get_file_name_encoding_eof_test(self):371 def test_get_file_encoding_eof_test(self):
368 """372 """
369 Test get_file_encoding when the end of the file is reached373 Test get_file_encoding when the end of the file is reached
370 """374 """
371 # GIVEN: A mocked UniversalDetector instance which isn't set to done and a mocked open, with 1040 bytes of test375 # GIVEN: A mocked UniversalDetector instance which isn't set to done and a mocked open, with 1040 bytes of test
372 # data (enough to run the iterator twice)376 # data (enough to run the iterator twice)
373 with patch('openlp.core.common.UniversalDetector') as mocked_universal_detector, \377 with patch('openlp.core.common.UniversalDetector') as mocked_universal_detector, \
374 patch('builtins.open', return_value=BytesIO(b"data" * 260)) as mocked_open:378 patch.object(Path, 'open', return_value=BytesIO(b"data" * 260)) as mocked_open:
375 encoding_result = {'encoding': 'UTF-8', 'confidence': 0.99}379 encoding_result = {'encoding': 'UTF-8', 'confidence': 0.99}
376 mocked_universal_detector_inst = MagicMock(mock=mocked_universal_detector,380 mocked_universal_detector_inst = MagicMock(mock=mocked_universal_detector,
377 **{'done': False, 'result': encoding_result})381 **{'done': False, 'result': encoding_result})
378 mocked_universal_detector.return_value = mocked_universal_detector_inst382 mocked_universal_detector.return_value = mocked_universal_detector_inst
379383
380 # WHEN: Calling get_file_encoding384 # WHEN: Calling get_file_encoding
381 result = get_file_encoding('file name')385 result = get_file_encoding(Path('file name'))
382386
383 # THEN: The feed method of UniversalDetector should have been called twice before returning a result387 # THEN: The feed method of UniversalDetector should have been called twice before returning a result
384 mocked_open.assert_called_once_with('file name', 'rb')388 mocked_open.assert_called_once_with('rb')
385 self.assertEqual(mocked_universal_detector_inst.feed.mock_calls, [call(b"data" * 256), call(b"data" * 4)])389 self.assertEqual(mocked_universal_detector_inst.feed.mock_calls, [call(b"data" * 256), call(b"data" * 4)])
386 mocked_universal_detector_inst.close.assert_called_once_with()390 mocked_universal_detector_inst.close.assert_called_once_with()
387 self.assertEqual(result, encoding_result)391 self.assertEqual(result, encoding_result)
388392
389 def test_get_file_name_encoding_oserror_test(self):393 def test_get_file_encoding_oserror_test(self):
390 """394 """
391 Test get_file_encoding when the end of the file is reached395 Test get_file_encoding when the end of the file is reached
392 """396 """
@@ -397,7 +401,7 @@
397 patch('openlp.core.common.log') as mocked_log:401 patch('openlp.core.common.log') as mocked_log:
398402
399 # WHEN: Calling get_file_encoding403 # WHEN: Calling get_file_encoding
400 result = get_file_encoding('file name')404 result = get_file_encoding(Path('file name'))
401405
402 # THEN: log.exception should be called and get_file_encoding should return None406 # THEN: log.exception should be called and get_file_encoding should return None
403 mocked_log.exception.assert_called_once_with('Error detecting file encoding')407 mocked_log.exception.assert_called_once_with('Error detecting file encoding')
404408
=== modified file 'tests/functional/openlp_core_lib/test_db.py'
--- tests/functional/openlp_core_lib/test_db.py 2017-06-09 13:45:18 +0000
+++ tests/functional/openlp_core_lib/test_db.py 2017-08-24 19:54:19 +0000
@@ -24,6 +24,7 @@
24"""24"""
25import os25import os
26import shutil26import shutil
27from pathlib import Path
2728
28from tempfile import mkdtemp29from tempfile import mkdtemp
29from unittest import TestCase30from unittest import TestCase
@@ -129,10 +130,10 @@
129 # GIVEN: Mocked out AppLocation class and delete_file method, a test plugin name and a db location130 # GIVEN: Mocked out AppLocation class and delete_file method, a test plugin name and a db location
130 with patch('openlp.core.lib.db.AppLocation') as MockedAppLocation, \131 with patch('openlp.core.lib.db.AppLocation') as MockedAppLocation, \
131 patch('openlp.core.lib.db.delete_file') as mocked_delete_file:132 patch('openlp.core.lib.db.delete_file') as mocked_delete_file:
132 MockedAppLocation.get_section_data_path.return_value = 'test-dir'133 MockedAppLocation.get_section_data_path.return_value = Path('test-dir')
133 mocked_delete_file.return_value = True134 mocked_delete_file.return_value = True
134 test_plugin = 'test'135 test_plugin = 'test'
135 test_location = os.path.join('test-dir', test_plugin)136 test_location = Path('test-dir', test_plugin)
136137
137 # WHEN: delete_database is run without a database file138 # WHEN: delete_database is run without a database file
138 result = delete_database(test_plugin)139 result = delete_database(test_plugin)
@@ -149,11 +150,11 @@
149 # GIVEN: Mocked out AppLocation class and delete_file method, a test plugin name and a db location150 # GIVEN: Mocked out AppLocation class and delete_file method, a test plugin name and a db location
150 with patch('openlp.core.lib.db.AppLocation') as MockedAppLocation, \151 with patch('openlp.core.lib.db.AppLocation') as MockedAppLocation, \
151 patch('openlp.core.lib.db.delete_file') as mocked_delete_file:152 patch('openlp.core.lib.db.delete_file') as mocked_delete_file:
152 MockedAppLocation.get_section_data_path.return_value = 'test-dir'153 MockedAppLocation.get_section_data_path.return_value = Path('test-dir')
153 mocked_delete_file.return_value = False154 mocked_delete_file.return_value = False
154 test_plugin = 'test'155 test_plugin = 'test'
155 test_db_file = 'mydb.sqlite'156 test_db_file = 'mydb.sqlite'
156 test_location = os.path.join('test-dir', test_db_file)157 test_location = Path('test-dir', test_db_file)
157158
158 # WHEN: delete_database is run without a database file159 # WHEN: delete_database is run without a database file
159 result = delete_database(test_plugin, test_db_file)160 result = delete_database(test_plugin, test_db_file)
160161
=== removed file 'tests/functional/openlp_core_lib/test_file_dialog.py'
--- tests/functional/openlp_core_lib/test_file_dialog.py 2017-08-07 21:12:42 +0000
+++ tests/functional/openlp_core_lib/test_file_dialog.py 1970-01-01 00:00:00 +0000
@@ -1,45 +0,0 @@
1# -*- coding: utf-8 -*-
2# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
3
4###############################################################################
5# OpenLP - Open Source Lyrics Projection #
6# --------------------------------------------------------------------------- #
7# Copyright (c) 2008-2017 OpenLP Developers #
8# --------------------------------------------------------------------------- #
9# This program is free software; you can redistribute it and/or modify it #
10# under the terms of the GNU General Public License as published by the Free #
11# Software Foundation; version 2 of the License. #
12# #
13# This program is distributed in the hope that it will be useful, but WITHOUT #
14# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
15# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
16# more details. #
17# #
18# You should have received a copy of the GNU General Public License along #
19# with this program; if not, write to the Free Software Foundation, Inc., 59 #
20# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
21###############################################################################
22"""
23Package to test the openlp.core.ui.lib.filedialog package.
24"""
25from unittest import TestCase
26from unittest.mock import MagicMock, patch
27
28
29class TestFileDialog(TestCase):
30 """
31 Test the functions in the :mod:`filedialog` module.
32 """
33 def setUp(self):
34 self.os_patcher = patch('openlp.core.ui.lib.filedialog.os')
35 self.qt_gui_patcher = patch('openlp.core.ui.lib.filedialog.QtWidgets')
36 self.ui_strings_patcher = patch('openlp.core.ui.lib.filedialog.UiStrings')
37 self.mocked_os = self.os_patcher.start()
38 self.mocked_qt_gui = self.qt_gui_patcher.start()
39 self.mocked_ui_strings = self.ui_strings_patcher.start()
40 self.mocked_parent = MagicMock()
41
42 def tearDown(self):
43 self.os_patcher.stop()
44 self.qt_gui_patcher.stop()
45 self.ui_strings_patcher.stop()
460
=== modified file 'tests/functional/openlp_core_lib/test_lib.py'
--- tests/functional/openlp_core_lib/test_lib.py 2017-08-23 20:21:11 +0000
+++ tests/functional/openlp_core_lib/test_lib.py 2017-08-24 19:54:19 +0000
@@ -24,6 +24,7 @@
24"""24"""
25import os25import os
26from datetime import datetime, timedelta26from datetime import datetime, timedelta
27from pathlib import Path
27from unittest import TestCase28from unittest import TestCase
28from unittest.mock import MagicMock, patch29from unittest.mock import MagicMock, patch
2930
@@ -148,35 +149,34 @@
148 """149 """
149 Test the get_text_file_string() function when a file does not exist150 Test the get_text_file_string() function when a file does not exist
150 """151 """
151 with patch('openlp.core.lib.os.path.isfile') as mocked_isfile:152 # GIVEN: A patched is_file which returns False, and a file path
152 # GIVEN: A mocked out isfile which returns true, and a text file name153 with patch.object(Path, 'is_file', return_value=False):
153 filename = 'testfile.txt'154 file_path = Path('testfile.txt')
154 mocked_isfile.return_value = False
155155
156 # WHEN: get_text_file_string is called156 # WHEN: get_text_file_string is called
157 result = get_text_file_string(filename)157 result = get_text_file_string(file_path)
158158
159 # THEN: The result should be False159 # THEN: The result should be False
160 mocked_isfile.assert_called_with(filename)160 file_path.is_file.assert_called_with()
161 self.assertFalse(result, 'False should be returned if no file exists')161 self.assertFalse(result, 'False should be returned if no file exists')
162162
163 def test_get_text_file_string_read_error(self):163 def test_get_text_file_string_read_error(self):
164 """164 """
165 Test the get_text_file_string() method when a read error happens165 Test the get_text_file_string() method when a read error happens
166 """166 """
167 with patch('openlp.core.lib.os.path.isfile') as mocked_isfile, \167 # GIVEN: A patched open which raises an exception and is_file which returns True
168 patch('openlp.core.lib.open', create=True) as mocked_open:168 with patch.object(Path, 'is_file'), \
169 # GIVEN: A mocked-out open() which raises an exception and isfile returns True169 patch.object(Path, 'open'):
170 filename = 'testfile.txt'170 file_path = Path('testfile.txt')
171 mocked_isfile.return_value = True171 file_path.is_file.return_value = True
172 mocked_open.side_effect = IOError()172 file_path.open.side_effect = IOError()
173173
174 # WHEN: get_text_file_string is called174 # WHEN: get_text_file_string is called
175 result = get_text_file_string(filename)175 result = get_text_file_string(file_path)
176176
177 # THEN: None should be returned177 # THEN: None should be returned
178 mocked_isfile.assert_called_with(filename)178 file_path.is_file.assert_called_once_with()
179 mocked_open.assert_called_with(filename, 'r', encoding='utf-8')179 file_path.open.assert_called_once_with('r', encoding='utf-8')
180 self.assertIsNone(result, 'None should be returned if the file cannot be opened')180 self.assertIsNone(result, 'None should be returned if the file cannot be opened')
181181
182 def test_get_text_file_string_decode_error(self):182 def test_get_text_file_string_decode_error(self):
183183
=== modified file 'tests/functional/openlp_core_ui/test_firsttimeform.py'
--- tests/functional/openlp_core_ui/test_firsttimeform.py 2017-04-24 05:17:55 +0000
+++ tests/functional/openlp_core_ui/test_firsttimeform.py 2017-08-24 19:54:19 +0000
@@ -25,6 +25,7 @@
25import os25import os
26import tempfile26import tempfile
27import urllib27import urllib
28from pathlib import Path
28from unittest import TestCase29from unittest import TestCase
29from unittest.mock import MagicMock, patch30from unittest.mock import MagicMock, patch
3031
@@ -116,7 +117,7 @@
116 mocked_settings.value.return_value = True117 mocked_settings.value.return_value = True
117 MockedSettings.return_value = mocked_settings118 MockedSettings.return_value = mocked_settings
118 mocked_gettempdir.return_value = 'temp'119 mocked_gettempdir.return_value = 'temp'
119 expected_temp_path = os.path.join('temp', 'openlp')120 expected_temp_path = Path('temp', 'openlp')
120121
121 # WHEN: The set_defaults() method is run122 # WHEN: The set_defaults() method is run
122 frw.set_defaults()123 frw.set_defaults()
123124
=== modified file 'tests/functional/openlp_core_ui/test_thememanager.py'
--- tests/functional/openlp_core_ui/test_thememanager.py 2017-06-01 06:18:47 +0000
+++ tests/functional/openlp_core_ui/test_thememanager.py 2017-08-24 19:54:19 +0000
@@ -90,7 +90,7 @@
90 # theme, check_directory_exists and thememanager-attributes.90 # theme, check_directory_exists and thememanager-attributes.
91 with patch('builtins.open') as mocked_open, \91 with patch('builtins.open') as mocked_open, \
92 patch('openlp.core.ui.thememanager.shutil.copyfile') as mocked_copyfile, \92 patch('openlp.core.ui.thememanager.shutil.copyfile') as mocked_copyfile, \
93 patch('openlp.core.ui.thememanager.check_directory_exists') as mocked_check_directory_exists:93 patch('openlp.core.ui.thememanager.check_directory_exists'):
94 mocked_open.return_value = MagicMock()94 mocked_open.return_value = MagicMock()
95 theme_manager = ThemeManager(None)95 theme_manager = ThemeManager(None)
96 theme_manager.old_background_image = None96 theme_manager.old_background_image = None
@@ -118,7 +118,7 @@
118 # theme, check_directory_exists and thememanager-attributes.118 # theme, check_directory_exists and thememanager-attributes.
119 with patch('builtins.open') as mocked_open, \119 with patch('builtins.open') as mocked_open, \
120 patch('openlp.core.ui.thememanager.shutil.copyfile') as mocked_copyfile, \120 patch('openlp.core.ui.thememanager.shutil.copyfile') as mocked_copyfile, \
121 patch('openlp.core.ui.thememanager.check_directory_exists') as mocked_check_directory_exists:121 patch('openlp.core.ui.thememanager.check_directory_exists'):
122 mocked_open.return_value = MagicMock()122 mocked_open.return_value = MagicMock()
123 theme_manager = ThemeManager(None)123 theme_manager = ThemeManager(None)
124 theme_manager.old_background_image = None124 theme_manager.old_background_image = None
125125
=== modified file 'tests/functional/openlp_plugins/bibles/test_manager.py'
--- tests/functional/openlp_plugins/bibles/test_manager.py 2016-12-31 11:01:36 +0000
+++ tests/functional/openlp_plugins/bibles/test_manager.py 2017-08-24 19:54:19 +0000
@@ -22,6 +22,7 @@
22"""22"""
23This module contains tests for the manager submodule of the Bibles plugin.23This module contains tests for the manager submodule of the Bibles plugin.
24"""24"""
25from pathlib import Path
25from unittest import TestCase26from unittest import TestCase
26from unittest.mock import MagicMock, patch27from unittest.mock import MagicMock, patch
2728
@@ -50,7 +51,6 @@
50 """51 """
51 # GIVEN: An instance of BibleManager and a mocked bible52 # GIVEN: An instance of BibleManager and a mocked bible
52 with patch.object(BibleManager, 'reload_bibles'), \53 with patch.object(BibleManager, 'reload_bibles'), \
53 patch('openlp.plugins.bibles.lib.manager.os.path.join', side_effect=lambda x, y: '{}/{}'.format(x, y)),\
54 patch('openlp.plugins.bibles.lib.manager.delete_file', return_value=True) as mocked_delete_file:54 patch('openlp.plugins.bibles.lib.manager.delete_file', return_value=True) as mocked_delete_file:
55 instance = BibleManager(MagicMock())55 instance = BibleManager(MagicMock())
56 # We need to keep a reference to the mock for close_all as it gets set to None later on!56 # We need to keep a reference to the mock for close_all as it gets set to None later on!
@@ -66,4 +66,4 @@
66 self.assertTrue(result)66 self.assertTrue(result)
67 mocked_close_all.assert_called_once_with()67 mocked_close_all.assert_called_once_with()
68 self.assertIsNone(mocked_bible.session)68 self.assertIsNone(mocked_bible.session)
69 mocked_delete_file.assert_called_once_with('bibles/KJV.sqlite')69 mocked_delete_file.assert_called_once_with(Path('bibles', 'KJV.sqlite'))
7070
=== modified file 'tests/functional/openlp_plugins/media/test_mediaplugin.py'
--- tests/functional/openlp_plugins/media/test_mediaplugin.py 2017-06-06 20:58:12 +0000
+++ tests/functional/openlp_plugins/media/test_mediaplugin.py 2017-08-24 19:54:19 +0000
@@ -38,20 +38,18 @@
38 def setUp(self):38 def setUp(self):
39 Registry.create()39 Registry.create()
4040
41 @patch(u'openlp.plugins.media.mediaplugin.Plugin.initialise')41 @patch('openlp.plugins.media.mediaplugin.Plugin.initialise')
42 def test_initialise(self, mocked_initialise):42 def test_initialise(self, mocked_initialise):
43 """43 """
44 Test that the initialise() method overwrites the built-in one, but still calls it44 Test that the initialise() method overwrites the built-in one, but still calls it
45 """45 """
46 # GIVEN: A media plugin instance and a mocked settings object46 # GIVEN: A media plugin instance
47 media_plugin = MediaPlugin()47 media_plugin = MediaPlugin()
48 mocked_settings = MagicMock()
49 mocked_settings.get_files_from_config.return_value = True # Not the real value, just need something "true-ish"
5048
51 # WHEN: initialise() is called49 # WHEN: initialise() is called
52 media_plugin.initialise()50 media_plugin.initialise()
5351
54 # THEN: The settings should be upgraded and the base initialise() method should be called52 # THEN: The the base initialise() method should be called
55 mocked_initialise.assert_called_with()53 mocked_initialise.assert_called_with()
5654
57 def test_about_text(self):55 def test_about_text(self):
5856
=== modified file 'tests/functional/openlp_plugins/presentations/test_presentationcontroller.py'
--- tests/functional/openlp_plugins/presentations/test_presentationcontroller.py 2017-05-30 18:42:35 +0000
+++ tests/functional/openlp_plugins/presentations/test_presentationcontroller.py 2017-08-24 19:54:19 +0000
@@ -24,6 +24,7 @@
24classes and related methods.24classes and related methods.
25"""25"""
26import os26import os
27from pathlib import Path
27from unittest import TestCase28from unittest import TestCase
28from unittest.mock import MagicMock, mock_open, patch29from unittest.mock import MagicMock, mock_open, patch
2930
@@ -38,7 +39,8 @@
38 """39 """
39 def setUp(self):40 def setUp(self):
40 self.get_thumbnail_folder_patcher = \41 self.get_thumbnail_folder_patcher = \
41 patch('openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument.get_thumbnail_folder')42 patch('openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument.get_thumbnail_folder',
43 return_value=Path())
42 self.get_thumbnail_folder_patcher.start()44 self.get_thumbnail_folder_patcher.start()
43 mocked_plugin = MagicMock()45 mocked_plugin = MagicMock()
44 mocked_plugin.settings_section = 'presentations'46 mocked_plugin.settings_section = 'presentations'
@@ -225,7 +227,7 @@
225 PresentationDocument(self.mock_controller, 'Name')227 PresentationDocument(self.mock_controller, 'Name')
226228
227 # THEN: check_directory_exists should have been called with 'returned/path/'229 # THEN: check_directory_exists should have been called with 'returned/path/'
228 self.mock_check_directory_exists.assert_called_once_with('returned/path/')230 self.mock_check_directory_exists.assert_called_once_with(Path('returned', 'path'))
229231
230 self._setup_patcher.start()232 self._setup_patcher.start()
231233
232234
=== modified file 'tests/interfaces/openlp_core_common/test_utils.py'
--- tests/interfaces/openlp_core_common/test_utils.py 2016-12-31 11:01:36 +0000
+++ tests/interfaces/openlp_core_common/test_utils.py 2017-08-24 19:54:19 +0000
@@ -22,7 +22,7 @@
22"""22"""
23Functional tests to test the AppLocation class and related methods.23Functional tests to test the AppLocation class and related methods.
24"""24"""
25import os25from pathlib import Path
26from unittest import TestCase26from unittest import TestCase
2727
28from openlp.core.common import is_not_image_file28from openlp.core.common import is_not_image_file
@@ -59,7 +59,7 @@
59 Test the method handles an image file59 Test the method handles an image file
60 """60 """
61 # Given and empty string61 # Given and empty string
62 file_name = os.path.join(TEST_RESOURCES_PATH, 'church.jpg')62 file_name = Path(TEST_RESOURCES_PATH, 'church.jpg')
6363
64 # WHEN testing for it64 # WHEN testing for it
65 result = is_not_image_file(file_name)65 result = is_not_image_file(file_name)
@@ -72,7 +72,7 @@
72 Test the method handles a non image file72 Test the method handles a non image file
73 """73 """
74 # Given and empty string74 # Given and empty string
75 file_name = os.path.join(TEST_RESOURCES_PATH, 'serviceitem_custom_1.osj')75 file_name = Path(TEST_RESOURCES_PATH, 'serviceitem_custom_1.osj')
7676
77 # WHEN testing for it77 # WHEN testing for it
78 result = is_not_image_file(file_name)78 result = is_not_image_file(file_name)