merge trunk

This commit is contained in:
Tomas Groth 2016-06-14 21:06:54 +02:00
commit e89803a3ad
176 changed files with 1568 additions and 1167 deletions

17
nose2.cfg Normal file
View File

@ -0,0 +1,17 @@
[unittest]
verbose = True
[log-capture]
always-on = True
clear-handlers = True
filter = -nose
log-level = ERROR
[test-result]
always-on = True
descriptions = True
[coverage]
always-on = False
coverage = openlp
coverage-report = html

View File

@ -55,6 +55,7 @@ class Registry(object):
registry = cls()
registry.service_list = {}
registry.functions_list = {}
registry.working_flags = {}
# Allow the tests to remove Registry entries but not the live system
registry.running_under_test = 'nose' in sys.argv[0]
registry.initialising = True
@ -90,8 +91,7 @@ class Registry(object):
def remove(self, key):
"""
Removes the registry value from the list based on the key passed in (Only valid and active for testing
framework).
Removes the registry value from the list based on the key passed in.
:param key: The service to be deleted.
"""
@ -145,3 +145,34 @@ class Registry(object):
trace_error_handler(log)
log.error("Event {event} called but not registered".format(event=event))
return results
def get_flag(self, key):
"""
Extracts the working_flag value from the list based on the key passed in
:param key: The flag to be retrieved.
"""
if key in self.working_flags:
return self.working_flags[key]
else:
trace_error_handler(log)
log.error('Working Flag {key} not found in list'.format(key=key))
raise KeyError('Working Flag {key} not found in list'.format(key=key))
def set_flag(self, key, reference):
"""
Sets a working_flag based on the key passed in.
:param key: The working_flag to be created this is usually a major class like "renderer" or "main_window" .
:param reference: The data to be saved.
"""
self.working_flags[key] = reference
def remove_flag(self, key):
"""
Removes the working flags value from the list based on the key passed.
:param key: The working_flag to be deleted.
"""
if key in self.working_flags:
del self.working_flags[key]

View File

@ -129,7 +129,7 @@ class Settings(QtCore.QSettings):
'advanced/recent file count': 4,
'advanced/save current plugin': False,
'advanced/slide limits': SlideLimits.End,
'advanced/slide max height': 0,
'advanced/slide max height': -4,
'advanced/single click preview': False,
'advanced/single click service preview': False,
'advanced/x11 bypass wm': X11_BYPASS_DEFAULT,

View File

@ -24,13 +24,12 @@ The :mod:`lib` module contains most of the components and libraries that make
OpenLP work.
"""
from distutils.version import LooseVersion
import logging
import os
from distutils.version import LooseVersion
from PyQt5 import QtCore, QtGui, Qt, QtWidgets
from openlp.core.common import translate
log = logging.getLogger(__name__ + '.__init__')
@ -342,7 +341,6 @@ from .exceptions import ValidationError
from .filedialog import FileDialog
from .screen import ScreenList
from .formattingtags import FormattingTags
from .spelltextedit import SpellTextEdit
from .plugin import PluginStatus, StringContent, Plugin
from .pluginmanager import PluginManager
from .settingstab import SettingsTab

View File

@ -58,7 +58,7 @@ SocketSTate = QAbstractSocket.SocketState
PJLINK_PREFIX = '%'
PJLINK_CLASS = '1'
PJLINK_HEADER = '%s%s' % (PJLINK_PREFIX, PJLINK_CLASS)
PJLINK_HEADER = '{prefix}{linkclass}'.format(prefix=PJLINK_PREFIX, linkclass=PJLINK_CLASS)
PJLINK_SUFFIX = CR
@ -160,8 +160,10 @@ class PJLink1(QTcpSocket):
self.source = None
self.other_info = None
if hasattr(self, 'timer'):
log.debug('({ip}): Calling timer.stop()'.format(ip=self.ip))
self.timer.stop()
if hasattr(self, 'socket_timer'):
log.debug('({ip}): Calling socket_timer.stop()'.format(ip=self.ip))
self.socket_timer.stop()
self.send_queue = []
self.send_busy = False

View File

@ -87,11 +87,14 @@ class AdvancedTab(SettingsTab):
self.ui_layout.addRow(self.expand_service_item_check_box)
self.slide_max_height_label = QtWidgets.QLabel(self.ui_group_box)
self.slide_max_height_label.setObjectName('slide_max_height_label')
self.slide_max_height_spin_box = QtWidgets.QSpinBox(self.ui_group_box)
self.slide_max_height_spin_box.setObjectName('slide_max_height_spin_box')
self.slide_max_height_spin_box.setRange(0, 1000)
self.slide_max_height_spin_box.setSingleStep(20)
self.ui_layout.addRow(self.slide_max_height_label, self.slide_max_height_spin_box)
self.slide_max_height_combo_box = QtWidgets.QComboBox(self.ui_group_box)
self.slide_max_height_combo_box.addItem('', userData=0)
self.slide_max_height_combo_box.addItem('', userData=-4)
# Generate numeric values for combo box dynamically
for px in range(60, 801, 5):
self.slide_max_height_combo_box.addItem(str(px) + 'px', userData=px)
self.slide_max_height_combo_box.setObjectName('slide_max_height_combo_box')
self.ui_layout.addRow(self.slide_max_height_label, self.slide_max_height_combo_box)
self.autoscroll_label = QtWidgets.QLabel(self.ui_group_box)
self.autoscroll_label.setObjectName('autoscroll_label')
self.autoscroll_combo_box = QtWidgets.QComboBox(self.ui_group_box)
@ -265,7 +268,8 @@ class AdvancedTab(SettingsTab):
'Expand new service items on creation'))
self.slide_max_height_label.setText(translate('OpenLP.AdvancedTab',
'Max height for non-text slides\nin slide controller:'))
self.slide_max_height_spin_box.setSpecialValueText(translate('OpenLP.AdvancedTab', 'Disabled'))
self.slide_max_height_combo_box.setItemText(0, translate('OpenLP.AdvancedTab', 'Disabled'))
self.slide_max_height_combo_box.setItemText(1, translate('OpenLP.AdvancedTab', 'Automatic'))
self.autoscroll_label.setText(translate('OpenLP.AdvancedTab',
'When changing slides:'))
self.autoscroll_combo_box.setItemText(0, translate('OpenLP.AdvancedTab', 'Do not auto-scroll'))
@ -355,10 +359,13 @@ class AdvancedTab(SettingsTab):
self.single_click_preview_check_box.setChecked(settings.value('single click preview'))
self.single_click_service_preview_check_box.setChecked(settings.value('single click service preview'))
self.expand_service_item_check_box.setChecked(settings.value('expand service item'))
self.slide_max_height_spin_box.setValue(settings.value('slide max height'))
slide_max_height_value = settings.value('slide max height')
for i in range(0, self.slide_max_height_combo_box.count()):
if self.slide_max_height_combo_box.itemData(i) == slide_max_height_value:
self.slide_max_height_combo_box.setCurrentIndex(i)
autoscroll_value = settings.value('autoscrolling')
for i in range(0, len(self.autoscroll_map)):
if self.autoscroll_map[i] == autoscroll_value:
if self.autoscroll_map[i] == autoscroll_value and i < self.autoscroll_combo_box.count():
self.autoscroll_combo_box.setCurrentIndex(i)
self.enable_auto_close_check_box.setChecked(settings.value('enable exit confirmation'))
self.hide_mouse_check_box.setChecked(settings.value('hide mouse'))
@ -439,7 +446,9 @@ class AdvancedTab(SettingsTab):
settings.setValue('single click preview', self.single_click_preview_check_box.isChecked())
settings.setValue('single click service preview', self.single_click_service_preview_check_box.isChecked())
settings.setValue('expand service item', self.expand_service_item_check_box.isChecked())
settings.setValue('slide max height', self.slide_max_height_spin_box.value())
slide_max_height_index = self.slide_max_height_combo_box.currentIndex()
slide_max_height_value = self.slide_max_height_combo_box.itemData(slide_max_height_index)
settings.setValue('slide max height', slide_max_height_value)
settings.setValue('autoscrolling', self.autoscroll_map[self.autoscroll_combo_box.currentIndex()])
settings.setValue('enable exit confirmation', self.enable_auto_close_check_box.isChecked())
settings.setValue('hide mouse', self.hide_mouse_check_box.isChecked())

View File

@ -28,6 +28,7 @@ from .dockwidget import OpenLPDockWidget
from .wizard import OpenLPWizard, WizardStrings
from .mediadockmanager import MediaDockManager
from .listpreviewwidget import ListPreviewWidget
from .spelltextedit import SpellTextEdit
__all__ = ['ColorButton', 'ListPreviewWidget', 'ListWidgetWithDnD', 'OpenLPToolbar', 'OpenLPDockWidget',
'OpenLPWizard', 'WizardStrings', 'MediaDockManager', 'ListPreviewWidget']
'OpenLPWizard', 'WizardStrings', 'MediaDockManager', 'ListPreviewWidget', 'SpellTextEdit']

View File

@ -63,6 +63,7 @@ class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties):
# Initialize variables.
self.service_item = ServiceItem()
self.screen_ratio = screen_ratio
self.auto_row_height = 100
# Connect signals
self.verticalHeader().sectionResized.connect(self.row_resized)
@ -87,8 +88,14 @@ class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties):
height = self.viewport().width() // self.screen_ratio
max_img_row_height = Settings().value('advanced/slide max height')
# Adjust for row height cap if in use.
if isinstance(max_img_row_height, int) and max_img_row_height > 0 and height > max_img_row_height:
height = max_img_row_height
if isinstance(max_img_row_height, int):
if max_img_row_height > 0 and height > max_img_row_height:
height = max_img_row_height
elif max_img_row_height < 0:
# If auto setting, show that number of slides, or if the resulting slides too small, 100px.
# E.g. If setting is -4, 4 slides will be visible, unless those slides are < 100px high.
self.auto_row_height = max(self.viewport().height() / (-1 * max_img_row_height), 100)
height = min(height, self.auto_row_height)
# Apply new height to slides
for frame_number in range(len(self.service_item.get_frames())):
self.setRowHeight(frame_number, height)
@ -99,7 +106,7 @@ class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties):
"""
# Only for non-text slides when row height cap in use
max_img_row_height = Settings().value('advanced/slide max height')
if self.service_item.is_text() or not isinstance(max_img_row_height, int) or max_img_row_height <= 0:
if self.service_item.is_text() or not isinstance(max_img_row_height, int) or max_img_row_height == 0:
return
# Get and validate label widget containing slide & adjust max width
try:
@ -165,11 +172,15 @@ class ListPreviewWidget(QtWidgets.QTableWidget, RegistryProperties):
slide_height = width // self.screen_ratio
# Setup and validate row height cap if in use.
max_img_row_height = Settings().value('advanced/slide max height')
if isinstance(max_img_row_height, int) and max_img_row_height > 0:
if slide_height > max_img_row_height:
if isinstance(max_img_row_height, int) and max_img_row_height != 0:
if max_img_row_height > 0 and slide_height > max_img_row_height:
# Manual Setting
slide_height = max_img_row_height
label.setMaximumWidth(max_img_row_height * self.screen_ratio)
label.resize(max_img_row_height * self.screen_ratio, max_img_row_height)
elif max_img_row_height < 0 and slide_height > self.auto_row_height:
# Auto Setting
slide_height = self.auto_row_height
label.setMaximumWidth(slide_height * self.screen_ratio)
label.resize(slide_height * self.screen_ratio, slide_height)
# Build widget with stretch padding
container = QtWidgets.QWidget()
hbox = QtWidgets.QHBoxLayout()

View File

@ -142,6 +142,7 @@ class SpellTextEdit(QtWidgets.QPlainTextEdit):
"""
Replaces the selected text with word.
"""
tag = tag.replace('&', '')
for html in FormattingTags.get_html_tags():
if tag == html['desc']:
cursor = self.textCursor()

View File

@ -134,6 +134,7 @@ def format_milliseconds(milliseconds):
:param milliseconds: Milliseconds to format
:return: Time string in format: hh.mm.ss,ttt
"""
milliseconds = int(milliseconds)
seconds, millis = divmod(milliseconds, 1000)
minutes, seconds = divmod(seconds, 60)
hours, minutes = divmod(minutes, 60)

View File

@ -25,7 +25,8 @@ The UI widgets of the print service dialog.
from PyQt5 import QtCore, QtWidgets, QtPrintSupport
from openlp.core.common import UiStrings, translate
from openlp.core.lib import SpellTextEdit, build_icon
from openlp.core.lib import build_icon
from openlp.core.ui.lib import SpellTextEdit
class ZoomSize(object):

View File

@ -25,7 +25,7 @@ The :mod:`~openlp.core.ui.servicenoteform` module contains the `ServiceNoteForm`
from PyQt5 import QtCore, QtWidgets
from openlp.core.common import Registry, RegistryProperties, translate
from openlp.core.lib import SpellTextEdit
from openlp.core.ui.lib import SpellTextEdit
from openlp.core.lib.ui import create_button_box

View File

@ -407,7 +407,7 @@ class BibleMediaItem(MediaManagerItem):
self.initialise_chapter_verse(bible, first_book['name'], first_book['book_reference_id'])
def initialise_chapter_verse(self, bible, book, book_ref_id):
log.debug('initialise_chapter_verse {bible}, {book), {ref}'.format(bible=bible, book=book, ref=book_ref_id))
log.debug('initialise_chapter_verse {bible}, {book}, {ref}'.format(bible=bible, book=book, ref=book_ref_id))
book = self.plugin.manager.get_book_by_id(bible, book_ref_id)
self.chapter_count = self.plugin.manager.get_chapter_count(bible, book)
verse_count = self.plugin.manager.get_verse_count_by_book_ref_id(bible, book_ref_id, 1)

View File

@ -23,8 +23,9 @@
from PyQt5 import QtWidgets
from openlp.core.common import UiStrings, translate
from openlp.core.lib import SpellTextEdit, build_icon
from openlp.core.lib import build_icon
from openlp.core.lib.ui import create_button, create_button_box
from openlp.core.ui.lib import SpellTextEdit
class Ui_CustomSlideEditDialog(object):

View File

@ -141,7 +141,8 @@ class HttpRouter(RegistryProperties):
"""
Initialise the router stack and any other variables.
"""
auth_code = "%s:%s" % (Settings().value('remotes/user id'), Settings().value('remotes/password'))
auth_code = "{user}:{password}".format(user=Settings().value('remotes/user id'),
password=Settings().value('remotes/password'))
try:
self.auth = base64.b64encode(auth_code)
except TypeError:
@ -189,7 +190,7 @@ class HttpRouter(RegistryProperties):
if self.headers['Authorization'] is None:
self.do_authorisation()
self.wfile.write(bytes('no auth header received', 'UTF-8'))
elif self.headers['Authorization'] == 'Basic %s' % self.auth:
elif self.headers['Authorization'] == 'Basic {auth}'.format(auth=self.auth):
self.do_http_success()
self.call_function(function, *args)
else:
@ -231,7 +232,7 @@ class HttpRouter(RegistryProperties):
for route, func in self.routes:
match = re.match(route, url_path_split.path)
if match:
log.debug('Route "%s" matched "%s"', route, url_path)
log.debug('Route "{route}" matched "{path}"'.format(route=route, path=url_path))
args = []
for param in match.groups():
args.append(param)
@ -319,9 +320,9 @@ class HttpRouter(RegistryProperties):
stage = translate('RemotePlugin.Mobile', 'Stage View')
live = translate('RemotePlugin.Mobile', 'Live View')
self.template_vars = {
'app_title': "%s %s" % (UiStrings().OLPV2x, remote),
'stage_title': "%s %s" % (UiStrings().OLPV2x, stage),
'live_title': "%s %s" % (UiStrings().OLPV2x, live),
'app_title': "{main} {remote}".format(main=UiStrings().OLPV2x, remote=remote),
'stage_title': "{main} {stage}".format(main=UiStrings().OLPV2x, stage=stage),
'live_title': "{main} {live}".format(main=UiStrings().OLPV2x, live=live),
'service_manager': translate('RemotePlugin.Mobile', 'Service Manager'),
'slide_controller': translate('RemotePlugin.Mobile', 'Slide Controller'),
'alerts': translate('RemotePlugin.Mobile', 'Alerts'),
@ -354,7 +355,7 @@ class HttpRouter(RegistryProperties):
:param file_name: file name with path
:return:
"""
log.debug('serve file request %s' % file_name)
log.debug('serve file request {name}'.format(name=file_name))
parts = file_name.split('/')
if len(parts) == 1:
file_name = os.path.join(parts[0], 'stage.html')
@ -381,10 +382,10 @@ class HttpRouter(RegistryProperties):
content = Template(filename=path, input_encoding='utf-8', output_encoding='utf-8').render(**variables)
else:
file_handle = open(path, 'rb')
log.debug('Opened %s' % path)
log.debug('Opened {path}'.format(path=path))
content = file_handle.read()
except IOError:
log.exception('Failed to open %s' % path)
log.exception('Failed to open {path}'.format(path=path))
return self.do_not_found()
finally:
if file_handle:
@ -402,7 +403,7 @@ class HttpRouter(RegistryProperties):
Ultimately for i18n, this could first look for xx/file.html before falling back to file.html.
where xx is the language, e.g. 'en'
"""
log.debug('serve file request %s' % file_name)
log.debug('serve file request {name}'.format(name=file_name))
if not file_name:
file_name = 'index.html'
if '.' not in file_name:
@ -433,7 +434,9 @@ class HttpRouter(RegistryProperties):
:param dimensions: image size
:param controller_name: controller to be called
"""
log.debug('serve thumbnail %s/thumbnails%s/%s' % (controller_name, dimensions, file_name))
log.debug('serve thumbnail {cname}/thumbnails{dim}/{fname}'.format(cname=controller_name,
dim=dimensions,
fname=file_name))
supported_controllers = ['presentations', 'images']
# -1 means use the default dimension in ImageManager
width = -1
@ -539,7 +542,7 @@ class HttpRouter(RegistryProperties):
:param var: variable - not used
"""
log.debug("controller_text var = %s" % var)
log.debug("controller_text var = {var}".format(var=var))
current_item = self.live_controller.service_item
data = []
if current_item:
@ -594,7 +597,8 @@ class HttpRouter(RegistryProperties):
:param display_type: This is the type of slide controller, either ``preview`` or ``live``.
:param action: The action to perform.
"""
event = getattr(self.live_controller, 'slidecontroller_%s_%s' % (display_type, action))
event = getattr(self.live_controller, 'slidecontroller_{display}_{action}'.format(display=display_type,
action=action))
if self.request_data:
try:
data = json.loads(self.request_data)['request']['id']
@ -623,7 +627,7 @@ class HttpRouter(RegistryProperties):
:param action: The action to perform.
"""
event = getattr(self.service_manager, 'servicemanager_%s_item' % action)
event = getattr(self.service_manager, 'servicemanager_{action}_item'.format(action=action))
if self.request_data:
try:
data = int(json.loads(self.request_data)['request']['id'])
@ -680,7 +684,7 @@ class HttpRouter(RegistryProperties):
return self.do_http_error()
plugin = self.plugin_manager.get_plugin_by_name(plugin_name)
if plugin.status == PluginStatus.Active and plugin.media_item:
getattr(plugin.media_item, '%s_go_live' % plugin_name).emit([request_id, True])
getattr(plugin.media_item, '{name}_go_live'.format(name=plugin_name)).emit([request_id, True])
return self.do_http_success()
def add_to_service(self, plugin_name):
@ -696,5 +700,5 @@ class HttpRouter(RegistryProperties):
plugin = self.plugin_manager.get_plugin_by_name(plugin_name)
if plugin.status == PluginStatus.Active and plugin.media_item:
item_id = plugin.media_item.create_item_from_id(request_id)
getattr(plugin.media_item, '%s_add_to_service' % plugin_name).emit([item_id, True])
getattr(plugin.media_item, '{name}_add_to_service'.format(name=plugin_name)).emit([item_id, True])
self.do_http_success()

View File

@ -136,11 +136,13 @@ class OpenLPServer(RegistryProperties):
while loop < 4:
try:
self.httpd = server_class((address, port), CustomHandler)
log.debug("Server started for class %s %s %d" % (server_class, address, port))
log.debug("Server started for class {name} {address} {port:d}".format(name=server_class,
address=address,
port=port))
break
except OSError:
log.debug("failed to start http server thread state %d %s" %
(loop, self.http_thread.isRunning()))
log.debug("failed to start http server thread state "
"{loop:d} {running}".format(loop=loop, running=self.http_thread.isRunning()))
loop += 1
time.sleep(0.1)
except:

View File

@ -192,14 +192,14 @@ class RemoteTab(SettingsTab):
'Show thumbnails of non-text slides in remote and stage view.'))
self.android_app_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'Android App'))
self.android_qr_description_label.setText(
translate('RemotePlugin.RemoteTab', 'Scan the QR code or click <a href="%s">download</a> to install the '
'Android app from Google Play.') %
'https://play.google.com/store/apps/details?id=org.openlp.android2')
translate('RemotePlugin.RemoteTab',
'Scan the QR code or click <a href="{qr}">download</a> to install the Android app from Google '
'Play.').format(qr='https://play.google.com/store/apps/details?id=org.openlp.android2'))
self.ios_app_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'iOS App'))
self.ios_qr_description_label.setText(
translate('RemotePlugin.RemoteTab', 'Scan the QR code or click <a href="%s">download</a> to install the '
'iOS app from the App Store.') %
'https://itunes.apple.com/app/id1096218725')
translate('RemotePlugin.RemoteTab',
'Scan the QR code or click <a href="{qr}">download</a> to install the iOS app from the App '
'Store.').format(qr='https://itunes.apple.com/app/id1096218725'))
self.https_settings_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'HTTPS Server'))
self.https_error_label.setText(
translate('RemotePlugin.RemoteTab', 'Could not find an SSL certificate. The HTTPS server will not be '
@ -217,18 +217,18 @@ class RemoteTab(SettingsTab):
Update the display based on the data input on the screen
"""
ip_address = self.get_ip_address(self.address_edit.text())
http_url = 'http://%s:%s/' % (ip_address, self.port_spin_box.value())
https_url = 'https://%s:%s/' % (ip_address, self.https_port_spin_box.value())
self.remote_url.setText('<a href="%s">%s</a>' % (http_url, http_url))
self.remote_https_url.setText('<a href="%s">%s</a>' % (https_url, https_url))
http_url = 'http://{url}:{text}/'.format(url=ip_address, text=self.port_spin_box.value())
https_url = 'https://{url}:{text}/'.format(url=ip_address, text=self.https_port_spin_box.value())
self.remote_url.setText('<a href="{url}">{url}</a>'.format(url=http_url))
self.remote_https_url.setText('<a href="{url}">{url}</a>'.format(url=https_url))
http_url_temp = http_url + 'stage'
https_url_temp = https_url + 'stage'
self.stage_url.setText('<a href="%s">%s</a>' % (http_url_temp, http_url_temp))
self.stage_https_url.setText('<a href="%s">%s</a>' % (https_url_temp, https_url_temp))
self.stage_url.setText('<a href="{url}">{url}</a>'.format(url=http_url_temp))
self.stage_https_url.setText('<a href="{url}">{url}</a>'.format(url=https_url_temp))
http_url_temp = http_url + 'main'
https_url_temp = https_url + 'main'
self.live_url.setText('<a href="%s">%s</a>' % (http_url_temp, http_url_temp))
self.live_https_url.setText('<a href="%s">%s</a>' % (https_url_temp, https_url_temp))
self.live_url.setText('<a href="{url}">{url}</a>'.format(url=http_url_temp))
self.live_https_url.setText('<a href="{url}">{url}</a>'.format(url=https_url_temp))
def get_ip_address(self, ip_address):
"""

View File

@ -130,6 +130,7 @@ class DuplicateSongRemovalForm(OpenLPWizard, RegistryProperties):
Song wizard localisation.
"""
self.setWindowTitle(translate('Wizard', 'Wizard'))
# TODO: Check format() using template strings
self.title_label.setText(WizardStrings.HeaderStyle % translate('OpenLP.Ui',
'Welcome to the Duplicate Song Removal Wizard'))
self.information_label.setText(
@ -148,8 +149,8 @@ class DuplicateSongRemovalForm(OpenLPWizard, RegistryProperties):
Set the wizard review page header text.
"""
self.review_page.setTitle(
translate('Wizard', 'Review duplicate songs (%s/%s)') %
(self.review_current_count, self.review_total_count))
translate('Wizard', 'Review duplicate songs ({current}/{total})').format(current=self.review_current_count,
total=self.review_total_count))
def custom_page_changed(self, page_id):
"""

View File

@ -50,7 +50,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
"""
Class to manage the editing of a song
"""
log.info('%s EditSongForm loaded', __name__)
log.info('{name} EditSongForm loaded'.format(name=__name__))
def __init__(self, media_item, parent, manager):
"""
@ -185,20 +185,23 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
verse = verse.data(QtCore.Qt.UserRole)
if verse not in verse_names:
verses.append(verse)
verse_names.append('%s%s' % (VerseType.translated_tag(verse[0]), verse[1:]))
verse_names.append('{verse1}{verse2}'.format(verse1=VerseType.translated_tag(verse[0]),
verse2=verse[1:]))
for count, item in enumerate(order):
if item not in verses:
invalid_verses.append(order_names[count])
if invalid_verses:
valid = create_separated_list(verse_names)
if len(invalid_verses) > 1:
msg = translate('SongsPlugin.EditSongForm', 'There are no verses corresponding to "%(invalid)s". '
'Valid entries are %(valid)s.\nPlease enter the verses separated by spaces.') % \
{'invalid': ', '.join(invalid_verses), 'valid': valid}
msg = translate('SongsPlugin.EditSongForm',
'There are no verses corresponding to "{invalid}". Valid entries are {valid}.\n'
'Please enter the verses separated by spaces.'
).format(invalid=', '.join(invalid_verses), valid=valid)
else:
msg = translate('SongsPlugin.EditSongForm', 'There is no verse corresponding to "%(invalid)s".'
'Valid entries are %(valid)s.\nPlease enter the verses separated by spaces.') % \
{'invalid': invalid_verses[0], 'valid': valid}
msg = translate('SongsPlugin.EditSongForm',
'There is no verse corresponding to "{invalid}". Valid entries are {valid}.\n'
'Please enter the verses separated by spaces.').format(invalid=invalid_verses[0],
valid=valid)
critical_error_message_box(title=translate('SongsPlugin.EditSongForm', 'Invalid Verse Order'),
message=msg)
return len(invalid_verses) == 0
@ -242,23 +245,24 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
field = item.data(QtCore.Qt.UserRole)
verse_tags.append(field)
if not self._validate_tags(tags):
misplaced_tags.append('%s %s' % (VerseType.translated_name(field[0]), field[1:]))
misplaced_tags.append('{field1} {field2}'.format(field1=VerseType.translated_name(field[0]),
field2=field[1:]))
if misplaced_tags:
critical_error_message_box(
message=translate('SongsPlugin.EditSongForm',
'There are misplaced formatting tags in the following verses:\n\n%s\n\n'
'Please correct these tags before continuing.' % ', '.join(misplaced_tags)))
'There are misplaced formatting tags in the following verses:\n\n{tag}\n\n'
'Please correct these tags before continuing.').format(tag=', '.join(misplaced_tags)))
return False
for tag in verse_tags:
if verse_tags.count(tag) > 26:
# lp#1310523: OpenLyrics allows only a-z variants of one verse:
# http://openlyrics.info/dataformat.html#verse-name
critical_error_message_box(message=translate(
'SongsPlugin.EditSongForm', 'You have %(count)s verses named %(name)s %(number)s. '
'You can have at most 26 verses with the same name' %
{'count': verse_tags.count(tag),
'name': VerseType.translated_name(tag[0]),
'number': tag[1:]}))
'SongsPlugin.EditSongForm',
'You have {count} verses named {name} {number}. You can have at most '
'26 verses with the same name').format(count=verse_tags.count(tag),
name=VerseType.translated_name(tag[0]),
number=tag[1:]))
return False
return True
@ -313,7 +317,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
self.song.verse_order = re.sub('([' + verse.upper() + verse.lower() + '])(\W|$)',
r'\g<1>1\2', self.song.verse_order)
except:
log.exception('Problem processing song Lyrics \n%s', sxml.dump_xml())
log.exception('Problem processing song Lyrics \n{xml}'.forma(xml=sxml.dump_xml()))
raise
def keyPressEvent(self, event):
@ -492,7 +496,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
verse[0]['type'] = VerseType.tags[index]
if verse[0]['label'] == '':
verse[0]['label'] = '1'
verse_def = '%s%s' % (verse[0]['type'], verse[0]['label'])
verse_def = '{verse}{label}'.format(verse=verse[0]['type'], label=verse[0]['label'])
item = QtWidgets.QTableWidgetItem(verse[1])
item.setData(QtCore.Qt.UserRole, verse_def)
self.verse_list_widget.setItem(count, 0, item)
@ -501,7 +505,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
for count, verse in enumerate(verses):
self.verse_list_widget.setRowCount(self.verse_list_widget.rowCount() + 1)
item = QtWidgets.QTableWidgetItem(verse)
verse_def = '%s%s' % (VerseType.tags[VerseType.Verse], str(count + 1))
verse_def = '{verse}{count:d}'.format(verse=VerseType.tags[VerseType.Verse], count=(count + 1))
item.setData(QtCore.Qt.UserRole, verse_def)
self.verse_list_widget.setItem(count, 0, item)
if self.song.verse_order:
@ -514,7 +518,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
if verse_index is None:
verse_index = VerseType.from_tag(verse_def[0])
verse_tag = VerseType.translated_tags[verse_index].upper()
translated.append('%s%s' % (verse_tag, verse_def[1:]))
translated.append('{tag}{verse}'.format(tag=verse_tag, verse=verse_def[1:]))
self.verse_order_edit.setText(' '.join(translated))
else:
self.verse_order_edit.setText('')
@ -554,7 +558,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
item = self.verse_list_widget.item(row, 0)
verse_def = item.data(QtCore.Qt.UserRole)
verse_tag = VerseType.translated_tag(verse_def[0])
row_def = '%s%s' % (verse_tag, verse_def[1:])
row_def = '{tag}{verse}'.format(tag=verse_tag, verse=verse_def[1:])
row_label.append(row_def)
self.verse_list_widget.setVerticalHeaderLabels(row_label)
self.verse_list_widget.resizeRowsToContents()
@ -742,7 +746,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
self.verse_form.set_verse('', True)
if self.verse_form.exec():
after_text, verse_tag, verse_num = self.verse_form.get_verse()
verse_def = '%s%s' % (verse_tag, verse_num)
verse_def = '{tag}{number}'.format(tag=verse_tag, number=verse_num)
item = QtWidgets.QTableWidgetItem(after_text)
item.setData(QtCore.Qt.UserRole, verse_def)
item.setText(after_text)
@ -760,7 +764,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
self.verse_form.set_verse(temp_text, True, verse_id)
if self.verse_form.exec():
after_text, verse_tag, verse_num = self.verse_form.get_verse()
verse_def = '%s%s' % (verse_tag, verse_num)
verse_def = '{tag}{number}'.format(tag=verse_tag, number=verse_num)
item.setData(QtCore.Qt.UserRole, verse_def)
item.setText(after_text)
# number of lines has changed, repaint the list moving the data
@ -793,7 +797,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
field = item.data(QtCore.Qt.UserRole)
verse_tag = VerseType.translated_name(field[0])
verse_num = field[1:]
verse_list += '---[%s:%s]---\n' % (verse_tag, verse_num)
verse_list += '---[{tag}:{number}]---\n'.format(tag=verse_tag, number=verse_num)
verse_list += item.text()
verse_list += '\n'
self.verse_form.set_verse(verse_list)
@ -828,7 +832,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
verse_num = match.group(1)
else:
verse_num = '1'
verse_def = '%s%s' % (verse_tag, verse_num)
verse_def = '{tag}{number}'.format(tag=verse_tag, number=verse_num)
else:
if parts.endswith('\n'):
parts = parts.rstrip('\n')
@ -919,7 +923,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
"""
Loads file(s) from the filesystem.
"""
filters = '%s (*)' % UiStrings().AllFiles
filters = '{text} (*)'.format(text=UiStrings().AllFiles)
file_names = FileDialog.getOpenFileNames(self, translate('SongsPlugin.EditSongForm', 'Open File(s)'), '',
filters)
for filename in file_names:
@ -1027,7 +1031,7 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
for item in order_text.split():
verse_tag = VerseType.tags[VerseType.from_translated_tag(item[0])]
verse_num = item[1:].lower()
order.append('%s%s' % (verse_tag, verse_num))
order.append('{tag}{number}'.format(tag=verse_tag, number=verse_num))
self.song.verse_order = ' '.join(order)
self.song.ccli_number = self.ccli_number_edit.text()
theme_name = self.theme_combo_box.currentText()
@ -1082,12 +1086,12 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties):
try:
os.remove(audio)
except:
log.exception('Could not remove file: %s', audio)
log.exception('Could not remove file: {audio}'.format(audio=audio))
if not files:
try:
os.rmdir(save_path)
except OSError:
log.exception('Could not remove directory: %s', save_path)
log.exception('Could not remove directory: {path}'.format(path=save_path))
clean_song(self.manager, self.song)
self.manager.save_object(self.song)
self.media_item.auto_select_id = self.song.id

View File

@ -22,7 +22,8 @@
from PyQt5 import QtWidgets
from openlp.core.lib import SpellTextEdit, build_icon, translate
from openlp.core.ui.lib import SpellTextEdit
from openlp.core.lib import build_icon, translate
from openlp.core.lib.ui import UiStrings, create_button_box
from openlp.plugins.songs.lib import VerseType

View File

@ -59,7 +59,7 @@ class EditVerseForm(QtWidgets.QDialog, Ui_EditVerseDialog):
if self.verse_text_edit.textCursor().columnNumber() != 0:
self.verse_text_edit.insertPlainText('\n')
verse_tag = VerseType.translated_name(verse_tag)
self.verse_text_edit.insertPlainText('---[%s:%s]---\n' % (verse_tag, verse_num))
self.verse_text_edit.insertPlainText('---[{tag}:{number}]---\n'.format(tag=verse_tag, number=verse_num))
self.verse_text_edit.setFocus()
def on_split_button_clicked(self):
@ -107,7 +107,7 @@ class EditVerseForm(QtWidgets.QDialog, Ui_EditVerseDialog):
self.verse_type_combo_box.currentIndex()]
if not text:
return
position = text.rfind('---[%s' % verse_name, 0, position)
position = text.rfind('---[{verse}'.format(verse=verse_name), 0, position)
if position == -1:
self.verse_number_box.setValue(1)
return
@ -124,7 +124,7 @@ class EditVerseForm(QtWidgets.QDialog, Ui_EditVerseDialog):
verse_num = 1
self.verse_number_box.setValue(verse_num)
def set_verse(self, text, single=False, tag='%s1' % VerseType.tags[VerseType.Verse]):
def set_verse(self, text, single=False, tag='{verse}1'.format(verse=VerseType.tags[VerseType.Verse])):
"""
Save the verse
@ -142,7 +142,7 @@ class EditVerseForm(QtWidgets.QDialog, Ui_EditVerseDialog):
self.insert_button.setVisible(False)
else:
if not text:
text = '---[%s:1]---\n' % VerseType.translated_names[VerseType.Verse]
text = '---[{tag}:1]---\n'.format(tag=VerseType.translated_names[VerseType.Verse])
self.verse_type_combo_box.setCurrentIndex(0)
self.verse_number_box.setValue(1)
self.insert_button.setVisible(True)
@ -167,5 +167,5 @@ class EditVerseForm(QtWidgets.QDialog, Ui_EditVerseDialog):
"""
text = self.verse_text_edit.toPlainText()
if not text.startswith('---['):
text = '---[%s:1]---\n%s' % (VerseType.translated_names[VerseType.Verse], text)
text = '---[{tag}:1]---\n{text}'.format(tag=VerseType.translated_names[VerseType.Verse], text=text)
return text

View File

@ -34,7 +34,7 @@ class MediaFilesForm(QtWidgets.QDialog, Ui_MediaFilesDialog):
"""
Class to show a list of files from the
"""
log.info('%s MediaFilesForm loaded', __name__)
log.info('{name} MediaFilesForm loaded'.format(name=__name__))
def __init__(self, parent):
super(MediaFilesForm, self).__init__(parent, QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.WindowTitleHint)

View File

@ -143,6 +143,7 @@ class SongExportForm(OpenLPWizard):
Song wizard localisation.
"""
self.setWindowTitle(translate('SongsPlugin.ExportWizardForm', 'Song Export Wizard'))
# TODO: Verify format() with template variables
self.title_label.setText(WizardStrings.HeaderStyle %
translate('OpenLP.Ui', 'Welcome to the Song Export Wizard'))
self.information_label.setText(
@ -151,7 +152,7 @@ class SongExportForm(OpenLPWizard):
self.available_songs_page.setTitle(translate('SongsPlugin.ExportWizardForm', 'Select Songs'))
self.available_songs_page.setSubTitle(translate('SongsPlugin.ExportWizardForm',
'Check the songs you want to export.'))
self.search_label.setText('%s:' % UiStrings().Search)
self.search_label.setText('{text}:'.format(text=UiStrings().Search))
self.uncheck_button.setText(translate('SongsPlugin.ExportWizardForm', 'Uncheck All'))
self.check_button.setText(translate('SongsPlugin.ExportWizardForm', 'Check All'))
self.export_song_page.setTitle(translate('SongsPlugin.ExportWizardForm', 'Select Directory'))
@ -223,7 +224,7 @@ class SongExportForm(OpenLPWizard):
if song.temporary:
continue
authors = create_separated_list([author.display_name for author in song.authors])
title = '%s (%s)' % (str(song.title), authors)
title = '{title} ({author})'.format(title=song.title, author=authors)
item = QtWidgets.QListWidgetItem(title)
item.setData(QtCore.Qt.UserRole, song)
item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsEnabled)
@ -257,7 +258,7 @@ class SongExportForm(OpenLPWizard):
self.progress_label.setText(translate('SongsPlugin.SongExportForm', 'Your song export failed.'))
except OSError as ose:
self.progress_label.setText(translate('SongsPlugin.SongExportForm', 'Your song export failed because this '
'error occurred: %s') % ose.strerror)
'error occurred: {error}').format(error=ose.strerror))
def on_search_line_edit_changed(self, text):
"""

View File

@ -132,6 +132,7 @@ class SongImportForm(OpenLPWizard, RegistryProperties):
Song wizard localisation.
"""
self.setWindowTitle(translate('SongsPlugin.ImportWizardForm', 'Song Import Wizard'))
# TODO: Verify format() with template variables
self.title_label.setText(WizardStrings.HeaderStyle % translate('OpenLP.Ui',
'Welcome to the Song Import Wizard'))
self.information_label.setText(
@ -236,7 +237,7 @@ class SongImportForm(OpenLPWizard, RegistryProperties):
"""
if filters:
filters += ';;'
filters += '%s (*)' % UiStrings().AllFiles
filters += '{text} (*)'.format(text=UiStrings().AllFiles)
file_names = FileDialog.getOpenFileNames(
self, title,
Settings().value(self.plugin.settings_section + '/last directory import'), filters)
@ -271,9 +272,11 @@ class SongImportForm(OpenLPWizard, RegistryProperties):
select_mode, format_name, ext_filter = SongFormat.get(this_format, 'selectMode', 'name', 'filter')
file_path_edit = self.format_widgets[this_format]['file_path_edit']
if select_mode == SongFormatSelect.SingleFile:
# TODO: Verify format() with template variables
self.get_file_name(
WizardStrings.OpenTypeFile % format_name, file_path_edit, 'last directory import', ext_filter)
elif select_mode == SongFormatSelect.SingleFolder:
# TODO: Verify format() with template variables
self.get_folder(WizardStrings.OpenTypeFolder % format_name, file_path_edit, 'last directory import')
def on_add_button_clicked(self):
@ -283,6 +286,7 @@ class SongImportForm(OpenLPWizard, RegistryProperties):
this_format = self.current_format
select_mode, format_name, ext_filter, custom_title = \
SongFormat.get(this_format, 'selectMode', 'name', 'filter', 'getFilesTitle')
# TODO: Verify format() with template variables
title = custom_title if custom_title else WizardStrings.OpenTypeFile % format_name
if select_mode == SongFormatSelect.MultipleFiles:
self.get_files(title, self.format_widgets[this_format]['file_list_widget'], ext_filter)

View File

@ -164,7 +164,8 @@ class SongMaintenanceForm(QtWidgets.QDialog, Ui_SongMaintenanceDialog, RegistryP
books = self.manager.get_all_objects(Book)
books.sort(key=get_book_key)
for book in books:
book_name = QtWidgets.QListWidgetItem('%s (%s)' % (book.name, book.publisher))
book_name = QtWidgets.QListWidgetItem('{name} ({publisher})'.format(name=book.name,
publisher=book.publisher))
book_name.setData(QtCore.Qt.UserRole, book.id)
self.song_books_list_widget.addItem(book_name)
@ -310,11 +311,12 @@ class SongMaintenanceForm(QtWidgets.QDialog, Ui_SongMaintenanceDialog, RegistryP
else:
critical_error_message_box(
message=translate('SongsPlugin.SongMaintenanceForm', 'Could not save your changes.'))
elif critical_error_message_box(message=translate(
'SongsPlugin.SongMaintenanceForm', 'The author %s already exists. Would you like to make songs with '
'author %s use the existing author %s?') %
(author.display_name, temp_display_name, author.display_name), parent=self, question=True) == \
QtWidgets.QMessageBox.Yes:
elif critical_error_message_box(
message=translate(
'SongsPlugin.SongMaintenanceForm',
'The author {original} already exists. Would you like to make songs with author {new} use the '
'existing author {original}?').format(original=author.display_name, new=temp_display_name),
parent=self, question=True) == QtWidgets.QMessageBox.Yes:
self._merge_objects(author, self.merge_authors, self.reset_authors)
else:
# We restore the author's old first and last name as well as
@ -346,9 +348,10 @@ class SongMaintenanceForm(QtWidgets.QDialog, Ui_SongMaintenanceDialog, RegistryP
critical_error_message_box(
message=translate('SongsPlugin.SongMaintenanceForm', 'Could not save your changes.'))
elif critical_error_message_box(
message=translate('SongsPlugin.SongMaintenanceForm',
'The topic %s already exists. Would you like to make songs with topic %s use the '
'existing topic %s?') % (topic.name, temp_name, topic.name),
message=translate('SongsPlugin.SongMaintenanceForm',
'The topic {original} already exists. Would you like to make songs with '
'topic {new} use the existing topic {original}?').format(original=topic.name,
new=temp_name),
parent=self, question=True) == QtWidgets.QMessageBox.Yes:
self._merge_objects(topic, self.merge_topics, self.reset_topics)
else:
@ -384,9 +387,10 @@ class SongMaintenanceForm(QtWidgets.QDialog, Ui_SongMaintenanceDialog, RegistryP
critical_error_message_box(
message=translate('SongsPlugin.SongMaintenanceForm', 'Could not save your changes.'))
elif critical_error_message_box(
message=translate('SongsPlugin.SongMaintenanceForm',
'The book %s already exists. Would you like to make '
'songs with book %s use the existing book %s?') % (book.name, temp_name, book.name),
message=translate('SongsPlugin.SongMaintenanceForm',
'The book {original} already exists. Would you like to make songs with '
'book {new} use the existing book {original}?').format(original=book.name,
new=temp_name),
parent=self, question=True) == QtWidgets.QMessageBox.Yes:
self._merge_objects(book, self.merge_song_books, self.reset_song_books)
else:

View File

@ -242,7 +242,8 @@ class Ui_SongSelectDialog(object):
self.search_label.setText(translate('SongsPlugin.SongSelectForm', 'Search Text:'))
self.search_button.setText(translate('SongsPlugin.SongSelectForm', 'Search'))
self.stop_button.setText(translate('SongsPlugin.SongSelectForm', 'Stop'))
self.result_count_label.setText(translate('SongsPlugin.SongSelectForm', 'Found %s song(s)') % 0)
self.result_count_label.setText(translate('SongsPlugin.SongSelectForm',
'Found {count:d} song(s)').format(count=0))
self.logout_button.setText(translate('SongsPlugin.SongSelectForm', 'Logout'))
self.view_button.setText(translate('SongsPlugin.SongSelectForm', 'View'))
self.title_label.setText(translate('SongsPlugin.SongSelectForm', 'Title:'))

View File

@ -305,7 +305,8 @@ class SongSelectForm(QtWidgets.QDialog, Ui_SongSelectDialog):
self.search_progress_bar.setValue(0)
self.set_progress_visible(True)
self.search_results_widget.clear()
self.result_count_label.setText(translate('SongsPlugin.SongSelectForm', 'Found %s song(s)') % self.song_count)
self.result_count_label.setText(translate('SongsPlugin.SongSelectForm',
'Found {count:d} song(s)').format(count=self.song_count))
self.application.process_events()
self.song_count = 0
search_history = self.search_combobox.getItems()
@ -343,7 +344,8 @@ class SongSelectForm(QtWidgets.QDialog, Ui_SongSelectDialog):
:param song:
"""
self.song_count += 1
self.result_count_label.setText(translate('SongsPlugin.SongSelectForm', 'Found %s song(s)') % self.song_count)
self.result_count_label.setText(translate('SongsPlugin.SongSelectForm',
'Found {count:d} song(s)').format(count=self.song_count))
item_title = song['title'] + ' (' + ', '.join(song['authors']) + ')'
song_item = QtWidgets.QListWidgetItem(item_title, self.search_results_widget)
song_item.setData(QtCore.Qt.UserRole, song)

View File

@ -534,11 +534,11 @@ def delete_song(song_id, song_plugin):
try:
os.remove(media_file.file_name)
except OSError:
log.exception('Could not remove file: %s', media_file.file_name)
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))
if os.path.exists(save_path):
os.rmdir(save_path)
except OSError:
log.exception('Could not remove directory: %s', save_path)
log.exception('Could not remove directory: {path}'.format(path=save_path))
song_plugin.manager.delete_object(Song, song_id)

View File

@ -39,7 +39,7 @@ class Author(BaseModel):
"""
def get_display_name(self, author_type=None):
if author_type:
return "%s (%s)" % (self.display_name, AuthorType.Types[author_type])
return "{name} ({author})".format(name=self.display_name, author=AuthorType.Types[author_type])
return self.display_name
@ -105,7 +105,9 @@ class Book(BaseModel):
Book model
"""
def __repr__(self):
return '<Book id="%s" name="%s" publisher="%s" />' % (str(self.id), self.name, self.publisher)
return '<Book id="{myid:d}" name="{name}" publisher="{publisher}" />'.format(myid=self.id,
name=self.name,
publisher=self.publisher)
class MediaFile(BaseModel):
@ -187,7 +189,7 @@ class SongBookEntry(BaseModel):
@staticmethod
def get_display_name(songbook_name, entry):
if entry:
return "%s #%s" % (songbook_name, entry)
return "{name} #{entry}".format(name=songbook_name, entry=entry)
return songbook_name

View File

@ -56,13 +56,13 @@ try:
from .importers.songsoffellowship import SongsOfFellowshipImport
HAS_SOF = True
except ImportError:
log.exception('Error importing %s', 'SongsOfFellowshipImport')
log.exception('Error importing {text}'.format(text='SongsOfFellowshipImport'))
HAS_SOF = False
try:
from .importers.openoffice import OpenOfficeImport
HAS_OOO = True
except ImportError:
log.exception('Error importing %s', 'OooImport')
log.exception('Error importing {text}'.format(text='OooImport'))
HAS_OOO = False
HAS_MEDIASHOUT = False
if is_win():
@ -70,21 +70,21 @@ if is_win():
from .importers.mediashout import MediaShoutImport
HAS_MEDIASHOUT = True
except ImportError:
log.exception('Error importing %s', 'MediaShoutImport')
log.exception('Error importing {text}'.format(text='MediaShoutImport'))
HAS_WORSHIPCENTERPRO = False
if is_win():
try:
from .importers.worshipcenterpro import WorshipCenterProImport
HAS_WORSHIPCENTERPRO = True
except ImportError:
log.exception('Error importing %s', 'WorshipCenterProImport')
log.exception('Error importing {text}'.format(text='WorshipCenterProImport'))
HAS_OPSPRO = False
if is_win():
try:
from .importers.opspro import OPSProImport
HAS_OPSPRO = True
except ImportError:
log.exception('Error importing %s', 'OPSProImport')
log.exception('Error importing {text}'.format(text='OPSProImport'))
class SongFormatSelect(object):
@ -198,7 +198,7 @@ class SongFormat(object):
'class': OpenLyricsImport,
'name': 'OpenLyrics',
'prefix': 'openLyrics',
'filter': '%s (*.xml)' % translate('SongsPlugin.ImportWizardForm', 'OpenLyrics Files'),
'filter': '{text} (*.xml)'.format(text=translate('SongsPlugin.ImportWizardForm', 'OpenLyrics Files')),
'comboBoxText': translate('SongsPlugin.ImportWizardForm', 'OpenLyrics or OpenLP 2 Exported Song')
},
OpenLP2: {
@ -206,7 +206,7 @@ class SongFormat(object):
'name': UiStrings().OLPV2,
'prefix': 'openLP2',
'selectMode': SongFormatSelect.SingleFile,
'filter': '%s (*.sqlite)' % (translate('SongsPlugin.ImportWizardForm', 'OpenLP 2 Databases'))
'filter': '{text} (*.sqlite)'.format(text=translate('SongsPlugin.ImportWizardForm', 'OpenLP 2 Databases'))
},
Generic: {
'name': translate('SongsPlugin.ImportWizardForm', 'Generic Document/Presentation'),
@ -221,46 +221,50 @@ class SongFormat(object):
'class': CCLIFileImport,
'name': 'CCLI/SongSelect',
'prefix': 'ccli',
'filter': '%s (*.usr *.txt *.bin)' % translate('SongsPlugin.ImportWizardForm', 'CCLI SongSelect Files')
'filter': '{text} (*.usr *.txt *.bin)'.format(text=translate('SongsPlugin.ImportWizardForm',
'CCLI SongSelect Files'))
},
DreamBeam: {
'class': DreamBeamImport,
'name': 'DreamBeam',
'prefix': 'dreamBeam',
'filter': '%s (*.xml)' % translate('SongsPlugin.ImportWizardForm', 'DreamBeam Song Files')
'filter': '{text} (*.xml)'.format(text=translate('SongsPlugin.ImportWizardForm', 'DreamBeam Song Files'))
},
EasySlides: {
'class': EasySlidesImport,
'name': 'EasySlides',
'prefix': 'easySlides',
'selectMode': SongFormatSelect.SingleFile,
'filter': '%s (*.xml)' % translate('SongsPlugin.ImportWizardForm', 'EasySlides XML File')
'filter': '{text} (*.xml)'.format(text=translate('SongsPlugin.ImportWizardForm', 'EasySlides XML File'))
},
EasyWorshipDB: {
'class': EasyWorshipSongImport,
'name': 'EasyWorship Song Database',
'prefix': 'ew',
'selectMode': SongFormatSelect.SingleFile,
'filter': '%s (*.db)' % translate('SongsPlugin.ImportWizardForm', 'EasyWorship Song Database')
'filter': '{text} (*.db)'.format(text=translate('SongsPlugin.ImportWizardForm',
'EasyWorship Song Database'))
},
EasyWorshipService: {
'class': EasyWorshipSongImport,
'name': 'EasyWorship Service File',
'prefix': 'ew',
'selectMode': SongFormatSelect.SingleFile,
'filter': '%s (*.ews)' % translate('SongsPlugin.ImportWizardForm', 'EasyWorship Service File')
'filter': '{text} (*.ews)'.format(text=translate('SongsPlugin.ImportWizardForm',
'EasyWorship Service File'))
},
FoilPresenter: {
'class': FoilPresenterImport,
'name': 'Foilpresenter',
'prefix': 'foilPresenter',
'filter': '%s (*.foil)' % translate('SongsPlugin.ImportWizardForm', 'Foilpresenter Song Files')
'filter': '{text} (*.foil)'.format(text=translate('SongsPlugin.ImportWizardForm',
'Foilpresenter Song Files'))
},
Lyrix: {
'class': LyrixImport,
'name': 'LyriX',
'prefix': 'lyrix',
'filter': '%s (*.txt)' % translate('SongsPlugin.ImportWizardForm', 'LyriX Files'),
'filter': '{text} (*.txt)'.format(text=translate('SongsPlugin.ImportWizardForm', 'LyriX Files')),
'comboBoxText': translate('SongsPlugin.ImportWizardForm', 'LyriX (Exported TXT-files)')
},
MediaShout: {
@ -268,7 +272,7 @@ class SongFormat(object):
'prefix': 'mediaShout',
'canDisable': True,
'selectMode': SongFormatSelect.SingleFile,
'filter': '%s (*.mdb)' % translate('SongsPlugin.ImportWizardForm', 'MediaShout Database'),
'filter': '{text} (*.mdb)'.format(text=translate('SongsPlugin.ImportWizardForm', 'MediaShout Database')),
'disabledLabelText': translate('SongsPlugin.ImportWizardForm',
'The MediaShout importer is only supported on Windows. It has '
'been disabled due to a missing Python module. If you want to '
@ -285,7 +289,7 @@ class SongFormat(object):
'prefix': 'OPSPro',
'canDisable': True,
'selectMode': SongFormatSelect.SingleFile,
'filter': '%s (*.mdb)' % translate('SongsPlugin.ImportWizardForm', 'OPS Pro database'),
'filter': '{text} (*.mdb)'.format(text=translate('SongsPlugin.ImportWizardForm', 'OPS Pro database')),
'disabledLabelText': translate('SongsPlugin.ImportWizardForm',
'The OPS Pro importer is only supported on Windows. It has been '
'disabled due to a missing Python module. If you want to use this '
@ -295,7 +299,7 @@ class SongFormat(object):
'class': PowerPraiseImport,
'name': 'PowerPraise',
'prefix': 'powerPraise',
'filter': '%s (*.ppl)' % translate('SongsPlugin.ImportWizardForm', 'PowerPraise Song Files')
'filter': '{text} (*.ppl)'.format(text=translate('SongsPlugin.ImportWizardForm', 'PowerPraise Song Files'))
},
PowerSong: {
'class': PowerSongImport,
@ -309,26 +313,29 @@ class SongFormat(object):
'class': PresentationManagerImport,
'name': 'PresentationManager',
'prefix': 'presentationManager',
'filter': '%s (*.sng)' % translate('SongsPlugin.ImportWizardForm', 'PresentationManager Song Files')
'filter': '{text} (*.sng)'.format(text=translate('SongsPlugin.ImportWizardForm',
'PresentationManager Song Files'))
},
ProPresenter: {
'class': ProPresenterImport,
'name': 'ProPresenter 4, 5 and 6',
'prefix': 'proPresenter',
'filter': '%s (*.pro4 *.pro5 *.pro6)' % translate('SongsPlugin.ImportWizardForm', 'ProPresenter Song Files')
'filter': '{text} (*.pro4 *.pro5 *.pro6)'.format(text=translate('SongsPlugin.ImportWizardForm',
'ProPresenter Song Files'))
},
SongBeamer: {
'class': SongBeamerImport,
'name': 'SongBeamer',
'prefix': 'songBeamer',
'filter': '%s (*.sng)' % translate('SongsPlugin.ImportWizardForm', 'SongBeamer Files')
'filter': '{text} (*.sng)'.format(text=translate('SongsPlugin.ImportWizardForm',
'SongBeamer Files'))
},
SongPro: {
'class': SongProImport,
'name': 'SongPro',
'prefix': 'songPro',
'selectMode': SongFormatSelect.SingleFile,
'filter': '%s (*.txt)' % translate('SongsPlugin.ImportWizardForm', 'SongPro Text Files'),
'filter': '{text} (*.txt)'.format(text=translate('SongsPlugin.ImportWizardForm', 'SongPro Text Files')),
'comboBoxText': translate('SongsPlugin.ImportWizardForm', 'SongPro (Export File)'),
'descriptionText': translate('SongsPlugin.ImportWizardForm',
'In SongPro, export your songs using the File -> Export menu')
@ -337,13 +344,15 @@ class SongFormat(object):
'class': SongShowPlusImport,
'name': 'SongShow Plus',
'prefix': 'songShowPlus',
'filter': '%s (*.sbsong)' % translate('SongsPlugin.ImportWizardForm', 'SongShow Plus Song Files')
'filter': '{text} (*.sbsong)'.format(text=translate('SongsPlugin.ImportWizardForm',
'SongShow Plus Song Files'))
},
SongsOfFellowship: {
'name': 'Songs of Fellowship',
'prefix': 'songsOfFellowship',
'canDisable': True,
'filter': '%s (*.rtf)' % translate('SongsPlugin.ImportWizardForm', 'Songs Of Fellowship Song Files'),
'filter': '{text} (*.rtf)'.format(text=translate('SongsPlugin.ImportWizardForm',
'Songs Of Fellowship Song Files')),
'disabledLabelText': translate('SongsPlugin.ImportWizardForm',
'The Songs of Fellowship importer has been disabled because '
'OpenLP cannot access OpenOffice or LibreOffice.')
@ -352,30 +361,33 @@ class SongFormat(object):
'class': SundayPlusImport,
'name': 'SundayPlus',
'prefix': 'sundayPlus',
'filter': '%s (*.ptf)' % translate('SongsPlugin.ImportWizardForm', 'SundayPlus Song Files')
'filter': '{text} (*.ptf)'.format(text=translate('SongsPlugin.ImportWizardForm', 'SundayPlus Song Files'))
},
VideoPsalm: {
'class': VideoPsalmImport,
'name': 'VideoPsalm',
'prefix': 'videopsalm',
'selectMode': SongFormatSelect.SingleFile,
'filter': '%s (*.json)' % translate('SongsPlugin.ImportWizardForm', 'VideoPsalm Files'),
'filter': '{text} (*.json)'.format(text=translate('SongsPlugin.ImportWizardForm', 'VideoPsalm Files')),
'comboBoxText': translate('SongsPlugin.ImportWizardForm', 'VideoPsalm'),
'descriptionText': translate('SongsPlugin.ImportWizardForm', 'The VideoPsalm songbooks are normally located'
' in %s') % 'C:\\Users\\Public\\Documents\\VideoPsalm\\SongBooks\\'
' in {path}').format(path='C:\\Users\\Public\\Documents\\VideoPsalm'
'\\SongBooks\\')
},
WordsOfWorship: {
'class': WordsOfWorshipImport,
'name': 'Words of Worship',
'prefix': 'wordsOfWorship',
'filter': '%s (*.wsg *.wow-song)' % translate('SongsPlugin.ImportWizardForm', 'Words Of Worship Song Files')
'filter': '{text} (*.wsg *.wow-song)'.format(text=translate('SongsPlugin.ImportWizardForm',
'Words Of Worship Song Files'))
},
WorshipAssistant: {
'class': WorshipAssistantImport,
'name': 'Worship Assistant 0',
'prefix': 'worshipAssistant',
'selectMode': SongFormatSelect.SingleFile,
'filter': '%s (*.csv)' % translate('SongsPlugin.ImportWizardForm', 'Worship Assistant Files'),
'filter': '{text} (*.csv)'.format(text=translate('SongsPlugin.ImportWizardForm',
'Worship Assistant Files')),
'comboBoxText': translate('SongsPlugin.ImportWizardForm', 'Worship Assistant (CSV)'),
'descriptionText': translate('SongsPlugin.ImportWizardForm',
'In Worship Assistant, export your Database to a CSV file.')
@ -385,7 +397,8 @@ class SongFormat(object):
'prefix': 'worshipCenterPro',
'canDisable': True,
'selectMode': SongFormatSelect.SingleFile,
'filter': '%s (*.mdb)' % translate('SongsPlugin.ImportWizardForm', 'WorshipCenter Pro Song Files'),
'filter': '{text} (*.mdb)'.format(text=translate('SongsPlugin.ImportWizardForm',
'WorshipCenter Pro Song Files')),
'disabledLabelText': translate('SongsPlugin.ImportWizardForm',
'The WorshipCenter Pro importer is only supported on Windows. It has been '
'disabled due to a missing Python module. If you want to use this '

View File

@ -58,7 +58,7 @@ class CCLIFileImport(SongImport):
self.import_wizard.progress_bar.setMaximum(len(self.import_source))
for filename in self.import_source:
filename = str(filename)
log.debug('Importing CCLI File: %s', filename)
log.debug('Importing CCLI File: {name}'.format(name=filename))
if os.path.isfile(filename):
detect_file = open(filename, 'rb')
detect_content = detect_file.read(2048)
@ -76,17 +76,17 @@ class CCLIFileImport(SongImport):
infile.close()
ext = os.path.splitext(filename)[1]
if ext.lower() == '.usr' or ext.lower() == '.bin':
log.info('SongSelect USR format file found: %s', filename)
log.info('SongSelect USR format file found: {name}'.format(name=filename))
if not self.do_import_usr_file(lines):
self.log_error(filename)
elif ext.lower() == '.txt':
log.info('SongSelect TEXT format file found: %s', filename)
log.info('SongSelect TEXT format file found: {name}'.format(name=filename))
if not self.do_import_txt_file(lines):
self.log_error(filename)
else:
self.log_error(filename, translate('SongsPlugin.CCLIFileImport', 'The file does not have a valid '
'extension.'))
log.info('Extension %s is not valid', filename)
log.info('Extension {name} is not valid'.format(name=filename))
if self.stop_import_flag:
return
@ -146,7 +146,7 @@ class CCLIFileImport(SongImport):
:param text_list: An array of strings containing the usr file content.
"""
log.debug('USR file text: %s', text_list)
log.debug('USR file text: {text}'.format(text=text_list))
song_author = ''
song_topics = ''
for line in text_list:
@ -193,7 +193,7 @@ class CCLIFileImport(SongImport):
if check_first_verse_line:
if verse_lines[0].startswith('(PRE-CHORUS'):
verse_type = VerseType.tags[VerseType.PreChorus]
log.debug('USR verse PRE-CHORUS: %s', verse_lines[0])
log.debug('USR verse PRE-CHORUS: {lines}'.format(lines=verse_lines[0]))
verse_text = verse_lines[1]
elif verse_lines[0].startswith('(BRIDGE'):
verse_type = VerseType.tags[VerseType.Bridge]
@ -248,7 +248,7 @@ class CCLIFileImport(SongImport):
# e.g. CCLI-Liedlizenznummer: 14 / CCLI License No. 14
"""
log.debug('TXT file text: %s', text_list)
log.debug('TXT file text: {text}'.format(text=text_list))
line_number = 0
check_first_verse_line = False
verse_text = ''

View File

@ -90,7 +90,7 @@ class DreamBeamImport(SongImport):
try:
parsed_file = etree.parse(open(file, 'r'), parser)
except etree.XMLSyntaxError:
log.exception('XML syntax error in file %s' % file)
log.exception('XML syntax error in file {name}'.format(name=file))
self.log_error(file, SongStrings.XMLSyntaxError)
continue
xml = etree.tostring(parsed_file).decode()
@ -115,15 +115,17 @@ class DreamBeamImport(SongImport):
verse_type = lyrics_item.get('Type')
verse_number = lyrics_item.get('Number')
verse_text = str(lyrics_item.text)
self.add_verse(verse_text, ('%s%s' % (verse_type[:1], verse_number)))
self.add_verse(verse_text,
'{verse}{number}'.format(verse=verse_type[:1], number=verse_number))
if hasattr(song_xml, 'Collection'):
self.song_book_name = str(song_xml.Collection.text)
if hasattr(song_xml, 'Number'):
self.song_number = str(song_xml.Number.text)
if hasattr(song_xml, 'Sequence'):
for lyrics_sequence_item in (song_xml.Sequence.iterchildren()):
self.verse_order_list.append("%s%s" % (lyrics_sequence_item.get('Type')[:1],
lyrics_sequence_item.get('Number')))
item = lyrics_sequence_item.get('Type')[:1]
self.verse_order_list.append("{item}{number}".format(item=item),
lyrics_sequence_item.get('Number'))
if hasattr(song_xml, 'Notes'):
self.comments = str(song_xml.Notes.text)
else:

View File

@ -45,7 +45,7 @@ class EasySlidesImport(SongImport):
super(EasySlidesImport, self).__init__(manager, **kwargs)
def do_import(self):
log.info('Importing EasySlides XML file %s', self.import_source)
log.info('Importing EasySlides XML file {source}'.format(source=self.import_source))
parser = etree.XMLParser(remove_blank_text=True)
parsed_file = etree.parse(self.import_source, parser)
xml = etree.tostring(parsed_file).decode()
@ -96,10 +96,10 @@ class EasySlidesImport(SongImport):
try:
setattr(self, self_attribute, str(import_attribute).strip())
except UnicodeDecodeError:
log.exception('UnicodeDecodeError decoding %s' % import_attribute)
log.exception('UnicodeDecodeError decoding {attribute}'.format(attribute=import_attribute))
self._success = False
except AttributeError:
log.exception('No attribute %s' % import_attribute)
log.exception('No attribute {attribute}'.format(attribute=import_attribute))
if mandatory:
self._success = False
@ -119,7 +119,7 @@ class EasySlidesImport(SongImport):
try:
self.add_copyright(str(element).strip())
except UnicodeDecodeError:
log.exception('Unicode error on decoding copyright: %s' % element)
log.exception('Unicode error on decoding copyright: {element}'.format(element=element))
self._success = False
except AttributeError:
pass
@ -157,9 +157,10 @@ class EasySlidesImport(SongImport):
separators = (separator_lines > 0)
# the number of different regions in song - 1
if len(region_lines) > 1:
log.info('EasySlidesImport: the file contained a song named "%s"'
'with more than two regions, but only two regions are tested, encountered regions were: %s',
self.title, ','.join(list(region_lines.keys())))
log.info('EasySlidesImport: the file contained a song named "{title}"'
'with more than two regions, but only two regions are tested, '
'encountered regions were: {keys}'.format(title=self.title,
keys=','.join(list(region_lines.keys()))))
# if the song has regions
regions = (len(region_lines) > 0)
# if the regions are inside verses
@ -232,7 +233,7 @@ class EasySlidesImport(SongImport):
for [reg, vt, vn, inst] in our_verse_order:
if self._list_has(verses, [reg, vt, vn, inst]):
# this is false, but needs user input
versetag = '%s%s' % (vt, vn)
versetag = '{tag}{number}'.format(tag=vt, number=vn)
versetags.append(versetag)
lines = '\n'.join(verses[reg][vt][vn][inst])
self.add_verse(lines, versetag)
@ -259,7 +260,8 @@ class EasySlidesImport(SongImport):
if tag in versetags:
self.verse_order_list.append(tag)
else:
log.info('Got order item %s, which is not in versetags, dropping item from presentation order', tag)
log.info('Got order item {tag}, which is not in versetags, dropping item from presentation '
'order'.format(tag=tag))
except UnicodeDecodeError:
log.exception('Unicode decode error while decoding Sequence')
self._success = False

View File

@ -171,15 +171,16 @@ class EasyWorshipSongImport(SongImport):
if copyright:
self.copyright += ', '
self.copyright += translate('SongsPlugin.EasyWorshipSongImport',
'Administered by %s') % admin
'Administered by {admin}').format(admin=admin)
# Set the SongImport object members.
self.set_song_import_object(authors, inflated_content)
if self.stop_import_flag:
break
if self.entry_error_log:
self.log_error(self.import_source,
translate('SongsPlugin.EasyWorshipSongImport', '"%s" could not be imported. %s')
% (self.title, self.entry_error_log))
translate('SongsPlugin.EasyWorshipSongImport',
'"{title}" could not be imported. {entry}').format(title=self.title,
entry=self.entry_error_log))
self.entry_error_log = ''
elif not self.finish():
self.log_error(self.import_source)
@ -306,7 +307,7 @@ class EasyWorshipSongImport(SongImport):
if copy:
self.copyright += ', '
self.copyright += translate('SongsPlugin.EasyWorshipSongImport',
'Administered by %s') % admin.decode(self.encoding)
'Administered by {admin}').format(admin=admin.decode(self.encoding))
if ccli:
self.ccli_number = ccli.decode(self.encoding)
if authors:
@ -319,15 +320,17 @@ class EasyWorshipSongImport(SongImport):
break
if self.entry_error_log:
self.log_error(self.import_source,
translate('SongsPlugin.EasyWorshipSongImport', '"%s" could not be imported. %s')
% (self.title, self.entry_error_log))
translate('SongsPlugin.EasyWorshipSongImport',
'"{title}" could not be imported. '
'{entry}').format(title=self.title, entry=self.entry_error_log))
self.entry_error_log = ''
elif not self.finish():
self.log_error(self.import_source)
except Exception as e:
self.log_error(self.import_source,
translate('SongsPlugin.EasyWorshipSongImport', '"%s" could not be imported. %s')
% (self.title, e))
translate('SongsPlugin.EasyWorshipSongImport',
'"{title}" could not be imported. {error}').format(title=self.title,
error=e))
db_file.close()
self.memo_file.close()
@ -421,7 +424,7 @@ class EasyWorshipSongImport(SongImport):
fsl = ['>']
for field_desc in field_descriptions:
if field_desc.field_type == FieldType.String:
fsl.append('%ds' % field_desc.size)
fsl.append('{size:d}s'.format(size=field_desc.size))
elif field_desc.field_type == FieldType.Int16:
fsl.append('H')
elif field_desc.field_type == FieldType.Int32:
@ -429,13 +432,13 @@ class EasyWorshipSongImport(SongImport):
elif field_desc.field_type == FieldType.Logical:
fsl.append('B')
elif field_desc.field_type == FieldType.Memo:
fsl.append('%ds' % field_desc.size)
fsl.append('{size:d}s'.format(size=field_desc.size))
elif field_desc.field_type == FieldType.Blob:
fsl.append('%ds' % field_desc.size)
fsl.append('{size:d}s'.format(size=field_desc.size))
elif field_desc.field_type == FieldType.Timestamp:
fsl.append('Q')
else:
fsl.append('%ds' % field_desc.size)
fsl.append('{size:d}s'.format(size=field_desc.size))
self.record_structure = struct.Struct(''.join(fsl))
self.field_descriptions = field_descriptions

View File

@ -121,6 +121,7 @@ class FoilPresenterImport(SongImport):
for file_path in self.import_source:
if self.stop_import_flag:
return
# TODO: Verify format() with template strings
self.import_wizard.increment_progress_bar(WizardStrings.ImportingType % os.path.basename(file_path))
try:
parsed_file = etree.parse(file_path, parser)
@ -128,7 +129,7 @@ class FoilPresenterImport(SongImport):
self.foil_presenter.xml_to_song(xml)
except etree.XMLSyntaxError:
self.log_error(file_path, SongStrings.XMLSyntaxError)
log.exception('XML syntax error in file %s' % file_path)
log.exception('XML syntax error in file {path}'.format(path=file_path))
class FoilPresenter(object):

View File

@ -102,8 +102,8 @@ class LyrixImport(SongImport):
else:
current_verse += '\n' + line
except Exception as e:
self.log_error(translate('SongsPlugin.LyrixImport', 'File %s' % file.name),
translate('SongsPlugin.LyrixImport', 'Error: %s') % e)
self.log_error(translate('SongsPlugin.LyrixImport', 'File {name}').format(name=file.name),
translate('SongsPlugin.LyrixImport', 'Error: {error}').format(error=e))
return
self.title = song_title
self.parse_author(author)

View File

@ -23,6 +23,10 @@
The :mod:`mediashout` module provides the functionality for importing
a MediaShout database into the OpenLP database.
"""
# WARNING: See https://docs.python.org/2/library/sqlite3.html for value substitution
# in SQL statements
import pyodbc
from openlp.core.lib import translate
@ -47,8 +51,8 @@ class MediaShoutImport(SongImport):
Receive a single file to import.
"""
try:
conn = pyodbc.connect('DRIVER={Microsoft Access Driver (*.mdb)};DBQ=%s;PWD=6NOZ4eHK7k' %
self.import_source)
conn = pyodbc.connect('DRIVER={Microsoft Access Driver (*.mdb)};DBQ={source};'
'PWD=6NOZ4eHK7k'.format(sorce=self.import_source))
except:
# Unfortunately no specific exception type
self.log_error(self.import_source, translate('SongsPlugin.MediaShoutImport',
@ -61,16 +65,15 @@ class MediaShoutImport(SongImport):
for song in songs:
if self.stop_import_flag:
break
cursor.execute('SELECT Type, Number, Text FROM Verses WHERE Record = %s ORDER BY Type, Number'
% song.Record)
cursor.execute('SELECT Type, Number, Text FROM Verses WHERE Record = ? ORDER BY Type, Number', song.Record)
verses = cursor.fetchall()
cursor.execute('SELECT Type, Number, POrder FROM PlayOrder WHERE Record = %s ORDER BY POrder' % song.Record)
cursor.execute('SELECT Type, Number, POrder FROM PlayOrder WHERE Record = ? ORDER BY POrder', song.Record)
verse_order = cursor.fetchall()
cursor.execute('SELECT Name FROM Themes INNER JOIN SongThemes ON SongThemes.ThemeId = Themes.ThemeId '
'WHERE SongThemes.Record = %s' % song.Record)
'WHERE SongThemes.Record = ?', song.Record)
topics = cursor.fetchall()
cursor.execute('SELECT Name FROM Groups INNER JOIN SongGroups ON SongGroups.GroupId = Groups.GroupId '
'WHERE SongGroups.Record = %s' % song.Record)
'WHERE SongGroups.Record = ?', song.Record)
topics += cursor.fetchall()
self.process_song(song, verses, verse_order, topics)

View File

@ -102,7 +102,7 @@ class OpenLPSongImport(SongImport):
self.log_error(self.import_source, translate('SongsPlugin.OpenLPSongImport',
'Not a valid OpenLP 2 song database.'))
return
self.import_source = 'sqlite:///%s' % self.import_source
self.import_source = 'sqlite:///{url}'.format(url=self.import_source)
# Load the db file and reflect it
engine = create_engine(self.import_source)
source_meta = MetaData()
@ -239,8 +239,10 @@ class OpenLPSongImport(SongImport):
self.manager.save_object(new_song)
if progress_dialog:
progress_dialog.setValue(progress_dialog.value() + 1)
# TODO: Verify format() with template strings
progress_dialog.setLabelText(WizardStrings.ImportingType % new_song.title)
else:
# TODO: Verify format() with template strings
self.import_wizard.increment_progress_bar(WizardStrings.ImportingType % new_song.title)
if self.stop_import_flag:
break

View File

@ -58,6 +58,7 @@ class OpenLyricsImport(SongImport):
for file_path in self.import_source:
if self.stop_import_flag:
return
# TODO: Verify format() with template strings
self.import_wizard.increment_progress_bar(WizardStrings.ImportingType % os.path.basename(file_path))
try:
# Pass a file object, because lxml does not cope with some
@ -66,9 +67,10 @@ class OpenLyricsImport(SongImport):
xml = etree.tostring(parsed_file).decode()
self.open_lyrics.xml_to_song(xml)
except etree.XMLSyntaxError:
log.exception('XML syntax error in file %s' % file_path)
log.exception('XML syntax error in file {path}'.format(file_path))
self.log_error(file_path, SongStrings.XMLSyntaxError)
except OpenLyricsError as exception:
log.exception('OpenLyricsException %d in file %s: %s' %
(exception.type, file_path, exception.log_message))
log.exception('OpenLyricsException {error:d} in file {name}: {text}'.format(error=exception.type,
name=file_path,
text=exception.log_message))
self.log_error(file_path, exception.display_message)

View File

@ -161,7 +161,7 @@ class OpenOfficeImport(SongImport):
else:
self.import_wizard.increment_progress_bar('Processing file ' + file_path, 0)
except AttributeError:
log.exception("open_ooo_file failed: %s", url)
log.exception("open_ooo_file failed: {url}".format(url=url))
return
def create_property(self, name, value):

View File

@ -254,8 +254,8 @@ class OpenSongImport(SongImport):
length = 0
while length < len(verse_num) and verse_num[length].isnumeric():
length += 1
verse_def = '%s%s' % (verse_tag, verse_num[:length])
verse_joints[verse_def] = '%s\n[---]\n%s' % (verse_joints[verse_def], lines) \
verse_def = '{tag}{number}'.format(tag=verse_tag, number=verse_num[:length])
verse_joints[verse_def] = '{verse}\n[---]\n{lines}'.format(verse=verse_joints[verse_def], lines=lines) \
if verse_def in verse_joints else lines
# Parsing the dictionary produces the elements in a non-intuitive order. While it "works", it's not a
# natural layout should the user come back to edit the song. Instead we sort by the verse type, so that we
@ -287,11 +287,11 @@ class OpenSongImport(SongImport):
verse_num = '1'
verse_index = VerseType.from_loose_input(verse_tag)
verse_tag = VerseType.tags[verse_index]
verse_def = '%s%s' % (verse_tag, verse_num)
verse_def = '{tag}{number}'.format(tag=verse_tag, number=verse_num)
if verse_num in verses.get(verse_tag, {}):
self.verse_order_list.append(verse_def)
else:
log.info('Got order %s but not in verse tags, dropping this item from presentation order',
verse_def)
log.info('Got order {order} but not in verse tags, dropping this item from presentation '
'order'.format(order=verse_def))
if not self.finish():
self.log_error(file.name)

View File

@ -23,6 +23,10 @@
The :mod:`opspro` module provides the functionality for importing
a OPS Pro database into the OpenLP database.
"""
# WARNING: See https://docs.python.org/2/library/sqlite3.html for value substitution
# in SQL statements
import logging
import re
import pyodbc
@ -51,10 +55,11 @@ class OPSProImport(SongImport):
"""
password = self.extract_mdb_password()
try:
conn = pyodbc.connect('DRIVER={Microsoft Access Driver (*.mdb)};DBQ=%s;PWD=%s' % (self.import_source,
password))
conn = pyodbc.connect('DRIVER={Microsoft Access Driver (*.mdb)};DBQ={source};'
'PWD={password}'.format(source=self.import_source, password=password))
except (pyodbc.DatabaseError, pyodbc.IntegrityError, pyodbc.InternalError, pyodbc.OperationalError) as e:
log.warning('Unable to connect the OPS Pro database %s. %s', self.import_source, str(e))
log.warning('Unable to connect the OPS Pro database {source}. {error}'.format(source=self.import_source,
error=str(e)))
# Unfortunately no specific exception type
self.log_error(self.import_source, translate('SongsPlugin.OPSProImport',
'Unable to connect the OPS Pro database.'))
@ -68,19 +73,19 @@ class OPSProImport(SongImport):
if self.stop_import_flag:
break
# Type means: 0=Original, 1=Projection, 2=Own
cursor.execute('SELECT Lyrics, Type, IsDualLanguage FROM Lyrics WHERE SongID = %d AND Type < 2 '
'ORDER BY Type DESC' % song.ID)
cursor.execute('SELECT Lyrics, Type, IsDualLanguage FROM Lyrics WHERE SongID = ? AND Type < 2 '
'ORDER BY Type DESC', song.ID)
lyrics = cursor.fetchone()
cursor.execute('SELECT CategoryName FROM Category INNER JOIN SongCategory '
'ON Category.ID = SongCategory.CategoryID WHERE SongCategory.SongID = %d '
'ORDER BY CategoryName' % song.ID)
'ON Category.ID = SongCategory.CategoryID WHERE SongCategory.SongID = ? '
'ORDER BY CategoryName', song.ID)
topics = cursor.fetchall()
try:
self.process_song(song, lyrics, topics)
except Exception as e:
self.log_error(self.import_source,
translate('SongsPlugin.OPSProImport', '"%s" could not be imported. %s')
% (song.Title, e))
translate('SongsPlugin.OPSProImport',
'"{title}" could not be imported. {error}').format(title=song.Title, error=e))
def process_song(self, song, lyrics, topics):
"""

View File

@ -41,6 +41,7 @@ class PowerPraiseImport(SongImport):
for file_path in self.import_source:
if self.stop_import_flag:
return
# TODO: Verify format() with template strings
self.import_wizard.increment_progress_bar(WizardStrings.ImportingType % os.path.basename(file_path))
root = objectify.parse(open(file_path, 'rb')).getroot()
self.process_song(root)
@ -66,7 +67,7 @@ class PowerPraiseImport(SongImport):
else:
verse_def = 'o'
verse_count[verse_def] = verse_count.get(verse_def, 0) + 1
verse_def = '%s%d' % (verse_def, verse_count[verse_def])
verse_def = '{verse}{count:d}'.format(verse=verse_def, count=verse_count[verse_def])
verse_text = []
for slide in part.slide:
if not hasattr(slide, 'line'):

View File

@ -96,7 +96,7 @@ class PowerSongImport(SongImport):
self.import_source = ''
if not self.import_source or not isinstance(self.import_source, list):
self.log_error(translate('SongsPlugin.PowerSongImport', 'No songs to import.'),
translate('SongsPlugin.PowerSongImport', 'No %s files found.') % ps_string)
translate('SongsPlugin.PowerSongImport', 'No {text} files found.').format(text=ps_string))
return
self.import_wizard.progress_bar.setMaximum(len(self.import_source))
for file in self.import_source:
@ -113,9 +113,9 @@ class PowerSongImport(SongImport):
field = self._read_string(song_data)
except ValueError:
parse_error = True
self.log_error(os.path.basename(file), str(
translate('SongsPlugin.PowerSongImport', 'Invalid %s file. Unexpected byte value.')) %
ps_string)
self.log_error(os.path.basename(file),
translate('SongsPlugin.PowerSongImport',
'Invalid {text} file. Unexpected byte value.').format(text=ps_string))
break
else:
if label == 'TITLE':
@ -131,19 +131,20 @@ class PowerSongImport(SongImport):
continue
# Check that file had TITLE field
if not self.title:
self.log_error(os.path.basename(file), str(
translate('SongsPlugin.PowerSongImport', 'Invalid %s file. Missing "TITLE" header.')) % ps_string)
self.log_error(os.path.basename(file),
translate('SongsPlugin.PowerSongImport',
'Invalid {text} file. Missing "TITLE" header.').format(text=ps_string))
continue
# Check that file had COPYRIGHTLINE label
if not found_copyright:
self.log_error(self.title, str(
translate('SongsPlugin.PowerSongImport', 'Invalid %s file. Missing "COPYRIGHTLINE" header.')) %
ps_string)
self.log_error(self.title,
translate('SongsPlugin.PowerSongImport',
'Invalid {text} file. Missing "COPYRIGHTLINE" header.').format(text=ps_string))
continue
# Check that file had at least one verse
if not self.verses:
self.log_error(self.title, str(
translate('SongsPlugin.PowerSongImport', 'Verses not found. Missing "PART" header.')))
self.log_error(self.title,
translate('SongsPlugin.PowerSongImport', 'Verses not found. Missing "PART" header.'))
continue
if not self.finish():
self.log_error(self.title)

View File

@ -44,6 +44,7 @@ class PresentationManagerImport(SongImport):
for file_path in self.import_source:
if self.stop_import_flag:
return
# TODO: Verify format() with template strings
self.import_wizard.increment_progress_bar(WizardStrings.ImportingType % os.path.basename(file_path))
try:
tree = etree.parse(file_path, parser=etree.XMLParser(recover=True))
@ -96,7 +97,7 @@ class PresentationManagerImport(SongImport):
verse_def = 'o'
if not is_duplicate: # Only increment verse number if no duplicate
verse_count[verse_def] = verse_count.get(verse_def, 0) + 1
verse_def = '%s%d' % (verse_def, verse_count[verse_def])
verse_def = '{verse}{count:d}'.format(verse=verse_def, count=verse_count[verse_def])
if not is_duplicate: # Only add verse if no duplicate
self.add_verse(str(verse).strip(), verse_def)
verse_order_list.append(verse_def)

View File

@ -46,6 +46,7 @@ class ProPresenterImport(SongImport):
for file_path in self.import_source:
if self.stop_import_flag:
return
# TODO: Verify format() with template strings
self.import_wizard.increment_progress_bar(WizardStrings.ImportingType % os.path.basename(file_path))
root = objectify.parse(open(file_path, 'rb')).getroot()
self.process_song(root, file_path)
@ -87,7 +88,7 @@ class ProPresenterImport(SongImport):
RTFData = slide.displayElements.RVTextElement.get('RTFData')
rtf = base64.standard_b64decode(RTFData)
words, encoding = strip_rtf(rtf.decode())
self.add_verse(words, "v%d" % count)
self.add_verse(words, "v{count}".format(count=count))
# ProPresenter 5
elif(self.version >= 500 and self.version < 600):
@ -103,7 +104,7 @@ class ProPresenterImport(SongImport):
RTFData = slide.displayElements.RVTextElement.get('RTFData')
rtf = base64.standard_b64decode(RTFData)
words, encoding = strip_rtf(rtf.decode())
self.add_verse(words, "v%d" % count)
self.add_verse(words, "v{count:d}".format(count=count))
# ProPresenter 6
elif(self.version >= 600 and self.version < 700):
@ -127,7 +128,7 @@ class ProPresenterImport(SongImport):
words, encoding = strip_rtf(data.decode())
break
if words:
self.add_verse(words, "v%d" % count)
self.add_verse(words, "v{count:d}".format(count=count))
if not self.finish():
self.log_error(self.import_source)

View File

@ -117,7 +117,7 @@ class SongImport(QtCore.QObject):
self.import_wizard.error_report_text_edit.setVisible(True)
self.import_wizard.error_copy_to_button.setVisible(True)
self.import_wizard.error_save_to_button.setVisible(True)
self.import_wizard.error_report_text_edit.append('- %s (%s)' % (file_path, reason))
self.import_wizard.error_report_text_edit.append('- {path} ({error})'.format(path=file_path, error=reason))
def stop_import(self):
"""
@ -326,10 +326,11 @@ class SongImport(QtCore.QObject):
if not self.check_complete():
self.set_defaults()
return False
log.info('committing song %s to database', self.title)
log.info('committing song {title} to database'.format(title=self.title))
song = Song()
song.title = self.title
if self.import_wizard is not None:
# TODO: Verify format() with template variables
self.import_wizard.increment_progress_bar(WizardStrings.ImportingType % song.title)
song.alternate_title = self.alternate_title
# Values will be set when cleaning the song.
@ -344,11 +345,11 @@ class SongImport(QtCore.QObject):
if verse_def[0].lower() in VerseType.tags:
verse_tag = verse_def[0].lower()
else:
new_verse_def = '%s%d' % (VerseType.tags[VerseType.Other], other_count)
new_verse_def = '{tag}{count:d}'.format(tag=VerseType.tags[VerseType.Other], count=other_count)
verses_changed_to_other[verse_def] = new_verse_def
other_count += 1
verse_tag = VerseType.tags[VerseType.Other]
log.info('Versetype %s changing to %s', verse_def, new_verse_def)
log.info('Versetype {old} changing to {new}'.format(old=verse_def, new=new_verse_def))
verse_def = new_verse_def
sxml.add_verse_to_lyrics(verse_tag, verse_def[1:], verse_text, lang)
song.lyrics = str(sxml.extract_xml(), 'utf-8')

View File

@ -101,6 +101,7 @@ class SongShowPlusImport(SongImport):
self.other_count = 0
self.other_list = {}
file_name = os.path.split(file)[1]
# TODO: Verify format() with template variables
self.import_wizard.increment_progress_bar(WizardStrings.ImportingType % file_name, 0)
song_data = open(file, 'rb')
while True:
@ -153,13 +154,16 @@ class SongShowPlusImport(SongImport):
if match:
self.ccli_number = int(match.group())
else:
log.warning("Can't parse CCLI Number from string: %s" % self.decode(data))
log.warning("Can't parse CCLI Number from string: {text}".format(text=self.decode(data)))
elif block_key == VERSE:
self.add_verse(self.decode(data), "%s%s" % (VerseType.tags[VerseType.Verse], verse_no))
self.add_verse(self.decode(data), "{tag}{number}".format(tag=VerseType.tags[VerseType.Verse],
number=verse_no))
elif block_key == CHORUS:
self.add_verse(self.decode(data), "%s%s" % (VerseType.tags[VerseType.Chorus], verse_no))
self.add_verse(self.decode(data), "{tag}{number}".format(tag=VerseType.tags[VerseType.Chorus],
number=verse_no))
elif block_key == BRIDGE:
self.add_verse(self.decode(data), "%s%s" % (VerseType.tags[VerseType.Bridge], verse_no))
self.add_verse(self.decode(data), "{tag}{number}".format(tag=VerseType.tags[VerseType.Bridge],
number=verse_no))
elif block_key == TOPIC:
self.topics.append(self.decode(data))
elif block_key == COMMENTS:
@ -176,7 +180,7 @@ class SongShowPlusImport(SongImport):
verse_tag = self.to_openlp_verse_tag(verse_name)
self.add_verse(self.decode(data), verse_tag)
else:
log.debug("Unrecognised blockKey: %s, data: %s" % (block_key, data))
log.debug("Unrecognised blockKey: {key}, data: {data}".format(key=block_key, data=data))
song_data.seek(next_block_starts)
self.verse_order_list = self.ssp_verse_order_list
song_data.close()

View File

@ -141,7 +141,7 @@ class SundayPlusImport(SongImport):
if len(value):
verse_type = VerseType.tags[VerseType.from_loose_input(value[0])]
if len(value) >= 2 and value[-1] in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']:
verse_type = "%s%s" % (verse_type, value[-1])
verse_type = "{verse}{value}".format(verse=verse_type, value=value[-1])
elif name == 'HOTKEY':
value = self.decode(value).strip()
# HOTKEY always appears after MARKER_NAME, so it

View File

@ -115,7 +115,7 @@ class VideoPsalmImport(SongImport):
for verse in song['Verses']:
self.add_verse(verse['Text'], 'v')
if not self.finish():
self.log_error('Could not import %s' % self.title)
self.log_error('Could not import {title}'.format(title=self.title))
except Exception as e:
self.log_error(song_file.name, translate('SongsPlugin.VideoPsalmImport', 'Error: %s') % e)
song_file.close()
self.log_error(song_file.name, translate('SongsPlugin.VideoPsalmImport', 'Error: {error}').format(error=e))

View File

@ -108,8 +108,8 @@ class WordsOfWorshipImport(SongImport):
if song_data.read(19).decode() != 'WoW File\nSong Words':
self.log_error(source,
translate('SongsPlugin.WordsofWorshipSongImport',
'Invalid Words of Worship song file. Missing "%s" header.')
% 'WoW File\\nSong Words')
'Invalid Words of Worship song file. Missing "{text}" '
'header.').format(text='WoW File\\nSong Words'))
continue
# Seek to byte which stores number of blocks in the song
song_data.seek(56)
@ -118,8 +118,8 @@ class WordsOfWorshipImport(SongImport):
if song_data.read(16).decode() != 'CSongDoc::CBlock':
self.log_error(source,
translate('SongsPlugin.WordsofWorshipSongImport',
'Invalid Words of Worship song file. Missing "%s" string.')
% 'CSongDoc::CBlock')
'Invalid Words of Worship song file. Missing "{text}" '
'string.').format(text='CSongDoc::CBlock'))
continue
# Seek to the beginning of the first block
song_data.seek(82)

View File

@ -91,11 +91,11 @@ class WorshipAssistantImport(SongImport):
records = list(songs_reader)
except csv.Error as e:
self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Error reading CSV file.'),
translate('SongsPlugin.WorshipAssistantImport', 'Line %d: %s') %
(songs_reader.line_num, e))
translate('SongsPlugin.WorshipAssistantImport',
'Line {number:d}: {error}').format(number=songs_reader.line_num, error=e))
return
num_records = len(records)
log.info('%s records found in CSV file' % num_records)
log.info('{count} records found in CSV file'.format(count=num_records))
self.import_wizard.progress_bar.setMaximum(num_records)
# Create regex to strip html tags
re_html_strip = re.compile(r'<[^>]+>')
@ -122,12 +122,14 @@ class WorshipAssistantImport(SongImport):
verse_order_list = [x.strip() for x in record['ROADMAP'].split(',')]
lyrics = record['LYRICS2']
except UnicodeDecodeError as e:
self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Record %d' % index),
translate('SongsPlugin.WorshipAssistantImport', 'Decoding error: %s') % e)
self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Record {count:d}').format(count=index),
translate('SongsPlugin.WorshipAssistantImport',
'Decoding error: {error}').format(error=e))
continue
except TypeError as e:
self.log_error(translate('SongsPlugin.WorshipAssistantImport',
'File not valid WorshipAssistant CSV format.'), 'TypeError: %s' % e)
'File not valid WorshipAssistant CSV format.'),
'TypeError: {error}'.format(error=e))
return
verse = ''
used_verses = []
@ -180,6 +182,7 @@ class WorshipAssistantImport(SongImport):
cleaned_verse_order_list.append(verse)
self.verse_order_list = cleaned_verse_order_list
if not self.finish():
self.log_error(translate('SongsPlugin.WorshipAssistantImport', 'Record %d') % index +
self.log_error(translate('SongsPlugin.WorshipAssistantImport',
'Record {count:d}').format(count=index) +
(': "' + self.title + '"' if self.title else ''))
songs_file.close()

View File

@ -49,9 +49,11 @@ class WorshipCenterProImport(SongImport):
Receive a single file to import.
"""
try:
conn = pyodbc.connect('DRIVER={Microsoft Access Driver (*.mdb)};DBQ=%s' % self.import_source)
conn = pyodbc.connect('DRIVER={Microsoft Access Driver (*.mdb)};'
'DBQ={source}'.format(source=self.import_source))
except (pyodbc.DatabaseError, pyodbc.IntegrityError, pyodbc.InternalError, pyodbc.OperationalError) as e:
log.warning('Unable to connect the WorshipCenter Pro database %s. %s', self.import_source, str(e))
log.warning('Unable to connect the WorshipCenter Pro '
'database {source}. {error}'.format(source=self.import_source, error=str(e)))
# Unfortunately no specific exception type
self.log_error(self.import_source, translate('SongsPlugin.WorshipCenterProImport',
'Unable to connect the WorshipCenter Pro database.'))

View File

@ -84,10 +84,11 @@ class ZionWorxImport(SongImport):
records = list(songs_reader)
except csv.Error as e:
self.log_error(translate('SongsPlugin.ZionWorxImport', 'Error reading CSV file.'),
translate('SongsPlugin.ZionWorxImport', 'Line %d: %s') % (songs_reader.line_num, e))
translate('SongsPlugin.ZionWorxImport',
'Line {number:d}: {error}').format(number=songs_reader.line_num, error=e))
return
num_records = len(records)
log.info('%s records found in CSV file' % num_records)
log.info('{count} records found in CSV file'.format(count=num_records))
self.import_wizard.progress_bar.setMaximum(num_records)
for index, record in enumerate(records, 1):
if self.stop_import_flag:
@ -101,12 +102,12 @@ class ZionWorxImport(SongImport):
self.add_copyright(self._decode(record['Copyright']))
lyrics = self._decode(record['Lyrics'])
except UnicodeDecodeError as e:
self.log_error(translate('SongsPlugin.ZionWorxImport', 'Record %d' % index),
translate('SongsPlugin.ZionWorxImport', 'Decoding error: %s') % e)
self.log_error(translate('SongsPlugin.ZionWorxImport', 'Record {index}').format(index=index),
translate('SongsPlugin.ZionWorxImport', 'Decoding error: {error}').format(error=e))
continue
except TypeError as e:
self.log_error(translate(
'SongsPlugin.ZionWorxImport', 'File not valid ZionWorx CSV format.'), 'TypeError: %s' % e)
self.log_error(translate('SongsPlugin.ZionWorxImport', 'File not valid ZionWorx CSV format.'),
'TypeError: {error}'.format(error=e))
return
verse = ''
for line in lyrics.splitlines():

View File

@ -129,7 +129,7 @@ class SongMediaItem(MediaManagerItem):
self.display_copyright_symbol = Settings().value(self.settings_section + '/display copyright symbol')
def retranslateUi(self):
self.search_text_label.setText('%s:' % UiStrings().Search)
self.search_text_label.setText('{text}:'.format(text=UiStrings().Search))
self.search_text_button.setText(UiStrings().Search)
self.maintenance_action.setText(SongStrings.SongMaintenance)
self.maintenance_action.setToolTip(translate('SongsPlugin.MediaItem',
@ -166,12 +166,14 @@ class SongMediaItem(MediaManagerItem):
translate('SongsPlugin.MediaItem', 'CCLI number'),
translate('SongsPlugin.MediaItem', 'Search CCLI number...'))
])
self.search_text_edit.set_current_search_type(Settings().value('%s/last search type' % self.settings_section))
self.search_text_edit.set_current_search_type(
Settings().value('{section}/last search type'.format(section=self.settings_section)))
self.config_update()
def on_search_text_button_clicked(self):
# Save the current search type to the configuration.
Settings().setValue('%s/last search type' % self.settings_section, self.search_text_edit.current_search_type())
Settings().setValue('{section}/last search type'.format(section=self.settings_section),
self.search_text_edit.current_search_type())
# Reload the list considering the new search type.
search_keywords = str(self.search_text_edit.displayText())
search_type = self.search_text_edit.current_search_type()
@ -181,31 +183,31 @@ class SongMediaItem(MediaManagerItem):
self.display_results_song(search_results)
elif search_type == SongSearch.Titles:
log.debug('Titles Search')
search_string = '%' + clean_string(search_keywords) + '%'
search_string = '%{text}%'.format(text=clean_string(search_keywords))
search_results = self.plugin.manager.get_all_objects(Song, Song.search_title.like(search_string))
self.display_results_song(search_results)
elif search_type == SongSearch.Lyrics:
log.debug('Lyrics Search')
search_string = '%' + clean_string(search_keywords) + '%'
search_string = '%{text}%'.format(text=clean_string(search_keywords))
search_results = self.plugin.manager.get_all_objects(Song, Song.search_lyrics.like(search_string))
self.display_results_song(search_results)
elif search_type == SongSearch.Authors:
log.debug('Authors Search')
search_string = '%' + search_keywords + '%'
search_string = '%{text}%'.format(text=search_keywords)
search_results = self.plugin.manager.get_all_objects(
Author, Author.display_name.like(search_string))
self.display_results_author(search_results)
elif search_type == SongSearch.Topics:
log.debug('Topics Search')
search_string = '%' + search_keywords + '%'
search_string = '%{text}%'.format(text=search_keywords)
search_results = self.plugin.manager.get_all_objects(
Topic, Topic.name.like(search_string))
self.display_results_topic(search_results)
elif search_type == SongSearch.Books:
log.debug('Songbook Search')
search_keywords = search_keywords.rpartition(' ')
search_book = search_keywords[0] + '%'
search_entry = search_keywords[2] + '%'
search_book = '{text}%'.format(text=search_keywords[0])
search_entry = '{text}%'.format(text=search_keywords[2])
search_results = (self.plugin.manager.session.query(SongBookEntry.entry, Book.name, Song.title, Song.id)
.join(Song)
.join(Book)
@ -214,26 +216,26 @@ class SongMediaItem(MediaManagerItem):
self.display_results_book(search_results)
elif search_type == SongSearch.Themes:
log.debug('Theme Search')
search_string = '%' + search_keywords + '%'
search_string = '%{text}%'.format(text=search_keywords)
search_results = self.plugin.manager.get_all_objects(
Song, Song.theme_name.like(search_string))
self.display_results_themes(search_results)
elif search_type == SongSearch.Copyright:
log.debug('Copyright Search')
search_string = '%' + search_keywords + '%'
search_string = '%{text}%'.format(text=search_keywords)
search_results = self.plugin.manager.get_all_objects(
Song, and_(Song.copyright.like(search_string), Song.copyright != ''))
self.display_results_song(search_results)
elif search_type == SongSearch.CCLInumber:
log.debug('CCLI number Search')
search_string = '%' + search_keywords + '%'
search_string = '%{text}%'.format(text=search_keywords)
search_results = self.plugin.manager.get_all_objects(
Song, and_(Song.ccli_number.like(search_string), Song.ccli_number != ''))
self.display_results_cclinumber(search_results)
self.check_search_result()
def search_entire(self, search_keywords):
search_string = '%' + clean_string(search_keywords) + '%'
search_string = '%{text}%'.format(text=clean_string(search_keywords))
return self.plugin.manager.get_all_objects(
Song, or_(Song.search_title.like(search_string), Song.search_lyrics.like(search_string),
Song.comments.like(search_string)))
@ -272,7 +274,8 @@ class SongMediaItem(MediaManagerItem):
if song.temporary:
continue
author_list = [author.display_name for author in song.authors]
song_detail = '%s (%s)' % (song.title, create_separated_list(author_list)) if author_list else song.title
text = create_separated_list(author_list) if author_list else song.title
song_detail = '{title} ({author})'.format(title=song.title, author=text)
song_name = QtWidgets.QListWidgetItem(song_detail)
song_name.setData(QtCore.Qt.UserRole, song.id)
self.list_view.addItem(song_name)
@ -305,7 +308,7 @@ class SongMediaItem(MediaManagerItem):
# Do not display temporary songs
if song.temporary:
continue
song_detail = '%s (%s)' % (author.display_name, song.title)
song_detail = '{author} ({title})'.format(author=author.display_name, title=song.title)
song_name = QtWidgets.QListWidgetItem(song_detail)
song_name.setData(QtCore.Qt.UserRole, song.id)
self.list_view.addItem(song_name)
@ -325,7 +328,8 @@ class SongMediaItem(MediaManagerItem):
self.list_view.clear()
search_results.sort(key=get_songbook_key)
for result in search_results:
song_detail = '%s #%s: %s' % (result[1], result[0], result[2])
song_detail = '{result1} #{result0}: {result2}'.format(result1=result[1], result0=result[0],
result2=result[2])
song_name = QtWidgets.QListWidgetItem(song_detail)
song_name.setData(QtCore.Qt.UserRole, result[3])
self.list_view.addItem(song_name)
@ -354,7 +358,7 @@ class SongMediaItem(MediaManagerItem):
# Do not display temporary songs
if song.temporary:
continue
song_detail = '%s (%s)' % (topic.name, song.title)
song_detail = '{topic} ({title})'.format(topic=topic.name, title=song.title)
song_name = QtWidgets.QListWidgetItem(song_detail)
song_name.setData(QtCore.Qt.UserRole, song.id)
self.list_view.addItem(song_name)
@ -377,7 +381,7 @@ class SongMediaItem(MediaManagerItem):
# Do not display temporary songs
if song.temporary:
continue
song_detail = '%s (%s)' % (song.theme_name, song.title)
song_detail = '{theme} ({song})'.format(theme=song.theme_name, song=song.title)
song_name = QtWidgets.QListWidgetItem(song_detail)
song_name.setData(QtCore.Qt.UserRole, song.id)
self.list_view.addItem(song_name)
@ -400,7 +404,7 @@ class SongMediaItem(MediaManagerItem):
# Do not display temporary songs
if song.temporary:
continue
song_detail = '%s (%s)' % (song.ccli_number, song.title)
song_detail = '{ccli} ({song})'.format(ccli=song.ccli_number, song=song.title)
song_name = QtWidgets.QListWidgetItem(song_detail)
song_name.setData(QtCore.Qt.UserRole, song.id)
self.list_view.addItem(song_name)
@ -456,7 +460,7 @@ class SongMediaItem(MediaManagerItem):
Called by ServiceManager or SlideController by event passing the Song Id in the payload along with an indicator
to say which type of display is required.
"""
log.debug('on_remote_edit for song %s' % song_id)
log.debug('on_remote_edit for song {song}'.format(song=song_id))
song_id = int(song_id)
valid = self.plugin.manager.get_object(Song, song_id)
if valid:
@ -499,7 +503,8 @@ class SongMediaItem(MediaManagerItem):
if QtWidgets.QMessageBox.question(
self, UiStrings().ConfirmDelete,
translate('SongsPlugin.MediaItem',
'Are you sure you want to delete the "%d" selected song(s)?') % len(items),
'Are you sure you want to delete the "{items:d}" '
'selected song(s)?').format(items=len(items)),
QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No),
QtWidgets.QMessageBox.Yes) == QtWidgets.QMessageBox.No:
return
@ -524,8 +529,9 @@ class SongMediaItem(MediaManagerItem):
old_song = self.plugin.manager.get_object(Song, item_id)
song_xml = self.open_lyrics.song_to_xml(old_song)
new_song = self.open_lyrics.xml_to_song(song_xml)
new_song.title = '%s <%s>' % \
(new_song.title, translate('SongsPlugin.MediaItem', 'copy', 'For song cloning'))
new_song.title = '{title} <{text}>'.format(title=new_song.title,
text=translate('SongsPlugin.MediaItem',
'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))
@ -552,7 +558,8 @@ class SongMediaItem(MediaManagerItem):
:param remote: Triggered from remote
:param context: Why is it being generated
"""
log.debug('generate_slide_data: %s, %s, %s' % (service_item, item, self.remote_song))
log.debug('generate_slide_data: {service}, {item}, {remote}'.format(service=service_item, item=item,
remote=self.remote_song))
item_id = self._get_id_of_item_to_generate(item, self.remote_song)
service_item.add_capability(ItemCapabilities.CanEdit)
service_item.add_capability(ItemCapabilities.CanPreview)
@ -581,7 +588,7 @@ class SongMediaItem(MediaManagerItem):
if verse_index is None:
verse_index = VerseType.from_tag(verse_tag)
verse_tag = VerseType.translated_tags[verse_index].upper()
verse_def = '%s%s' % (verse_tag, verse[0]['label'])
verse_def = '{tag}{label}'.format(tag=verse_tag, label=verse[0]['label'])
service_item.add_from_text(str(verse[1]), verse_def)
else:
# Loop through the verse list and expand the song accordingly.
@ -596,7 +603,7 @@ class SongMediaItem(MediaManagerItem):
else:
verse_index = VerseType.from_tag(verse[0]['type'])
verse_tag = VerseType.translated_tags[verse_index]
verse_def = '%s%s' % (verse_tag, verse[0]['label'])
verse_def = '{tag}{label}'.format(tzg=verse_tag, text=verse[0]['label'])
service_item.add_from_text(verse[1], verse_def)
service_item.title = song.title
author_list = self.generate_footer(service_item, song)
@ -639,23 +646,24 @@ class SongMediaItem(MediaManagerItem):
item.raw_footer = []
item.raw_footer.append(song.title)
if authors_none:
item.raw_footer.append("%s: %s" % (translate('OpenLP.Ui', 'Written by'),
create_separated_list(authors_none)))
item.raw_footer.append("{text}: {authors}".format(text=translate('OpenLP.Ui', 'Written by'),
authors=create_separated_list(authors_none)))
if authors_words_music:
item.raw_footer.append("%s: %s" % (AuthorType.Types[AuthorType.WordsAndMusic],
create_separated_list(authors_words_music)))
item.raw_footer.append("{text}: {authors}".format(text=AuthorType.Types[AuthorType.WordsAndMusic],
authors=create_separated_list(authors_words_music)))
if authors_words:
item.raw_footer.append("%s: %s" % (AuthorType.Types[AuthorType.Words],
create_separated_list(authors_words)))
item.raw_footer.append("{text}: {authors}".format(text=AuthorType.Types[AuthorType.Words],
authors=create_separated_list(authors_words)))
if authors_music:
item.raw_footer.append("%s: %s" % (AuthorType.Types[AuthorType.Music],
create_separated_list(authors_music)))
item.raw_footer.append("{text}: {authors}".format(text=AuthorType.Types[AuthorType.Music],
authors=create_separated_list(authors_music)))
if authors_translation:
item.raw_footer.append("%s: %s" % (AuthorType.Types[AuthorType.Translation],
create_separated_list(authors_translation)))
item.raw_footer.append("{text}: {authors}".format(text=AuthorType.Types[AuthorType.Translation],
authors=create_separated_list(authors_translation)))
if song.copyright:
if self.display_copyright_symbol:
item.raw_footer.append("%s %s" % (SongStrings.CopyrightSymbol, song.copyright))
item.raw_footer.append("{symbol} {song}".format(symbol=SongStrings.CopyrightSymbol,
song=song.copyright))
else:
item.raw_footer.append(song.copyright)
if self.display_songbook and song.songbook_entries:

View File

@ -61,18 +61,20 @@ class OpenLyricsExport(RegistryProperties):
if self.parent.stop_export_flag:
return False
self.parent.increment_progress_bar(
translate('SongsPlugin.OpenLyricsExport', 'Exporting "%s"...') % song.title)
translate('SongsPlugin.OpenLyricsExport', 'Exporting "{title}"...').format(title=song.title))
xml = open_lyrics.song_to_xml(song)
tree = etree.ElementTree(etree.fromstring(xml.encode()))
filename = '%s (%s)' % (song.title, ', '.join([author.display_name for author in song.authors]))
filename = '{title} ({author})'.format(title=song.title,
author=', '.join([author.display_name for author in song.authors]))
filename = clean_filename(filename)
# Ensure the filename isn't too long for some filesystems
filename_with_ext = '%s.xml' % filename[0:250 - len(self.save_path)]
filename_with_ext = '{name}.xml'.format(name=filename[0:250 - len(self.save_path)])
# Make sure we're not overwriting an existing file
conflicts = 0
while os.path.exists(os.path.join(self.save_path, filename_with_ext)):
conflicts += 1
filename_with_ext = '%s-%d.xml' % (filename[0:247 - len(self.save_path)], conflicts)
filename_with_ext = '{name}-{extra}.xml'.format(name=filename[0:247 - len(self.save_path)],
extra=conflicts)
# Pass a file object, because lxml does not cope with some special
# characters in the path (see lp:757673 and lp:744337).
tree.write(open(os.path.join(self.save_path, filename_with_ext), 'wb'), encoding='utf-8',

View File

@ -70,6 +70,7 @@ from openlp.plugins.songs.lib.db import Author, AuthorType, Book, Song, Topic
log = logging.getLogger(__name__)
NAMESPACE = 'http://openlyrics.info/namespace/2009/song'
# TODO: Verify format() with template variable
NSMAP = '{' + NAMESPACE + '}' + '%s'
@ -126,7 +127,7 @@ class SongXML(object):
try:
self.song_xml = objectify.fromstring(xml)
except etree.XMLSyntaxError:
log.exception('Invalid xml %s', xml)
log.exception('Invalid xml {text}'.format(text=xml))
xml_iter = self.song_xml.getiterator()
for element in xml_iter:
if element.tag == 'verse':
@ -422,7 +423,7 @@ class OpenLyrics(object):
:param tags_element: Some tag elements
"""
available_tags = FormattingTags.get_html_tags()
start_tag = '{%s}' % tag_name
start_tag = '{{{name}}}'.format(name=tag_name)
for tag in available_tags:
if tag['start tag'] == start_tag:
# Create new formatting tag in openlyrics xml.
@ -449,18 +450,18 @@ class OpenLyrics(object):
xml_tags = tags_element.xpath('tag/attribute::name')
# Some formatting tag has only starting part e.g. <br>. Handle this case.
if tag in end_tags:
text = text.replace('{%s}' % tag, '<tag name="%s">' % tag)
text = text.replace('{{{tag}}}'.format(tag=tag), '<tag name="{tag}">'.format(tag=tag))
else:
text = text.replace('{%s}' % tag, '<tag name="%s"/>' % tag)
text = text.replace('{{{tag}}}'.format(tag=tag), '<tag name="{tag}"/>'.format(tag=tag))
# Add tag to <format> element if tag not present.
if tag not in xml_tags:
self._add_tag_to_formatting(tag, tags_element)
# Replace end tags.
for tag in end_tags:
text = text.replace('{/%s}' % tag, '</tag>')
text = text.replace('{/{tag}}}'.format(tag=tag), '</tag>')
# Replace \n with <br/>.
text = text.replace('\n', '<br/>')
element = etree.XML('<lines>%s</lines>' % text)
element = etree.XML('<lines>{text}</lines>'.format(text=text))
verse_element.append(element)
return element
@ -566,9 +567,9 @@ class OpenLyrics(object):
name = tag.get('name')
if name is None:
continue
start_tag = '{%s}' % name[:5]
start_tag = '{{{name}}}'.format(name=name[:5])
# Some tags have only start tag e.g. {br}
end_tag = '{/' + name[:5] + '}' if hasattr(tag, 'close') else ''
end_tag = '{{/{name}}}'.format(name=name[:5]) if hasattr(tag, 'close') else ''
openlp_tag = {
'desc': name,
'start tag': start_tag,
@ -604,26 +605,30 @@ class OpenLyrics(object):
text = ''
use_endtag = True
# Skip <comment> elements - not yet supported.
# TODO: Verify format() with template variables
if element.tag == NSMAP % 'comment':
if element.tail:
# Append tail text at chord element.
text += element.tail
return text
# Skip <chord> element - not yet supported.
# TODO: Verify format() with template variables
elif element.tag == NSMAP % 'chord':
if element.tail:
# Append tail text at chord element.
text += element.tail
return text
# Convert line breaks <br/> to \n.
# TODO: Verify format() with template variables
elif newlines and element.tag == NSMAP % 'br':
text += '\n'
if element.tail:
text += element.tail
return text
# Start formatting tag.
# TODO: Verify format() with template variables
if element.tag == NSMAP % 'tag':
text += '{%s}' % element.get('name')
text += '{{{name}}}'.format(name=element.get('name'))
# Some formattings may have only start tag.
# Handle this case if element has no children and contains no text.
if not element and not element.text:
@ -636,8 +641,9 @@ class OpenLyrics(object):
# Use recursion since nested formatting tags are allowed.
text += self._process_lines_mixed_content(child, newlines)
# Append text from tail and add formatting end tag.
# TODO: Verify format() with template variables
if element.tag == NSMAP % 'tag' and use_endtag:
text += '{/%s}' % element.get('name')
text += '{/{name}}}'.format(name=element.get('name'))
# Append text from tail.
if element.tail:
text += element.tail
@ -663,6 +669,7 @@ class OpenLyrics(object):
# Loop over the "line" elements removing comments and chords.
for line in element:
# Skip comment lines.
# TODO: Verify format() with template variables
if line.tag == NSMAP % 'comment':
continue
if text:

View File

@ -78,7 +78,7 @@ class SongSelectImport(object):
try:
login_page = BeautifulSoup(self.opener.open(LOGIN_URL).read(), 'lxml')
except (TypeError, URLError) as e:
log.exception('Could not login to SongSelect, %s', e)
log.exception('Could not login to SongSelect, {error}'.format(error=e))
return False
if callback:
callback()
@ -92,7 +92,7 @@ class SongSelectImport(object):
try:
posted_page = BeautifulSoup(self.opener.open(LOGIN_URL, data.encode('utf-8')).read(), 'lxml')
except (TypeError, URLError) as e:
log.exception('Could not login to SongSelect, %s', e)
log.exception('Could not login to SongSelect, {error}'.format(error=e))
return False
if callback:
callback()
@ -105,7 +105,7 @@ class SongSelectImport(object):
try:
self.opener.open(LOGOUT_URL)
except (TypeError, URLError) as e:
log.exception('Could not log of SongSelect, %s', e)
log.exception('Could not log of SongSelect, {error}'.format(error=e))
def search(self, search_text, max_results, callback=None):
"""
@ -127,7 +127,7 @@ class SongSelectImport(object):
results_page = BeautifulSoup(self.opener.open(SEARCH_URL + '?' + urlencode(params)).read(), 'lxml')
search_results = results_page.find_all('li', 'result pane')
except (TypeError, URLError) as e:
log.exception('Could not search SongSelect, %s', e)
log.exception('Could not search SongSelect, {error}'.format(error=e))
search_results = None
if not search_results:
break
@ -158,7 +158,7 @@ class SongSelectImport(object):
try:
song_page = BeautifulSoup(self.opener.open(song['link']).read(), 'lxml')
except (TypeError, URLError) as e:
log.exception('Could not get song from SongSelect, %s', e)
log.exception('Could not get song from SongSelect, {error}'.format(error=e))
return None
if callback:
callback()
@ -203,7 +203,7 @@ class SongSelectImport(object):
verse_type = VerseType.from_loose_input(verse_type)
verse_number = int(verse_number)
song_xml.add_verse_to_lyrics(VerseType.tags[verse_type], verse_number, verse['lyrics'])
verse_order.append('%s%s' % (VerseType.tags[verse_type], verse_number))
verse_order.append('{tag}{number}'.format(tag=VerseType.tags[verse_type], number=verse_number))
db_song.verse_order = ' '.join(verse_order)
db_song.lyrics = song_xml.extract_xml()
clean_song(self.db_manager, db_song)

View File

@ -74,8 +74,8 @@ class SongsTab(SettingsTab):
'Import missing songs from service files'))
self.display_songbook_check_box.setText(translate('SongsPlugin.SongsTab', 'Display songbook in footer'))
self.display_copyright_check_box.setText(translate('SongsPlugin.SongsTab',
'Display "%s" symbol before copyright info') %
SongStrings.CopyrightSymbol)
'Display "{symbol}" symbol before copyright '
'info').format(symbol=SongStrings.CopyrightSymbol))
def on_search_as_type_check_box_changed(self, check_state):
self.song_search = (check_state == QtCore.Qt.Checked)

View File

@ -81,9 +81,10 @@ class SongUsageDetailForm(QtWidgets.QDialog, Ui_SongUsageDetailDialog, RegistryP
)
return
check_directory_exists(path)
file_name = translate('SongUsagePlugin.SongUsageDetailForm', 'usage_detail_%s_%s.txt') % \
(self.from_date_calendar.selectedDate().toString('ddMMyyyy'),
self.to_date_calendar.selectedDate().toString('ddMMyyyy'))
file_name = translate('SongUsagePlugin.SongUsageDetailForm',
'usage_detail_{old}_{new}.txt'
).format(old=self.from_date_calendar.selectedDate().toString('ddMMyyyy'),
new=self.to_date_calendar.selectedDate().toString('ddMMyyyy'))
Settings().setValue(self.plugin.settings_section + '/from date', self.from_date_calendar.selectedDate())
Settings().setValue(self.plugin.settings_section + '/to date', self.to_date_calendar.selectedDate())
usage = self.plugin.manager.get_all_objects(
@ -95,21 +96,23 @@ class SongUsageDetailForm(QtWidgets.QDialog, Ui_SongUsageDetailDialog, RegistryP
try:
file_handle = open(report_file_name, 'wb')
for instance in usage:
record = '\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",' \
'\"%s\",\"%s\"\n' % \
(instance.usagedate, instance.usagetime, instance.title, instance.copyright,
instance.ccl_number, instance.authors, instance.plugin_name, instance.source)
record = ('\"{date}\",\"{time}\",\"{title}\",\"{copyright}\",\"{ccli}\",\"{authors}\",'
'\"{name}\",\"{source}\"\n').format(date=instance.usagedate, time=instance.usagetime,
title=instance.title, copyright=instance.copyright,
ccli=instance.ccl_number, authors=instance.authors,
name=instance.plugin_name, source=instance.source)
file_handle.write(record.encode('utf-8'))
self.main_window.information_message(
translate('SongUsagePlugin.SongUsageDetailForm', 'Report Creation'),
translate('SongUsagePlugin.SongUsageDetailForm',
'Report \n%s \nhas been successfully created. ') % report_file_name
'Report \n{name} \nhas been successfully created. ').format(name=report_file_name)
)
except OSError as ose:
log.exception('Failed to write out song usage records')
critical_error_message_box(translate('SongUsagePlugin.SongUsageDetailForm', 'Report Creation Failed'),
translate('SongUsagePlugin.SongUsageDetailForm',
'An error occurred while creating the report: %s') % ose.strerror)
'An error occurred while creating the report: {error}'
).format(error=ose.strerror))
finally:
if file_handle:
file_handle.close()

View File

@ -29,7 +29,7 @@ from tests.helpers.testmixin import TestMixin
class TestInitFunctions(TestMixin, TestCase):
def parse_options_basic_test(self):
def test_parse_options_basic(self):
"""
Test the parse options process works
@ -46,7 +46,7 @@ class TestInitFunctions(TestMixin, TestCase):
self.assertEquals(args.style, None, 'There are no style flags to be processed')
self.assertEquals(args.rargs, [], 'The service file should be blank')
def parse_options_debug_test(self):
def test_parse_options_debug(self):
"""
Test the parse options process works for debug only
@ -63,7 +63,7 @@ class TestInitFunctions(TestMixin, TestCase):
self.assertEquals(args.style, None, 'There are no style flags to be processed')
self.assertEquals(args.rargs, [], 'The service file should be blank')
def parse_options_debug_and_portable_test(self):
def test_parse_options_debug_and_portable(self):
"""
Test the parse options process works for debug and portable
@ -80,7 +80,7 @@ class TestInitFunctions(TestMixin, TestCase):
self.assertEquals(args.style, None, 'There are no style flags to be processed')
self.assertEquals(args.rargs, [], 'The service file should be blank')
def parse_options_all_no_file_test(self):
def test_parse_options_all_no_file(self):
"""
Test the parse options process works with two options
@ -97,7 +97,7 @@ class TestInitFunctions(TestMixin, TestCase):
self.assertEquals(args.style, None, 'There are no style flags to be processed')
self.assertEquals(args.rargs, [], 'The service file should be blank')
def parse_options_file_test(self):
def test_parse_options_file(self):
"""
Test the parse options process works with a file
@ -114,7 +114,7 @@ class TestInitFunctions(TestMixin, TestCase):
self.assertEquals(args.style, None, 'There are no style flags to be processed')
self.assertEquals(args.rargs, 'dummy_temp', 'The service file should not be blank')
def parse_options_file_and_debug_test(self):
def test_parse_options_file_and_debug(self):
"""
Test the parse options process works with a file

View File

@ -49,7 +49,7 @@ class TestCategoryActionList(TestCase):
"""
del self.list
def contains_test(self):
def test_contains(self):
"""
Test the __contains__() method
"""
@ -61,7 +61,7 @@ class TestCategoryActionList(TestCase):
self.assertTrue(self.action1 in self.list)
self.assertFalse(self.action2 in self.list)
def len_test(self):
def test_len(self):
"""
Test the __len__ method
"""
@ -77,7 +77,7 @@ class TestCategoryActionList(TestCase):
# THEN: Check the length.
self.assertEqual(len(self.list), 1, "The length should be 1.")
def append_test(self):
def test_append(self):
"""
Test the append() method
"""
@ -92,7 +92,7 @@ class TestCategoryActionList(TestCase):
self.assertEqual(self.list.actions[0], (0, self.action1))
self.assertEqual(self.list.actions[1], (1, self.action2))
def add_test(self):
def test_add(self):
"""
Test the add() method
"""
@ -111,7 +111,7 @@ class TestCategoryActionList(TestCase):
self.assertEqual(self.list.actions[0], (41, self.action2))
self.assertEqual(self.list.actions[1], (42, self.action1))
def iterator_test(self):
def test_iterator(self):
"""
Test the __iter__ and __next__ methods
"""
@ -126,7 +126,7 @@ class TestCategoryActionList(TestCase):
self.assertIs(l[0], self.action1)
self.assertIs(l[1], self.action2)
def remove_test(self):
def test_remove(self):
"""
Test the remove() method
"""

View File

@ -36,7 +36,7 @@ class TestAppLocation(TestCase):
"""
A test suite to test out various methods around the AppLocation class.
"""
def get_data_path_test(self):
def test_get_data_path(self):
"""
Test the AppLocation.get_data_path() method
"""
@ -60,7 +60,7 @@ class TestAppLocation(TestCase):
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"')
def get_data_path_with_custom_location_test(self):
def test_get_data_path_with_custom_location(self):
"""
Test the AppLocation.get_data_path() method when a custom location is set in the settings
"""
@ -80,7 +80,7 @@ class TestAppLocation(TestCase):
mocked_settings.value.assert_called_with('advanced/data path')
self.assertEqual('custom/dir', data_path, 'Result should be "custom/dir"')
def get_files_no_section_no_extension_test(self):
def test_get_files_no_section_no_extension(self):
"""
Test the AppLocation.get_files() method with no parameters passed.
"""
@ -96,7 +96,7 @@ class TestAppLocation(TestCase):
# Then: check if the file lists are identical.
self.assertListEqual(FILE_LIST, result, 'The file lists should be identical.')
def get_files_test(self):
def test_get_files(self):
"""
Test the AppLocation.get_files() method with all parameters passed.
"""
@ -115,7 +115,7 @@ class TestAppLocation(TestCase):
# Then: check if the file lists are identical.
self.assertListEqual(['file5.mp3', 'file6.mp3'], result, 'The file lists should be identical.')
def get_section_data_path_test(self):
def test_get_section_data_path(self):
"""
Test the AppLocation.get_section_data_path() method
"""
@ -132,7 +132,7 @@ class TestAppLocation(TestCase):
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"')
def get_directory_for_app_dir_test(self):
def test_get_directory_for_app_dir(self):
"""
Test the AppLocation.get_directory() method for AppLocation.AppDir
"""
@ -146,7 +146,7 @@ class TestAppLocation(TestCase):
# THEN: check that the correct directory is returned
self.assertEqual(os.path.join('app', 'dir'), directory, 'Directory should be "app/dir"')
def get_directory_for_plugins_dir_test(self):
def test_get_directory_for_plugins_dir(self):
"""
Test the AppLocation.get_directory() method for AppLocation.PluginsDir
"""
@ -167,7 +167,7 @@ class TestAppLocation(TestCase):
# THEN: The correct directory should be returned
self.assertEqual(os.path.join('plugins', 'dir'), directory, 'Directory should be "plugins/dir"')
def get_frozen_path_in_unfrozen_app_test(self):
def test_get_frozen_path_in_unfrozen_app(self):
"""
Test the _get_frozen_path() function when the application is not frozen (compiled by PyInstaller)
"""
@ -181,7 +181,7 @@ class TestAppLocation(TestCase):
# THEN: The non-frozen parameter is returned
self.assertEqual('not frozen', frozen_path, '_get_frozen_path should return "not frozen"')
def get_frozen_path_in_frozen_app_test(self):
def test_get_frozen_path_in_frozen_app(self):
"""
Test the get_frozen_path() function when the application is frozen (compiled by PyInstaller)
"""

View File

@ -34,7 +34,7 @@ class TestCommonFunctions(TestCase):
"""
A test suite to test out various functions in the openlp.core.common module.
"""
def check_directory_exists_test(self):
def test_check_directory_exists(self):
"""
Test the check_directory_exists() function
"""
@ -73,7 +73,7 @@ class TestCommonFunctions(TestCase):
mocked_exists.assert_called_with(directory_to_check)
self.assertRaises(ValueError, check_directory_exists, directory_to_check)
def de_hump_conversion_test(self):
def test_de_hump_conversion(self):
"""
Test the de_hump function with a class name
"""
@ -86,7 +86,7 @@ class TestCommonFunctions(TestCase):
# THEN: the new string should be converted to python format
self.assertTrue(new_string == "my_class", 'The class name should have been converted')
def de_hump_static_test(self):
def test_de_hump_static(self):
"""
Test the de_hump function with a python string
"""
@ -99,7 +99,7 @@ class TestCommonFunctions(TestCase):
# THEN: the new string should be converted to python format
self.assertTrue(new_string == "my_class", 'The class name should have been preserved')
def trace_error_handler_test(self):
def test_trace_error_handler(self):
"""
Test the trace_error_handler() method
"""
@ -115,7 +115,7 @@ class TestCommonFunctions(TestCase):
mocked_logger.error.assert_called_with(
'OpenLP Error trace\n File openlp.fake at line 56 \n\t called trace_error_handler_test')
def translate_test(self):
def test_translate(self):
"""
Test the translate() function
"""
@ -132,7 +132,7 @@ class TestCommonFunctions(TestCase):
mocked_translate.assert_called_with(context, text, comment)
self.assertEqual('Translated string', result, 'The translated string should have been returned')
def is_win_test(self):
def test_is_win(self):
"""
Test the is_win() function
"""
@ -148,7 +148,7 @@ class TestCommonFunctions(TestCase):
self.assertFalse(is_macosx(), 'is_macosx() should return False')
self.assertFalse(is_linux(), 'is_linux() should return False')
def is_macosx_test(self):
def test_is_macosx(self):
"""
Test the is_macosx() function
"""
@ -164,7 +164,7 @@ class TestCommonFunctions(TestCase):
self.assertFalse(is_win(), 'is_win() should return False')
self.assertFalse(is_linux(), 'is_linux() should return False')
def is_linux_test(self):
def test_is_linux(self):
"""
Test the is_linux() function
"""
@ -180,7 +180,7 @@ class TestCommonFunctions(TestCase):
self.assertFalse(is_win(), 'is_win() should return False')
self.assertFalse(is_macosx(), 'is_macosx() should return False')
def clean_button_text_test(self):
def test_clean_button_text(self):
"""
Test the clean_button_text() function.
"""

View File

@ -67,7 +67,7 @@ class TestUtilsDBFunctions(TestCase):
time.sleep(1)
retries += 1
def delete_column_test(self):
def test_delete_column(self):
"""
Test deleting a single column in a table
"""
@ -85,7 +85,7 @@ class TestUtilsDBFunctions(TestCase):
if column.name == 'song_book_id':
self.fail("The column 'song_book_id' should have been deleted.")
def delete_columns_test(self):
def test_delete_columns(self):
"""
Test deleting multiple columns in a table
"""

View File

@ -48,7 +48,7 @@ class TestInit(TestCase, TestMixin):
"""
self.destroy_settings()
def add_actions_empty_list_test(self):
def test_add_actions_empty_list(self):
"""
Test that no actions are added when the list is empty
"""
@ -63,7 +63,7 @@ class TestInit(TestCase, TestMixin):
self.assertEqual(0, mocked_target.addSeparator.call_count, 'addSeparator method should not have been called')
self.assertEqual(0, mocked_target.addAction.call_count, 'addAction method should not have been called')
def add_actions_none_action_test(self):
def test_add_actions_none_action(self):
"""
Test that a separator is added when a None action is in the list
"""
@ -78,7 +78,7 @@ class TestInit(TestCase, TestMixin):
mocked_target.addSeparator.assert_called_with()
self.assertEqual(0, mocked_target.addAction.call_count, 'addAction method should not have been called')
def add_actions_add_action_test(self):
def test_add_actions_add_action(self):
"""
Test that an action is added when a valid action is in the list
"""
@ -93,7 +93,7 @@ class TestInit(TestCase, TestMixin):
self.assertEqual(0, mocked_target.addSeparator.call_count, 'addSeparator method should not have been called')
mocked_target.addAction.assert_called_with('action')
def add_actions_action_and_none_test(self):
def test_add_actions_action_and_none(self):
"""
Test that an action and a separator are added when a valid action and None are in the list
"""
@ -108,7 +108,7 @@ class TestInit(TestCase, TestMixin):
mocked_target.addSeparator.assert_called_with()
mocked_target.addAction.assert_called_with('action')
def get_uno_instance_pipe_test(self):
def test_get_uno_instance_pipe(self):
"""
Test that when the UNO connection type is "pipe" the resolver is given the "pipe" URI
"""
@ -121,7 +121,7 @@ class TestInit(TestCase, TestMixin):
# THEN: the resolve method is called with the correct argument
mock_resolver.resolve.assert_called_with('uno:pipe,name=openlp_pipe;urp;StarOffice.ComponentContext')
def get_uno_instance_socket_test(self):
def test_get_uno_instance_socket(self):
"""
Test that when the UNO connection type is other than "pipe" the resolver is given the "socket" URI
"""
@ -134,7 +134,7 @@ class TestInit(TestCase, TestMixin):
# THEN: the resolve method is called with the correct argument
mock_resolver.resolve.assert_called_with('uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext')
def get_uno_command_libreoffice_command_exists_test(self):
def test_get_uno_command_libreoffice_command_exists(self):
"""
Test the ``get_uno_command`` function uses the libreoffice command when available.
:return:
@ -151,7 +151,7 @@ class TestInit(TestCase, TestMixin):
'libreoffice --nologo --norestore --minimized --nodefault --nofirststartwizard'
' "--accept=pipe,name=openlp_pipe;urp;"')
def get_uno_command_only_soffice_command_exists_test(self):
def test_get_uno_command_only_soffice_command_exists(self):
"""
Test the ``get_uno_command`` function uses the soffice command when the libreoffice command is not available.
:return:
@ -169,7 +169,7 @@ class TestInit(TestCase, TestMixin):
self.assertEquals(result, 'soffice --nologo --norestore --minimized --nodefault --nofirststartwizard'
' "--accept=pipe,name=openlp_pipe;urp;"')
def get_uno_command_when_no_command_exists_test(self):
def test_get_uno_command_when_no_command_exists(self):
"""
Test the ``get_uno_command`` function raises an FileNotFoundError when neither the libreoffice or soffice
commands are available.
@ -183,7 +183,7 @@ class TestInit(TestCase, TestMixin):
# THEN: a FileNotFoundError exception should be raised
self.assertRaises(FileNotFoundError, get_uno_command)
def get_uno_command_connection_type_test(self):
def test_get_uno_command_connection_type(self):
"""
Test the ``get_uno_command`` function when the connection type is anything other than pipe.
:return:
@ -198,7 +198,7 @@ class TestInit(TestCase, TestMixin):
self.assertEqual(result, 'libreoffice --nologo --norestore --minimized --nodefault --nofirststartwizard'
' "--accept=socket,host=localhost,port=2002;urp;"')
def get_filesystem_encoding_sys_function_not_called_test(self):
def test_get_filesystem_encoding_sys_function_not_called(self):
"""
Test the get_filesystem_encoding() function does not call the sys.getdefaultencoding() function
"""
@ -215,7 +215,7 @@ class TestInit(TestCase, TestMixin):
self.assertEqual(0, mocked_getdefaultencoding.called, 'getdefaultencoding should not have been called')
self.assertEqual('cp1252', result, 'The result should be "cp1252"')
def get_filesystem_encoding_sys_function_is_called_test(self):
def test_get_filesystem_encoding_sys_function_is_called(self):
"""
Test the get_filesystem_encoding() function calls the sys.getdefaultencoding() function
"""
@ -233,7 +233,7 @@ class TestInit(TestCase, TestMixin):
mocked_getdefaultencoding.assert_called_with()
self.assertEqual('utf-8', result, 'The result should be "utf-8"')
def split_filename_with_file_path_test(self):
def test_split_filename_with_file_path(self):
"""
Test the split_filename() function with a path to a file
"""
@ -253,7 +253,7 @@ class TestInit(TestCase, TestMixin):
# THEN: A tuple should be returned.
self.assertEqual(wanted_result, result, 'A tuple with the dir and file name should have been returned')
def split_filename_with_dir_path_test(self):
def test_split_filename_with_dir_path(self):
"""
Test the split_filename() function with a path to a directory
"""
@ -274,7 +274,7 @@ class TestInit(TestCase, TestMixin):
self.assertEqual(wanted_result, result,
'A two-entry tuple with the directory and file name (empty) should have been returned.')
def clean_filename_test(self):
def test_clean_filename(self):
"""
Test the clean_filename() function
"""
@ -288,7 +288,7 @@ class TestInit(TestCase, TestMixin):
# THEN: The file name should be cleaned.
self.assertEqual(wanted_name, result, 'The file name should not contain any special characters.')
def delete_file_no_path_test(self):
def test_delete_file_no_path(self):
"""
Test the delete_file function when called with out a valid path
"""
@ -299,7 +299,7 @@ class TestInit(TestCase, TestMixin):
# THEN: delete_file should return False
self.assertFalse(result, "delete_file should return False when called with ''")
def delete_file_path_success_test(self):
def test_delete_file_path_success(self):
"""
Test the delete_file function when it successfully deletes a file
"""
@ -312,7 +312,7 @@ class TestInit(TestCase, TestMixin):
# THEN: delete_file should return True
self.assertTrue(result, 'delete_file should return True when it successfully deletes a file')
def delete_file_path_no_file_exists_test(self):
def test_delete_file_path_no_file_exists(self):
"""
Test the delete_file function when the file to remove does not exist
"""
@ -325,7 +325,7 @@ class TestInit(TestCase, TestMixin):
# THEN: delete_file should return True
self.assertTrue(result, 'delete_file should return True when the file doesnt exist')
def delete_file_path_exception_test(self):
def test_delete_file_path_exception(self):
"""
Test the delete_file function when os.remove raises an exception
"""

View File

@ -33,7 +33,7 @@ class TestLanguageManager(TestCase):
A test suite to test out various methods around the common __init__ class.
"""
def get_locale_key_test(self):
def test_get_locale_key(self):
"""
Test the get_locale_key(string) function
"""
@ -50,7 +50,7 @@ class TestLanguageManager(TestCase):
self.assertEqual(['Aushang', '\u00C4u\u00DFerung', 'Auszug'], sorted_list,
'Strings should be sorted properly')
def get_natural_key_test(self):
def test_get_natural_key(self):
"""
Test the get_natural_key(string) function
"""

View File

@ -33,7 +33,7 @@ TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../', '..',
class TestRegistry(TestCase):
def registry_service_test(self):
def test_registry_service(self):
"""
Test the registry creation and its usage
"""
@ -59,13 +59,13 @@ class TestRegistry(TestCase):
temp = Registry().get('test2')
self.assertEqual(temp, None, 'None should have been returned for missing service')
# WHEN I try to replace a component I should be allowed (testing only)
# WHEN I try to replace a component I should be allowed
Registry().remove('test1')
# THEN I will get an exception
temp = Registry().get('test1')
self.assertEqual(temp, None, 'None should have been returned for deleted service')
def registry_function_test(self):
def test_registry_function(self):
"""
Test the registry function creation and their usages
"""
@ -93,7 +93,44 @@ class TestRegistry(TestCase):
# THEN: I expect then function to have been called and a return given
self.assertEqual(return_value[0], 'function_2', 'A return value is provided and matches')
def remove_function_test(self):
def test_registry_working_flags(self):
"""
Test the registry working flags creation and its usage
"""
# GIVEN: A new registry
Registry.create()
# WHEN: I add a working flag it should save it
my_data = 'Lamas'
my_data2 = 'More Lamas'
Registry().set_flag('test1', my_data)
# THEN: we should be able retrieve the saved component
temp = Registry().get_flag('test1')
self.assertEquals(temp, my_data, 'The value should have been saved')
# WHEN: I add a component for the second time I am not mad.
# THEN and I will not get an exception
Registry().set_flag('test1', my_data2)
temp = Registry().get_flag('test1')
self.assertEquals(temp, my_data2, 'The value should have been updated')
# WHEN I try to get back a non existent Working Flag
# THEN I will get an exception
with self.assertRaises(KeyError) as context1:
temp = Registry().get_flag('test2')
self.assertEqual(context1.exception.args[0], 'Working Flag test2 not found in list',
'KeyError exception should have been thrown for missing working flag')
# WHEN I try to replace a working flag I should be allowed
Registry().remove_flag('test1')
# THEN I will get an exception
with self.assertRaises(KeyError) as context:
temp = Registry().get_flag('test1')
self.assertEqual(context.exception.args[0], 'Working Flag test1 not found in list',
'KeyError exception should have been thrown for duplicate working flag')
def test_remove_function(self):
"""
Test the remove_function() method
"""

View File

@ -32,7 +32,7 @@ TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../', '..',
class TestRegistryMixin(TestCase):
def registry_mixin_missing_test(self):
def test_registry_mixin_missing(self):
"""
Test the registry creation and its usage
"""
@ -45,7 +45,7 @@ class TestRegistryMixin(TestCase):
# THEN: The following methods are missing
self.assertEqual(len(Registry().functions_list), 0), 'The function should not be in the dict anymore.'
def registry_mixin_present_test(self):
def test_registry_mixin_present(self):
"""
Test the registry creation and its usage
"""

View File

@ -25,7 +25,8 @@ Test the registry properties
from unittest import TestCase
from openlp.core.common import Registry, RegistryProperties
from tests.functional import MagicMock
from tests.functional import MagicMock, patch
class TestRegistryProperties(TestCase, RegistryProperties):
@ -38,7 +39,7 @@ class TestRegistryProperties(TestCase, RegistryProperties):
"""
Registry.create()
def no_application_test(self):
def test_no_application(self):
"""
Test property if no registry value assigned
"""
@ -47,13 +48,30 @@ class TestRegistryProperties(TestCase, RegistryProperties):
# THEN the application should be none
self.assertEqual(self.application, None, 'The application value should be None')
def application_test(self):
def test_application(self):
"""
Test property if registry value assigned
"""
# GIVEN an Empty Registry
application = MagicMock()
# WHEN the application is registered
Registry().register('application', application)
# THEN the application should be none
self.assertEqual(self.application, application, 'The application value should match')
@patch('openlp.core.common.registryproperties.is_win')
def test_application_on_windows(self, mocked_is_win):
"""
Test property if registry value assigned on Windows
"""
# GIVEN an Empty Registry and we're on Windows
application = MagicMock()
mocked_is_win.return_value = True
# WHEN the application is registered
Registry().register('application', application)
# THEN the application should be none
self.assertEqual(self.application, application, 'The application value should match')

View File

@ -47,7 +47,7 @@ class TestSettings(TestCase, TestMixin):
"""
self.destroy_settings()
def recent_files_conv_test(self):
def test_recent_files_conv(self):
"""
Test that recent_files_conv, converts various possible types of values correctly.
"""
@ -66,7 +66,7 @@ class TestSettings(TestCase, TestMixin):
# THEN: The actual result should be the same as the expected result
self.assertEqual(actual_result, expected_result)
def settings_basic_test(self):
def test_settings_basic(self):
"""
Test the Settings creation and its default usage
"""
@ -84,7 +84,7 @@ class TestSettings(TestCase, TestMixin):
# THEN the new value is returned when re-read
self.assertTrue(Settings().value('core/has run wizard'), 'The saved value should have been returned')
def settings_override_test(self):
def test_settings_override(self):
"""
Test the Settings creation and its override usage
"""
@ -106,7 +106,7 @@ class TestSettings(TestCase, TestMixin):
# THEN the new value is returned when re-read
self.assertEqual('very short', Settings().value('test/extend'), 'The saved value should be returned')
def settings_override_with_group_test(self):
def test_settings_override_with_group(self):
"""
Test the Settings creation and its override usage - with groups
"""
@ -130,7 +130,7 @@ class TestSettings(TestCase, TestMixin):
# THEN the new value is returned when re-read
self.assertEqual('very short', Settings().value('test/extend'), 'The saved value should be returned')
def settings_nonexisting_test(self):
def test_settings_nonexisting(self):
"""
Test the Settings on query for non-existing value
"""
@ -142,7 +142,7 @@ class TestSettings(TestCase, TestMixin):
# THEN: An exception with the non-existing key should be thrown
self.assertEqual(str(cm.exception), "'core/does not exists'", 'We should get an exception')
def extend_default_settings_test(self):
def test_extend_default_settings(self):
"""
Test that the extend_default_settings method extends the default settings
"""

View File

@ -29,7 +29,7 @@ from openlp.core.common import UiStrings
class TestUiStrings(TestCase):
def check_same_instance_test(self):
def test_check_same_instance(self):
"""
Test the UiStrings class - we always should have only one instance of the UiStrings class.
"""

View File

@ -44,7 +44,7 @@ class TestVersionchecker(TestMixin, TestCase):
"""
self.destroy_settings()
def version_thread_triggered_test(self):
def test_version_thread_triggered(self):
"""
Test the version thread call does not trigger UI
:return:

View File

@ -37,7 +37,7 @@ class TestDB(TestCase):
"""
A test case for all the tests for the :mod:`~openlp.core.lib.db` module.
"""
def init_db_calls_correct_functions_test(self):
def test_init_db_calls_correct_functions(self):
"""
Test that the init_db function makes the correct function calls
"""
@ -67,7 +67,7 @@ class TestDB(TestCase):
self.assertIs(session, mocked_scoped_session_object, 'The ``session`` object should be the mock')
self.assertIs(metadata, mocked_metadata, 'The ``metadata`` object should be the mock')
def init_db_defaults_test(self):
def test_init_db_defaults(self):
"""
Test that initialising an in-memory SQLite database via ``init_db`` uses the defaults
"""
@ -81,7 +81,7 @@ class TestDB(TestCase):
self.assertIsInstance(session, ScopedSession, 'The ``session`` object should be a ``ScopedSession`` instance')
self.assertIsInstance(metadata, MetaData, 'The ``metadata`` object should be a ``MetaData`` instance')
def get_upgrade_op_test(self):
def test_get_upgrade_op(self):
"""
Test that the ``get_upgrade_op`` function creates a MigrationContext and an Operations object
"""
@ -105,7 +105,7 @@ class TestDB(TestCase):
MockedMigrationContext.configure.assert_called_with(mocked_connection)
MockedOperations.assert_called_with(mocked_context)
def delete_database_without_db_file_name_test(self):
def test_delete_database_without_db_file_name(self):
"""
Test that the ``delete_database`` function removes a database file, without the file name parameter
"""
@ -125,7 +125,7 @@ class TestDB(TestCase):
mocked_delete_file.assert_called_with(test_location)
self.assertTrue(result, 'The result of delete_file should be True (was rigged that way)')
def delete_database_with_db_file_name_test(self):
def test_delete_database_with_db_file_name(self):
"""
Test that the ``delete_database`` function removes a database file, with the file name supplied
"""

View File

@ -26,7 +26,7 @@ class TestFileDialog(TestCase):
self.qt_gui_patcher.stop()
self.ui_strings_patcher.stop()
def get_open_file_names_canceled_test(self):
def test_get_open_file_names_canceled(self):
"""
Test that FileDialog.getOpenFileNames() returns and empty QStringList when QFileDialog is canceled
(returns an empty QStringList)
@ -45,7 +45,7 @@ class TestFileDialog(TestCase):
'FileDialog.getOpenFileNames should return and empty list when QFileDialog.getOpenFileNames '
'is canceled')
def returned_file_list_test(self):
def test_returned_file_list(self):
"""
Test that FileDialog.getOpenFileNames handles a list of files properly when QFileList.getOpenFileNames
returns a good file name, a url encoded file name and a non-existing file

View File

@ -47,7 +47,7 @@ class TestFormattingTags(TestCase):
"""
FormattingTags.html_expands = []
def get_html_tags_no_user_tags_test(self):
def test_get_html_tags_no_user_tags(self):
"""
Test the FormattingTags class' get_html_tags static method.
"""
@ -68,7 +68,7 @@ class TestFormattingTags(TestCase):
# THEN: Lists should be identical.
assert old_tags_list == new_tags_list, 'The formatting tag lists should be identical.'
def get_html_tags_with_user_tags_test(self):
def test_get_html_tags_with_user_tags(self):
"""
FormattingTags class - test the get_html_tags(), add_html_tags() and remove_html_tag() methods.
"""

View File

@ -216,7 +216,7 @@ class Htmbuilder(TestCase, TestMixin):
"""
self.destroy_settings()
def build_html_test(self):
def test_build_html(self):
"""
Test the build_html() function
"""
@ -246,7 +246,7 @@ class Htmbuilder(TestCase, TestMixin):
# THEN: The returned html should match.
self.assertEqual(html, HTML, 'The returned html should match')
def build_background_css_radial_test(self):
def test_build_background_css_radial(self):
"""
Test the build_background_css() function with a radial background
"""
@ -262,7 +262,7 @@ class Htmbuilder(TestCase, TestMixin):
# THEN: The returned css should match.
self.assertEqual(BACKGROUND_CSS_RADIAL, css, 'The background css should be equal.')
def build_lyrics_css_test(self):
def test_build_lyrics_css(self):
"""
Test the build_lyrics_css() function
"""
@ -283,7 +283,7 @@ class Htmbuilder(TestCase, TestMixin):
# THEN: The css should be equal.
self.assertEqual(LYRICS_CSS, css, 'The lyrics css should be equal.')
def build_lyrics_outline_css_test(self):
def test_build_lyrics_outline_css(self):
"""
Test the build_lyrics_outline_css() function
"""
@ -300,7 +300,7 @@ class Htmbuilder(TestCase, TestMixin):
# THEN: The css should be equal.
self.assertEqual(LYRICS_OUTLINE_CSS, css, 'The outline css should be equal.')
def build_lyrics_format_css_test(self):
def test_build_lyrics_format_css(self):
"""
Test the build_lyrics_format_css() function
"""
@ -323,7 +323,7 @@ class Htmbuilder(TestCase, TestMixin):
# THEN: They should be equal.
self.assertEqual(LYRICS_FORMAT_CSS, css, 'The lyrics format css should be equal.')
def build_footer_css_test(self):
def test_build_footer_css(self):
"""
Test the build_footer_css() function
"""
@ -341,7 +341,7 @@ class Htmbuilder(TestCase, TestMixin):
# THEN: THE css should be the same.
self.assertEqual(FOOTER_CSS, css, 'The footer strings should be equal.')
def build_footer_css_wrap_test(self):
def test_build_footer_css_wrap(self):
"""
Test the build_footer_css() function
"""
@ -360,7 +360,7 @@ class Htmbuilder(TestCase, TestMixin):
# THEN: Footer should wrap
self.assertEqual(FOOTER_CSS_WRAP, css, 'The footer strings should be equal.')
def build_footer_invalid_test(self):
def test_build_footer_invalid(self):
"""
Test the build_footer_css() function
"""
@ -381,7 +381,7 @@ class Htmbuilder(TestCase, TestMixin):
self.assertEqual(FOOTER_CSS_INVALID, css[0], 'The footer strings should be blank.')
self.assertEqual(FOOTER_CSS_INVALID, css[1], 'The footer strings should be blank.')
def webkit_version_test(self):
def test_webkit_version(self):
"""
Test the webkit_version() function
"""

View File

@ -57,7 +57,7 @@ class TestImageManager(TestCase, TestMixin):
"""
del self.app
def basic_image_manager_test(self):
def test_basic_image_manager(self):
"""
Test the Image Manager setup basic functionality
"""
@ -83,7 +83,7 @@ class TestImageManager(TestCase, TestMixin):
self.image_manager.get_image(TEST_PATH, 'church1.jpg')
self.assertNotEquals(context.exception, '', 'KeyError exception should have been thrown for missing image')
def different_dimension_image_test(self):
def test_different_dimension_image(self):
"""
Test the Image Manager with dimensions
"""
@ -115,7 +115,7 @@ class TestImageManager(TestCase, TestMixin):
self.image_manager.get_image(full_path, 'church.jpg', 120, 120)
self.assertNotEquals(context.exception, '', 'KeyError exception should have been thrown for missing dimension')
def process_cache_test(self):
def test_process_cache(self):
"""
Test the process_cache method
"""

View File

@ -38,7 +38,7 @@ TEST_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..',
class TestLib(TestCase):
def str_to_bool_with_bool_true_test(self):
def test_str_to_bool_with_bool_true(self):
"""
Test the str_to_bool function with boolean input of True
"""
@ -52,7 +52,7 @@ class TestLib(TestCase):
self.assertIsInstance(true_result, bool, 'The result should be a boolean')
self.assertTrue(true_result, 'The result should be True')
def str_to_bool_with_bool_false_test(self):
def test_str_to_bool_with_bool_false(self):
"""
Test the str_to_bool function with boolean input of False
"""
@ -66,7 +66,7 @@ class TestLib(TestCase):
self.assertIsInstance(false_result, bool, 'The result should be a boolean')
self.assertFalse(false_result, 'The result should be True')
def str_to_bool_with_integer_test(self):
def test_str_to_bool_with_integer(self):
"""
Test the str_to_bool function with an integer input
"""
@ -79,7 +79,7 @@ class TestLib(TestCase):
# THEN: we should get back a false
self.assertFalse(int_result, 'The result should be False')
def str_to_bool_with_invalid_string_test(self):
def test_str_to_bool_with_invalid_string(self):
"""
Test the str_to_bool function with an invalid string
"""
@ -92,7 +92,7 @@ class TestLib(TestCase):
# THEN: we should get back a false
self.assertFalse(str_result, 'The result should be False')
def str_to_bool_with_string_false_test(self):
def test_str_to_bool_with_string_false(self):
"""
Test the str_to_bool function with a string saying "false"
"""
@ -105,7 +105,7 @@ class TestLib(TestCase):
# THEN: we should get back a false
self.assertFalse(false_result, 'The result should be False')
def str_to_bool_with_string_no_test(self):
def test_str_to_bool_with_string_no(self):
"""
Test the str_to_bool function with a string saying "NO"
"""
@ -118,7 +118,7 @@ class TestLib(TestCase):
# THEN: we should get back a false
self.assertFalse(str_result, 'The result should be False')
def str_to_bool_with_true_string_value_test(self):
def test_str_to_bool_with_true_string_value(self):
"""
Test the str_to_bool function with a string set to "True"
"""
@ -131,7 +131,7 @@ class TestLib(TestCase):
# THEN: we should get back a true
self.assertTrue(true_result, 'The result should be True')
def str_to_bool_with_yes_string_value_test(self):
def test_str_to_bool_with_yes_string_value(self):
"""
Test the str_to_bool function with a string set to "yes"
"""
@ -144,7 +144,7 @@ class TestLib(TestCase):
# THEN: we should get back a true
self.assertTrue(str_result, 'The result should be True')
def get_text_file_string_no_file_test(self):
def test_get_text_file_string_no_file(self):
"""
Test the get_text_file_string() function when a file does not exist
"""
@ -160,7 +160,7 @@ class TestLib(TestCase):
mocked_isfile.assert_called_with(filename)
self.assertFalse(result, 'False should be returned if no file exists')
def get_text_file_string_read_error_test(self):
def test_get_text_file_string_read_error(self):
"""
Test the get_text_file_string() method when a read error happens
"""
@ -179,13 +179,13 @@ class TestLib(TestCase):
mocked_open.assert_called_with(filename, 'r', encoding='utf-8')
self.assertIsNone(result, 'None should be returned if the file cannot be opened')
def get_text_file_string_decode_error_test(self):
def test_get_text_file_string_decode_error(self):
"""
Test the get_text_file_string() method when the contents cannot be decoded
"""
self.skipTest('Impossible to test due to conflicts when mocking out the "open" function')
def build_icon_with_qicon_test(self):
def test_build_icon_with_qicon(self):
"""
Test the build_icon() function with a QIcon instance
"""
@ -200,7 +200,7 @@ class TestLib(TestCase):
# THEN: The result should be our mocked QIcon
self.assertIs(mocked_icon, result, 'The result should be the mocked QIcon')
def build_icon_with_resource_test(self):
def test_build_icon_with_resource(self):
"""
Test the build_icon() function with a resource URI
"""
@ -222,7 +222,7 @@ class TestLib(TestCase):
# best we can do is to assert that we get back a MagicMock object.
self.assertIsInstance(result, MagicMock, 'The result should be a MagicMock, because we mocked it out')
def image_to_byte_test(self):
def test_image_to_byte(self):
"""
Test the image_to_byte() function
"""
@ -248,7 +248,7 @@ class TestLib(TestCase):
self.assertEqual('base64mock', result, 'The result should be the return value of the mocked out '
'base64 method')
def create_thumb_with_size_test(self):
def test_create_thumb_with_size(self):
"""
Test the create_thumb() function with a given size.
"""
@ -282,7 +282,7 @@ class TestLib(TestCase):
except:
pass
def create_thumb_no_size_test(self):
def test_create_thumb_no_size(self):
"""
Test the create_thumb() function with no size specified.
"""
@ -316,7 +316,7 @@ class TestLib(TestCase):
except:
pass
def create_thumb_invalid_size_test(self):
def test_create_thumb_invalid_size(self):
"""
Test the create_thumb() function with invalid size specified.
"""
@ -351,7 +351,7 @@ class TestLib(TestCase):
except:
pass
def create_thumb_width_only_test(self):
def test_create_thumb_width_only(self):
"""
Test the create_thumb() function with a size of only width specified.
"""
@ -386,7 +386,7 @@ class TestLib(TestCase):
except:
pass
def create_thumb_height_only_test(self):
def test_create_thumb_height_only(self):
"""
Test the create_thumb() function with a size of only height specified.
"""
@ -421,7 +421,7 @@ class TestLib(TestCase):
except:
pass
def create_thumb_empty_img_test(self):
def test_create_thumb_empty_img(self):
"""
Test the create_thumb() function with a size of only height specified.
"""
@ -469,7 +469,7 @@ class TestLib(TestCase):
except:
pass
def check_item_selected_true_test(self):
def test_check_item_selected_true(self):
"""
Test that the check_item_selected() function returns True when there are selected indexes
"""
@ -486,7 +486,7 @@ class TestLib(TestCase):
mocked_list_widget.selectedIndexes.assert_called_with()
self.assertTrue(result, 'The result should be True')
def check_item_selected_false_test(self):
def test_check_item_selected_false(self):
"""
Test that the check_item_selected() function returns False when there are no selected indexes.
"""
@ -507,7 +507,7 @@ class TestLib(TestCase):
MockedQtWidgets.QMessageBox.information.assert_called_with('parent', 'mocked translate', 'message')
self.assertFalse(result, 'The result should be False')
def clean_tags_test(self):
def test_clean_tags(self):
"""
Test clean_tags() method.
"""
@ -529,7 +529,7 @@ class TestLib(TestCase):
# THEN: The strings should be identical.
self.assertEqual(wanted_string, result_string, 'The strings should be identical')
def expand_tags_test(self):
def test_expand_tags(self):
"""
Test the expand_tags() method.
"""
@ -568,7 +568,7 @@ class TestLib(TestCase):
# THEN: The strings should be identical.
self.assertEqual(wanted_string, result_string, 'The strings should be identical.')
def validate_thumb_file_does_not_exist_test(self):
def test_validate_thumb_file_does_not_exist(self):
"""
Test the validate_thumb() function when the thumbnail does not exist
"""
@ -585,7 +585,7 @@ class TestLib(TestCase):
mocked_os.path.exists.assert_called_with(thumb_path)
assert result is False, 'The result should be False'
def validate_thumb_file_exists_and_newer_test(self):
def test_validate_thumb_file_exists_and_newer(self):
"""
Test the validate_thumb() function when the thumbnail exists and has a newer timestamp than the file
"""
@ -605,7 +605,7 @@ class TestLib(TestCase):
# THEN: we should have called a few functions, and the result should be True
# mocked_os.path.exists.assert_called_with(thumb_path)
def validate_thumb_file_exists_and_older_test(self):
def test_validate_thumb_file_exists_and_older(self):
"""
Test the validate_thumb() function when the thumbnail exists but is older than the file
"""
@ -629,7 +629,7 @@ class TestLib(TestCase):
mocked_os.stat.assert_any_call(thumb_path)
assert result is False, 'The result should be False'
def resize_thumb_test(self):
def test_resize_thumb(self):
"""
Test the resize_thumb() function
"""
@ -650,7 +650,7 @@ class TestLib(TestCase):
self.assertEqual(wanted_width, result_size.width(), 'The image should have the requested width.')
self.assertEqual(image.pixel(0, 0), wanted_background_rgb, 'The background should be white.')
def create_separated_list_qlocate_test(self):
def test_create_separated_list_qlocate(self):
"""
Test the create_separated_list function using the Qt provided method
"""
@ -669,7 +669,7 @@ class TestLib(TestCase):
assert string_result == 'Author 1, Author 2, and Author 3', 'The string should be u\'Author 1, ' \
'Author 2, and Author 3\'.'
def create_separated_list_empty_list_test(self):
def test_create_separated_list_empty_list(self):
"""
Test the create_separated_list function with an empty list
"""
@ -685,7 +685,7 @@ class TestLib(TestCase):
# THEN: We shoud have an emptry string.
assert string_result == '', 'The string sould be empty.'
def create_separated_list_with_one_item_test(self):
def test_create_separated_list_with_one_item(self):
"""
Test the create_separated_list function with a list consisting of only one entry
"""
@ -701,7 +701,7 @@ class TestLib(TestCase):
# THEN: We should have "Author 1"
assert string_result == 'Author 1', 'The string should be u\'Author 1\'.'
def create_separated_list_with_two_items_test(self):
def test_create_separated_list_with_two_items(self):
"""
Test the create_separated_list function with a list of two entries
"""
@ -718,7 +718,7 @@ class TestLib(TestCase):
# THEN: We should have "Author 1 and Author 2"
assert string_result == 'Author 1 and Author 2', 'The string should be u\'Author 1 and Author 2\'.'
def create_separated_list_with_three_items_test(self):
def test_create_separated_list_with_three_items(self):
"""
Test the create_separated_list function with a list of three items
"""

View File

@ -44,7 +44,7 @@ class TestMediaManagerItem(TestCase, TestMixin):
@patch(u'openlp.core.lib.mediamanageritem.Settings')
@patch(u'openlp.core.lib.mediamanageritem.MediaManagerItem.on_preview_click')
def on_double_clicked_test(self, mocked_on_preview_click, MockedSettings):
def test_on_double_clicked(self, mocked_on_preview_click, MockedSettings):
"""
Test that when an item is double-clicked then the item is previewed
"""
@ -60,7 +60,7 @@ class TestMediaManagerItem(TestCase, TestMixin):
# THEN: on_preview_click() should have been called
mocked_on_preview_click.assert_called_with()
def required_icons_test(self):
def test_required_icons(self):
"""
Test the default icons for plugins
"""
@ -77,7 +77,7 @@ class TestMediaManagerItem(TestCase, TestMixin):
@patch(u'openlp.core.lib.mediamanageritem.Settings')
@patch(u'openlp.core.lib.mediamanageritem.MediaManagerItem.on_live_click')
def on_double_clicked_go_live_test(self, mocked_on_live_click, MockedSettings):
def test_on_double_clicked_go_live(self, mocked_on_live_click, MockedSettings):
"""
Test that when "Double-click to go live" is enabled that the item goes live
"""
@ -96,7 +96,7 @@ class TestMediaManagerItem(TestCase, TestMixin):
@patch(u'openlp.core.lib.mediamanageritem.Settings')
@patch(u'openlp.core.lib.mediamanageritem.MediaManagerItem.on_live_click')
@patch(u'openlp.core.lib.mediamanageritem.MediaManagerItem.on_preview_click')
def on_double_clicked_single_click_preview_test(self, mocked_on_preview_click, mocked_on_live_click,
def test_on_double_clicked_single_click_preview(self, mocked_on_preview_click, mocked_on_live_click,
MockedSettings):
"""
Test that when "Single-click preview" is enabled then nothing happens on double-click

View File

@ -49,7 +49,7 @@ class TestPluginManager(TestCase):
Registry().register('main_window', self.mocked_main_window)
Registry().register('settings_form', self.mocked_settings_form)
def hook_media_manager_with_disabled_plugin_test(self):
def test_hook_media_manager_with_disabled_plugin(self):
"""
Test running the hook_media_manager() method with a disabled plugin
"""
@ -66,7 +66,7 @@ class TestPluginManager(TestCase):
self.assertEqual(0, mocked_plugin.create_media_manager_item.call_count,
'The create_media_manager_item() method should not have been called.')
def hook_media_manager_with_active_plugin_test(self):
def test_hook_media_manager_with_active_plugin(self):
"""
Test running the hook_media_manager() method with an active plugin
"""
@ -82,7 +82,7 @@ class TestPluginManager(TestCase):
# THEN: The create_media_manager_item() method should have been called
mocked_plugin.create_media_manager_item.assert_called_with()
def hook_settings_tabs_with_disabled_plugin_and_no_form_test(self):
def test_hook_settings_tabs_with_disabled_plugin_and_no_form(self):
"""
Test running the hook_settings_tabs() method with a disabled plugin and no form
"""
@ -99,7 +99,7 @@ class TestPluginManager(TestCase):
self.assertEqual(0, mocked_plugin.create_media_manager_item.call_count,
'The create_media_manager_item() method should not have been called.')
def hook_settings_tabs_with_disabled_plugin_and_mocked_form_test(self):
def test_hook_settings_tabs_with_disabled_plugin_and_mocked_form(self):
"""
Test running the hook_settings_tabs() method with a disabled plugin and a mocked form
"""
@ -121,7 +121,7 @@ class TestPluginManager(TestCase):
self.assertEqual(mocked_settings_form.plugin_manager.plugins, plugin_manager.plugins,
'The plugins on the settings form should be the same as the plugins in the plugin manager')
def hook_settings_tabs_with_active_plugin_and_mocked_form_test(self):
def test_hook_settings_tabs_with_active_plugin_and_mocked_form(self):
"""
Test running the hook_settings_tabs() method with an active plugin and a mocked settings form
"""
@ -143,7 +143,7 @@ class TestPluginManager(TestCase):
self.assertEqual(plugin_manager.plugins, mocked_settings_form.plugin_manager.plugins,
'The plugins on the settings form should be the same as the plugins in the plugin manager')
def hook_settings_tabs_with_active_plugin_and_no_form_test(self):
def test_hook_settings_tabs_with_active_plugin_and_no_form(self):
"""
Test running the hook_settings_tabs() method with an active plugin and no settings form
"""
@ -159,7 +159,7 @@ class TestPluginManager(TestCase):
# THEN: The create_settings_tab() method should have been called
mocked_plugin.create_settings_tab.assert_called_with(self.mocked_settings_form)
def hook_import_menu_with_disabled_plugin_test(self):
def test_hook_import_menu_with_disabled_plugin(self):
"""
Test running the hook_import_menu() method with a disabled plugin
"""
@ -176,7 +176,7 @@ class TestPluginManager(TestCase):
self.assertEqual(0, mocked_plugin.add_import_menu_item.call_count,
'The add_import_menu_item() method should not have been called.')
def hook_import_menu_with_active_plugin_test(self):
def test_hook_import_menu_with_active_plugin(self):
"""
Test running the hook_import_menu() method with an active plugin
"""
@ -192,7 +192,7 @@ class TestPluginManager(TestCase):
# THEN: The add_import_menu_item() method should have been called
mocked_plugin.add_import_menu_item.assert_called_with(self.mocked_main_window.file_import_menu)
def hook_export_menu_with_disabled_plugin_test(self):
def test_hook_export_menu_with_disabled_plugin(self):
"""
Test running the hook_export_menu() method with a disabled plugin
"""
@ -209,7 +209,7 @@ class TestPluginManager(TestCase):
self.assertEqual(0, mocked_plugin.add_export_menu_item.call_count,
'The add_export_menu_item() method should not have been called.')
def hook_export_menu_with_active_plugin_test(self):
def test_hook_export_menu_with_active_plugin(self):
"""
Test running the hook_export_menu() method with an active plugin
"""
@ -225,7 +225,7 @@ class TestPluginManager(TestCase):
# THEN: The add_export_menu_item() method should have been called
mocked_plugin.add_export_menu_item.assert_called_with(self.mocked_main_window.file_export_menu)
def hook_upgrade_plugin_settings_with_disabled_plugin_test(self):
def test_hook_upgrade_plugin_settings_with_disabled_plugin(self):
"""
Test running the hook_upgrade_plugin_settings() method with a disabled plugin
"""
@ -243,7 +243,7 @@ class TestPluginManager(TestCase):
self.assertEqual(0, mocked_plugin.upgrade_settings.call_count,
'The upgrade_settings() method should not have been called.')
def hook_upgrade_plugin_settings_with_active_plugin_test(self):
def test_hook_upgrade_plugin_settings_with_active_plugin(self):
"""
Test running the hook_upgrade_plugin_settings() method with an active plugin
"""
@ -260,7 +260,7 @@ class TestPluginManager(TestCase):
# THEN: The add_export_menu_item() method should have been called
mocked_plugin.upgrade_settings.assert_called_with(settings)
def hook_tools_menu_with_disabled_plugin_test(self):
def test_hook_tools_menu_with_disabled_plugin(self):
"""
Test running the hook_tools_menu() method with a disabled plugin
"""
@ -277,7 +277,7 @@ class TestPluginManager(TestCase):
self.assertEqual(0, mocked_plugin.add_tools_menu_item.call_count,
'The add_tools_menu_item() method should not have been called.')
def hook_tools_menu_with_active_plugin_test(self):
def test_hook_tools_menu_with_active_plugin(self):
"""
Test running the hook_tools_menu() method with an active plugin
"""
@ -293,7 +293,7 @@ class TestPluginManager(TestCase):
# THEN: The add_tools_menu_item() method should have been called
mocked_plugin.add_tools_menu_item.assert_called_with(self.mocked_main_window.tools_menu)
def initialise_plugins_with_disabled_plugin_test(self):
def test_initialise_plugins_with_disabled_plugin(self):
"""
Test running the initialise_plugins() method with a disabled plugin
"""
@ -311,7 +311,7 @@ class TestPluginManager(TestCase):
mocked_plugin.is_active.assert_called_with()
self.assertEqual(0, mocked_plugin.initialise.call_count, 'The initialise() method should not have been called.')
def initialise_plugins_with_active_plugin_test(self):
def test_initialise_plugins_with_active_plugin(self):
"""
Test running the initialise_plugins() method with an active plugin
"""
@ -329,7 +329,7 @@ class TestPluginManager(TestCase):
mocked_plugin.is_active.assert_called_with()
mocked_plugin.initialise.assert_called_with()
def finalise_plugins_with_disabled_plugin_test(self):
def test_finalise_plugins_with_disabled_plugin(self):
"""
Test running the finalise_plugins() method with a disabled plugin
"""
@ -347,7 +347,7 @@ class TestPluginManager(TestCase):
mocked_plugin.is_active.assert_called_with()
self.assertEqual(0, mocked_plugin.finalise.call_count, 'The finalise() method should not have been called.')
def finalise_plugins_with_active_plugin_test(self):
def test_finalise_plugins_with_active_plugin(self):
"""
Test running the finalise_plugins() method with an active plugin
"""
@ -365,7 +365,7 @@ class TestPluginManager(TestCase):
mocked_plugin.is_active.assert_called_with()
mocked_plugin.finalise.assert_called_with()
def get_plugin_by_name_does_not_exist_test(self):
def test_get_plugin_by_name_does_not_exist(self):
"""
Test running the get_plugin_by_name() method to find a plugin that does not exist
"""
@ -381,7 +381,7 @@ class TestPluginManager(TestCase):
# THEN: The is_active() and finalise() methods should have been called
self.assertIsNone(result, 'The result for get_plugin_by_name should be None')
def get_plugin_by_name_exists_test(self):
def test_get_plugin_by_name_exists(self):
"""
Test running the get_plugin_by_name() method to find a plugin that exists
"""
@ -397,7 +397,7 @@ class TestPluginManager(TestCase):
# THEN: The is_active() and finalise() methods should have been called
self.assertEqual(result, mocked_plugin, 'The result for get_plugin_by_name should be the mocked plugin')
def new_service_created_with_disabled_plugin_test(self):
def test_new_service_created_with_disabled_plugin(self):
"""
Test running the new_service_created() method with a disabled plugin
"""
@ -416,7 +416,7 @@ class TestPluginManager(TestCase):
self.assertEqual(0, mocked_plugin.new_service_created.call_count,
'The new_service_created() method should not have been called.')
def new_service_created_with_active_plugin_test(self):
def test_new_service_created_with_active_plugin(self):
"""
Test running the new_service_created() method with an active plugin
"""

View File

@ -35,6 +35,20 @@ from tests.resources.projector.data import TEST_PIN, TEST_SALT, TEST_CONNECT_AUT
pjlink_test = PJLink1(name='test', ip='127.0.0.1', pin=TEST_PIN, no_poll=True)
class DummyTimer(object):
'''
Dummy class to fake timers
'''
def __init__(self, *args, **kwargs):
pass
def start(self, *args, **kwargs):
pass
def stop(self, *args, **kwargs):
pass
class TestPJLink(TestCase):
"""
Tests for the PJLink module
@ -43,13 +57,10 @@ class TestPJLink(TestCase):
@patch.object(pjlink_test, 'send_command')
@patch.object(pjlink_test, 'waitForReadyRead')
@patch('openlp.core.common.qmd5_hash')
def authenticated_connection_call_test(self,
mock_qmd5_hash,
mock_waitForReadyRead,
mock_send_command,
def test_authenticated_connection_call(self, mock_qmd5_hash, mock_waitForReadyRead, mock_send_command,
mock_readyRead):
"""
Fix for projector connect with PJLink authentication exception. Ticket 92187.
Ticket 92187: Fix for projector connect with PJLink authentication exception.
"""
# GIVEN: Test object
pjlink = pjlink_test
@ -63,9 +74,23 @@ class TestPJLink(TestCase):
self.assertTrue(mock_qmd5_hash.called_with(TEST_PIN,
"Connection request should have been called with TEST_PIN"))
def non_standard_class_reply_test(self):
def test_projector_class(self):
"""
bugfix 1550891 - CLSS request returns non-standard 'Class N' reply
Test class version from projector
"""
# GIVEN: Test object
pjlink = pjlink_test
# WHEN: Process class response
pjlink.process_clss('1')
# THEN: Projector class should be set to 1
self.assertEquals(pjlink.pjlink_class, '1',
'Projector should have returned class=1')
def test_non_standard_class_reply(self):
"""
Bugfix 1550891: CLSS request returns non-standard 'Class N' reply
"""
# GIVEN: Test object
pjlink = pjlink_test
@ -78,7 +103,7 @@ class TestPJLink(TestCase):
'Non-standard class reply should have set proper class')
@patch.object(pjlink_test, 'change_status')
def status_change_test(self, mock_change_status):
def test_status_change(self, mock_change_status):
"""
Test process_command call with ERR2 (Parameter) status
"""
@ -95,7 +120,7 @@ class TestPJLink(TestCase):
ERROR_STRING[E_PARAMETER]))
@patch.object(pjlink_test, 'process_inpt')
def projector_return_ok_test(self, mock_process_inpt):
def test_projector_return_ok(self, mock_process_inpt):
"""
Test projector calls process_inpt command when process_command is called with INPT option
"""
@ -110,7 +135,7 @@ class TestPJLink(TestCase):
"process_inpt should have been called with 31")
@patch.object(pjlink_test, 'projectorReceivedData')
def projector_process_lamp_test(self, mock_projectorReceivedData):
def test_projector_process_lamp(self, mock_projectorReceivedData):
"""
Test status lamp on/off and hours
"""
@ -127,7 +152,7 @@ class TestPJLink(TestCase):
'Lamp hours should have been set to 22222')
@patch.object(pjlink_test, 'projectorReceivedData')
def projector_process_multiple_lamp_test(self, mock_projectorReceivedData):
def test_projector_process_multiple_lamp(self, mock_projectorReceivedData):
"""
Test status multiple lamp on/off and hours
"""
@ -154,7 +179,7 @@ class TestPJLink(TestCase):
'Lamp 3 hours should have been set to 33333')
@patch.object(pjlink_test, 'projectorReceivedData')
def projector_process_power_on_test(self, mock_projectorReceivedData):
def test_projector_process_power_on(self, mock_projectorReceivedData):
"""
Test status power to ON
"""
@ -169,7 +194,7 @@ class TestPJLink(TestCase):
self.assertEquals(pjlink.power, S_ON, 'Power should have been set to ON')
@patch.object(pjlink_test, 'projectorReceivedData')
def projector_process_power_off_test(self, mock_projectorReceivedData):
def test_projector_process_power_off(self, mock_projectorReceivedData):
"""
Test status power to STANDBY
"""
@ -184,7 +209,7 @@ class TestPJLink(TestCase):
self.assertEquals(pjlink.power, S_STANDBY, 'Power should have been set to STANDBY')
@patch.object(pjlink_test, 'projectorUpdateIcons')
def projector_process_avmt_closed_unmuted_test(self, mock_projectorReceivedData):
def test_projector_process_avmt_closed_unmuted(self, mock_projectorReceivedData):
"""
Test avmt status shutter closed and audio muted
"""
@ -201,7 +226,7 @@ class TestPJLink(TestCase):
self.assertFalse(pjlink.mute, 'Audio should be off')
@patch.object(pjlink_test, 'projectorUpdateIcons')
def projector_process_avmt_open_muted_test(self, mock_projectorReceivedData):
def test_projector_process_avmt_open_muted(self, mock_projectorReceivedData):
"""
Test avmt status shutter open and mute on
"""
@ -218,7 +243,7 @@ class TestPJLink(TestCase):
self.assertTrue(pjlink.mute, 'Audio should be off')
@patch.object(pjlink_test, 'projectorUpdateIcons')
def projector_process_avmt_open_unmuted_test(self, mock_projectorReceivedData):
def test_projector_process_avmt_open_unmuted(self, mock_projectorReceivedData):
"""
Test avmt status shutter open and mute off off
"""
@ -235,7 +260,7 @@ class TestPJLink(TestCase):
self.assertFalse(pjlink.mute, 'Audio should be on')
@patch.object(pjlink_test, 'projectorUpdateIcons')
def projector_process_avmt_closed_muted_test(self, mock_projectorReceivedData):
def test_projector_process_avmt_closed_muted(self, mock_projectorReceivedData):
"""
Test avmt status shutter closed and mute off
"""
@ -251,7 +276,7 @@ class TestPJLink(TestCase):
self.assertTrue(pjlink.shutter, 'Shutter should have been set to closed')
self.assertTrue(pjlink.mute, 'Audio should be on')
def projector_process_input_test(self):
def test_projector_process_input(self):
"""
Test input source status shows current input
"""
@ -264,3 +289,46 @@ class TestPJLink(TestCase):
# THEN: Input selected should reflect current input
self.assertEquals(pjlink.source, '1', 'Input source should be set to "1"')
def test_projector_reset_information(self):
"""
Test reset_information() resets all information and stops timers
"""
# GIVEN: Test object and test data
pjlink = pjlink_test
pjlink.power = S_ON
pjlink.pjlink_name = 'OPENLPTEST'
pjlink.manufacturer = 'PJLINK'
pjlink.model = '1'
pjlink.shutter = True
pjlink.mute = True
pjlink.lamp = True
pjlink.fan = True
pjlink.source_available = True
pjlink.other_info = 'ANOTHER TEST'
pjlink.send_queue = True
pjlink.send_busy = True
pjlink.timer = DummyTimer()
pjlink.socket_timer = DummyTimer()
# WHEN: reset_information() is called
with patch.object(pjlink.timer, 'stop') as mock_timer:
with patch.object(pjlink.socket_timer, 'stop') as mock_socket_timer:
pjlink.reset_information()
# THEN: All information should be reset and timers stopped
self.assertEquals(pjlink.power, S_OFF, 'Projector power should be OFF')
self.assertIsNone(pjlink.pjlink_name, 'Projector pjlink_name should be None')
self.assertIsNone(pjlink.manufacturer, 'Projector manufacturer should be None')
self.assertIsNone(pjlink.model, 'Projector model should be None')
self.assertIsNone(pjlink.shutter, 'Projector shutter should be None')
self.assertIsNone(pjlink.mute, 'Projector shuttter should be None')
self.assertIsNone(pjlink.lamp, 'Projector lamp should be None')
self.assertIsNone(pjlink.fan, 'Projector fan should be None')
self.assertIsNone(pjlink.source_available, 'Projector source_available should be None')
self.assertIsNone(pjlink.source, 'Projector source should be None')
self.assertIsNone(pjlink.other_info, 'Projector other_info should be None')
self.assertEquals(pjlink.send_queue, [], 'Projector send_queue should be an empty list')
self.assertFalse(pjlink.send_busy, 'Projector send_busy should be False')
self.assertTrue(mock_timer.called, 'Projector timer.stop() should have been called')
self.assertTrue(mock_socket_timer.called, 'Projector socket_timer.stop() should have been called')

View File

@ -107,7 +107,7 @@ class TestProjectorDB(TestCase):
time.sleep(1)
retries += 1
def find_record_by_ip_test(self):
def test_find_record_by_ip(self):
"""
Test find record by IP
"""
@ -121,7 +121,7 @@ class TestProjectorDB(TestCase):
self.assertTrue(compare_data(Projector(**TEST2_DATA), record),
'Record found should have been test_2 data')
def find_record_by_name_test(self):
def test_find_record_by_name(self):
"""
Test find record by name
"""
@ -135,7 +135,7 @@ class TestProjectorDB(TestCase):
self.assertTrue(compare_data(Projector(**TEST2_DATA), record),
'Record found should have been test_2 data')
def record_delete_test(self):
def test_record_delete(self):
"""
Test record can be deleted
"""
@ -150,7 +150,7 @@ class TestProjectorDB(TestCase):
found = self.projector.get_projector_by_ip(TEST3_DATA['ip'])
self.assertFalse(found, 'test_3 record should have been deleted')
def record_edit_test(self):
def test_record_edit(self):
"""
Test edited record returns the same record ID with different data
"""
@ -176,7 +176,7 @@ class TestProjectorDB(TestCase):
self.assertEqual(record_id, record.id, 'Edited record should have the same ID')
self.assertTrue(compare_data(Projector(**TEST3_DATA), record), 'Edited record should have new data')
def source_add_test(self):
def test_source_add(self):
"""
Test source entry for projector item
"""
@ -194,7 +194,7 @@ class TestProjectorDB(TestCase):
item = self.projector.get_projector_by_id(item_id)
self.assertTrue(compare_source(item.source_list[0], source))
def manufacturer_repr_test(self):
def test_manufacturer_repr(self):
"""
Test Manufacturer.__repr__ text
"""
@ -208,7 +208,7 @@ class TestProjectorDB(TestCase):
self.assertEqual(str(manufacturer), '<Manufacturer(name="OpenLP Test")>',
'Manufacturer.__repr__() should have returned a proper representation string')
def model_repr_test(self):
def test_model_repr(self):
"""
Test Model.__repr__ text
"""
@ -222,7 +222,7 @@ class TestProjectorDB(TestCase):
self.assertEqual(str(model), '<Model(name='"OpenLP Test"')>',
'Model.__repr__() should have returned a proper representation string')
def source_repr_test(self):
def test_source_repr(self):
"""
Test Source.__repr__ text
"""
@ -238,7 +238,7 @@ class TestProjectorDB(TestCase):
self.assertEqual(str(source), '<Source(pjlink_name="Test object", pjlink_code="11", text="Input text")>',
'Source.__repr__() should have returned a proper representation string')
def projector_repr_test(self):
def test_projector_repr(self):
"""
Test Projector.__repr__() text
"""
@ -265,3 +265,22 @@ class TestProjectorDB(TestCase):
'manufacturer="IN YOUR DREAMS", model="OpenLP", other="None", sources="None", '
'source_list="[]") >',
'Projector.__repr__() should have returned a proper representation string')
def test_projectorsource_repr(self):
"""
Test ProjectorSource.__repr__() text
"""
# GIVEN: test setup
projector1 = Projector(**TEST1_DATA)
self.projector.add_projector(projector1)
item = self.projector.get_projector_by_id(projector1.id)
item_id = item.id
# WHEN: A source entry is saved for item
source = ProjectorSource(projector_id=item_id, code='11', text='First RGB source')
self.projector.add_source(source)
# THEN: __repr__ should return a proper string
self.assertEqual(str(source),
'<ProjectorSource(id="1", code="11", text="First RGB source", projector_id="1")>',
'ProjectorSource.__repr__)_ should have returned a proper representation string')

View File

@ -59,7 +59,7 @@ class TestRenderer(TestCase):
"""
del self.screens
def default_screen_layout_test(self):
def test_default_screen_layout(self):
"""
Test the default layout calculations
"""
@ -73,7 +73,7 @@ class TestRenderer(TestCase):
self.assertEqual(renderer.footer_start, 691, 'The base renderer should be a live controller')
@patch('openlp.core.lib.renderer.FormattingTags.get_html_tags')
def get_start_tags_test(self, mocked_get_html_tags):
def test_get_start_tags(self, mocked_get_html_tags):
"""
Test the get_start_tags() method
"""
@ -95,7 +95,7 @@ class TestRenderer(TestCase):
self.assertEqual(result, expected_tuple), 'A tuple should be returned containing the text with correct ' \
'tags, the opening tags, and the opening html tags.'
def word_split_test(self):
def test_word_split(self):
"""
Test the word_split() method
"""
@ -109,7 +109,7 @@ class TestRenderer(TestCase):
# THEN: The word lists should be the same.
self.assertListEqual(result_words, expected_words)
def format_slide_logical_split_test(self):
def test_format_slide_logical_split(self):
"""
Test that a line with text and a logic break does not break the renderer just returns the input
"""
@ -126,7 +126,7 @@ class TestRenderer(TestCase):
# THEN: The word lists should be the same.
self.assertListEqual(result_words, expected_words)
def format_slide_blank_before_split_test(self):
def test_format_slide_blank_before_split(self):
"""
Test that a line with blanks before the logical split at handled
"""
@ -143,7 +143,7 @@ class TestRenderer(TestCase):
# THEN: The blanks have been removed.
self.assertListEqual(result_words, expected_words)
def format_slide_blank_after_split_test(self):
def test_format_slide_blank_after_split(self):
"""
Test that a line with blanks before the logical split at handled
"""

View File

@ -62,7 +62,7 @@ class TestScreenList(TestCase):
del self.screens
del self.application
def add_desktop_test(self):
def test_add_desktop(self):
"""
Test the ScreenList.screen_count_changed method to check if new monitors are detected by OpenLP.
"""

View File

@ -54,7 +54,7 @@ class TestServiceItem(TestCase):
Registry().register('renderer', mocked_renderer)
Registry().register('image_manager', MagicMock())
def service_item_basic_test(self):
def test_service_item_basic(self):
"""
Test the Service Item - basic test
"""
@ -67,7 +67,7 @@ class TestServiceItem(TestCase):
self.assertTrue(service_item.is_valid, 'The new service item should be valid')
self.assertTrue(service_item.missing_frames(), 'There should not be any frames in the service item')
def service_item_load_custom_from_service_test(self):
def test_service_item_load_custom_from_service(self):
"""
Test the Service Item - adding a custom slide from a saved service
"""
@ -97,7 +97,7 @@ class TestServiceItem(TestCase):
self.assertEqual('Slide 2', service_item.get_frame_title(1), '"Slide 2" has been returned as the title')
self.assertEqual('', service_item.get_frame_title(2), 'Blank has been returned as the title of slide 3')
def service_item_load_image_from_service_test(self):
def test_service_item_load_image_from_service(self):
"""
Test the Service Item - adding an image from a saved service
"""
@ -141,7 +141,7 @@ class TestServiceItem(TestCase):
self.assertTrue(service_item.is_capable(ItemCapabilities.CanAppend),
'This service item should be able to have new items added to it')
def service_item_load_image_from_local_service_test(self):
def test_service_item_load_image_from_local_service(self):
"""
Test the Service Item - adding an image from a saved local service
"""
@ -206,7 +206,7 @@ class TestServiceItem(TestCase):
self.assertTrue(service_item.is_capable(ItemCapabilities.CanAppend),
'This service item should be able to have new items added to it')
def add_from_command_for_a_presentation_test(self):
def test_add_from_command_for_a_presentation(self):
"""
Test the Service Item - adding a presentation
"""
@ -226,7 +226,7 @@ class TestServiceItem(TestCase):
self.assertEqual(service_item.service_item_type, ServiceItemType.Command, 'It should be a Command')
self.assertEqual(service_item.get_frames()[0], frame, 'Frames should match')
def add_from_comamnd_without_display_title_and_notes_test(self):
def test_add_from_comamnd_without_display_title_and_notes(self):
"""
Test the Service Item - add from command, but not presentation
"""
@ -246,7 +246,7 @@ class TestServiceItem(TestCase):
@patch(u'openlp.core.lib.serviceitem.ServiceItem.image_manager')
@patch('openlp.core.lib.serviceitem.AppLocation.get_section_data_path')
def add_from_command_for_a_presentation_thumb_test(self, mocked_get_section_data_path, mocked_image_manager):
def test_add_from_command_for_a_presentation_thumb(self, mocked_get_section_data_path, mocked_image_manager):
"""
Test the Service Item - adding a presentation, updating the thumb path & adding the thumb to image_manager
"""
@ -274,7 +274,7 @@ class TestServiceItem(TestCase):
self.assertEqual(service_item.get_frames()[0], frame, 'Frames should match')
self.assertEqual(1, mocked_image_manager.add_image.call_count, 'image_manager should be used')
def service_item_load_optical_media_from_service_test(self):
def test_service_item_load_optical_media_from_service(self):
"""
Test the Service Item - load an optical media item
"""
@ -295,7 +295,7 @@ class TestServiceItem(TestCase):
self.assertEqual(service_item.end_time, 672.069, 'End time should be 672.069')
self.assertEqual(service_item.media_length, 17.694, 'Media length should be 17.694')
def service_item_load_song_and_audio_from_service_test(self):
def test_service_item_load_song_and_audio_from_service(self):
"""
Test the Service Item - adding a song slide from a saved service
"""

View File

@ -44,7 +44,7 @@ class TestTheme(TestCase):
"""
pass
def new_theme_test(self):
def test_new_theme(self):
"""
Test the theme creation - basic test
"""

View File

@ -37,7 +37,7 @@ class TestUi(TestCase):
Test the functions in the ui module
"""
def add_welcome_page_test(self):
def test_add_welcome_page(self):
"""
Test appending a welcome page to a wizard
"""
@ -51,7 +51,7 @@ class TestUi(TestCase):
self.assertEqual(1, len(wizard.pageIds()), 'The wizard should have one page.')
self.assertIsInstance(wizard.page(0).pixmap(QtWidgets.QWizard.WatermarkPixmap), QtGui.QPixmap)
def create_button_box_test(self):
def test_create_button_box(self):
"""
Test creating a button box for a dialog
"""
@ -79,7 +79,7 @@ class TestUi(TestCase):
self.assertEqual(1, len(btnbox.buttons()))
self.assertEqual(QtWidgets.QDialogButtonBox.HelpRole, btnbox.buttonRole(btnbox.buttons()[0]))
def create_horizontal_adjusting_combo_box_test(self):
def test_create_horizontal_adjusting_combo_box(self):
"""
Test creating a horizontal adjusting combo box
"""
@ -94,7 +94,7 @@ class TestUi(TestCase):
self.assertEqual('combo1', combo.objectName())
self.assertEqual(QtWidgets.QComboBox.AdjustToMinimumContentsLength, combo.sizeAdjustPolicy())
def create_button_test(self):
def test_create_button(self):
"""
Test creating a button
"""
@ -126,7 +126,7 @@ class TestUi(TestCase):
self.assertEqual('my_btn', btn.objectName())
self.assertTrue(btn.isEnabled())
def create_action_test(self):
def test_create_action(self):
"""
Test creating an action
"""
@ -151,7 +151,7 @@ class TestUi(TestCase):
self.assertEqual('my tooltip', action.toolTip())
self.assertEqual('my statustip', action.statusTip())
def create_action_on_mac_osx_test(self):
def test_create_action_on_mac_osx(self):
"""
Test creating an action on OS X calls the correct method
"""
@ -169,7 +169,7 @@ class TestUi(TestCase):
# THEN: setIconVisibleInMenu should be called
mocked_action.setIconVisibleInMenu.assert_called_with(False)
def create_action_not_on_mac_osx_test(self):
def test_create_action_not_on_mac_osx(self):
"""
Test creating an action on something other than OS X doesn't call the method
"""
@ -188,7 +188,7 @@ class TestUi(TestCase):
self.assertEqual(0, mocked_action.setIconVisibleInMenu.call_count,
'setIconVisibleInMenu should not have been called')
def create_checked_disabled_invisible_action_test(self):
def test_create_checked_disabled_invisible_action(self):
"""
Test that an invisible, disabled, checked action is created correctly
"""
@ -203,7 +203,7 @@ class TestUi(TestCase):
self.assertFalse(action.isEnabled(), 'The action should be disabled')
self.assertFalse(action.isVisible(), 'The action should be invisble')
def create_action_separator_test(self):
def test_create_action_separator(self):
"""
Test creating an action as separator
"""
@ -216,7 +216,7 @@ class TestUi(TestCase):
# THEN: The action should be a separator
self.assertTrue(action.isSeparator(), 'The action should be a separator')
def create_valign_selection_widgets_test(self):
def test_create_valign_selection_widgets(self):
"""
Test creating a combo box for valign selection
"""
@ -233,7 +233,7 @@ class TestUi(TestCase):
for text in [UiStrings().Top, UiStrings().Middle, UiStrings().Bottom]:
self.assertTrue(combo.findText(text) >= 0)
def find_and_set_in_combo_box_test(self):
def test_find_and_set_in_combo_box(self):
"""
Test finding a string in a combo box and setting it as the selected item if present
"""
@ -260,7 +260,7 @@ class TestUi(TestCase):
# THEN: The index should have changed
self.assertEqual(2, combo.currentIndex())
def create_widget_action_test(self):
def test_create_widget_action(self):
"""
Test creating an action for a widget
"""
@ -274,7 +274,7 @@ class TestUi(TestCase):
self.assertIsInstance(action, QtWidgets.QAction)
self.assertEqual(action.objectName(), 'some action')
def set_case_insensitive_completer_test(self):
def test_set_case_insensitive_completer(self):
"""
Test setting a case insensitive completer on a widget
"""

View File

@ -33,7 +33,7 @@ class TestUtils(TestCase):
"""
A test suite to test out various methods around the AppLocation class.
"""
def get_user_agent_linux_test(self):
def test_get_user_agent_linux(self):
"""
Test that getting a user agent on Linux returns a user agent suitable for Linux
"""
@ -49,7 +49,7 @@ class TestUtils(TestCase):
result = 'Linux' in user_agent or 'CrOS' in user_agent
self.assertTrue(result, 'The user agent should be a valid Linux user agent')
def get_user_agent_windows_test(self):
def test_get_user_agent_windows(self):
"""
Test that getting a user agent on Windows returns a user agent suitable for Windows
"""
@ -64,7 +64,7 @@ class TestUtils(TestCase):
# THEN: The user agent is a Linux (or ChromeOS) user agent
self.assertIn('Windows', user_agent, 'The user agent should be a valid Windows user agent')
def get_user_agent_macos_test(self):
def test_get_user_agent_macos(self):
"""
Test that getting a user agent on OS X returns a user agent suitable for OS X
"""
@ -79,7 +79,7 @@ class TestUtils(TestCase):
# THEN: The user agent is a Linux (or ChromeOS) user agent
self.assertIn('Mac OS X', user_agent, 'The user agent should be a valid OS X user agent')
def get_user_agent_default_test(self):
def test_get_user_agent_default(self):
"""
Test that getting a user agent on a non-Linux/Windows/OS X platform returns the default user agent
"""
@ -94,7 +94,7 @@ class TestUtils(TestCase):
# THEN: The user agent is a Linux (or ChromeOS) user agent
self.assertIn('NetBSD', user_agent, 'The user agent should be the default user agent')
def get_web_page_no_url_test(self):
def test_get_web_page_no_url(self):
"""
Test that sending a URL of None to the get_web_page method returns None
"""
@ -107,7 +107,7 @@ class TestUtils(TestCase):
# THEN: None should be returned
self.assertIsNone(result, 'The return value of get_web_page should be None')
def get_web_page_test(self):
def test_get_web_page(self):
"""
Test that the get_web_page method works correctly
"""
@ -137,7 +137,7 @@ class TestUtils(TestCase):
self.assertEqual(0, MockRegistry.call_count, 'The Registry() object should have never been called')
self.assertEqual(mocked_page_object, returned_page, 'The returned page should be the mock object')
def get_web_page_with_header_test(self):
def test_get_web_page_with_header(self):
"""
Test that adding a header to the call to get_web_page() adds the header to the request
"""
@ -166,7 +166,7 @@ class TestUtils(TestCase):
mocked_page_object.geturl.assert_called_with()
self.assertEqual(mocked_page_object, returned_page, 'The returned page should be the mock object')
def get_web_page_with_user_agent_in_headers_test(self):
def test_get_web_page_with_user_agent_in_headers(self):
"""
Test that adding a user agent in the header when calling get_web_page() adds that user agent to the request
"""
@ -194,7 +194,7 @@ class TestUtils(TestCase):
mocked_page_object.geturl.assert_called_with()
self.assertEqual(mocked_page_object, returned_page, 'The returned page should be the mock object')
def get_web_page_update_openlp_test(self):
def test_get_web_page_update_openlp(self):
"""
Test that passing "update_openlp" as true to get_web_page calls Registry().get('app').process_events()
"""

View File

@ -38,7 +38,7 @@ class TestFirstTimeWizard(TestMixin, TestCase):
"""
Test First Time Wizard import functions
"""
def webpage_connection_retry_test(self):
def test_webpage_connection_retry(self):
"""
Test get_web_page will attempt CONNECTION_RETRIES+1 connections - bug 1409031
"""

View File

@ -78,7 +78,7 @@ class TestFirstTimeForm(TestCase, TestMixin):
if os.path.isfile(self.tempfile):
os.remove(self.tempfile)
def initialise_test(self):
def test_initialise(self):
"""
Test if we can intialise the FirstTimeForm
"""
@ -97,7 +97,7 @@ class TestFirstTimeForm(TestCase, TestMixin):
self.assertListEqual([], frw.theme_screenshot_workers, 'The list of workers should be empty')
self.assertFalse(frw.has_run_wizard, 'has_run_wizard should be False')
def set_defaults_test(self):
def test_set_defaults(self):
"""
Test that the default values are set when set_defaults() is run
"""
@ -134,7 +134,7 @@ class TestFirstTimeForm(TestCase, TestMixin):
mocked_gettempdir.assert_called_with()
mocked_check_directory_exists.assert_called_with(expected_temp_path)
def update_screen_list_combo_test(self):
def test_update_screen_list_combo(self):
"""
Test that the update_screen_list_combo() method works correctly
"""
@ -157,7 +157,7 @@ class TestFirstTimeForm(TestCase, TestMixin):
mocked_display_combo_box.count.assert_called_with()
mocked_display_combo_box.setCurrentIndex.assert_called_with(1)
def on_cancel_button_clicked_test(self):
def test_on_cancel_button_clicked(self):
"""
Test that the cancel button click slot shuts down the threads correctly
"""
@ -184,7 +184,7 @@ class TestFirstTimeForm(TestCase, TestMixin):
self.assertEqual(1, mocked_time.sleep.call_count, 'sleep() should have only been called once')
mocked_set_normal_cursor.assert_called_with()
def broken_config_test(self):
def test_broken_config(self):
"""
Test if we can handle an config file with missing data
"""
@ -200,7 +200,7 @@ class TestFirstTimeForm(TestCase, TestMixin):
# THEN: The First Time Form should not have web access
self.assertFalse(first_time_form.web_access, 'There should not be web access with a broken config file')
def invalid_config_test(self):
def test_invalid_config(self):
"""
Test if we can handle an config file in invalid format
"""
@ -218,7 +218,7 @@ class TestFirstTimeForm(TestCase, TestMixin):
@patch('openlp.core.ui.firsttimeform.get_web_page')
@patch('openlp.core.ui.firsttimeform.QtWidgets.QMessageBox')
def network_error_test(self, mocked_message_box, mocked_get_web_page):
def test_network_error(self, mocked_message_box, mocked_get_web_page):
"""
Test we catch a network error in First Time Wizard - bug 1409627
"""
@ -238,7 +238,7 @@ class TestFirstTimeForm(TestCase, TestMixin):
'first_time_form should have caught Network Error')
@patch('openlp.core.ui.firsttimeform.urllib.request.urlopen')
def socket_timeout_test(self, mocked_urlopen):
def test_socket_timeout(self, mocked_urlopen):
"""
Test socket timeout gets caught
"""

View File

@ -32,7 +32,7 @@ class TestFormattingTagController(TestCase):
def setUp(self):
self.services = FormattingTagController()
def strip_test(self):
def test_strip(self):
"""
Test that the _strip strips the correct chars
"""
@ -45,7 +45,7 @@ class TestFormattingTagController(TestCase):
# THEN: The tag should be returned with the wrappers removed.
self.assertEqual(result, 'tag', 'FormattingTagForm._strip should return u\'tag\' when called with u\'{tag}\'')
def end_tag_changed_processes_correctly_test(self):
def test_end_tag_changed_processes_correctly(self):
"""
Test that the end html tags are generated correctly
"""
@ -70,7 +70,7 @@ class TestFormattingTagController(TestCase):
self.assertTrue(error == test['valid'], 'Function should not generate unexpected error messages : %s ' %
error)
def start_tag_changed_processes_correctly_test(self):
def test_start_tag_changed_processes_correctly(self):
"""
Test that the end html tags are generated correctly
"""
@ -93,7 +93,7 @@ class TestFormattingTagController(TestCase):
self.assertTrue(error == test['valid'], 'Function should not generate unexpected error messages : %s ' %
error)
def start_html_to_end_html_test(self):
def test_start_html_to_end_html(self):
"""
Test that the end html tags are generated correctly
"""

View File

@ -50,7 +50,7 @@ class TestFormattingTagForm(TestCase):
"""
self.setup_patcher.stop()
def on_row_selected_test(self):
def test_on_row_selected(self):
"""
Test that the appropriate actions are preformed when on_row_selected is called
"""
@ -64,7 +64,7 @@ class TestFormattingTagForm(TestCase):
# THEN: setEnabled and should have been called on delete_button
form.delete_button.setEnabled.assert_called_with(True)
def on_new_clicked_test(self):
def test_on_new_clicked(self):
"""
Test that clicking the Add a new tag button does the right thing
"""

View File

@ -70,7 +70,7 @@ class TestMainDisplay(TestCase, TestMixin):
self.mocked_audio_player.stop()
del self.screens
def initial_main_display_test(self):
def test_initial_main_display(self):
"""
Test the initial Main Display state
"""
@ -84,7 +84,7 @@ class TestMainDisplay(TestCase, TestMixin):
# THEN: The controller should be a live controller.
self.assertEqual(main_display.is_live, True, 'The main display should be a live controller')
def set_transparency_enabled_test(self):
def test_set_transparency_enabled(self):
"""
Test setting the display to be transparent
"""
@ -103,7 +103,7 @@ class TestMainDisplay(TestCase, TestMixin):
self.assertTrue(main_display.testAttribute(QtCore.Qt.WA_TranslucentBackground),
'The MainDisplay should have a translucent background')
def set_transparency_disabled_test(self):
def test_set_transparency_disabled(self):
"""
Test setting the display to be opaque
"""
@ -120,7 +120,7 @@ class TestMainDisplay(TestCase, TestMixin):
self.assertFalse(main_display.testAttribute(QtCore.Qt.WA_TranslucentBackground),
'The MainDisplay should not have a translucent background')
def css_changed_test(self):
def test_css_changed(self):
"""
Test that when the CSS changes, the plugins are looped over and given an opportunity to update the CSS
"""
@ -143,7 +143,7 @@ class TestMainDisplay(TestCase, TestMixin):
mocked_bibles_plugin.refresh_css.assert_called_with(main_display.frame)
@skipUnless(is_macosx(), 'Can only run test on Mac OS X due to pyobjc dependency.')
def macosx_display_window_flags_state_test(self):
def test_macosx_display_window_flags_state(self):
"""
Test that on Mac OS X we set the proper window flags
"""
@ -160,7 +160,7 @@ class TestMainDisplay(TestCase, TestMixin):
'The window flags should be Qt.Window, and Qt.FramelessWindowHint.')
@skipUnless(is_macosx(), 'Can only run test on Mac OS X due to pyobjc dependency.')
def macosx_display_test(self):
def test_macosx_display(self):
"""
Test display on Mac OS X
"""
@ -186,7 +186,7 @@ class TestMainDisplay(TestCase, TestMixin):
'Window collection behavior should be NSWindowCollectionBehaviorManaged')
@patch(u'openlp.core.ui.maindisplay.Settings')
def show_display_startup_logo_test(self, MockedSettings):
def test_show_display_startup_logo(self, MockedSettings):
# GIVEN: Mocked show_display, setting for logo visibility
display = MagicMock()
main_display = MainDisplay(display)
@ -206,7 +206,7 @@ class TestMainDisplay(TestCase, TestMixin):
main_display.setVisible.assert_called_once_with(True)
@patch(u'openlp.core.ui.maindisplay.Settings')
def show_display_hide_startup_logo_test(self, MockedSettings):
def test_show_display_hide_startup_logo(self, MockedSettings):
# GIVEN: Mocked show_display, setting for logo visibility
display = MagicMock()
main_display = MainDisplay(display)
@ -227,7 +227,7 @@ class TestMainDisplay(TestCase, TestMixin):
@patch(u'openlp.core.ui.maindisplay.Settings')
@patch(u'openlp.core.ui.maindisplay.build_html')
def build_html_no_video_test(self, MockedSettings, Mocked_build_html):
def test_build_html_no_video(self, MockedSettings, Mocked_build_html):
# GIVEN: Mocked display
display = MagicMock()
mocked_media_controller = MagicMock()
@ -255,7 +255,7 @@ class TestMainDisplay(TestCase, TestMixin):
@patch(u'openlp.core.ui.maindisplay.Settings')
@patch(u'openlp.core.ui.maindisplay.build_html')
def build_html_video_test(self, MockedSettings, Mocked_build_html):
def test_build_html_video(self, MockedSettings, Mocked_build_html):
# GIVEN: Mocked display
display = MagicMock()
mocked_media_controller = MagicMock()

View File

@ -72,7 +72,7 @@ class TestMainWindow(TestCase, TestMixin):
def tearDown(self):
del self.main_window
def cmd_line_file_test(self):
def test_cmd_line_file(self):
"""
Test that passing a service file from the command line loads the service.
"""
@ -87,7 +87,7 @@ class TestMainWindow(TestCase, TestMixin):
# THEN the service from the arguments is loaded
mocked_load_path.assert_called_with(service), 'load_path should have been called with the service\'s path'
def cmd_line_arg_test(self):
def test_cmd_line_arg(self):
"""
Test that passing a non service file does nothing.
"""
@ -102,7 +102,7 @@ class TestMainWindow(TestCase, TestMixin):
# THEN the file should not be opened
assert not mocked_load_path.called, 'load_path should not have been called'
def main_window_title_test(self):
def test_main_window_title(self):
"""
Test that running a new instance of OpenLP set the window title correctly
"""
@ -114,7 +114,7 @@ class TestMainWindow(TestCase, TestMixin):
self.assertEqual(self.main_window.windowTitle(), UiStrings().OLPV2x,
'The main window\'s title should be the same as the OLPV2x string in UiStrings class')
def set_service_modifed_test(self):
def test_set_service_modifed(self):
"""
Test that when setting the service's title the main window's title is set correctly
"""
@ -127,7 +127,7 @@ class TestMainWindow(TestCase, TestMixin):
self.assertEqual(self.main_window.windowTitle(), '%s - %s*' % (UiStrings().OLPV2x, 'test.osz'),
'The main window\'s title should be set to "<the contents of UiStrings().OLPV2x> - test.osz*"')
def set_service_unmodified_test(self):
def test_set_service_unmodified(self):
"""
Test that when setting the service's title the main window's title is set correctly
"""
@ -140,7 +140,7 @@ class TestMainWindow(TestCase, TestMixin):
self.assertEqual(self.main_window.windowTitle(), '%s - %s' % (UiStrings().OLPV2x, 'test.osz'),
'The main window\'s title should be set to "<the contents of UiStrings().OLPV2x> - test.osz"')
def mainwindow_configuration_test(self):
def test_mainwindow_configuration(self):
"""
Check that the Main Window initialises the Registry Correctly
"""
@ -158,7 +158,7 @@ class TestMainWindow(TestCase, TestMixin):
self.assertTrue('plugin_manager' in self.registry.service_list,
'The plugin_manager should have been registered.')
def on_search_shortcut_triggered_shows_media_manager_test(self):
def test_on_search_shortcut_triggered_shows_media_manager(self):
"""
Test that the media manager is made visible when the search shortcut is triggered
"""
@ -174,7 +174,7 @@ class TestMainWindow(TestCase, TestMixin):
# THEN: The media manager dock is made visible
mocked_media_manager_dock.setVisible.assert_called_with(True)
def on_search_shortcut_triggered_focuses_widget_test(self):
def test_on_search_shortcut_triggered_focuses_widget(self):
"""
Test that the focus is set on the widget when the search shortcut is triggered
"""
@ -198,7 +198,7 @@ class TestMainWindow(TestCase, TestMixin):
@patch('openlp.core.ui.mainwindow.FirstTimeForm')
@patch('openlp.core.ui.mainwindow.QtWidgets.QMessageBox.warning')
@patch('openlp.core.ui.mainwindow.Settings')
def on_first_time_wizard_clicked_show_projectors_after_test(self, mocked_Settings, mocked_warning,
def test_on_first_time_wizard_clicked_show_projectors_after(self, mocked_Settings, mocked_warning,
mocked_FirstTimeForm, mocked_application,
mocked_first_time,
mocked_plugin_manager):
@ -225,7 +225,7 @@ class TestMainWindow(TestCase, TestMixin):
@patch('openlp.core.ui.mainwindow.FirstTimeForm')
@patch('openlp.core.ui.mainwindow.QtWidgets.QMessageBox.warning')
@patch('openlp.core.ui.mainwindow.Settings')
def on_first_time_wizard_clicked_hide_projectors_after_test(self, mocked_Settings, mocked_warning,
def test_on_first_time_wizard_clicked_hide_projectors_after(self, mocked_Settings, mocked_warning,
mocked_FirstTimeForm, mocked_application,
mocked_first_time,
mocked_plugin_manager):

View File

@ -40,7 +40,7 @@ class TestServiceManager(TestCase):
"""
Registry.create()
def initial_service_manager_test(self):
def test_initial_service_manager(self):
"""
Test the initial of service manager.
"""
@ -50,7 +50,7 @@ class TestServiceManager(TestCase):
# THEN: The the controller should be registered in the registry.
self.assertNotEqual(Registry().get('service_manager'), None, 'The base service manager should be registered')
def create_basic_service_test(self):
def test_create_basic_service(self):
"""
Test the create basic service array
"""
@ -65,7 +65,7 @@ class TestServiceManager(TestCase):
self.assertEqual(service['openlp_core']['service-theme'], 'test_theme', 'The test theme should be saved')
self.assertEqual(service['openlp_core']['lite-service'], False, 'The lite service should be saved')
def supported_suffixes_test(self):
def test_supported_suffixes(self):
"""
Test the create basic service array
"""
@ -79,7 +79,7 @@ class TestServiceManager(TestCase):
self.assertEqual('ppt' in service_manager.suffixes, True, 'The suffix ppt should be in the list')
self.assertEqual('pptx' in service_manager.suffixes, True, 'The suffix pptx should be in the list')
def build_context_menu_test(self):
def test_build_context_menu(self):
"""
Test the creation of a context menu from a null service item.
"""
@ -123,7 +123,7 @@ class TestServiceManager(TestCase):
self.assertEquals(service_manager.theme_menu.menuAction().setVisible.call_count, 1,
'Should have been called once')
def build_song_context_menu_test(self):
def test_build_song_context_menu(self):
"""
Test the creation of a context menu from service item of type text from Songs.
"""
@ -189,7 +189,7 @@ class TestServiceManager(TestCase):
self.assertEquals(service_manager.auto_play_slides_loop.setChecked.call_count, 1, 'Should have be called once')
self.assertEquals(service_manager.timed_slide_interval.setChecked.call_count, 1, 'Should have be called once')
def build_bible_context_menu_test(self):
def test_build_bible_context_menu(self):
"""
Test the creation of a context menu from service item of type text from Bibles.
"""
@ -254,7 +254,7 @@ class TestServiceManager(TestCase):
self.assertEquals(service_manager.auto_play_slides_loop.setChecked.call_count, 1, 'Should have be called once')
self.assertEquals(service_manager.timed_slide_interval.setChecked.call_count, 1, 'Should have be called once')
def build_custom_context_menu_test(self):
def test_build_custom_context_menu(self):
"""
Test the creation of a context menu from service item of type text from Custom.
"""
@ -319,7 +319,7 @@ class TestServiceManager(TestCase):
self.assertEquals(service_manager.auto_play_slides_loop.setChecked.call_count, 1, 'Should have be called once')
self.assertEquals(service_manager.timed_slide_interval.setChecked.call_count, 1, 'Should have be called once')
def build_image_context_menu_test(self):
def test_build_image_context_menu(self):
"""
Test the creation of a context menu from service item of type Image from Image.
"""
@ -382,7 +382,7 @@ class TestServiceManager(TestCase):
self.assertEquals(service_manager.auto_play_slides_loop.setChecked.call_count, 1, 'Should have be called once')
self.assertEquals(service_manager.timed_slide_interval.setChecked.call_count, 1, 'Should have be called once')
def build_media_context_menu_test(self):
def test_build_media_context_menu(self):
"""
Test the creation of a context menu from service item of type Command from Media.
"""
@ -439,7 +439,7 @@ class TestServiceManager(TestCase):
# THEN the following additional calls should have occurred.
self.assertEquals(service_manager.time_action.setVisible.call_count, 3, 'Should have be called three times')
def build_presentation_pdf_context_menu_test(self):
def test_build_presentation_pdf_context_menu(self):
"""
Test the creation of a context menu from service item of type Command with PDF from Presentation.
"""
@ -492,7 +492,7 @@ class TestServiceManager(TestCase):
self.assertEquals(service_manager.theme_menu.menuAction().setVisible.call_count, 1,
'Should have be called once')
def build_presentation_non_pdf_context_menu_test(self):
def test_build_presentation_non_pdf_context_menu(self):
"""
Test the creation of a context menu from service item of type Command with Impress from Presentation.
"""
@ -544,7 +544,7 @@ class TestServiceManager(TestCase):
@patch(u'openlp.core.ui.servicemanager.Settings')
@patch(u'PyQt5.QtCore.QTimer.singleShot')
def single_click_preview_test_true(self, mocked_singleShot, MockedSettings):
def test_single_click_preview_true(self, mocked_singleShot, MockedSettings):
"""
Test that when "Preview items when clicked in Service Manager" enabled the preview timer starts
"""
@ -561,7 +561,7 @@ class TestServiceManager(TestCase):
@patch(u'openlp.core.ui.servicemanager.Settings')
@patch(u'PyQt5.QtCore.QTimer.singleShot')
def single_click_preview_test_false(self, mocked_singleShot, MockedSettings):
def test_single_click_preview_false(self, mocked_singleShot, MockedSettings):
"""
Test that when "Preview items when clicked in Service Manager" disabled the preview timer doesn't start
"""
@ -578,7 +578,7 @@ class TestServiceManager(TestCase):
@patch(u'openlp.core.ui.servicemanager.Settings')
@patch(u'PyQt5.QtCore.QTimer.singleShot')
@patch(u'openlp.core.ui.servicemanager.ServiceManager.make_live')
def single_click_preview_test_double(self, mocked_make_live, mocked_singleShot, MockedSettings):
def test_single_click_preview_double(self, mocked_make_live, mocked_singleShot, MockedSettings):
"""
Test that when a double click has registered the preview timer doesn't start
"""
@ -594,7 +594,7 @@ class TestServiceManager(TestCase):
self.assertEquals(mocked_singleShot.call_count, 0, 'Should not be called')
@patch(u'openlp.core.ui.servicemanager.ServiceManager.make_preview')
def single_click_timeout_test_single(self, mocked_make_preview):
def test_single_click_timeout_single(self, mocked_make_preview):
"""
Test that when a single click has been registered, the item is sent to preview
"""
@ -607,7 +607,7 @@ class TestServiceManager(TestCase):
@patch(u'openlp.core.ui.servicemanager.ServiceManager.make_preview')
@patch(u'openlp.core.ui.servicemanager.ServiceManager.make_live')
def single_click_timeout_test_double(self, mocked_make_live, mocked_make_preview):
def test_single_click_timeout_double(self, mocked_make_live, mocked_make_preview):
"""
Test that when a double click has been registered, the item does not goes to preview
"""

View File

@ -39,7 +39,7 @@ class TestSettingsForm(TestCase):
"""
Registry.create()
def insert_tab_visible_test(self):
def test_insert_tab_visible(self):
"""
Test that the insert_tab() method works correctly when a visible tab is inserted
"""
@ -59,7 +59,7 @@ class TestSettingsForm(TestCase):
mocked_add_widget.assert_called_with(general_tab)
self.assertEqual(1, mocked_add_item.call_count, 'addItem should have been called')
def insert_tab_not_visible_test(self):
def test_insert_tab_not_visible(self):
"""
Test that the insert_tab() method works correctly when a tab that should not be visible is inserted
"""
@ -77,7 +77,7 @@ class TestSettingsForm(TestCase):
mocked_add_widget.assert_called_with(general_tab)
self.assertEqual(0, mocked_add_item.call_count, 'addItem should not have been called')
def accept_with_inactive_plugins_test(self):
def test_accept_with_inactive_plugins(self):
"""
Test that the accept() method works correctly when some of the plugins are inactive
"""
@ -105,7 +105,7 @@ class TestSettingsForm(TestCase):
mocked_general_save.assert_called_with()
self.assertEqual(0, mocked_theme_save.call_count, 'The Themes tab\'s save() should not have been called')
def list_item_changed_invalid_item_test(self):
def test_list_item_changed_invalid_item(self):
"""
Test that the list_item_changed() slot handles a non-existent item
"""
@ -124,7 +124,7 @@ class TestSettingsForm(TestCase):
# THEN: The rest of the method should not have been called
self.assertEqual(0, mocked_count.call_count, 'The count method of the stacked layout should not be called')
def reject_with_inactive_items_test(self):
def test_reject_with_inactive_items(self):
"""
Test that the reject() method works correctly when some of the plugins are inactive
"""

View File

@ -35,7 +35,7 @@ from tests.functional import MagicMock, patch
class TestSlideController(TestCase):
def initial_slide_controller_test(self):
def test_initial_slide_controller(self):
"""
Test the initial slide controller state .
"""
@ -46,7 +46,7 @@ class TestSlideController(TestCase):
# THEN: The controller should not be a live controller.
self.assertEqual(slide_controller.is_live, False, 'The base slide controller should not be a live controller')
def text_service_item_blank_test(self):
def test_text_service_item_blank(self):
"""
Test that loading a text-based service item into the slide controller sets the correct blank menu
"""
@ -65,7 +65,7 @@ class TestSlideController(TestCase):
# THEN: the call to set the visible items on the toolbar should be correct
toolbar.set_widget_visible.assert_called_with(WIDE_MENU, True)
def non_text_service_item_blank_test(self):
def test_non_text_service_item_blank(self):
"""
Test that loading a non-text service item into the slide controller sets the correct blank menu
"""
@ -85,7 +85,7 @@ class TestSlideController(TestCase):
toolbar.set_widget_visible.assert_called_with(NON_TEXT_MENU, True)
@patch('openlp.core.ui.slidecontroller.Settings')
def receive_spin_delay_test(self, MockedSettings):
def test_receive_spin_delay(self, MockedSettings):
"""
Test that the spin box is updated accordingly after a call to receive_spin_delay()
"""
@ -103,7 +103,7 @@ class TestSlideController(TestCase):
mocked_value.assert_called_with('core/loop delay')
mocked_delay_spin_box.setValue.assert_called_with(1)
def toggle_display_blank_test(self):
def test_toggle_display_blank(self):
"""
Check that the toggle_display('blank') method calls the on_blank_display() method
"""
@ -124,7 +124,7 @@ class TestSlideController(TestCase):
self.assertEqual(0, mocked_on_theme_display.call_count, 'on_theme_display should not have been called')
self.assertEqual(0, mocked_on_hide_display.call_count, 'on_hide_display should not have been called')
def toggle_display_hide_test(self):
def test_toggle_display_hide(self):
"""
Check that the toggle_display('hide') method calls the on_blank_display() method
"""
@ -145,7 +145,7 @@ class TestSlideController(TestCase):
self.assertEqual(0, mocked_on_theme_display.call_count, 'on_theme_display should not have been called')
self.assertEqual(0, mocked_on_hide_display.call_count, 'on_hide_display should not have been called')
def toggle_display_theme_test(self):
def test_toggle_display_theme(self):
"""
Check that the toggle_display('theme') method calls the on_theme_display() method
"""
@ -166,7 +166,7 @@ class TestSlideController(TestCase):
self.assertEqual(0, mocked_on_blank_display.call_count, 'on_blank_display should not have been called')
self.assertEqual(0, mocked_on_hide_display.call_count, 'on_hide_display should not have been called')
def toggle_display_desktop_test(self):
def test_toggle_display_desktop(self):
"""
Check that the toggle_display('desktop') method calls the on_hide_display() method
"""
@ -187,7 +187,7 @@ class TestSlideController(TestCase):
self.assertEqual(0, mocked_on_blank_display.call_count, 'on_blank_display should not have been called')
self.assertEqual(0, mocked_on_theme_display.call_count, 'on_theme_display should not have been called')
def toggle_display_show_test(self):
def test_toggle_display_show(self):
"""
Check that the toggle_display('show') method calls all the on_X_display() methods
"""
@ -208,7 +208,7 @@ class TestSlideController(TestCase):
mocked_on_theme_display.assert_called_once_with(False)
mocked_on_hide_display.assert_called_once_with(False)
def live_escape_test(self):
def test_live_escape(self):
"""
Test that when the live_escape() method is called, the display is set to invisible and any media is stopped
"""
@ -231,7 +231,7 @@ class TestSlideController(TestCase):
mocked_display.setVisible.assert_called_once_with(False)
mocked_media_controller.media_stop.assert_called_once_with(slide_controller)
def on_go_live_live_controller_test(self):
def test_on_go_live_live_controller(self):
"""
Test that when the on_go_live() method is called the message is sent to the live controller and focus is
set correctly.
@ -259,7 +259,7 @@ class TestSlideController(TestCase):
mocked_live_controller.add_service_manager_item.assert_called_once_with(mocked_service_item, 1)
mocked_live_controller.preview_widget.setFocus.assert_called_once_with()
def on_go_live_service_manager_test(self):
def test_on_go_live_service_manager(self):
"""
Test that when the on_go_live() method is called the message is sent to the live controller and focus is
set correctly.
@ -290,7 +290,7 @@ class TestSlideController(TestCase):
mocked_service_manager.preview_live.assert_called_once_with(42, 1)
mocked_live_controller.preview_widget.setFocus.assert_called_once_with()
def service_previous_test(self):
def test_service_previous(self):
"""
Check that calling the service_previous() method adds the previous key to the queue and processes the queue
"""
@ -308,7 +308,7 @@ class TestSlideController(TestCase):
mocked_keypress_queue.append.assert_called_once_with(ServiceItemAction.Previous)
mocked_process_queue.assert_called_once_with()
def service_next_test(self):
def test_service_next(self):
"""
Check that calling the service_next() method adds the next key to the queue and processes the queue
"""
@ -327,7 +327,7 @@ class TestSlideController(TestCase):
mocked_process_queue.assert_called_once_with()
@patch('openlp.core.ui.slidecontroller.Settings')
def update_slide_limits_test(self, MockedSettings):
def test_update_slide_limits(self, MockedSettings):
"""
Test that calling the update_slide_limits() method updates the slide limits
"""
@ -346,7 +346,7 @@ class TestSlideController(TestCase):
mocked_value.assert_called_once_with('advanced/slide limits')
self.assertEqual(10, slide_controller.slide_limits, 'Slide limits should have been updated to 10')
def enable_tool_bar_live_test(self):
def test_enable_tool_bar_live(self):
"""
Check that when enable_tool_bar on a live slide controller is called, enable_live_tool_bar is called
"""
@ -366,7 +366,7 @@ class TestSlideController(TestCase):
mocked_enable_live_tool_bar.assert_called_once_with(mocked_service_item)
self.assertEqual(0, mocked_enable_preview_tool_bar.call_count, 'The preview method should not have been called')
def enable_tool_bar_preview_test(self):
def test_enable_tool_bar_preview(self):
"""
Check that when enable_tool_bar on a preview slide controller is called, enable_preview_tool_bar is called
"""
@ -386,7 +386,7 @@ class TestSlideController(TestCase):
mocked_enable_preview_tool_bar.assert_called_once_with(mocked_service_item)
self.assertEqual(0, mocked_enable_live_tool_bar.call_count, 'The live method should not have been called')
def refresh_service_item_text_test(self):
def test_refresh_service_item_text(self):
"""
Test that the refresh_service_item() method refreshes a text service item
"""
@ -409,7 +409,7 @@ class TestSlideController(TestCase):
mocked_service_item.render.assert_called_once_with()
mocked_process_item.assert_called_once_with(mocked_service_item, 5)
def refresh_service_item_image_test(self):
def test_refresh_service_item_image(self):
"""
Test that the refresh_service_item() method refreshes a image service item
"""
@ -432,7 +432,7 @@ class TestSlideController(TestCase):
mocked_service_item.render.assert_called_once_with()
mocked_process_item.assert_called_once_with(mocked_service_item, 5)
def refresh_service_item_not_image_or_text_test(self):
def test_refresh_service_item_not_image_or_text(self):
"""
Test that the refresh_service_item() method does not refresh a service item if it's neither text or an image
"""
@ -456,7 +456,7 @@ class TestSlideController(TestCase):
self.assertEqual(0, mocked_process_item.call_count,
'The mocked_process_item() method should not have been called')
def add_service_item_with_song_edit_test(self):
def test_add_service_item_with_song_edit(self):
"""
Test the add_service_item() method when song_edit is True
"""
@ -476,7 +476,7 @@ class TestSlideController(TestCase):
self.assertFalse(slide_controller.song_edit, 'song_edit should be False')
mocked_process_item.assert_called_once_with(mocked_item, 2)
def add_service_item_without_song_edit_test(self):
def test_add_service_item_without_song_edit(self):
"""
Test the add_service_item() method when song_edit is False
"""
@ -496,7 +496,7 @@ class TestSlideController(TestCase):
self.assertFalse(slide_controller.song_edit, 'song_edit should be False')
mocked_process_item.assert_called_once_with(mocked_item, 0)
def replace_service_manager_item_different_items_test(self):
def test_replace_service_manager_item_different_items(self):
"""
Test that when the service items are not the same, nothing happens
"""
@ -517,7 +517,7 @@ class TestSlideController(TestCase):
self.assertEqual(0, mocked_preview_widget.current_slide_number.call_count,
'The preview_widgetcurrent_slide_number.() method should not have been called')
def replace_service_manager_item_same_item_test(self):
def test_replace_service_manager_item_same_item(self):
"""
Test that when the service item is the same, the service item is reprocessed
"""
@ -538,7 +538,7 @@ class TestSlideController(TestCase):
mocked_preview_widget.current_slide_number.assert_called_with()
mocked_process_item.assert_called_once_with(mocked_item, 7)
def on_slide_blank_test(self):
def test_on_slide_blank(self):
"""
Test on_slide_blank
"""
@ -552,7 +552,7 @@ class TestSlideController(TestCase):
# THEN: on_blank_display should have been called with True
slide_controller.on_blank_display.assert_called_once_with(True)
def on_slide_unblank_test(self):
def test_on_slide_unblank(self):
"""
Test on_slide_unblank
"""
@ -566,7 +566,7 @@ class TestSlideController(TestCase):
# THEN: on_blank_display should have been called with False
slide_controller.on_blank_display.assert_called_once_with(False)
def on_slide_selected_index_no_service_item_test(self):
def test_on_slide_selected_index_no_service_item(self):
"""
Test that when there is no service item, the on_slide_selected_index() method returns immediately
"""
@ -582,7 +582,7 @@ class TestSlideController(TestCase):
self.assertEqual(0, mocked_item.is_command.call_count, 'The service item should have not been called')
@patch.object(Registry, 'execute')
def on_slide_selected_index_service_item_command_test(self, mocked_execute):
def test_on_slide_selected_index_service_item_command(self, mocked_execute):
"""
Test that when there is a command service item, the command is executed
"""
@ -612,7 +612,7 @@ class TestSlideController(TestCase):
self.assertEqual(0, mocked_slide_selected.call_count, 'slide_selected should not have been called')
@patch.object(Registry, 'execute')
def on_slide_selected_index_service_item_not_command_test(self, mocked_execute):
def test_on_slide_selected_index_service_item_not_command(self, mocked_execute):
"""
Test that when there is a service item but it's not a command, the preview widget is updated
"""
@ -641,7 +641,7 @@ class TestSlideController(TestCase):
mocked_slide_selected.assert_called_once_with()
@patch.object(Registry, 'execute')
def process_item_test(self, mocked_execute):
def test_process_item(self, mocked_execute):
"""
Test that presentation service-items is closed when followed by a media service-item
"""
@ -685,7 +685,7 @@ class TestSlideController(TestCase):
self.assertEqual('mocked_presentation_item_stop', mocked_execute.call_args_list[1][0][0],
'The presentation should have been stopped.')
def live_stolen_focus_shortcuts_test(self):
def test_live_stolen_focus_shortcuts(self):
"""
Test that all the needed shortcuts are available in scenarios where Live has stolen focus.
These are found under def __add_actions_to_widget(self, widget): in slidecontroller.py
@ -715,7 +715,7 @@ class TestSlideController(TestCase):
@patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager')
@patch(u'PyQt5.QtCore.QTimer.singleShot')
def update_preview_test_live(self, mocked_singleShot, mocked_image_manager):
def test_update_preview_live(self, mocked_singleShot, mocked_image_manager):
"""
Test that the preview screen is updated with a screen grab for live service items
"""
@ -758,7 +758,7 @@ class TestSlideController(TestCase):
@patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager')
@patch(u'PyQt5.QtCore.QTimer.singleShot')
def update_preview_test_pres(self, mocked_singleShot, mocked_image_manager):
def test_update_preview_pres(self, mocked_singleShot, mocked_image_manager):
"""
Test that the preview screen is updated with the correct preview for presentation service items
"""
@ -800,7 +800,7 @@ class TestSlideController(TestCase):
@patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager')
@patch(u'PyQt5.QtCore.QTimer.singleShot')
def update_preview_test_media(self, mocked_singleShot, mocked_image_manager):
def test_update_preview_media(self, mocked_singleShot, mocked_image_manager):
"""
Test that the preview screen is updated with the correct preview for media service items
"""
@ -842,7 +842,7 @@ class TestSlideController(TestCase):
@patch(u'openlp.core.ui.slidecontroller.SlideController.image_manager')
@patch(u'PyQt5.QtCore.QTimer.singleShot')
def update_preview_test_image(self, mocked_singleShot, mocked_image_manager):
def test_update_preview_image(self, mocked_singleShot, mocked_image_manager):
"""
Test that the preview screen is updated with the correct preview for image service items
"""
@ -885,7 +885,7 @@ class TestSlideController(TestCase):
class TestInfoLabel(TestCase):
def paint_event_text_fits_test(self):
def test_paint_event_text_fits(self):
"""
Test the paintEvent method when text fits the label
"""
@ -913,7 +913,7 @@ class TestInfoLabel(TestCase):
# THEN: The text should be drawn centered with the complete test_string
mocked_qpainter().drawText.assert_called_once_with(mocked_rect(), QtCore.Qt.AlignCenter, test_string)
def paint_event_text_doesnt_fit_test(self):
def test_paint_event_text_doesnt_fit(self):
"""
Test the paintEvent method when text fits the label
"""
@ -944,7 +944,7 @@ class TestInfoLabel(TestCase):
mocked_qpainter().drawText.assert_called_once_with(mocked_rect(), QtCore.Qt.AlignLeft, elided_test_string)
@patch('builtins.super')
def set_text_test(self, mocked_super):
def test_set_text(self, mocked_super):
"""
Test the reimplemented setText method
"""
@ -963,7 +963,7 @@ class TestInfoLabel(TestCase):
class TestLiveController(TestCase):
def initial_live_controller_test(self):
def test_initial_live_controller(self):
"""
Test the initial live slide controller state .
"""
@ -978,7 +978,7 @@ class TestLiveController(TestCase):
class TestPreviewLiveController(TestCase):
def initial_preview_controller_test(self):
def test_initial_preview_controller(self):
"""
Test the initial preview slide controller state.
"""

View File

@ -34,7 +34,7 @@ class TestThemeManager(TestCase):
"""
Test the functions in the ThemeManager Class
"""
def select_image_file_dialog_cancelled_test(self):
def test_select_image_file_dialog_cancelled(self):
"""
Test the select image file dialog when the user presses cancel
"""
@ -62,7 +62,7 @@ class TestThemeManager(TestCase):
'All Files (*.*)')
mocked_set_background_page_values.assert_called_once_with()
def select_image_file_dialog_new_file_test(self):
def test_select_image_file_dialog_new_file(self):
"""
Test the select image file dialog when the user presses ok
"""

View File

@ -53,7 +53,7 @@ class TestThemeManager(TestCase):
"""
shutil.rmtree(self.temp_folder)
def export_theme_test(self):
def test_export_theme(self):
"""
Test exporting a theme .
"""
@ -73,7 +73,7 @@ class TestThemeManager(TestCase):
'Default', 'Default.xml'),
os.path.join('Default', 'Default.xml'))
def initial_theme_manager_test(self):
def test_initial_theme_manager(self):
"""
Test the instantiation of theme manager.
"""
@ -84,7 +84,7 @@ class TestThemeManager(TestCase):
# THEN: The the controller should be registered in the registry.
self.assertIsNotNone(Registry().get('theme_manager'), 'The base theme manager should be registered')
def write_theme_same_image_test(self):
def test_write_theme_same_image(self):
"""
Test that we don't try to overwrite a theme background image with itself
"""
@ -112,7 +112,7 @@ class TestThemeManager(TestCase):
# THEN: The mocked_copyfile should not have been called
self.assertFalse(mocked_copyfile.called, 'shutil.copyfile should not be called')
def write_theme_diff_images_test(self):
def test_write_theme_diff_images(self):
"""
Test that we do overwrite a theme background image when a new is submitted
"""
@ -139,7 +139,7 @@ class TestThemeManager(TestCase):
# THEN: The mocked_copyfile should not have been called
self.assertTrue(mocked_copyfile.called, 'shutil.copyfile should be called')
def write_theme_special_char_name_test(self):
def test_write_theme_special_char_name(self):
"""
Test that we can save themes with special characters in the name
"""
@ -160,7 +160,7 @@ class TestThemeManager(TestCase):
self.assertTrue(os.path.exists(os.path.join(self.temp_folder, 'theme 愛 name', 'theme 愛 name.xml')),
'Theme with special characters should have been created!')
def over_write_message_box_yes_test(self):
def test_over_write_message_box_yes(self):
"""
Test that theme_manager.over_write_message_box returns True when the user clicks yes.
"""
@ -180,7 +180,7 @@ class TestThemeManager(TestCase):
theme_manager, 'Theme Already Exists', 'Theme Theme Name already exists. Do you want to replace it?',
ANY, ANY)
def over_write_message_box_no_test(self):
def test_over_write_message_box_no(self):
"""
Test that theme_manager.over_write_message_box returns False when the user clicks no.
"""
@ -200,7 +200,7 @@ class TestThemeManager(TestCase):
theme_manager, 'Theme Already Exists', 'Theme Theme Name already exists. Do you want to replace it?',
ANY, ANY)
def unzip_theme_test(self):
def test_unzip_theme(self):
"""
Test that unzipping of themes works
"""
@ -222,7 +222,7 @@ class TestThemeManager(TestCase):
self.assertEqual(mocked_critical_error_message_box.call_count, 0, 'No errors should have happened')
shutil.rmtree(folder)
def unzip_theme_invalid_version_test(self):
def test_unzip_theme_invalid_version(self):
"""
Test that themes with invalid (< 2.0) or with no version attributes are rejected
"""

Some files were not shown because too many files have changed in this diff Show More