diff --git a/openlp/core/__init__.py b/openlp/core/__init__.py index 23436b6e6..af29cddae 100644 --- a/openlp/core/__init__.py +++ b/openlp/core/__init__.py @@ -33,6 +33,7 @@ import os import shutil import sys import time +from pathlib import Path from traceback import format_exception from PyQt5 import QtCore, QtGui, QtWidgets @@ -346,15 +347,18 @@ def set_up_logging(log_path): """ Setup our logging using log_path - :param log_path: the path + :param pathlib.Path log_path: The file to save the log to + :return: None + :rtype: None """ check_directory_exists(log_path, True) - filename = os.path.join(log_path, 'openlp.log') - logfile = logging.FileHandler(filename, 'w', encoding="UTF-8") + file_path = log_path / 'openlp.log' + # TODO: FileHandler accepts a Path object in Py3.6 + logfile = logging.FileHandler(str(file_path), 'w', encoding='UTF-8') logfile.setFormatter(logging.Formatter('%(asctime)s %(name)-55s %(levelname)-8s %(message)s')) log.addHandler(logfile) if log.isEnabledFor(logging.DEBUG): - print('Logging to: {name}'.format(name=filename)) + print('Logging to: {name}'.format(name=file_path)) def main(args=None): @@ -390,24 +394,24 @@ def main(args=None): application.setApplicationName('OpenLPPortable') Settings.setDefaultFormat(Settings.IniFormat) # Get location OpenLPPortable.ini - application_path = str(AppLocation.get_directory(AppLocation.AppDir)) - set_up_logging(os.path.abspath(os.path.join(application_path, '..', '..', 'Other'))) + portable_path = (AppLocation.get_directory(AppLocation.AppDir) / '..' / '..').resolve() + data_path = portable_path / 'Data' + set_up_logging(portable_path / 'Other') log.info('Running portable') - portable_settings_file = os.path.abspath(os.path.join(application_path, '..', '..', 'Data', 'OpenLP.ini')) + portable_settings_path = data_path / 'OpenLP.ini' # Make this our settings file - log.info('INI file: {name}'.format(name=portable_settings_file)) - Settings.set_filename(portable_settings_file) + log.info('INI file: {name}'.format(name=portable_settings_path)) + Settings.set_filename(str(portable_settings_path)) portable_settings = Settings() # Set our data path - data_path = os.path.abspath(os.path.join(application_path, '..', '..', 'Data',)) log.info('Data path: {name}'.format(name=data_path)) # Point to our data path - portable_settings.setValue('advanced/data path', data_path) + portable_settings.setValue('advanced/data path', str(data_path)) portable_settings.setValue('advanced/is portable', True) portable_settings.sync() else: application.setApplicationName('OpenLP') - set_up_logging(str(AppLocation.get_directory(AppLocation.CacheDir))) + set_up_logging(AppLocation.get_directory(AppLocation.CacheDir)) Registry.create() Registry().register('application', application) Registry().set_flag('no_web_server', args.no_web_server) diff --git a/openlp/core/api/endpoint/controller.py b/openlp/core/api/endpoint/controller.py index 9aa44cfff..85e9623f9 100644 --- a/openlp/core/api/endpoint/controller.py +++ b/openlp/core/api/endpoint/controller.py @@ -64,7 +64,7 @@ def controller_text(request): elif current_item.is_image() and not frame.get('image', '') and Settings().value('api/thumbnails'): item['tag'] = str(index + 1) thumbnail_path = os.path.join('images', 'thumbnails', frame['title']) - full_thumbnail_path = os.path.join(AppLocation.get_data_path(), thumbnail_path) + full_thumbnail_path = str(AppLocation.get_data_path() / thumbnail_path) # Create thumbnail if it doesn't exists if not os.path.exists(full_thumbnail_path): create_thumb(current_item.get_frame_path(index), full_thumbnail_path, False) @@ -82,7 +82,7 @@ def controller_text(request): if current_item.is_capable(ItemCapabilities.HasThumbnails) and \ Settings().value('api/thumbnails'): # If the file is under our app directory tree send the portion after the match - data_path = AppLocation.get_data_path() + data_path = str(AppLocation.get_data_path()) if frame['image'][0:len(data_path)] == data_path: item['img'] = urllib.request.pathname2url(frame['image'][len(data_path):]) Registry().get('image_manager').add_image(frame['image'], frame['title'], None, 88, 88) diff --git a/openlp/core/api/endpoint/pluginhelpers.py b/openlp/core/api/endpoint/pluginhelpers.py index cf3fac5ec..d2955ef61 100644 --- a/openlp/core/api/endpoint/pluginhelpers.py +++ b/openlp/core/api/endpoint/pluginhelpers.py @@ -125,12 +125,9 @@ def display_thumbnails(request, controller_name, log, dimensions, file_name, sli file_name = urllib.parse.unquote(file_name) if '..' not in file_name: # no hacking please if slide: - full_path = os.path.normpath(os.path.join(AppLocation.get_section_data_path(controller_name), - 'thumbnails', file_name, slide)) + full_path = str(AppLocation.get_section_data_path(controller_name) / 'thumbnails' / file_name / slide) else: - full_path = os.path.normpath(os.path.join(AppLocation.get_section_data_path(controller_name), - - 'thumbnails', file_name)) + full_path = str(AppLocation.get_section_data_path(controller_name) / 'thumbnails' / file_name) if os.path.exists(full_path): path, just_file_name = os.path.split(full_path) Registry().get('image_manager').add_image(full_path, just_file_name, None, width, height) diff --git a/openlp/core/api/http/endpoint.py b/openlp/core/api/http/endpoint.py index c20f1cb01..d6a923a50 100644 --- a/openlp/core/api/http/endpoint.py +++ b/openlp/core/api/http/endpoint.py @@ -68,11 +68,10 @@ class Endpoint(object): """ Render a mako template """ - root = os.path.join(str(AppLocation.get_section_data_path('remotes'))) + root = str(AppLocation.get_section_data_path('remotes')) if not self.template_dir: raise Exception('No template directory specified') path = os.path.join(root, self.template_dir, filename) - # path = os.path.abspath(os.path.join(self.template_dir, filename)) if self.static_dir: kwargs['static_url'] = '/{prefix}/static'.format(prefix=self.url_prefix) kwargs['static_url'] = kwargs['static_url'].replace('//', '/') diff --git a/openlp/core/api/http/wsgiapp.py b/openlp/core/api/http/wsgiapp.py index c852d5dc4..153344ab5 100644 --- a/openlp/core/api/http/wsgiapp.py +++ b/openlp/core/api/http/wsgiapp.py @@ -138,8 +138,12 @@ class WSGIApplication(object): Add a static directory as a route """ if route not in self.static_routes: - root = os.path.join(str(AppLocation.get_section_data_path('remotes'))) - self.static_routes[route] = DirectoryApp(os.path.abspath(os.path.join(root, static_dir))) + root = str(AppLocation.get_section_data_path('remotes')) + static_path = os.path.abspath(os.path.join(root, static_dir)) + if not os.path.exists(static_path): + log.error('Static path "%s" does not exist. Skipping creating static route/', static_path) + return + self.static_routes[route] = DirectoryApp(static_path) def dispatch(self, request): """ diff --git a/openlp/core/common/__init__.py b/openlp/core/common/__init__.py index 52da5af2c..632ef0de3 100644 --- a/openlp/core/common/__init__.py +++ b/openlp/core/common/__init__.py @@ -32,7 +32,6 @@ import sys import traceback from chardet.universaldetector import UniversalDetector from ipaddress import IPv4Address, IPv6Address, AddressValueError -from pathlib import Path from shutil import which from subprocess import check_output, CalledProcessError, STDOUT @@ -65,17 +64,19 @@ def trace_error_handler(logger): def check_directory_exists(directory, do_not_log=False): """ - Check a theme directory exists and if not create it + Check a directory exists and if not create it - :param directory: The directory to make sure exists - :param do_not_log: To not log anything. This is need for the start up, when the log isn't ready. + :param pathlib.Path directory: The directory to make sure exists + :param bool do_not_log: To not log anything. This is need for the start up, when the log isn't ready. + :return: None + :rtype: None """ if not do_not_log: log.debug('check_directory_exists {text}'.format(text=directory)) try: - if not os.path.exists(directory): - os.makedirs(directory) - except IOError as e: + if not directory.exists(): + directory.mkdir(parents=True) + except IOError: if not do_not_log: log.exception('failed to check if directory exists or create directory') @@ -85,19 +86,15 @@ def extension_loader(glob_pattern, excluded_files=[]): A utility function to find and load OpenLP extensions, such as plugins, presentation and media controllers and importers. - :param glob_pattern: A glob pattern used to find the extension(s) to be imported. Should be relative to the - application directory. i.e. openlp/plugins/*/*plugin.py - :type glob_pattern: str - - :param excluded_files: A list of file names to exclude that the glob pattern may find. - :type excluded_files: list of strings - + :param str glob_pattern: A glob pattern used to find the extension(s) to be imported. Should be relative to the + application directory. i.e. plugins/*/*plugin.py + :param list[str] excluded_files: A list of file names to exclude that the glob pattern may find. :return: None :rtype: None """ - base_dir_path = AppLocation.get_directory(AppLocation.AppDir).parent - for extension_path in base_dir_path.glob(glob_pattern): - extension_path = extension_path.relative_to(base_dir_path) + app_dir = AppLocation.get_directory(AppLocation.AppDir) + for extension_path in app_dir.glob(glob_pattern): + extension_path = extension_path.relative_to(app_dir) if extension_path.name in excluded_files: continue module_name = path_to_module(extension_path) @@ -106,21 +103,19 @@ def extension_loader(glob_pattern, excluded_files=[]): except (ImportError, OSError): # On some platforms importing vlc.py might cause OSError exceptions. (e.g. Mac OS X) log.warning('Failed to import {module_name} on path {extension_path}' - .format(module_name=module_name, extension_path=str(extension_path))) + .format(module_name=module_name, extension_path=extension_path)) def path_to_module(path): """ Convert a path to a module name (i.e openlp.core.common) - :param path: The path to convert to a module name. - :type path: Path - + :param pathlib.Path path: The path to convert to a module name. :return: The module name. :rtype: str """ module_path = path.with_suffix('') - return '.'.join(module_path.parts) + return 'openlp.' + '.'.join(module_path.parts) def get_frozen_path(frozen_option, non_frozen_option): @@ -378,20 +373,22 @@ def split_filename(path): return os.path.split(path) -def delete_file(file_path_name): +def delete_file(file_path): """ Deletes a file from the system. - :param file_path_name: The file, including path, to delete. + :param pathlib.Path file_path: The file, including path, to delete. + :return: True if the deletion was successful, or the file never existed. False otherwise. + :rtype: bool """ - if not file_path_name: + if not file_path: return False try: - if os.path.exists(file_path_name): - os.remove(file_path_name) + if file_path.exists(): + file_path.unlink() return True except (IOError, OSError): - log.exception("Unable to delete file {text}".format(text=file_path_name)) + log.exception('Unable to delete file {file_path}'.format(file_path=file_path)) return False @@ -411,18 +408,19 @@ def get_images_filter(): return IMAGES_FILTER -def is_not_image_file(file_name): +def is_not_image_file(file_path): """ Validate that the file is not an image file. - :param file_name: File name to be checked. + :param pathlib.Path file_path: The file to be checked. + :return: If the file is not an image + :rtype: bool """ - if not file_name: + if not (file_path and file_path.exists()): return True else: formats = [bytes(fmt).decode().lower() for fmt in QtGui.QImageReader.supportedImageFormats()] - file_part, file_extension = os.path.splitext(str(file_name)) - if file_extension[1:].lower() in formats and os.path.exists(file_name): + if file_path.suffix[1:].lower() in formats: return False return True @@ -431,10 +429,10 @@ def clean_filename(filename): """ Removes invalid characters from the given ``filename``. - :param filename: The "dirty" file name to clean. + :param str filename: The "dirty" file name to clean. + :return: The cleaned string + :rtype: str """ - if not isinstance(filename, str): - filename = str(filename, 'utf-8') return INVALID_FILE_CHARS.sub('_', CONTROL_CHARS.sub('', filename)) @@ -442,8 +440,9 @@ def check_binary_exists(program_path): """ Function that checks whether a binary exists. - :param program_path: The full path to the binary to check. + :param pathlib.Path program_path: The full path to the binary to check. :return: program output to be parsed + :rtype: bytes """ log.debug('testing program_path: {text}'.format(text=program_path)) try: @@ -453,26 +452,27 @@ def check_binary_exists(program_path): startupinfo.dwFlags |= STARTF_USESHOWWINDOW else: startupinfo = None - runlog = check_output([program_path, '--help'], stderr=STDOUT, startupinfo=startupinfo) + run_log = check_output([str(program_path), '--help'], stderr=STDOUT, startupinfo=startupinfo) except CalledProcessError as e: - runlog = e.output + run_log = e.output except Exception: trace_error_handler(log) - runlog = '' - log.debug('check_output returned: {text}'.format(text=runlog)) - return runlog + run_log = '' + log.debug('check_output returned: {text}'.format(text=run_log)) + return run_log -def get_file_encoding(filename): +def get_file_encoding(file_path): """ Utility function to incrementally detect the file encoding. - :param filename: Filename for the file to determine the encoding for. Str + :param pathlib.Path file_path: Filename for the file to determine the encoding for. :return: A dict with the keys 'encoding' and 'confidence' + :rtype: dict[str, float] """ detector = UniversalDetector() try: - with open(filename, 'rb') as detect_file: + with file_path.open('rb') as detect_file: while not detector.done: chunk = detect_file.read(1024) if not chunk: diff --git a/openlp/core/common/applocation.py b/openlp/core/common/applocation.py index d361c54d4..3bcdc9cb9 100644 --- a/openlp/core/common/applocation.py +++ b/openlp/core/common/applocation.py @@ -58,9 +58,6 @@ class AppLocation(object): CacheDir = 5 LanguageDir = 6 - # Base path where data/config/cache dir is located - BaseDir = None - @staticmethod def get_directory(dir_type=AppDir): """ @@ -78,8 +75,6 @@ class AppLocation(object): return get_frozen_path(FROZEN_APP_PATH, APP_PATH) / 'plugins' elif dir_type == AppLocation.LanguageDir: return get_frozen_path(FROZEN_APP_PATH, _get_os_dir_path(dir_type)) / 'i18n' - elif dir_type == AppLocation.DataDir and AppLocation.BaseDir: - return Path(AppLocation.BaseDir, 'data') else: return _get_os_dir_path(dir_type) @@ -96,7 +91,7 @@ class AppLocation(object): path = Path(Settings().value('advanced/data path')) else: path = AppLocation.get_directory(AppLocation.DataDir) - check_directory_exists(str(path)) + check_directory_exists(path) return path @staticmethod @@ -104,14 +99,10 @@ class AppLocation(object): """ Get a list of files from the data files path. - :param section: Defaults to *None*. The section of code getting the files - used to load from a section's data - subdirectory. - :type section: None | str - - :param extension: Defaults to ''. The extension to search for. For example:: + :param None | str section: Defaults to *None*. The section of code getting the files - used to load from a + section's data subdirectory. + :param str extension: Defaults to ''. The extension to search for. For example:: '.png' - :type extension: str - :return: List of files found. :rtype: list[pathlib.Path] """ @@ -134,7 +125,7 @@ class AppLocation(object): :rtype: pathlib.Path """ path = AppLocation.get_data_path() / section - check_directory_exists(str(path)) + check_directory_exists(path) return path @@ -143,14 +134,12 @@ def _get_os_dir_path(dir_type): Return a path based on which OS and environment we are running in. :param dir_type: AppLocation Enum of the requested path type - :type dir_type: AppLocation Enum - :return: The requested path :rtype: pathlib.Path """ # If running from source, return the language directory from the source directory if dir_type == AppLocation.LanguageDir: - directory = Path(os.path.abspath(os.path.join(os.path.dirname(openlp.__file__), '..', 'resources'))) + directory = Path(openlp.__file__, '..', '..').resolve() / 'resources' if directory.exists(): return directory if is_win(): @@ -158,14 +147,14 @@ def _get_os_dir_path(dir_type): if dir_type == AppLocation.DataDir: return openlp_folder_path / 'data' elif dir_type == AppLocation.LanguageDir: - return os.path.dirname(openlp.__file__) + return Path(openlp.__file__).parent return openlp_folder_path elif is_macosx(): openlp_folder_path = Path(os.getenv('HOME'), 'Library', 'Application Support', 'openlp') if dir_type == AppLocation.DataDir: return openlp_folder_path / 'Data' elif dir_type == AppLocation.LanguageDir: - return os.path.dirname(openlp.__file__) + return Path(openlp.__file__).parent return openlp_folder_path else: if dir_type == AppLocation.LanguageDir: diff --git a/openlp/core/common/settings.py b/openlp/core/common/settings.py index 6d79fdccd..8d12a69e5 100644 --- a/openlp/core/common/settings.py +++ b/openlp/core/common/settings.py @@ -502,31 +502,3 @@ class Settings(QtCore.QSettings): if isinstance(default_value, int): return int(setting) return setting - - def get_files_from_config(self, plugin): - """ - This removes the settings needed for old way we saved files (e. g. the image paths for the image plugin). A list - of file paths are returned. - - **Note**: Only a list of paths is returned; this does not convert anything! - - :param plugin: The Plugin object.The caller has to convert/save the list himself; o - """ - files_list = [] - # We need QSettings instead of Settings here to bypass our central settings dict. - # Do NOT do this anywhere else! - settings = QtCore.QSettings(self.fileName(), Settings.IniFormat) - settings.beginGroup(plugin.settings_section) - if settings.contains('{name} count'.format(name=plugin.name)): - # Get the count. - list_count = int(settings.value('{name} count'.format(name=plugin.name), 0)) - if list_count: - for counter in range(list_count): - # The keys were named e. g.: "image 0" - item = settings.value('{name} {counter:d}'.format(name=plugin.name, counter=counter), '') - if item: - files_list.append(item) - settings.remove('{name} {counter:d}'.format(name=plugin.name, counter=counter)) - settings.remove('{name} count'.format(name=plugin.name)) - settings.endGroup() - return files_list diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index 28fa2cc38..599876396 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -83,30 +83,28 @@ class ServiceItemAction(object): Next = 3 -def get_text_file_string(text_file): +def get_text_file_string(text_file_path): """ - Open a file and return its content as unicode string. If the supplied file name is not a file then the function + Open a file and return its content as a string. If the supplied file path is not a file then the function returns False. If there is an error loading the file or the content can't be decoded then the function will return None. - :param text_file: The name of the file. - :return: The file as a single string + :param pathlib.Path text_file_path: The path to the file. + :return: The contents of the file, False if the file does not exist, or None if there is an Error reading or + decoding the file. + :rtype: str | False | None """ - if not os.path.isfile(text_file): + if not text_file_path.is_file(): return False - file_handle = None content = None try: - file_handle = open(text_file, 'r', encoding='utf-8') - if file_handle.read(3) != '\xEF\xBB\xBF': - # no BOM was found - file_handle.seek(0) - content = file_handle.read() + with text_file_path.open('r', encoding='utf-8') as file_handle: + if file_handle.read(3) != '\xEF\xBB\xBF': + # no BOM was found + file_handle.seek(0) + content = file_handle.read() except (IOError, UnicodeError): - log.exception('Failed to open text file {text}'.format(text=text_file)) - finally: - if file_handle: - file_handle.close() + log.exception('Failed to open text file {text}'.format(text=text_file_path)) return content diff --git a/openlp/core/lib/db.py b/openlp/core/lib/db.py index 0021a41e7..6d13c1d9b 100644 --- a/openlp/core/lib/db.py +++ b/openlp/core/lib/db.py @@ -274,9 +274,9 @@ def delete_database(plugin_name, db_file_name=None): :param db_file_name: The database file name. Defaults to None resulting in the plugin_name being used. """ if db_file_name: - db_file_path = os.path.join(str(AppLocation.get_section_data_path(plugin_name)), db_file_name) + db_file_path = AppLocation.get_section_data_path(plugin_name) / db_file_name else: - db_file_path = os.path.join(str(AppLocation.get_section_data_path(plugin_name)), plugin_name) + db_file_path = AppLocation.get_section_data_path(plugin_name) / plugin_name return delete_file(db_file_path) diff --git a/openlp/core/lib/pluginmanager.py b/openlp/core/lib/pluginmanager.py index 5e4bf4e87..20af89e6c 100644 --- a/openlp/core/lib/pluginmanager.py +++ b/openlp/core/lib/pluginmanager.py @@ -69,7 +69,7 @@ class PluginManager(RegistryMixin, OpenLPMixin, RegistryProperties): """ Scan a directory for objects inheriting from the ``Plugin`` class. """ - glob_pattern = os.path.join('openlp', 'plugins', '*', '*plugin.py') + glob_pattern = os.path.join('plugins', '*', '*plugin.py') extension_loader(glob_pattern) plugin_classes = Plugin.__subclasses__() plugin_objects = [] diff --git a/openlp/core/lib/theme.py b/openlp/core/lib/theme.py index 78a2c240d..4a55b1e7e 100644 --- a/openlp/core/lib/theme.py +++ b/openlp/core/lib/theme.py @@ -158,9 +158,8 @@ class Theme(object): Initialise the theme object. """ # basic theme object with defaults - json_dir = os.path.join(str(AppLocation.get_directory(AppLocation.AppDir)), 'core', 'lib', 'json') - json_file = os.path.join(json_dir, 'theme.json') - jsn = get_text_file_string(json_file) + json_path = AppLocation.get_directory(AppLocation.AppDir) / 'core' / 'lib' / 'json' / 'theme.json' + jsn = get_text_file_string(json_path) jsn = json.loads(jsn) self.expand_json(jsn) self.background_filename = '' diff --git a/openlp/core/ui/firsttimeform.py b/openlp/core/ui/firsttimeform.py index 1f923fe8d..5623855d2 100644 --- a/openlp/core/ui/firsttimeform.py +++ b/openlp/core/ui/firsttimeform.py @@ -29,8 +29,9 @@ import time import urllib.request import urllib.parse import urllib.error +from configparser import ConfigParser, MissingSectionHeaderError, NoOptionError, NoSectionError +from pathlib import Path from tempfile import gettempdir -from configparser import ConfigParser, MissingSectionHeaderError, NoSectionError, NoOptionError from PyQt5 import QtCore, QtWidgets @@ -282,7 +283,7 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties): self.no_internet_cancel_button.setVisible(False) # Check if this is a re-run of the wizard. self.has_run_wizard = Settings().value('core/has run wizard') - check_directory_exists(os.path.join(gettempdir(), 'openlp')) + check_directory_exists(Path(gettempdir(), 'openlp')) def update_screen_list_combo(self): """ diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 5a3ac656d..54f70ccb2 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -30,6 +30,7 @@ import time from datetime import datetime from distutils import dir_util from distutils.errors import DistutilsFileError +from pathlib import Path from tempfile import gettempdir from PyQt5 import QtCore, QtGui, QtWidgets @@ -870,7 +871,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, RegistryProperties): setting_sections.extend([plugin.name for plugin in self.plugin_manager.plugins]) # Copy the settings file to the tmp dir, because we do not want to change the original one. temp_directory = os.path.join(str(gettempdir()), 'openlp') - check_directory_exists(temp_directory) + check_directory_exists(Path(temp_directory)) temp_config = os.path.join(temp_directory, os.path.basename(import_file_name)) shutil.copyfile(import_file_name, temp_config) settings = Settings() diff --git a/openlp/core/ui/media/mediacontroller.py b/openlp/core/ui/media/mediacontroller.py index b55eb64d1..9b6b0979a 100644 --- a/openlp/core/ui/media/mediacontroller.py +++ b/openlp/core/ui/media/mediacontroller.py @@ -177,7 +177,7 @@ class MediaController(RegistryMixin, OpenLPMixin, RegistryProperties): Check to see if we have any media Player's available. """ log.debug('_check_available_media_players') - controller_dir = os.path.join('openlp', 'core', 'ui', 'media') + controller_dir = os.path.join('core', 'ui', 'media') glob_pattern = os.path.join(controller_dir, '*player.py') extension_loader(glob_pattern, ['mediaplayer.py']) player_classes = MediaPlayer.__subclasses__() diff --git a/openlp/core/ui/printserviceform.py b/openlp/core/ui/printserviceform.py index c9e1d5a8a..9394de9ce 100644 --- a/openlp/core/ui/printserviceform.py +++ b/openlp/core/ui/printserviceform.py @@ -176,7 +176,7 @@ class PrintServiceForm(QtWidgets.QDialog, Ui_PrintServiceDialog, RegistryPropert html_data = self._add_element('html') self._add_element('head', parent=html_data) self._add_element('title', self.title_line_edit.text(), html_data.head) - css_path = os.path.join(str(AppLocation.get_data_path()), 'serviceprint', 'service_print.css') + css_path = AppLocation.get_data_path() / 'serviceprint' / 'service_print.css' custom_css = get_text_file_string(css_path) if not custom_css: custom_css = DEFAULT_CSS diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 93fa7f31b..bb37aa5c7 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -28,6 +28,7 @@ import os import shutil import zipfile from datetime import datetime, timedelta +from pathlib import Path from tempfile import mkstemp from PyQt5 import QtCore, QtGui, QtWidgets @@ -587,7 +588,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa audio_from = os.path.join(self.service_path, audio_from) save_file = os.path.join(self.service_path, audio_to) save_path = os.path.split(save_file)[0] - check_directory_exists(save_path) + check_directory_exists(Path(save_path)) if not os.path.exists(save_file): shutil.copy(audio_from, save_file) zip_file.write(audio_from, audio_to) @@ -614,7 +615,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa success = False self.main_window.add_recent_file(path_file_name) self.set_modified(False) - delete_file(temp_file_name) + delete_file(Path(temp_file_name)) return success def save_local_file(self): @@ -669,7 +670,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa return self.save_file_as() self.main_window.add_recent_file(path_file_name) self.set_modified(False) - delete_file(temp_file_name) + delete_file(Path(temp_file_name)) return success def save_file_as(self, field=None): @@ -774,7 +775,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa self.set_file_name(file_name) self.main_window.display_progress_bar(len(items)) self.process_service_items(items) - delete_file(p_file) + delete_file(Path(p_file)) self.main_window.add_recent_file(file_name) self.set_modified(False) Settings().setValue('servicemanager/last file', file_name) @@ -1343,7 +1344,7 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa Empties the service_path of temporary files on system exit. """ for file_name in os.listdir(self.service_path): - file_path = os.path.join(self.service_path, file_name) + file_path = Path(self.service_path, file_name) delete_file(file_path) if os.path.exists(os.path.join(self.service_path, 'audio')): shutil.rmtree(os.path.join(self.service_path, 'audio'), True) diff --git a/openlp/core/ui/themeform.py b/openlp/core/ui/themeform.py index bb471d0f1..69a45015a 100644 --- a/openlp/core/ui/themeform.py +++ b/openlp/core/ui/themeform.py @@ -24,6 +24,7 @@ The Theme wizard """ import logging import os +from pathlib import Path from PyQt5 import QtCore, QtGui, QtWidgets @@ -188,7 +189,8 @@ class ThemeForm(QtWidgets.QWizard, Ui_ThemeWizard, RegistryProperties): """ background_image = BackgroundType.to_string(BackgroundType.Image) if self.page(self.currentId()) == self.background_page and \ - self.theme.background_type == background_image and is_not_image_file(self.theme.background_filename): + self.theme.background_type == background_image and \ + is_not_image_file(Path(self.theme.background_filename)): QtWidgets.QMessageBox.critical(self, translate('OpenLP.ThemeWizard', 'Background Image Empty'), translate('OpenLP.ThemeWizard', 'You have not selected a ' 'background image. Please select one before continuing.')) diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index d7338db91..ec702c831 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -25,6 +25,7 @@ The Theme Manager manages adding, deleteing and modifying of themes. import os import zipfile import shutil +from pathlib import Path from xml.etree.ElementTree import ElementTree, XML from PyQt5 import QtCore, QtGui, QtWidgets @@ -161,9 +162,9 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage Set up the theme path variables """ self.path = str(AppLocation.get_section_data_path(self.settings_section)) - check_directory_exists(self.path) + check_directory_exists(Path(self.path)) self.thumb_path = os.path.join(self.path, 'thumbnails') - check_directory_exists(self.thumb_path) + check_directory_exists(Path(self.thumb_path)) def check_list_state(self, item, field=None): """ @@ -355,8 +356,8 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage """ self.theme_list.remove(theme) thumb = '{name}.png'.format(name=theme) - delete_file(os.path.join(self.path, thumb)) - delete_file(os.path.join(self.thumb_path, thumb)) + delete_file(Path(self.path, thumb)) + delete_file(Path(self.thumb_path, thumb)) try: # Windows is always unicode, so no need to encode filenames if is_win(): @@ -450,7 +451,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage for theme_file in files: theme_file = os.path.join(self.path, str(theme_file)) self.unzip_theme(theme_file, self.path) - delete_file(theme_file) + delete_file(Path(theme_file)) files = AppLocation.get_files(self.settings_section, '.png') # No themes have been found so create one if not files: @@ -514,12 +515,12 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage :return: The theme object. """ self.log_debug('get theme data for theme {name}'.format(name=theme_name)) - theme_file = os.path.join(self.path, str(theme_name), str(theme_name) + '.json') - theme_data = get_text_file_string(theme_file) + theme_file_path = Path(self.path, str(theme_name), '{file_name}.json'.format(file_name=theme_name)) + theme_data = get_text_file_string(theme_file_path) jsn = True if not theme_data: - theme_file = os.path.join(self.path, str(theme_name), str(theme_name) + '.xml') - theme_data = get_text_file_string(theme_file) + theme_file_path = theme_file_path.with_suffix('.xml') + theme_data = get_text_file_string(theme_file_path) jsn = False if not theme_data: self.log_debug('No theme data - using default theme') @@ -592,7 +593,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage # is directory or preview file continue full_name = os.path.join(directory, out_name) - check_directory_exists(os.path.dirname(full_name)) + check_directory_exists(Path(os.path.dirname(full_name))) if os.path.splitext(name)[1].lower() == '.xml' or os.path.splitext(name)[1].lower() == '.json': file_xml = str(theme_zip.read(name), 'utf-8') out_file = open(full_name, 'w', encoding='utf-8') @@ -670,10 +671,10 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage name = theme.theme_name theme_pretty = theme.export_theme() theme_dir = os.path.join(self.path, name) - check_directory_exists(theme_dir) + check_directory_exists(Path(theme_dir)) theme_file = os.path.join(theme_dir, name + '.json') if self.old_background_image and image_to != self.old_background_image: - delete_file(self.old_background_image) + delete_file(Path(self.old_background_image)) out_file = None try: out_file = open(theme_file, 'w', encoding='utf-8') diff --git a/openlp/plugins/bibles/lib/importers/csvbible.py b/openlp/plugins/bibles/lib/importers/csvbible.py index caf6e0216..cac6571a9 100644 --- a/openlp/plugins/bibles/lib/importers/csvbible.py +++ b/openlp/plugins/bibles/lib/importers/csvbible.py @@ -51,6 +51,7 @@ All CSV files are expected to use a comma (',') as the delimiter and double quot """ import csv from collections import namedtuple +from pathlib import Path from openlp.core.common import get_file_encoding, translate from openlp.core.lib.exceptions import ValidationError @@ -100,7 +101,7 @@ class CSVBible(BibleImport): :return: An iterable yielding namedtuples of type results_tuple """ try: - encoding = get_file_encoding(filename)['encoding'] + encoding = get_file_encoding(Path(filename))['encoding'] with open(filename, 'r', encoding=encoding, newline='') as csv_file: csv_reader = csv.reader(csv_file, delimiter=',', quotechar='"') return [results_tuple(*line) for line in csv_reader] diff --git a/openlp/plugins/bibles/lib/manager.py b/openlp/plugins/bibles/lib/manager.py index 4b7b78e08..a6de936ea 100644 --- a/openlp/plugins/bibles/lib/manager.py +++ b/openlp/plugins/bibles/lib/manager.py @@ -22,6 +22,7 @@ import logging import os +from pathlib import Path from openlp.core.common import AppLocation, OpenLPMixin, RegistryProperties, Settings, translate, delete_file, UiStrings from openlp.plugins.bibles.lib import LanguageSelection, parse_reference @@ -137,7 +138,7 @@ class BibleManager(OpenLPMixin, RegistryProperties): # Remove corrupted files. if name is None: bible.session.close_all() - delete_file(os.path.join(self.path, filename)) + delete_file(Path(self.path, filename)) continue log.debug('Bible Name: "{name}"'.format(name=name)) self.db_cache[name] = bible @@ -185,7 +186,7 @@ class BibleManager(OpenLPMixin, RegistryProperties): bible = self.db_cache[name] bible.session.close_all() bible.session = None - return delete_file(os.path.join(bible.path, bible.file)) + return delete_file(Path(bible.path, bible.file)) def get_bibles(self): """ diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py index 5856b9ccb..994a45b93 100644 --- a/openlp/plugins/images/lib/mediaitem.py +++ b/openlp/plugins/images/lib/mediaitem.py @@ -22,6 +22,7 @@ import logging import os +from pathlib import Path from PyQt5 import QtCore, QtGui, QtWidgets @@ -99,7 +100,7 @@ class ImageMediaItem(MediaManagerItem): self.list_view.setIndentation(self.list_view.default_indentation) self.list_view.allow_internal_dnd = True self.service_path = os.path.join(str(AppLocation.get_section_data_path(self.settings_section)), 'thumbnails') - check_directory_exists(self.service_path) + check_directory_exists(Path(self.service_path)) # Load images from the database self.load_full_list( self.manager.get_all_objects(ImageFilenames, order_by_ref=ImageFilenames.filename), initial_load=True) @@ -210,8 +211,8 @@ class ImageMediaItem(MediaManagerItem): """ images = self.manager.get_all_objects(ImageFilenames, ImageFilenames.group_id == image_group.id) for image in images: - delete_file(os.path.join(self.service_path, os.path.split(image.filename)[1])) - delete_file(self.generate_thumbnail_path(image)) + delete_file(Path(self.service_path, os.path.split(image.filename)[1])) + delete_file(Path(self.generate_thumbnail_path(image))) self.manager.delete_object(ImageFilenames, image.id) image_groups = self.manager.get_all_objects(ImageGroups, ImageGroups.parent_id == image_group.id) for group in image_groups: @@ -233,8 +234,8 @@ class ImageMediaItem(MediaManagerItem): if row_item: item_data = row_item.data(0, QtCore.Qt.UserRole) if isinstance(item_data, ImageFilenames): - delete_file(os.path.join(self.service_path, row_item.text(0))) - delete_file(self.generate_thumbnail_path(item_data)) + delete_file(Path(self.service_path, row_item.text(0))) + delete_file(Path(self.generate_thumbnail_path(item_data))) if item_data.group_id == 0: self.list_view.takeTopLevelItem(self.list_view.indexOfTopLevelItem(row_item)) else: diff --git a/openlp/plugins/media/lib/mediaitem.py b/openlp/plugins/media/lib/mediaitem.py index f3f5495c7..ea2142c1d 100644 --- a/openlp/plugins/media/lib/mediaitem.py +++ b/openlp/plugins/media/lib/mediaitem.py @@ -22,6 +22,7 @@ import logging import os +from pathlib import Path from PyQt5 import QtCore, QtWidgets @@ -301,7 +302,7 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties): """ self.list_view.clear() self.service_path = os.path.join(str(AppLocation.get_section_data_path(self.settings_section)), 'thumbnails') - check_directory_exists(self.service_path) + check_directory_exists(Path(self.service_path)) self.load_list(Settings().value(self.settings_section + '/media files')) self.rebuild_players() diff --git a/openlp/plugins/media/mediaplugin.py b/openlp/plugins/media/mediaplugin.py index 0c9d96126..af22a4f65 100644 --- a/openlp/plugins/media/mediaplugin.py +++ b/openlp/plugins/media/mediaplugin.py @@ -26,6 +26,7 @@ The Media plugin import logging import os import re +from pathlib import Path from PyQt5 import QtCore @@ -165,8 +166,7 @@ def process_check_binary(program_path): :param program_path:The full path to the binary to check. :return: If exists or not """ - program_type = None - runlog = check_binary_exists(program_path) + runlog = check_binary_exists(Path(program_path)) # Analyse the output to see it the program is mediainfo for line in runlog.splitlines(): decoded_line = line.decode() diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py index 1f751bbdc..fc9dc84d1 100644 --- a/openlp/plugins/presentations/lib/impresscontroller.py +++ b/openlp/plugins/presentations/lib/impresscontroller.py @@ -34,6 +34,7 @@ import logging import os import time +from pathlib import Path from openlp.core.common import is_win, Registry, get_uno_command, get_uno_instance, delete_file @@ -275,7 +276,7 @@ class ImpressDocument(PresentationDocument): try: doc.storeToURL(url_path, properties) self.convert_thumbnail(path, index + 1) - delete_file(path) + delete_file(Path(path)) except ErrorCodeIOException as exception: log.exception('ERROR! ErrorCodeIOException {error:d}'.format(error=exception.ErrCode)) except: diff --git a/openlp/plugins/presentations/lib/pdfcontroller.py b/openlp/plugins/presentations/lib/pdfcontroller.py index 128d940d9..b7b6b2a12 100644 --- a/openlp/plugins/presentations/lib/pdfcontroller.py +++ b/openlp/plugins/presentations/lib/pdfcontroller.py @@ -23,6 +23,7 @@ import os import logging import re +from pathlib import Path from shutil import which from subprocess import check_output, CalledProcessError @@ -69,7 +70,7 @@ class PdfController(PresentationController): :return: Type of the binary, 'gs' if ghostscript, 'mudraw' if mudraw, None if invalid. """ program_type = None - runlog = check_binary_exists(program_path) + runlog = check_binary_exists(Path(program_path)) # Analyse the output to see it the program is mudraw, ghostscript or neither for line in runlog.splitlines(): decoded_line = line.decode() diff --git a/openlp/plugins/presentations/lib/presentationcontroller.py b/openlp/plugins/presentations/lib/presentationcontroller.py index ce0e5dd8b..d0d2063d1 100644 --- a/openlp/plugins/presentations/lib/presentationcontroller.py +++ b/openlp/plugins/presentations/lib/presentationcontroller.py @@ -23,6 +23,7 @@ import logging import os import shutil +from pathlib import Path from PyQt5 import QtCore @@ -98,7 +99,7 @@ class PresentationDocument(object): """ self.slide_number = 0 self.file_path = name - check_directory_exists(self.get_thumbnail_folder()) + check_directory_exists(Path(self.get_thumbnail_folder())) def load_presentation(self): """ @@ -419,8 +420,8 @@ class PresentationController(object): self.thumbnail_folder = os.path.join( str(AppLocation.get_section_data_path(self.settings_section)), 'thumbnails') self.thumbnail_prefix = 'slide' - check_directory_exists(self.thumbnail_folder) - check_directory_exists(self.temp_folder) + check_directory_exists(Path(self.thumbnail_folder)) + check_directory_exists(Path(self.temp_folder)) def enabled(self): """ diff --git a/openlp/plugins/presentations/presentationplugin.py b/openlp/plugins/presentations/presentationplugin.py index a17d19c8f..a91f78794 100644 --- a/openlp/plugins/presentations/presentationplugin.py +++ b/openlp/plugins/presentations/presentationplugin.py @@ -125,7 +125,7 @@ class PresentationPlugin(Plugin): Check to see if we have any presentation software available. If not do not install the plugin. """ log.debug('check_pre_conditions') - controller_dir = os.path.join('openlp', 'plugins', 'presentations', 'lib') + controller_dir = os.path.join('plugins', 'presentations', 'lib') glob_pattern = os.path.join(controller_dir, '*controller.py') extension_loader(glob_pattern, ['presentationcontroller.py']) controller_classes = PresentationController.__subclasses__() diff --git a/openlp/plugins/remotes/remoteplugin.py b/openlp/plugins/remotes/remoteplugin.py index f26446206..1344c66d1 100644 --- a/openlp/plugins/remotes/remoteplugin.py +++ b/openlp/plugins/remotes/remoteplugin.py @@ -59,21 +59,22 @@ class RemotesPlugin(Plugin, OpenLPMixin): Create the internal file structure if it does not exist :return: """ - check_directory_exists(os.path.join(AppLocation.get_section_data_path('remotes'), 'assets')) - check_directory_exists(os.path.join(AppLocation.get_section_data_path('remotes'), 'images')) - check_directory_exists(os.path.join(AppLocation.get_section_data_path('remotes'), 'static')) - check_directory_exists(os.path.join(AppLocation.get_section_data_path('remotes'), 'static', 'index')) - check_directory_exists(os.path.join(AppLocation.get_section_data_path('remotes'), 'templates')) + check_directory_exists(AppLocation.get_section_data_path('remotes') / 'assets') + check_directory_exists(AppLocation.get_section_data_path('remotes') / 'images') + check_directory_exists(AppLocation.get_section_data_path('remotes') / 'static') + check_directory_exists(AppLocation.get_section_data_path('remotes') / 'static', 'index') + check_directory_exists(AppLocation.get_section_data_path('remotes') / 'templates') @staticmethod def about(): """ Information about this plugin """ - about_text = translate('RemotePlugin', 'Web Interface' - '
The web interface plugin provides the ability develop web based ' - 'interfaces using openlp web services. \nPredefined interfaces can be ' - 'download as well as custom developed interfaces') + about_text = translate( + 'RemotePlugin', + 'Web Interface' + '
The web interface plugin provides the ability to develop web based interfaces using OpenLP web ' + 'services.\nPredefined interfaces can be download as well as custom developed interfaces.') return about_text def set_plugin_text_strings(self): diff --git a/openlp/plugins/songs/forms/editsongform.py b/openlp/plugins/songs/forms/editsongform.py index 77573c5ac..aab09b9a8 100644 --- a/openlp/plugins/songs/forms/editsongform.py +++ b/openlp/plugins/songs/forms/editsongform.py @@ -1071,7 +1071,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties): log.debug(audio_files) save_path = os.path.join(str(AppLocation.get_section_data_path(self.media_item.plugin.name)), 'audio', str(self.song.id)) - check_directory_exists(save_path) + check_directory_exists(Path(save_path)) self.song.media_files = [] files = [] for row in range(self.audio_list_widget.count()): diff --git a/openlp/plugins/songs/lib/importers/songbeamer.py b/openlp/plugins/songs/lib/importers/songbeamer.py index a48a57e96..70edf1ad8 100644 --- a/openlp/plugins/songs/lib/importers/songbeamer.py +++ b/openlp/plugins/songs/lib/importers/songbeamer.py @@ -27,6 +27,7 @@ import os import re import base64 import math +from pathlib import Path from openlp.plugins.songs.lib import VerseType from openlp.plugins.songs.lib.importers.songimport import SongImport @@ -122,7 +123,7 @@ class SongBeamerImport(SongImport): file_name = os.path.split(import_file)[1] if os.path.isfile(import_file): # Detect the encoding - self.input_file_encoding = get_file_encoding(import_file)['encoding'] + self.input_file_encoding = get_file_encoding(Path(import_file))['encoding'] # The encoding should only be ANSI (cp1252), UTF-8, Unicode, Big-Endian-Unicode. # So if it doesn't start with 'u' we default to cp1252. See: # https://forum.songbeamer.com/viewtopic.php?p=419&sid=ca4814924e37c11e4438b7272a98b6f2 diff --git a/openlp/plugins/songs/lib/importers/songimport.py b/openlp/plugins/songs/lib/importers/songimport.py index 0b82d01af..8265cfc80 100644 --- a/openlp/plugins/songs/lib/importers/songimport.py +++ b/openlp/plugins/songs/lib/importers/songimport.py @@ -24,6 +24,7 @@ import logging import re import shutil import os +from pathlib import Path from PyQt5 import QtCore @@ -423,7 +424,7 @@ class SongImport(QtCore.QObject): if not hasattr(self, 'save_path'): self.save_path = os.path.join(str(AppLocation.get_section_data_path(self.import_wizard.plugin.name)), 'audio', str(song_id)) - check_directory_exists(self.save_path) + check_directory_exists(Path(self.save_path)) if not filename.startswith(self.save_path): old_file, filename = filename, os.path.join(self.save_path, os.path.split(filename)[1]) shutil.copyfile(old_file, filename) diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 14ae6897a..65d196f93 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -23,6 +23,7 @@ import logging import os import shutil +from pathlib import Path from PyQt5 import QtCore, QtWidgets from sqlalchemy.sql import and_, or_ @@ -89,7 +90,7 @@ class SongMediaItem(MediaManagerItem): for i, bga in enumerate(item.background_audio): dest_file = os.path.join( str(AppLocation.get_section_data_path(self.plugin.name)), 'audio', str(song.id), os.path.split(bga)[1]) - check_directory_exists(os.path.split(dest_file)[0]) + check_directory_exists(Path(os.path.split(dest_file)[0])) shutil.copyfile(os.path.join(str(AppLocation.get_section_data_path('servicemanager')), bga), dest_file) song.media_files.append(MediaFile.populate(weight=i, file_name=dest_file)) self.plugin.manager.save_object(song, True) @@ -535,7 +536,7 @@ class SongMediaItem(MediaManagerItem): if len(old_song.media_files) > 0: save_path = os.path.join( str(AppLocation.get_section_data_path(self.plugin.name)), 'audio', str(new_song.id)) - check_directory_exists(save_path) + check_directory_exists(Path(save_path)) for media_file in old_song.media_files: new_media_file_name = os.path.join(save_path, os.path.basename(media_file.file_name)) shutil.copyfile(media_file.file_name, new_media_file_name) diff --git a/openlp/plugins/songs/lib/openlyricsexport.py b/openlp/plugins/songs/lib/openlyricsexport.py index 9239bd567..9c2c923b1 100644 --- a/openlp/plugins/songs/lib/openlyricsexport.py +++ b/openlp/plugins/songs/lib/openlyricsexport.py @@ -25,6 +25,7 @@ format. """ import logging import os +from pathlib import Path from lxml import etree @@ -47,7 +48,7 @@ class OpenLyricsExport(RegistryProperties): self.manager = parent.plugin.manager self.songs = songs self.save_path = save_path - check_directory_exists(self.save_path) + check_directory_exists(Path(self.save_path)) def do_export(self): """ diff --git a/openlp/plugins/songusage/forms/songusagedetailform.py b/openlp/plugins/songusage/forms/songusagedetailform.py index 595d56fcd..9697fdbb3 100644 --- a/openlp/plugins/songusage/forms/songusagedetailform.py +++ b/openlp/plugins/songusage/forms/songusagedetailform.py @@ -22,6 +22,7 @@ import logging import os +from pathlib import Path from PyQt5 import QtCore, QtWidgets from sqlalchemy.sql import and_ @@ -78,7 +79,7 @@ class SongUsageDetailForm(QtWidgets.QDialog, Ui_SongUsageDetailDialog, RegistryP ' song usage report. \nPlease select an existing path on your computer.') ) return - check_directory_exists(path) + check_directory_exists(Path(path)) file_name = translate('SongUsagePlugin.SongUsageDetailForm', 'usage_detail_{old}_{new}.txt' ).format(old=self.from_date_calendar.selectedDate().toString('ddMMyyyy'), diff --git a/scripts/appveyor.yml b/scripts/appveyor.yml index 3d2ceda21..0405d0e2c 100644 --- a/scripts/appveyor.yml +++ b/scripts/appveyor.yml @@ -12,7 +12,7 @@ environment: install: # Install dependencies from pypi - - "%PYTHON%\\python.exe -m pip install sqlalchemy alembic chardet beautifulsoup4 Mako nose mock pyodbc==4.0.8 psycopg2 pypiwin32 pyenchant" + - "%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" # Install mysql dependency - "%PYTHON%\\python.exe -m pip install http://cdn.mysql.com/Downloads/Connector-Python/mysql-connector-python-2.0.4.zip#md5=3df394d89300db95163f17c843ef49df" # Download and install lxml and pyicu (originally from http://www.lfd.uci.edu/~gohlke/pythonlibs/) diff --git a/tests/functional/openlp_core_common/test_applocation.py b/tests/functional/openlp_core_common/test_applocation.py index 34ff861df..e6c3b5047 100644 --- a/tests/functional/openlp_core_common/test_applocation.py +++ b/tests/functional/openlp_core_common/test_applocation.py @@ -43,14 +43,12 @@ class TestAppLocation(TestCase): """ with patch('openlp.core.common.applocation.Settings') as mocked_class, \ patch('openlp.core.common.AppLocation.get_directory') as mocked_get_directory, \ - patch('openlp.core.common.applocation.check_directory_exists') as mocked_check_directory_exists, \ - patch('openlp.core.common.applocation.os') as mocked_os: + patch('openlp.core.common.applocation.check_directory_exists') as mocked_check_directory_exists: # GIVEN: A mocked out Settings class and a mocked out AppLocation.get_directory() mocked_settings = mocked_class.return_value mocked_settings.contains.return_value = False - mocked_get_directory.return_value = os.path.join('test', 'dir') + mocked_get_directory.return_value = Path('test', 'dir') mocked_check_directory_exists.return_value = True - mocked_os.path.normpath.return_value = os.path.join('test', 'dir') # WHEN: we call AppLocation.get_data_path() data_path = AppLocation.get_data_path() @@ -58,8 +56,8 @@ class TestAppLocation(TestCase): # THEN: check that all the correct methods were called, and the result is correct mocked_settings.contains.assert_called_with('advanced/data path') mocked_get_directory.assert_called_with(AppLocation.DataDir) - mocked_check_directory_exists.assert_called_with(os.path.join('test', 'dir')) - self.assertEqual(os.path.join('test', 'dir'), data_path, 'Result should be "test/dir"') + mocked_check_directory_exists.assert_called_with(Path('test', 'dir')) + self.assertEqual(Path('test', 'dir'), data_path, 'Result should be "test/dir"') def test_get_data_path_with_custom_location(self): """ @@ -125,7 +123,7 @@ class TestAppLocation(TestCase): data_path = AppLocation.get_section_data_path('section') # THEN: check that all the correct methods were called, and the result is correct - mocked_check_directory_exists.assert_called_with(os.path.join('test', 'dir', 'section')) + mocked_check_directory_exists.assert_called_with(Path('test', 'dir', 'section')) self.assertEqual(Path('test', 'dir', 'section'), data_path, 'Result should be "test/dir/section"') def test_get_directory_for_app_dir(self): diff --git a/tests/functional/openlp_core_common/test_common.py b/tests/functional/openlp_core_common/test_common.py index 78072ddd0..a09c8388d 100644 --- a/tests/functional/openlp_core_common/test_common.py +++ b/tests/functional/openlp_core_common/test_common.py @@ -35,44 +35,70 @@ class TestCommonFunctions(TestCase): """ A test suite to test out various functions in the openlp.core.common module. """ - def test_check_directory_exists(self): + def test_check_directory_exists_dir_exists(self): """ - Test the check_directory_exists() function + Test the check_directory_exists() function when the path already exists """ - with patch('openlp.core.lib.os.path.exists') as mocked_exists, \ - patch('openlp.core.lib.os.makedirs') as mocked_makedirs: - # GIVEN: A directory to check and a mocked out os.makedirs and os.path.exists - directory_to_check = 'existing/directory' + # GIVEN: A `Path` to check with patched out mkdir and exists methods + with patch.object(Path, 'exists') as mocked_exists, \ + patch.object(Path, 'mkdir') as mocked_mkdir, \ + patch('openlp.core.common.log'): - # WHEN: os.path.exists returns True and we check to see if the directory exists + # WHEN: `check_directory_exists` is called and the path exists mocked_exists.return_value = True - check_directory_exists(directory_to_check) + check_directory_exists(Path('existing', 'directory')) - # THEN: Only os.path.exists should have been called - mocked_exists.assert_called_with(directory_to_check) - self.assertIsNot(mocked_makedirs.called, 'os.makedirs should not have been called') + # THEN: The function should not attempt to create the directory + mocked_exists.assert_called_with() + self.assertFalse(mocked_mkdir.called) - # WHEN: os.path.exists returns False and we check the directory exists + def test_check_directory_exists_dir_doesnt_exists(self): + """ + Test the check_directory_exists() function when the path does not already exist + """ + # GIVEN: A `Path` to check with patched out mkdir and exists methods + with patch.object(Path, 'exists') as mocked_exists, \ + patch.object(Path, 'mkdir') as mocked_mkdir, \ + patch('openlp.core.common.log'): + + # WHEN: `check_directory_exists` is called and the path does not exist mocked_exists.return_value = False - check_directory_exists(directory_to_check) + check_directory_exists(Path('existing', 'directory')) - # THEN: Both the mocked functions should have been called - mocked_exists.assert_called_with(directory_to_check) - mocked_makedirs.assert_called_with(directory_to_check) + # THEN: The directory should have been created + mocked_exists.assert_called_with() + mocked_mkdir.assert_called_with(parents=True) - # WHEN: os.path.exists raises an IOError + def test_check_directory_exists_dir_io_error(self): + """ + Test the check_directory_exists() when an IOError is raised + """ + # GIVEN: A `Path` to check with patched out mkdir and exists methods + with patch.object(Path, 'exists') as mocked_exists, \ + patch.object(Path, 'mkdir'), \ + patch('openlp.core.common.log') as mocked_logger: + + # WHEN: An IOError is raised when checking the if the path exists. mocked_exists.side_effect = IOError() - check_directory_exists(directory_to_check) + check_directory_exists(Path('existing', 'directory')) - # THEN: We shouldn't get an exception though the mocked exists has been called - mocked_exists.assert_called_with(directory_to_check) + # THEN: The Error should have been logged + mocked_logger.exception.assert_called_once_with('failed to check if directory exists or create directory') + + def test_check_directory_exists_dir_value_error(self): + """ + Test the check_directory_exists() when an error other than IOError is raised + """ + # GIVEN: A `Path` to check with patched out mkdir and exists methods + with patch.object(Path, 'exists') as mocked_exists, \ + patch.object(Path, 'mkdir'), \ + patch('openlp.core.common.log'): # WHEN: Some other exception is raised mocked_exists.side_effect = ValueError() - # THEN: check_directory_exists raises an exception - mocked_exists.assert_called_with(directory_to_check) - self.assertRaises(ValueError, check_directory_exists, directory_to_check) + # THEN: `check_directory_exists` raises an exception + self.assertRaises(ValueError, check_directory_exists, Path('existing', 'directory')) def test_extension_loader_no_files_found(self): """ @@ -80,7 +106,7 @@ class TestCommonFunctions(TestCase): """ # GIVEN: A mocked `Path.glob` method which does not match any files with patch('openlp.core.common.AppLocation.get_directory', return_value=Path('/', 'app', 'dir', 'openlp')), \ - patch.object(common.Path, 'glob', return_value=[]), \ + patch.object(Path, 'glob', return_value=[]), \ patch('openlp.core.common.importlib.import_module') as mocked_import_module: # WHEN: Calling `extension_loader` @@ -95,7 +121,7 @@ class TestCommonFunctions(TestCase): """ # GIVEN: A mocked `Path.glob` method which returns a list of files with patch('openlp.core.common.AppLocation.get_directory', return_value=Path('/', 'app', 'dir', 'openlp')), \ - patch.object(common.Path, 'glob', return_value=[ + patch.object(Path, 'glob', return_value=[ Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file1.py'), Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file2.py'), Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file3.py'), @@ -115,7 +141,7 @@ class TestCommonFunctions(TestCase): """ # GIVEN: A mocked `import_module` which raises an `ImportError` with patch('openlp.core.common.AppLocation.get_directory', return_value=Path('/', 'app', 'dir', 'openlp')), \ - patch.object(common.Path, 'glob', return_value=[ + patch.object(Path, 'glob', return_value=[ Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file1.py')]), \ patch('openlp.core.common.importlib.import_module', side_effect=ImportError()), \ patch('openlp.core.common.log') as mocked_logger: @@ -132,7 +158,7 @@ class TestCommonFunctions(TestCase): """ # GIVEN: A mocked `SourceFileLoader` which raises an `OSError` with patch('openlp.core.common.AppLocation.get_directory', return_value=Path('/', 'app', 'dir', 'openlp')), \ - patch.object(common.Path, 'glob', return_value=[ + patch.object(Path, 'glob', return_value=[ Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file1.py')]), \ patch('openlp.core.common.importlib.import_module', side_effect=OSError()), \ patch('openlp.core.common.log') as mocked_logger: @@ -174,7 +200,7 @@ class TestCommonFunctions(TestCase): Test `path_to_module` when supplied with a `Path` object """ # GIVEN: A `Path` object - path = Path('openlp/core/ui/media/webkitplayer.py') + path = Path('core', 'ui', 'media', 'webkitplayer.py') # WHEN: Calling path_to_module with the `Path` object result = path_to_module(path) diff --git a/tests/functional/openlp_core_common/test_init.py b/tests/functional/openlp_core_common/test_init.py index b3e49eacb..141ebdf94 100644 --- a/tests/functional/openlp_core_common/test_init.py +++ b/tests/functional/openlp_core_common/test_init.py @@ -24,6 +24,7 @@ Functional tests to test the AppLocation class and related methods. """ import os from io import BytesIO +from pathlib import Path from unittest import TestCase from unittest.mock import MagicMock, PropertyMock, call, patch @@ -296,10 +297,10 @@ class TestInit(TestCase, TestMixin): """ # GIVEN: A blank path # WEHN: Calling delete_file - result = delete_file('') + result = delete_file(None) # THEN: delete_file should return False - self.assertFalse(result, "delete_file should return False when called with ''") + self.assertFalse(result, "delete_file should return False when called with None") def test_delete_file_path_success(self): """ @@ -309,84 +310,87 @@ class TestInit(TestCase, TestMixin): with patch('openlp.core.common.os', **{'path.exists.return_value': False}): # WHEN: Calling delete_file with a file path - result = delete_file('path/file.ext') + result = delete_file(Path('path', 'file.ext')) # THEN: delete_file should return True self.assertTrue(result, 'delete_file should return True when it successfully deletes a file') def test_delete_file_path_no_file_exists(self): """ - Test the delete_file function when the file to remove does not exist + Test the `delete_file` function when the file to remove does not exist """ - # GIVEN: A mocked os which returns False when os.path.exists is called - with patch('openlp.core.common.os', **{'path.exists.return_value': False}): + # GIVEN: A patched `exists` methods on the Path object, which returns False + with patch.object(Path, 'exists', return_value=False), \ + patch.object(Path, 'unlink') as mocked_unlink: - # WHEN: Calling delete_file with a file path - result = delete_file('path/file.ext') + # WHEN: Calling `delete_file with` a file path + result = delete_file(Path('path', 'file.ext')) - # THEN: delete_file should return True + # THEN: The function should not attempt to delete the file and it should return True + self.assertFalse(mocked_unlink.called) self.assertTrue(result, 'delete_file should return True when the file doesnt exist') def test_delete_file_path_exception(self): """ - Test the delete_file function when os.remove raises an exception + Test the delete_file function when an exception is raised """ - # GIVEN: A mocked os which returns True when os.path.exists is called and raises an OSError when os.remove is + # GIVEN: A test `Path` object with a patched exists method which raises an OSError # called. - with patch('openlp.core.common.os', **{'path.exists.return_value': True, 'path.exists.side_effect': OSError}), \ + with patch.object(Path, 'exists') as mocked_exists, \ patch('openlp.core.common.log') as mocked_log: + mocked_exists.side_effect = OSError - # WHEN: Calling delete_file with a file path - result = delete_file('path/file.ext') + # WHEN: Calling delete_file with a the test Path object + result = delete_file(Path('path', 'file.ext')) - # THEN: delete_file should log and exception and return False - self.assertEqual(mocked_log.exception.call_count, 1) - self.assertFalse(result, 'delete_file should return False when os.remove raises an OSError') + # THEN: The exception should be logged and `delete_file` should return False + self.assertTrue(mocked_log.exception.called) + self.assertFalse(result, 'delete_file should return False when an OSError is raised') - def test_get_file_name_encoding_done_test(self): + def test_get_file_encoding_done_test(self): """ Test get_file_encoding when the detector sets done to True """ # GIVEN: A mocked UniversalDetector instance with done attribute set to True after first iteration with patch('openlp.core.common.UniversalDetector') as mocked_universal_detector, \ - patch('builtins.open', return_value=BytesIO(b"data" * 260)) as mocked_open: + patch.object(Path, 'open', return_value=BytesIO(b"data" * 260)) as mocked_open: encoding_result = {'encoding': 'UTF-8', 'confidence': 0.99} mocked_universal_detector_inst = MagicMock(result=encoding_result) type(mocked_universal_detector_inst).done = PropertyMock(side_effect=[False, True]) mocked_universal_detector.return_value = mocked_universal_detector_inst # WHEN: Calling get_file_encoding - result = get_file_encoding('file name') + result = get_file_encoding(Path('file name')) # THEN: The feed method of UniversalDetector should only br called once before returning a result - mocked_open.assert_called_once_with('file name', 'rb') + mocked_open.assert_called_once_with('rb') self.assertEqual(mocked_universal_detector_inst.feed.mock_calls, [call(b"data" * 256)]) mocked_universal_detector_inst.close.assert_called_once_with() self.assertEqual(result, encoding_result) - def test_get_file_name_encoding_eof_test(self): + def test_get_file_encoding_eof_test(self): """ Test get_file_encoding when the end of the file is reached """ # GIVEN: A mocked UniversalDetector instance which isn't set to done and a mocked open, with 1040 bytes of test # data (enough to run the iterator twice) with patch('openlp.core.common.UniversalDetector') as mocked_universal_detector, \ - patch('builtins.open', return_value=BytesIO(b"data" * 260)) as mocked_open: + patch.object(Path, 'open', return_value=BytesIO(b"data" * 260)) as mocked_open: encoding_result = {'encoding': 'UTF-8', 'confidence': 0.99} mocked_universal_detector_inst = MagicMock(mock=mocked_universal_detector, **{'done': False, 'result': encoding_result}) mocked_universal_detector.return_value = mocked_universal_detector_inst # WHEN: Calling get_file_encoding - result = get_file_encoding('file name') + result = get_file_encoding(Path('file name')) # THEN: The feed method of UniversalDetector should have been called twice before returning a result - mocked_open.assert_called_once_with('file name', 'rb') + mocked_open.assert_called_once_with('rb') self.assertEqual(mocked_universal_detector_inst.feed.mock_calls, [call(b"data" * 256), call(b"data" * 4)]) mocked_universal_detector_inst.close.assert_called_once_with() self.assertEqual(result, encoding_result) - def test_get_file_name_encoding_oserror_test(self): + def test_get_file_encoding_oserror_test(self): """ Test get_file_encoding when the end of the file is reached """ @@ -397,7 +401,7 @@ class TestInit(TestCase, TestMixin): patch('openlp.core.common.log') as mocked_log: # WHEN: Calling get_file_encoding - result = get_file_encoding('file name') + result = get_file_encoding(Path('file name')) # THEN: log.exception should be called and get_file_encoding should return None mocked_log.exception.assert_called_once_with('Error detecting file encoding') diff --git a/tests/functional/openlp_core_lib/test_db.py b/tests/functional/openlp_core_lib/test_db.py index 1db1d5188..c36ade6a7 100644 --- a/tests/functional/openlp_core_lib/test_db.py +++ b/tests/functional/openlp_core_lib/test_db.py @@ -24,6 +24,7 @@ Package to test the openlp.core.lib package. """ import os import shutil +from pathlib import Path from tempfile import mkdtemp from unittest import TestCase @@ -129,10 +130,10 @@ class TestDB(TestCase): # GIVEN: Mocked out AppLocation class and delete_file method, a test plugin name and a db location with patch('openlp.core.lib.db.AppLocation') as MockedAppLocation, \ patch('openlp.core.lib.db.delete_file') as mocked_delete_file: - MockedAppLocation.get_section_data_path.return_value = 'test-dir' + MockedAppLocation.get_section_data_path.return_value = Path('test-dir') mocked_delete_file.return_value = True test_plugin = 'test' - test_location = os.path.join('test-dir', test_plugin) + test_location = Path('test-dir', test_plugin) # WHEN: delete_database is run without a database file result = delete_database(test_plugin) @@ -149,11 +150,11 @@ class TestDB(TestCase): # GIVEN: Mocked out AppLocation class and delete_file method, a test plugin name and a db location with patch('openlp.core.lib.db.AppLocation') as MockedAppLocation, \ patch('openlp.core.lib.db.delete_file') as mocked_delete_file: - MockedAppLocation.get_section_data_path.return_value = 'test-dir' + MockedAppLocation.get_section_data_path.return_value = Path('test-dir') mocked_delete_file.return_value = False test_plugin = 'test' test_db_file = 'mydb.sqlite' - test_location = os.path.join('test-dir', test_db_file) + test_location = Path('test-dir', test_db_file) # WHEN: delete_database is run without a database file result = delete_database(test_plugin, test_db_file) diff --git a/tests/functional/openlp_core_lib/test_file_dialog.py b/tests/functional/openlp_core_lib/test_file_dialog.py deleted file mode 100644 index 6336ce0a0..000000000 --- a/tests/functional/openlp_core_lib/test_file_dialog.py +++ /dev/null @@ -1,45 +0,0 @@ -# -*- coding: utf-8 -*- -# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 - -############################################################################### -# OpenLP - Open Source Lyrics Projection # -# --------------------------------------------------------------------------- # -# Copyright (c) 2008-2017 OpenLP Developers # -# --------------------------------------------------------------------------- # -# This program is free software; you can redistribute it and/or modify it # -# under the terms of the GNU General Public License as published by the Free # -# Software Foundation; version 2 of the License. # -# # -# This program is distributed in the hope that it will be useful, but WITHOUT # -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # -# more details. # -# # -# You should have received a copy of the GNU General Public License along # -# with this program; if not, write to the Free Software Foundation, Inc., 59 # -# Temple Place, Suite 330, Boston, MA 02111-1307 USA # -############################################################################### -""" -Package to test the openlp.core.ui.lib.filedialog package. -""" -from unittest import TestCase -from unittest.mock import MagicMock, patch - - -class TestFileDialog(TestCase): - """ - Test the functions in the :mod:`filedialog` module. - """ - def setUp(self): - self.os_patcher = patch('openlp.core.ui.lib.filedialog.os') - self.qt_gui_patcher = patch('openlp.core.ui.lib.filedialog.QtWidgets') - self.ui_strings_patcher = patch('openlp.core.ui.lib.filedialog.UiStrings') - self.mocked_os = self.os_patcher.start() - self.mocked_qt_gui = self.qt_gui_patcher.start() - self.mocked_ui_strings = self.ui_strings_patcher.start() - self.mocked_parent = MagicMock() - - def tearDown(self): - self.os_patcher.stop() - self.qt_gui_patcher.stop() - self.ui_strings_patcher.stop() diff --git a/tests/functional/openlp_core_lib/test_lib.py b/tests/functional/openlp_core_lib/test_lib.py index a897f8754..eefc4ccd8 100644 --- a/tests/functional/openlp_core_lib/test_lib.py +++ b/tests/functional/openlp_core_lib/test_lib.py @@ -24,6 +24,7 @@ Package to test the openlp.core.lib package. """ import os from datetime import datetime, timedelta +from pathlib import Path from unittest import TestCase from unittest.mock import MagicMock, patch @@ -148,35 +149,34 @@ class TestLib(TestCase): """ Test the get_text_file_string() function when a file does not exist """ - with patch('openlp.core.lib.os.path.isfile') as mocked_isfile: - # GIVEN: A mocked out isfile which returns true, and a text file name - filename = 'testfile.txt' - mocked_isfile.return_value = False + # GIVEN: A patched is_file which returns False, and a file path + with patch.object(Path, 'is_file', return_value=False): + file_path = Path('testfile.txt') # WHEN: get_text_file_string is called - result = get_text_file_string(filename) + result = get_text_file_string(file_path) # THEN: The result should be False - mocked_isfile.assert_called_with(filename) + file_path.is_file.assert_called_with() self.assertFalse(result, 'False should be returned if no file exists') def test_get_text_file_string_read_error(self): """ Test the get_text_file_string() method when a read error happens """ - with patch('openlp.core.lib.os.path.isfile') as mocked_isfile, \ - patch('openlp.core.lib.open', create=True) as mocked_open: - # GIVEN: A mocked-out open() which raises an exception and isfile returns True - filename = 'testfile.txt' - mocked_isfile.return_value = True - mocked_open.side_effect = IOError() + # GIVEN: A patched open which raises an exception and is_file which returns True + with patch.object(Path, 'is_file'), \ + patch.object(Path, 'open'): + file_path = Path('testfile.txt') + file_path.is_file.return_value = True + file_path.open.side_effect = IOError() # WHEN: get_text_file_string is called - result = get_text_file_string(filename) + result = get_text_file_string(file_path) # THEN: None should be returned - mocked_isfile.assert_called_with(filename) - mocked_open.assert_called_with(filename, 'r', encoding='utf-8') + file_path.is_file.assert_called_once_with() + file_path.open.assert_called_once_with('r', encoding='utf-8') self.assertIsNone(result, 'None should be returned if the file cannot be opened') def test_get_text_file_string_decode_error(self): diff --git a/tests/functional/openlp_core_ui/test_firsttimeform.py b/tests/functional/openlp_core_ui/test_firsttimeform.py index 2203ea63c..f86ac9edf 100644 --- a/tests/functional/openlp_core_ui/test_firsttimeform.py +++ b/tests/functional/openlp_core_ui/test_firsttimeform.py @@ -25,6 +25,7 @@ Package to test the openlp.core.ui.firsttimeform package. import os import tempfile import urllib +from pathlib import Path from unittest import TestCase from unittest.mock import MagicMock, patch @@ -116,7 +117,7 @@ class TestFirstTimeForm(TestCase, TestMixin): mocked_settings.value.return_value = True MockedSettings.return_value = mocked_settings mocked_gettempdir.return_value = 'temp' - expected_temp_path = os.path.join('temp', 'openlp') + expected_temp_path = Path('temp', 'openlp') # WHEN: The set_defaults() method is run frw.set_defaults() diff --git a/tests/functional/openlp_core_ui/test_thememanager.py b/tests/functional/openlp_core_ui/test_thememanager.py index 45209ebeb..d778fb8ef 100644 --- a/tests/functional/openlp_core_ui/test_thememanager.py +++ b/tests/functional/openlp_core_ui/test_thememanager.py @@ -90,7 +90,7 @@ class TestThemeManager(TestCase): # theme, check_directory_exists and thememanager-attributes. with patch('builtins.open') as mocked_open, \ patch('openlp.core.ui.thememanager.shutil.copyfile') as mocked_copyfile, \ - patch('openlp.core.ui.thememanager.check_directory_exists') as mocked_check_directory_exists: + patch('openlp.core.ui.thememanager.check_directory_exists'): mocked_open.return_value = MagicMock() theme_manager = ThemeManager(None) theme_manager.old_background_image = None @@ -118,7 +118,7 @@ class TestThemeManager(TestCase): # theme, check_directory_exists and thememanager-attributes. with patch('builtins.open') as mocked_open, \ patch('openlp.core.ui.thememanager.shutil.copyfile') as mocked_copyfile, \ - patch('openlp.core.ui.thememanager.check_directory_exists') as mocked_check_directory_exists: + patch('openlp.core.ui.thememanager.check_directory_exists'): mocked_open.return_value = MagicMock() theme_manager = ThemeManager(None) theme_manager.old_background_image = None diff --git a/tests/functional/openlp_plugins/bibles/test_manager.py b/tests/functional/openlp_plugins/bibles/test_manager.py index 03ae6185a..de924a476 100644 --- a/tests/functional/openlp_plugins/bibles/test_manager.py +++ b/tests/functional/openlp_plugins/bibles/test_manager.py @@ -22,6 +22,7 @@ """ This module contains tests for the manager submodule of the Bibles plugin. """ +from pathlib import Path from unittest import TestCase from unittest.mock import MagicMock, patch @@ -50,7 +51,6 @@ class TestManager(TestCase): """ # GIVEN: An instance of BibleManager and a mocked bible with patch.object(BibleManager, 'reload_bibles'), \ - patch('openlp.plugins.bibles.lib.manager.os.path.join', side_effect=lambda x, y: '{}/{}'.format(x, y)),\ patch('openlp.plugins.bibles.lib.manager.delete_file', return_value=True) as mocked_delete_file: instance = BibleManager(MagicMock()) # We need to keep a reference to the mock for close_all as it gets set to None later on! @@ -66,4 +66,4 @@ class TestManager(TestCase): self.assertTrue(result) mocked_close_all.assert_called_once_with() self.assertIsNone(mocked_bible.session) - mocked_delete_file.assert_called_once_with('bibles/KJV.sqlite') + mocked_delete_file.assert_called_once_with(Path('bibles', 'KJV.sqlite')) diff --git a/tests/functional/openlp_plugins/media/test_mediaplugin.py b/tests/functional/openlp_plugins/media/test_mediaplugin.py index 11ec7ba9e..b7cda1fd6 100644 --- a/tests/functional/openlp_plugins/media/test_mediaplugin.py +++ b/tests/functional/openlp_plugins/media/test_mediaplugin.py @@ -38,20 +38,18 @@ class MediaPluginTest(TestCase, TestMixin): def setUp(self): Registry.create() - @patch(u'openlp.plugins.media.mediaplugin.Plugin.initialise') + @patch('openlp.plugins.media.mediaplugin.Plugin.initialise') def test_initialise(self, mocked_initialise): """ Test that the initialise() method overwrites the built-in one, but still calls it """ - # GIVEN: A media plugin instance and a mocked settings object + # GIVEN: A media plugin instance media_plugin = MediaPlugin() - mocked_settings = MagicMock() - mocked_settings.get_files_from_config.return_value = True # Not the real value, just need something "true-ish" # WHEN: initialise() is called media_plugin.initialise() - # THEN: The settings should be upgraded and the base initialise() method should be called + # THEN: The the base initialise() method should be called mocked_initialise.assert_called_with() def test_about_text(self): diff --git a/tests/functional/openlp_plugins/presentations/test_presentationcontroller.py b/tests/functional/openlp_plugins/presentations/test_presentationcontroller.py index 9f02fb9c8..fcd7b4f36 100644 --- a/tests/functional/openlp_plugins/presentations/test_presentationcontroller.py +++ b/tests/functional/openlp_plugins/presentations/test_presentationcontroller.py @@ -24,6 +24,7 @@ Functional tests to test the PresentationController and PresentationDocument classes and related methods. """ import os +from pathlib import Path from unittest import TestCase from unittest.mock import MagicMock, mock_open, patch @@ -38,7 +39,8 @@ class TestPresentationController(TestCase): """ def setUp(self): self.get_thumbnail_folder_patcher = \ - patch('openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument.get_thumbnail_folder') + patch('openlp.plugins.presentations.lib.presentationcontroller.PresentationDocument.get_thumbnail_folder', + return_value=Path()) self.get_thumbnail_folder_patcher.start() mocked_plugin = MagicMock() mocked_plugin.settings_section = 'presentations' @@ -225,7 +227,7 @@ class TestPresentationDocument(TestCase): PresentationDocument(self.mock_controller, 'Name') # THEN: check_directory_exists should have been called with 'returned/path/' - self.mock_check_directory_exists.assert_called_once_with('returned/path/') + self.mock_check_directory_exists.assert_called_once_with(Path('returned', 'path')) self._setup_patcher.start() diff --git a/tests/interfaces/openlp_core_common/test_utils.py b/tests/interfaces/openlp_core_common/test_utils.py index c49304bc5..c7f74ddb5 100644 --- a/tests/interfaces/openlp_core_common/test_utils.py +++ b/tests/interfaces/openlp_core_common/test_utils.py @@ -22,7 +22,7 @@ """ Functional tests to test the AppLocation class and related methods. """ -import os +from pathlib import Path from unittest import TestCase from openlp.core.common import is_not_image_file @@ -59,7 +59,7 @@ class TestUtils(TestCase, TestMixin): Test the method handles an image file """ # Given and empty string - file_name = os.path.join(TEST_RESOURCES_PATH, 'church.jpg') + file_name = Path(TEST_RESOURCES_PATH, 'church.jpg') # WHEN testing for it result = is_not_image_file(file_name) @@ -72,7 +72,7 @@ class TestUtils(TestCase, TestMixin): Test the method handles a non image file """ # Given and empty string - file_name = os.path.join(TEST_RESOURCES_PATH, 'serviceitem_custom_1.osj') + file_name = Path(TEST_RESOURCES_PATH, 'serviceitem_custom_1.osj') # WHEN testing for it result = is_not_image_file(file_name)