forked from openlp/openlp
merge trunk
This commit is contained in:
commit
e89803a3ad
17
nose2.cfg
Normal file
17
nose2.cfg
Normal 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
|
@ -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]
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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())
|
||||
|
@ -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']
|
||||
|
@ -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:
|
||||
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()
|
||||
|
@ -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()
|
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -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()
|
||||
|
@ -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:
|
||||
|
@ -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):
|
||||
"""
|
||||
|
@ -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):
|
||||
"""
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
"""
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
@ -347,8 +349,9 @@ class SongMaintenanceForm(QtWidgets.QDialog, Ui_SongMaintenanceDialog, RegistryP
|
||||
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),
|
||||
'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:
|
||||
@ -385,8 +388,9 @@ class SongMaintenanceForm(QtWidgets.QDialog, Ui_SongMaintenanceDialog, RegistryP
|
||||
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),
|
||||
'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:
|
||||
|
@ -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:'))
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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 '
|
||||
|
@ -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 = ''
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
|
@ -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)
|
||||
|
@ -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):
|
||||
"""
|
||||
|
@ -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'):
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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')
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
@ -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.'))
|
||||
|
@ -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():
|
||||
|
@ -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:
|
||||
|
@ -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',
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -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)
|
||||
"""
|
||||
|
@ -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.
|
||||
"""
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -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')
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -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.
|
||||
"""
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
"""
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -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')
|
||||
|
@ -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')
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -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.
|
||||
"""
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -44,7 +44,7 @@ class TestTheme(TestCase):
|
||||
"""
|
||||
pass
|
||||
|
||||
def new_theme_test(self):
|
||||
def test_new_theme(self):
|
||||
"""
|
||||
Test the theme creation - basic test
|
||||
"""
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -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()
|
||||
"""
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -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()
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -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.
|
||||
"""
|
||||
|
@ -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
|
||||
"""
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user