Move applocation over to using pathlib

This commit is contained in:
Philip Ridout 2017-08-01 21:59:41 +01:00
parent b60a8b5a3e
commit 63bd98372a
34 changed files with 312 additions and 146 deletions

View File

@ -181,7 +181,7 @@ class OpenLP(OpenLPMixin, QtWidgets.QApplication):
"""
Check if the data folder path exists.
"""
data_folder_path = AppLocation.get_data_path()
data_folder_path = str(AppLocation.get_data_path())
if not os.path.exists(data_folder_path):
log.critical('Database was not found in: ' + data_folder_path)
status = QtWidgets.QMessageBox.critical(None, translate('OpenLP', 'Data Directory Error'),
@ -253,7 +253,7 @@ class OpenLP(OpenLPMixin, QtWidgets.QApplication):
'a backup of the old data folder?'),
defaultButton=QtWidgets.QMessageBox.Yes) == QtWidgets.QMessageBox.Yes:
# Create copy of data folder
data_folder_path = AppLocation.get_data_path()
data_folder_path = str(AppLocation.get_data_path())
timestamp = time.strftime("%Y%m%d-%H%M%S")
data_folder_backup_path = data_folder_path + '-' + timestamp
try:
@ -390,7 +390,7 @@ def main(args=None):
application.setApplicationName('OpenLPPortable')
Settings.setDefaultFormat(Settings.IniFormat)
# Get location OpenLPPortable.ini
application_path = AppLocation.get_directory(AppLocation.AppDir)
application_path = str(AppLocation.get_directory(AppLocation.AppDir))
set_up_logging(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'))
@ -407,7 +407,7 @@ def main(args=None):
portable_settings.sync()
else:
application.setApplicationName('OpenLP')
set_up_logging(AppLocation.get_directory(AppLocation.CacheDir))
set_up_logging(str(AppLocation.get_directory(AppLocation.CacheDir)))
Registry.create()
Registry().register('application', application)
application.setApplicationVersion(get_application_version()['version'])

View File

@ -95,9 +95,9 @@ def extension_loader(glob_pattern, excluded_files=[]):
:return: None
:rtype: None
"""
app_dir = Path(AppLocation.get_directory(AppLocation.AppDir)).parent
for extension_path in app_dir.glob(glob_pattern):
extension_path = extension_path.relative_to(app_dir)
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)
if extension_path.name in excluded_files:
continue
module_name = path_to_module(extension_path)

View File

@ -25,6 +25,7 @@ The :mod:`openlp.core.common.applocation` module provides an utility for OpenLP
import logging
import os
import sys
from pathlib import Path
from openlp.core.common import Settings, is_win, is_macosx
@ -42,6 +43,9 @@ from openlp.core.common import check_directory_exists, get_frozen_path
log = logging.getLogger(__name__)
FROZEN_APP_PATH = Path(sys.argv[0]).parent
APP_PATH = Path(openlp.__file__).parent
class AppLocation(object):
"""
@ -63,20 +67,19 @@ class AppLocation(object):
Return the appropriate directory according to the directory type.
:param dir_type: The directory type you want, for instance the data directory. Default *AppLocation.AppDir*
:type dir_type: AppLocation Enum
:return: The requested path
:rtype: pathlib.Path
"""
if dir_type == AppLocation.AppDir:
return get_frozen_path(os.path.abspath(os.path.dirname(sys.argv[0])), os.path.dirname(openlp.__file__))
if dir_type == AppLocation.AppDir or dir_type == AppLocation.VersionDir:
return get_frozen_path(FROZEN_APP_PATH, APP_PATH)
elif dir_type == AppLocation.PluginsDir:
app_path = os.path.abspath(os.path.dirname(sys.argv[0]))
return get_frozen_path(os.path.join(app_path, 'plugins'),
os.path.join(os.path.dirname(openlp.__file__), 'plugins'))
elif dir_type == AppLocation.VersionDir:
return get_frozen_path(os.path.abspath(os.path.dirname(sys.argv[0])), os.path.dirname(openlp.__file__))
return get_frozen_path(FROZEN_APP_PATH, APP_PATH) / 'plugins'
elif dir_type == AppLocation.LanguageDir:
app_path = get_frozen_path(os.path.abspath(os.path.dirname(sys.argv[0])), _get_os_dir_path(dir_type))
return os.path.join(app_path, 'i18n')
return get_frozen_path(FROZEN_APP_PATH, _get_os_dir_path(dir_type)) / 'i18n'
elif dir_type == AppLocation.DataDir and AppLocation.BaseDir:
return os.path.join(AppLocation.BaseDir, 'data')
return Path(AppLocation.BaseDir, 'data')
else:
return _get_os_dir_path(dir_type)
@ -84,84 +87,97 @@ class AppLocation(object):
def get_data_path():
"""
Return the path OpenLP stores all its data under.
:return: The data path to use.
:rtype: pathlib.Path
"""
# Check if we have a different data location.
if Settings().contains('advanced/data path'):
path = Settings().value('advanced/data path')
path = Path(Settings().value('advanced/data path'))
else:
path = AppLocation.get_directory(AppLocation.DataDir)
check_directory_exists(path)
return os.path.normpath(path)
check_directory_exists(str(path))
return path
@staticmethod
def get_files(section=None, extension=None):
def get_files(section=None, extension=''):
"""
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 section: Defaults to *None*. The section of code getting the files - used to load from a section's
data subdirectory.
:param extension:
Defaults to *None*. The extension to search for. For example::
'.png'
:param extension: Defaults to ''. The extension to search for. For example::
'.png'
:type extension: str
:return: List of files found.
:rtype: list[pathlib.Path]
"""
path = AppLocation.get_data_path()
if section:
path = os.path.join(path, section)
path = path / section
try:
files = os.listdir(path)
file_paths = path.glob('*' + extension)
return [file_path.relative_to(path) for file_path in file_paths] # TODO: Could/should this be an iterator?
except OSError:
return []
if extension:
return [filename for filename in files if extension == os.path.splitext(filename)[1]]
else:
# no filtering required
return files
@staticmethod
def get_section_data_path(section):
"""
Return the path a particular module stores its data under.
:type section: str
:rtype: pathlib.Path
"""
data_path = AppLocation.get_data_path()
path = os.path.join(data_path, section)
check_directory_exists(path)
path = AppLocation.get_data_path() / section
check_directory_exists(str(path))
return path
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 = os.path.abspath(os.path.join(os.path.dirname(openlp.__file__), '..', 'resources'))
if os.path.exists(directory):
directory = Path(os.path.abspath(os.path.join(os.path.dirname(openlp.__file__), '..', 'resources')))
if directory.exists():
return directory
if is_win():
openlp_folder_path = Path(os.getenv('APPDATA'), 'openlp')
if dir_type == AppLocation.DataDir:
return os.path.join(str(os.getenv('APPDATA')), 'openlp', 'data')
return openlp_folder_path / 'data'
elif dir_type == AppLocation.LanguageDir:
return os.path.dirname(openlp.__file__)
return os.path.join(str(os.getenv('APPDATA')), 'openlp')
return openlp_folder_path
elif is_macosx():
openlp_folder_path = Path(os.getenv('HOME'), 'Library', 'Application Support', 'openlp')
if dir_type == AppLocation.DataDir:
return os.path.join(str(os.getenv('HOME')), 'Library', 'Application Support', 'openlp', 'Data')
return openlp_folder_path / 'Data'
elif dir_type == AppLocation.LanguageDir:
return os.path.dirname(openlp.__file__)
return os.path.join(str(os.getenv('HOME')), 'Library', 'Application Support', 'openlp')
return openlp_folder_path
else:
if dir_type == AppLocation.LanguageDir:
for prefix in ['/usr/local', '/usr']:
directory = os.path.join(prefix, 'share', 'openlp')
if os.path.exists(directory):
return directory
return os.path.join('/usr', 'share', 'openlp')
directory = Path('/usr', 'local', 'share', 'openlp')
if directory.exists():
return directory
return Path('/usr', 'share', 'openlp')
if XDG_BASE_AVAILABLE:
if dir_type == AppLocation.DataDir:
return os.path.join(str(BaseDirectory.xdg_data_home), 'openlp')
if dir_type == AppLocation.DataDir or dir_type == AppLocation.CacheDir:
return Path(BaseDirectory.xdg_data_home, 'openlp')
elif dir_type == AppLocation.CacheDir:
return os.path.join(str(BaseDirectory.xdg_cache_home), 'openlp')
return Path(BaseDirectory.xdg_cache_home, 'openlp')
if dir_type == AppLocation.DataDir:
return os.path.join(str(os.getenv('HOME')), '.openlp', 'data')
return os.path.join(str(os.getenv('HOME')), '.openlp')
return Path(os.getenv('HOME'), '.openlp', 'data')
return Path(os.getenv('HOME'), '.openlp')

View File

@ -53,7 +53,7 @@ class LanguageManager(object):
"""
if LanguageManager.auto_language:
language = QtCore.QLocale.system().name()
lang_path = AppLocation.get_directory(AppLocation.LanguageDir)
lang_path = str(AppLocation.get_directory(AppLocation.LanguageDir))
app_translator = QtCore.QTranslator()
app_translator.load(language, lang_path)
# A translator for buttons and other default strings provided by Qt.
@ -72,7 +72,7 @@ class LanguageManager(object):
Find all available language files in this OpenLP install
"""
log.debug('Translation files: {files}'.format(files=AppLocation.get_directory(AppLocation.LanguageDir)))
trans_dir = QtCore.QDir(AppLocation.get_directory(AppLocation.LanguageDir))
trans_dir = QtCore.QDir(str(AppLocation.get_directory(AppLocation.LanguageDir)))
file_names = trans_dir.entryList(['*.qm'], QtCore.QDir.Files, QtCore.QDir.Name)
# Remove qm files from the list which start with "qt".
file_names = [file_ for file_ in file_names if not file_.startswith('qt')]

View File

@ -95,7 +95,7 @@ def get_application_version():
full_version = '{tag}-bzr{tree}'.format(tag=tag_version.strip(), tree=tree_revision.strip())
else:
# We're not running the development version, let's use the file.
file_path = AppLocation.get_directory(AppLocation.VersionDir)
file_path = str(AppLocation.get_directory(AppLocation.VersionDir))
file_path = os.path.join(file_path, '.version')
version_file = None
try:

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(AppLocation.get_section_data_path(plugin_name), db_file_name)
db_file_path = os.path.join(str(AppLocation.get_section_data_path(plugin_name)), db_file_name)
else:
db_file_path = os.path.join(AppLocation.get_section_data_path(plugin_name), plugin_name)
db_file_path = os.path.join(str(AppLocation.get_section_data_path(plugin_name)), plugin_name)
return delete_file(db_file_path)

61
openlp/core/lib/path.py Normal file
View File

@ -0,0 +1,61 @@
# -*- 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 #
###############################################################################
from pathlib import Path
def path_to_str(path):
"""
A utility function to convert a Path object or NoneType to a string equivalent.
:param path: The value to convert to a string
:type: pathlib.Path or None
:return: An empty string if :param:`path` is None, else a string representation of the :param:`path`
:rtype: str
"""
if not isinstance(path, Path) and path is not None:
raise TypeError('parameter \'path\' must be of type Path or NoneType')
if path is None:
return ''
else:
return str(path)
def str_to_path(string):
"""
A utility function to convert a str object to a Path or NoneType.
This function is of particular use because initating a Path object with an empty string causes the Path object to
point to the current working directory.
:param string: The string to convert
:type string: str
:return: None if :param:`string` is empty, or a Path object representation of :param:`string`
:rtype: pathlib.Path or None
"""
if not isinstance(string, str):
raise TypeError('parameter \'string\' must be of type str')
if string == '':
return None
return Path(string)

View File

@ -40,7 +40,7 @@ class PluginManager(RegistryMixin, OpenLPMixin, RegistryProperties):
"""
super(PluginManager, self).__init__(parent)
self.log_info('Plugin manager Initialising')
self.base_path = os.path.abspath(AppLocation.get_directory(AppLocation.PluginsDir))
self.base_path = os.path.abspath(str(AppLocation.get_directory(AppLocation.PluginsDir)))
self.log_debug('Base path {path}'.format(path=self.base_path))
self.plugins = []
self.log_info('Plugin manager Initialised')

View File

@ -335,7 +335,7 @@ class ServiceItem(RegistryProperties):
if image and not self.has_original_files and self.name == 'presentations':
file_location = os.path.join(path, file_name)
file_location_hash = md5_hash(file_location.encode('utf-8'))
image = os.path.join(AppLocation.get_section_data_path(self.name), 'thumbnails',
image = os.path.join(str(AppLocation.get_section_data_path(self.name)), 'thumbnails',
file_location_hash, ntpath.basename(image))
self._raw_frames.append({'title': file_name, 'image': image, 'path': path,
'display_title': display_title, 'notes': notes})

View File

@ -158,7 +158,7 @@ class Theme(object):
Initialise the theme object.
"""
# basic theme object with defaults
json_dir = os.path.join(AppLocation.get_directory(AppLocation.AppDir), 'core', 'lib', 'json')
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)
jsn = json.loads(jsn)

View File

@ -156,7 +156,7 @@ class AdvancedTab(SettingsTab):
self.data_directory_new_label = QtWidgets.QLabel(self.data_directory_group_box)
self.data_directory_new_label.setObjectName('data_directory_current_label')
self.data_directory_path_edit = PathEdit(self.data_directory_group_box, path_type=PathType.Directories,
default_path=AppLocation.get_directory(AppLocation.DataDir))
default_path=str(AppLocation.get_directory(AppLocation.DataDir)))
self.data_directory_layout.addRow(self.data_directory_new_label, self.data_directory_path_edit)
self.new_data_directory_has_files_label = QtWidgets.QLabel(self.data_directory_group_box)
self.new_data_directory_has_files_label.setObjectName('new_data_directory_has_files_label')
@ -373,7 +373,7 @@ class AdvancedTab(SettingsTab):
self.new_data_directory_has_files_label.hide()
self.data_directory_cancel_button.hide()
# Since data location can be changed, make sure the path is present.
self.data_directory_path_edit.path = AppLocation.get_data_path()
self.data_directory_path_edit.path = str(AppLocation.get_data_path())
# Don't allow data directory move if running portable.
if settings.value('advanced/is portable'):
self.data_directory_group_box.hide()
@ -497,7 +497,7 @@ class AdvancedTab(SettingsTab):
'closed.').format(path=new_data_path),
defaultButton=QtWidgets.QMessageBox.No)
if answer != QtWidgets.QMessageBox.Yes:
self.data_directory_path_edit.path = AppLocation.get_data_path()
self.data_directory_path_edit.path = str(AppLocation.get_data_path())
return
# Check if data already exists here.
self.check_data_overwrite(new_data_path)
@ -550,7 +550,7 @@ class AdvancedTab(SettingsTab):
"""
Cancel the data directory location change
"""
self.data_directory_path_edit.path = AppLocation.get_data_path()
self.data_directory_path_edit.path = str(AppLocation.get_data_path())
self.data_directory_copy_check_box.setChecked(False)
self.main_window.set_new_data_path(None)
self.main_window.set_copy_data(False)

View File

@ -554,8 +554,8 @@ class FirstTimeForm(QtWidgets.QWizard, UiFirstTimeWizard, RegistryProperties):
"""
# Build directories for downloads
songs_destination = os.path.join(gettempdir(), 'openlp')
bibles_destination = AppLocation.get_section_data_path('bibles')
themes_destination = AppLocation.get_section_data_path('themes')
bibles_destination = str(AppLocation.get_section_data_path('bibles'))
themes_destination = str(AppLocation.get_section_data_path('themes'))
missed_files = []
# Download songs
for i in range(self.songs_list_widget.count()):

View File

@ -484,7 +484,7 @@ class MainDisplay(OpenLPMixin, Display, RegistryProperties):
service_item = ServiceItem()
service_item.title = 'webkit'
service_item.processor = 'webkit'
path = os.path.join(AppLocation.get_section_data_path('themes'),
path = os.path.join(str(AppLocation.get_section_data_path('themes')),
self.service_item.theme_data.theme_name)
service_item.add_from_command(path,
self.service_item.theme_data.background_filename,

View File

@ -305,9 +305,9 @@ class Ui_MainWindow(object):
# Give QT Extra Hint that this is an About Menu Item
self.about_item.setMenuRole(QtWidgets.QAction.AboutRole)
if is_win():
self.local_help_file = os.path.join(AppLocation.get_directory(AppLocation.AppDir), 'OpenLP.chm')
self.local_help_file = os.path.join(str(AppLocation.get_directory(AppLocation.AppDir)), 'OpenLP.chm')
elif is_macosx():
self.local_help_file = os.path.join(AppLocation.get_directory(AppLocation.AppDir),
self.local_help_file = os.path.join(str(AppLocation.get_directory(AppLocation.AppDir)),
'..', 'Resources', 'OpenLP.help')
self.user_manual_item = create_action(main_window, 'userManualItem', icon=':/system/system_help_contents.png',
can_shortcuts=True, category=UiStrings().Help,
@ -788,7 +788,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, RegistryProperties):
"""
Open data folder
"""
path = AppLocation.get_data_path()
path = str(AppLocation.get_data_path())
QtGui.QDesktopServices.openUrl(QtCore.QUrl.fromLocalFile(path))
def on_update_theme_images(self):
@ -1438,7 +1438,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, RegistryProperties):
settings = QtCore.QSettings()
settings.setValue('advanced/data path', self.new_data_path)
# Check if the new data path is our default.
if self.new_data_path == AppLocation.get_directory(AppLocation.DataDir):
if self.new_data_path == str(AppLocation.get_directory(AppLocation.DataDir)):
settings.remove('advanced/data path')
self.application.set_normal_cursor()

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(AppLocation.get_data_path(), 'serviceprint', 'service_print.css')
css_path = os.path.join(str(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

@ -223,7 +223,7 @@ class Ui_ServiceManager(object):
self.service_manager_list.itemExpanded.connect(self.expanded)
# Last little bits of setting up
self.service_theme = Settings().value(self.main_window.service_manager_settings_section + '/service theme')
self.service_path = AppLocation.get_section_data_path('servicemanager')
self.service_path = str(AppLocation.get_section_data_path('servicemanager'))
# build the drag and drop context menu
self.dnd_menu = QtWidgets.QMenu()
self.new_action = self.dnd_menu.addAction(translate('OpenLP.ServiceManager', '&Add New Item'))

View File

@ -159,7 +159,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
"""
Set up the theme path variables
"""
self.path = AppLocation.get_section_data_path(self.settings_section)
self.path = str(AppLocation.get_section_data_path(self.settings_section))
check_directory_exists(self.path)
self.thumb_path = os.path.join(self.path, 'thumbnails')
check_directory_exists(self.thumb_path)
@ -445,7 +445,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
self.application.set_busy_cursor()
files = AppLocation.get_files(self.settings_section, '.otz')
for theme_file in files:
theme_file = os.path.join(self.path, theme_file)
theme_file = os.path.join(self.path, str(theme_file))
self.unzip_theme(theme_file, self.path)
delete_file(theme_file)
files = AppLocation.get_files(self.settings_section, '.png')
@ -470,6 +470,7 @@ class ThemeManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ThemeManage
files.sort(key=lambda file_name: get_locale_key(str(file_name)))
# now process the file list of png files
for name in files:
name = str(name)
# check to see file is in theme root directory
theme = os.path.join(self.path, name)
if os.path.exists(theme):

View File

@ -584,7 +584,7 @@ class BibleImportForm(OpenLPWizard):
elif self.currentPage() == self.license_details_page:
license_version = self.field('license_version')
license_copyright = self.field('license_copyright')
path = AppLocation.get_section_data_path('bibles')
path = str(AppLocation.get_section_data_path('bibles'))
if not license_version:
critical_error_message_box(
UiStrings().EmptyField,

View File

@ -470,7 +470,7 @@ class BiblesResourcesDB(QtCore.QObject, Manager):
Return the cursor object. Instantiate one if it doesn't exist yet.
"""
if BiblesResourcesDB.cursor is None:
file_path = os.path.join(AppLocation.get_directory(AppLocation.PluginsDir),
file_path = os.path.join(str(AppLocation.get_directory(AppLocation.PluginsDir)),
'bibles', 'resources', 'bibles_resources.sqlite')
conn = sqlite3.connect(file_path)
BiblesResourcesDB.cursor = conn.cursor()
@ -759,7 +759,7 @@ class AlternativeBookNamesDB(QtCore.QObject, Manager):
"""
if AlternativeBookNamesDB.cursor is None:
file_path = os.path.join(
AppLocation.get_directory(AppLocation.DataDir), 'bibles', 'alternative_book_names.sqlite')
str(AppLocation.get_directory(AppLocation.DataDir)), 'bibles', 'alternative_book_names.sqlite')
if not os.path.exists(file_path):
# create new DB, create table alternative_book_names
AlternativeBookNamesDB.conn = sqlite3.connect(file_path)

View File

@ -111,7 +111,7 @@ class BibleManager(OpenLPMixin, RegistryProperties):
self.settings_section = 'bibles'
self.web = 'Web'
self.db_cache = None
self.path = AppLocation.get_section_data_path(self.settings_section)
self.path = str(AppLocation.get_section_data_path(self.settings_section))
self.proxy_name = Settings().value(self.settings_section + '/proxy name')
self.suffix = '.sqlite'
self.import_wizard = None
@ -124,7 +124,7 @@ class BibleManager(OpenLPMixin, RegistryProperties):
of HTTPBible is loaded instead of the BibleDB class.
"""
log.debug('Reload bibles')
files = AppLocation.get_files(self.settings_section, self.suffix)
files = [str(file) for file in AppLocation.get_files(self.settings_section, self.suffix)]
if 'alternative_book_names.sqlite' in files:
files.remove('alternative_book_names.sqlite')
log.debug('Bible Files {text}'.format(text=files))

View File

@ -98,7 +98,7 @@ class ImageMediaItem(MediaManagerItem):
self.list_view.setIconSize(QtCore.QSize(88, 50))
self.list_view.setIndentation(self.list_view.default_indentation)
self.list_view.allow_internal_dnd = True
self.service_path = os.path.join(AppLocation.get_section_data_path(self.settings_section), 'thumbnails')
self.service_path = os.path.join(str(AppLocation.get_section_data_path(self.settings_section)), 'thumbnails')
check_directory_exists(self.service_path)
# Load images from the database
self.load_full_list(

View File

@ -300,7 +300,7 @@ class MediaMediaItem(MediaManagerItem, RegistryProperties):
Initialize media item.
"""
self.list_view.clear()
self.service_path = os.path.join(AppLocation.get_section_data_path(self.settings_section), 'thumbnails')
self.service_path = os.path.join(str(AppLocation.get_section_data_path(self.settings_section)), 'thumbnails')
check_directory_exists(self.service_path)
self.load_list(Settings().value(self.settings_section + '/media files'))
self.rebuild_players()

View File

@ -75,7 +75,7 @@ class MediaPlugin(Plugin):
exists = process_check_binary('mediainfo')
# If mediainfo is not in the path, try to find it in the application folder
if not exists:
exists = process_check_binary(os.path.join(AppLocation.get_directory(AppLocation.AppDir), 'mediainfo'))
exists = process_check_binary(os.path.join(str(AppLocation.get_directory(AppLocation.AppDir)), 'mediainfo'))
return exists
def app_startup(self):

View File

@ -122,10 +122,10 @@ class PdfController(PresentationController):
self.mutoolbin = pdf_program
else:
# Fallback to autodetection
application_path = AppLocation.get_directory(AppLocation.AppDir)
application_path = str(AppLocation.get_directory(AppLocation.AppDir))
if is_win():
# for windows we only accept mudraw.exe or mutool.exe in the base folder
application_path = AppLocation.get_directory(AppLocation.AppDir)
application_path = str(AppLocation.get_directory(AppLocation.AppDir))
if os.path.isfile(os.path.join(application_path, 'mudraw.exe')):
self.mudrawbin = os.path.join(application_path, 'mudraw.exe')
elif os.path.isfile(os.path.join(application_path, 'mutool.exe')):
@ -142,7 +142,7 @@ class PdfController(PresentationController):
self.gsbin = which('gs')
# Last option: check if mudraw or mutool is placed in OpenLP base folder
if not self.mudrawbin and not self.mutoolbin and not self.gsbin:
application_path = AppLocation.get_directory(AppLocation.AppDir)
application_path = str(AppLocation.get_directory(AppLocation.AppDir))
if os.path.isfile(os.path.join(application_path, 'mudraw')):
self.mudrawbin = os.path.join(application_path, 'mudraw')
elif os.path.isfile(os.path.join(application_path, 'mutool')):
@ -199,8 +199,8 @@ class PdfDocument(PresentationDocument):
:return: The resolution dpi to be used.
"""
# Use a postscript script to get size of the pdf. It is assumed that all pages have same size
gs_resolution_script = AppLocation.get_directory(
AppLocation.PluginsDir) + '/presentations/lib/ghostscript_get_resolution.ps'
gs_resolution_script = str(AppLocation.get_directory(
AppLocation.PluginsDir)) + '/presentations/lib/ghostscript_get_resolution.ps'
# Run the script on the pdf to get the size
runlog = []
try:

View File

@ -85,7 +85,7 @@ class PptviewController(PresentationController):
if self.process:
return
log.debug('start PPTView')
dll_path = os.path.join(AppLocation.get_directory(AppLocation.AppDir),
dll_path = os.path.join(str(AppLocation.get_directory(AppLocation.AppDir)),
'plugins', 'presentations', 'lib', 'pptviewlib', 'pptviewlib.dll')
self.process = cdll.LoadLibrary(dll_path)
if log.isEnabledFor(logging.DEBUG):

View File

@ -415,8 +415,9 @@ class PresentationController(object):
self.document_class = document_class
self.settings_section = self.plugin.settings_section
self.available = None
self.temp_folder = os.path.join(AppLocation.get_section_data_path(self.settings_section), name)
self.thumbnail_folder = os.path.join(AppLocation.get_section_data_path(self.settings_section), 'thumbnails')
self.temp_folder = os.path.join(str(AppLocation.get_section_data_path(self.settings_section)), name)
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)

View File

@ -171,8 +171,8 @@ class HttpRouter(RegistryProperties):
]
self.settings_section = 'remotes'
self.translate()
self.html_dir = os.path.join(AppLocation.get_directory(AppLocation.PluginsDir), 'remotes', 'html')
self.config_dir = os.path.join(AppLocation.get_data_path(), 'stages')
self.html_dir = os.path.join(str(AppLocation.get_directory(AppLocation.PluginsDir)), 'remotes', 'html')
self.config_dir = os.path.join(str(AppLocation.get_data_path()), 'stages')
def do_post_processor(self):
"""
@ -456,7 +456,7 @@ class HttpRouter(RegistryProperties):
if controller_name in supported_controllers:
full_path = urllib.parse.unquote(file_name)
if '..' not in full_path: # no hacking please
full_path = os.path.normpath(os.path.join(AppLocation.get_section_data_path(controller_name),
full_path = os.path.normpath(os.path.join(str(AppLocation.get_section_data_path(controller_name)),
'thumbnails/' + full_path))
if os.path.exists(full_path):
path, just_file_name = os.path.split(full_path)
@ -565,7 +565,7 @@ class HttpRouter(RegistryProperties):
elif current_item.is_image() and not frame.get('image', '') and Settings().value('remotes/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 = os.path.join(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)
@ -582,7 +582,7 @@ class HttpRouter(RegistryProperties):
if current_item.is_capable(ItemCapabilities.HasThumbnails) and \
Settings().value('remotes/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):])
item['text'] = str(frame['title'])

View File

@ -1065,7 +1065,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
self.manager.save_object(self.song)
audio_files = [a.file_name for a in self.song.media_files]
log.debug(audio_files)
save_path = os.path.join(AppLocation.get_section_data_path(self.media_item.plugin.name), 'audio',
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)
self.song.media_files = []

View File

@ -538,7 +538,7 @@ def delete_song(song_id, song_plugin):
except OSError:
log.exception('Could not remove file: {name}'.format(name=media_file.file_name))
try:
save_path = os.path.join(AppLocation.get_section_data_path(song_plugin.name), 'audio', str(song_id))
save_path = os.path.join(str(AppLocation.get_section_data_path(song_plugin.name)), 'audio', str(song_id))
if os.path.exists(save_path):
os.rmdir(save_path)
except OSError:

View File

@ -421,7 +421,7 @@ class SongImport(QtCore.QObject):
:param filename: The file to copy.
"""
if not hasattr(self, 'save_path'):
self.save_path = os.path.join(AppLocation.get_section_data_path(self.import_wizard.plugin.name),
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)
if not filename.startswith(self.save_path):

View File

@ -88,9 +88,9 @@ class SongMediaItem(MediaManagerItem):
song.media_files = []
for i, bga in enumerate(item.background_audio):
dest_file = os.path.join(
AppLocation.get_section_data_path(self.plugin.name), 'audio', str(song.id), os.path.split(bga)[1])
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])
shutil.copyfile(os.path.join(AppLocation.get_section_data_path('servicemanager'), bga), dest_file)
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)
@ -533,7 +533,7 @@ class SongMediaItem(MediaManagerItem):
'copy', 'For song cloning'))
# Copy audio files from the old to the new song
if len(old_song.media_files) > 0:
save_path = os.path.join(AppLocation.get_section_data_path(self.plugin.name), 'audio', str(new_song.id))
save_path = os.path.join(str(AppLocation.get_section_data_path(self.plugin.name)), 'audio', str(new_song.id))
check_directory_exists(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))

View File

@ -24,8 +24,9 @@ Functional tests to test the AppLocation class and related methods.
"""
import copy
import os
from pathlib import Path
from unittest import TestCase
from unittest.mock import patch
from unittest.mock import MagicMock, patch
from openlp.core.common import AppLocation, get_frozen_path
@ -64,56 +65,51 @@ class TestAppLocation(TestCase):
"""
Test the AppLocation.get_data_path() method when a custom location is set in the settings
"""
with patch('openlp.core.common.applocation.Settings') as mocked_class,\
patch('openlp.core.common.applocation.os') as mocked_os:
# GIVEN: A mocked out Settings class which returns a custom data location
mocked_settings = mocked_class.return_value
mocked_settings.contains.return_value = True
mocked_settings.value.return_value.toString.return_value = 'custom/dir'
mocked_os.path.normpath.return_value = 'custom/dir'
# GIVEN: A mocked out Settings class which returns a custom data location
mocked_settings_instance = MagicMock(
**{'contains.return_value': True, 'value.return_value': Path('custom', 'dir')})
with patch('openlp.core.common.applocation.Settings', return_value=mocked_settings_instance):
# WHEN: we call AppLocation.get_data_path()
data_path = AppLocation.get_data_path()
# THEN: the mocked Settings methods were called and the value returned was our set up value
mocked_settings.contains.assert_called_with('advanced/data path')
mocked_settings.value.assert_called_with('advanced/data path')
self.assertEqual('custom/dir', data_path, 'Result should be "custom/dir"')
mocked_settings_instance.contains.assert_called_with('advanced/data path')
mocked_settings_instance.value.assert_called_with('advanced/data path')
self.assertEqual(Path('custom', 'dir'), data_path, 'Result should be "custom/dir"')
def test_get_files_no_section_no_extension(self):
"""
Test the AppLocation.get_files() method with no parameters passed.
"""
with patch('openlp.core.common.AppLocation.get_data_path') as mocked_get_data_path, \
patch('openlp.core.common.applocation.os.listdir') as mocked_listdir:
# GIVEN: Our mocked modules/methods.
mocked_get_data_path.return_value = 'test/dir'
mocked_listdir.return_value = copy.deepcopy(FILE_LIST)
# GIVEN: Our mocked modules/methods.
with patch.object(Path, 'glob', return_value=[Path('/dir/file5.mp3'), Path('/dir/file6.mp3')]) as mocked_glob, \
patch('openlp.core.common.AppLocation.get_data_path', return_value=Path('/dir')):
# When: Get the list of files.
result = AppLocation.get_files()
# Then: Check if the section parameter was used correctly, and the glob argument was passed.
mocked_glob.assert_called_once_with('*')
# Then: check if the file lists are identical.
self.assertListEqual(FILE_LIST, result, 'The file lists should be identical.')
self.assertListEqual([Path('file5.mp3'), Path('file6.mp3')], result, 'The file lists should be identical.')
def test_get_files(self):
"""
Test the AppLocation.get_files() method with all parameters passed.
"""
with patch('openlp.core.common.AppLocation.get_data_path') as mocked_get_data_path, \
patch('openlp.core.common.applocation.os.listdir') as mocked_listdir:
# GIVEN: Our mocked modules/methods.
mocked_get_data_path.return_value = os.path.join('test', 'dir')
mocked_listdir.return_value = copy.deepcopy(FILE_LIST)
# GIVEN: Our mocked modules/methods.
with patch.object(Path, 'glob', return_value=[Path('/dir/section/file5.mp3'), Path('/dir/section/file6.mp3')]) \
as mocked_glob, \
patch('openlp.core.common.AppLocation.get_data_path', return_value=Path('/dir')):
# When: Get the list of files.
result = AppLocation.get_files('section', '.mp3')
# Then: Check if the section parameter was used correctly.
mocked_listdir.assert_called_with(os.path.join('test', 'dir', 'section'))
# Then: check if the file lists are identical.
self.assertListEqual(['file5.mp3', 'file6.mp3'], result, 'The file lists should be identical.')
# Then: The section parameter was used correctly, and the glob argument was passed..
mocked_glob.assert_called_once_with('*.mp3')
self.assertListEqual([Path('file5.mp3'), Path('file6.mp3')], result, 'The file lists should be identical.')
def test_get_section_data_path(self):
"""
@ -122,7 +118,7 @@ class TestAppLocation(TestCase):
with patch('openlp.core.common.AppLocation.get_data_path') as mocked_get_data_path, \
patch('openlp.core.common.applocation.check_directory_exists') as mocked_check_directory_exists:
# GIVEN: A mocked out AppLocation.get_data_path()
mocked_get_data_path.return_value = os.path.join('test', 'dir')
mocked_get_data_path.return_value = Path('test', 'dir')
mocked_check_directory_exists.return_value = True
# WHEN: we call AppLocation.get_data_path()
@ -130,7 +126,7 @@ class TestAppLocation(TestCase):
# 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'))
self.assertEqual(os.path.join('test', 'dir', 'section'), data_path, 'Result should be "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):
"""
@ -138,13 +134,13 @@ class TestAppLocation(TestCase):
"""
# GIVEN: A mocked out _get_frozen_path function
with patch('openlp.core.common.applocation.get_frozen_path') as mocked_get_frozen_path:
mocked_get_frozen_path.return_value = os.path.join('app', 'dir')
mocked_get_frozen_path.return_value = Path('app', 'dir')
# WHEN: We call AppLocation.get_directory
directory = AppLocation.get_directory(AppLocation.AppDir)
# THEN: check that the correct directory is returned
self.assertEqual(os.path.join('app', 'dir'), directory, 'Directory should be "app/dir"')
self.assertEqual(Path('app', 'dir'), directory, 'Directory should be "app/dir"')
def test_get_directory_for_plugins_dir(self):
"""
@ -157,7 +153,7 @@ class TestAppLocation(TestCase):
patch('openlp.core.common.applocation.sys') as mocked_sys:
mocked_abspath.return_value = os.path.join('plugins', 'dir')
mocked_split.return_value = ['openlp']
mocked_get_frozen_path.return_value = os.path.join('plugins', 'dir')
mocked_get_frozen_path.return_value = Path('dir')
mocked_sys.frozen = 1
mocked_sys.argv = ['openlp']
@ -165,7 +161,7 @@ class TestAppLocation(TestCase):
directory = AppLocation.get_directory(AppLocation.PluginsDir)
# THEN: The correct directory should be returned
self.assertEqual(os.path.join('plugins', 'dir'), directory, 'Directory should be "plugins/dir"')
self.assertEqual(Path('dir', 'plugins'), directory, 'Directory should be "dir/plugins"')
def test_get_frozen_path_in_unfrozen_app(self):
"""

View File

@ -79,7 +79,7 @@ class TestCommonFunctions(TestCase):
Test the `extension_loader` function when no files are found
"""
# GIVEN: A mocked `Path.glob` method which does not match any files
with patch('openlp.core.common.AppLocation.get_directory', return_value='/app/dir/openlp'), \
with patch('openlp.core.common.AppLocation.get_directory', return_value=Path('/', 'app', 'dir', 'openlp')), \
patch.object(common.Path, 'glob', return_value=[]), \
patch('openlp.core.common.importlib.import_module') as mocked_import_module:
@ -94,11 +94,12 @@ class TestCommonFunctions(TestCase):
Test the `extension_loader` function when it successfully finds and loads some files
"""
# GIVEN: A mocked `Path.glob` method which returns a list of files
with patch('openlp.core.common.AppLocation.get_directory', return_value='/app/dir/openlp'), \
patch.object(common.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'),
Path('/app/dir/openlp/import_dir/file4.py')]), \
with patch('openlp.core.common.AppLocation.get_directory', return_value=Path('/', 'app', 'dir', 'openlp')), \
patch.object(common.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'),
Path('/', 'app', 'dir', 'openlp', 'import_dir', 'file4.py')]), \
patch('openlp.core.common.importlib.import_module') as mocked_import_module:
# WHEN: Calling `extension_loader` with a list of files to exclude
@ -113,8 +114,9 @@ class TestCommonFunctions(TestCase):
Test the `extension_loader` function when `SourceFileLoader` raises a `ImportError`
"""
# GIVEN: A mocked `import_module` which raises an `ImportError`
with patch('openlp.core.common.AppLocation.get_directory', return_value='/app/dir/openlp'), \
patch.object(common.Path, 'glob', return_value=[Path('/app/dir/openlp/import_dir/file1.py')]), \
with patch('openlp.core.common.AppLocation.get_directory', return_value=Path('/', 'app', 'dir', 'openlp')), \
patch.object(common.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:
@ -129,8 +131,9 @@ class TestCommonFunctions(TestCase):
Test the `extension_loader` function when `import_module` raises a `ImportError`
"""
# GIVEN: A mocked `SourceFileLoader` which raises an `OSError`
with patch('openlp.core.common.AppLocation.get_directory', return_value='/app/dir/openlp'), \
patch.object(common.Path, 'glob', return_value=[Path('/app/dir/openlp/import_dir/file1.py')]), \
with patch('openlp.core.common.AppLocation.get_directory', return_value=Path('/', 'app', 'dir', 'openlp')), \
patch.object(common.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:

View File

@ -0,0 +1,88 @@
# -*- 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.lib.path package.
"""
import os
from pathlib import Path
from unittest import TestCase
from openlp.core.lib.path import path_to_str, str_to_path
class TestPath(TestCase):
"""
Tests for the :mod:`openlp.core.lib.path` module
"""
def test_path_to_str_type_error(self):
"""
Test that `path_to_str` raises a type error when called with an invalid type
"""
# GIVEN: The `path_to_str` function
# WHEN: Calling `path_to_str` with an invalid Type
# THEN: A TypeError should have been raised
with self.assertRaises(TypeError):
path_to_str(str())
def test_path_to_str_none(self):
"""
Test that `path_to_str` correctly converts the path parameter when passed with None
"""
# GIVEN: The `path_to_str` function
# WHEN: Calling the `path_to_str` function with None
result = path_to_str(None)
# THEN: `path_to_str` should return an empty string
self.assertEqual(result, '')
def test_path_to_str_path_object(self):
"""
Test that `path_to_str` correctly converts the path parameter when passed a Path object
"""
# GIVEN: The `path_to_str` function
# WHEN: Calling the `path_to_str` function with a Path object
result = path_to_str(Path('test/path'))
# THEN: `path_to_str` should return a string representation of the Path object
self.assertEqual(result, os.path.join('test', 'path'))
def test_str_to_path_type_error(self):
"""
Test that `str_to_path` raises a type error when called with an invalid type
"""
# GIVEN: The `str_to_path` function
# WHEN: Calling `str_to_path` with an invalid Type
# THEN: A TypeError should have been raised
with self.assertRaises(TypeError):
str_to_path(Path())
def test_str_to_path_empty_str(self):
"""
Test that `str_to_path` correctly converts the string parameter when passed with and empty string
"""
# GIVEN: The `str_to_path` function
# WHEN: Calling the `str_to_path` function with None
result = str_to_path('')
# THEN: `path_to_str` should return None
self.assertEqual(result, None)