Convert some more utility fuctions over to using the pathlib

This commit is contained in:
Philip Ridout 2017-08-12 18:45:56 +01:00
parent 081c5fe7a0
commit b384e6f2fa
42 changed files with 268 additions and 295 deletions

View File

@ -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):
@ -391,7 +395,7 @@ def main(args=None):
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')))
set_up_logging(Path(os.path.abspath(os.path.join(application_path, '..', '..', 'Other'))))
log.info('Running portable')
portable_settings_file = os.path.abspath(os.path.join(application_path, '..', '..', 'Data', 'OpenLP.ini'))
# Make this our settings file
@ -407,7 +411,7 @@ def main(args=None):
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)
application.setApplicationVersion(get_application_version()['version'])

View File

@ -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:

View File

@ -96,7 +96,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
@ -134,7 +134,7 @@ class AppLocation(object):
:rtype: pathlib.Path
"""
path = AppLocation.get_data_path() / section
check_directory_exists(str(path))
check_directory_exists(path)
return path

View File

@ -482,31 +482,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

View File

@ -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

View File

@ -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)

View File

@ -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 = []

View File

@ -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 = ''

View File

@ -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
@ -283,7 +284,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):
"""

View File

@ -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
@ -864,7 +865,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()

View File

@ -174,7 +174,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__()

View File

@ -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

View File

@ -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)

View File

@ -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.'))

View File

@ -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')

View File

@ -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]

View File

@ -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):
"""

View File

@ -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:

View File

@ -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()

View File

@ -26,11 +26,11 @@ The Media plugin
import logging
import os
import re
from shutil import which
from pathlib import Path
from PyQt5 import QtCore
from openlp.core.common import AppLocation, Settings, translate, check_binary_exists, is_win
from openlp.core.common import AppLocation, translate, check_binary_exists
from openlp.core.lib import Plugin, StringContent, build_icon
from openlp.plugins.media.lib import MediaMediaItem, MediaTab
@ -162,8 +162,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()

View File

@ -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:

View File

@ -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()

View File

@ -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):
"""

View File

@ -121,7 +121,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__()

View File

@ -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()):

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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):
"""

View File

@ -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'),

View File

@ -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):

View File

@ -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)

View File

@ -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')

View File

@ -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)

View File

@ -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()

View File

@ -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):

View File

@ -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()

View File

@ -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

View File

@ -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'))

View File

@ -38,22 +38,18 @@ class MediaPluginTest(TestCase, TestMixin):
def setUp(self):
Registry.create()
@patch(u'openlp.plugins.media.mediaplugin.Plugin.initialise')
@patch(u'openlp.plugins.media.mediaplugin.Settings')
def test_initialise(self, _mocked_settings, mocked_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"
_mocked_settings.return_value = mocked_settings
# 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):

View File

@ -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()

View File

@ -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)