From 779e95b52342df84330c367814b87cf7999a7640 Mon Sep 17 00:00:00 2001 From: Philip Ridout Date: Sun, 8 Oct 2017 18:33:03 +0100 Subject: [PATCH 01/22] Fix for samuel_m issue and bug #1672229 --- openlp/core/common/applocation.py | 2 +- openlp/core/lib/mediamanageritem.py | 4 +++- openlp/core/ui/lib/listwidgetwithdnd.py | 2 +- openlp/plugins/images/lib/mediaitem.py | 3 ++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/openlp/core/common/applocation.py b/openlp/core/common/applocation.py index 02a872303..a0c927666 100644 --- a/openlp/core/common/applocation.py +++ b/openlp/core/common/applocation.py @@ -85,7 +85,7 @@ class AppLocation(object): """ # Check if we have a different data location. if Settings().contains('advanced/data path'): - path = Settings().value('advanced/data path') + path = Path(Settings().value('advanced/data path')) else: path = AppLocation.get_directory(AppLocation.DataDir) check_directory_exists(path) diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py index 1c7a5b4ef..ce106854a 100644 --- a/openlp/core/lib/mediamanageritem.py +++ b/openlp/core/lib/mediamanageritem.py @@ -341,7 +341,9 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties): else: new_files.append(file_name) if new_files: - self.validate_and_load(new_files, data['target']) + if 'target' in data: + self.validate_and_load(new_files, data['target']) + self.validate_and_load(new_files) def dnd_move_internal(self, target): """ diff --git a/openlp/core/ui/lib/listwidgetwithdnd.py b/openlp/core/ui/lib/listwidgetwithdnd.py index 1758d46fb..e8f0b729f 100755 --- a/openlp/core/ui/lib/listwidgetwithdnd.py +++ b/openlp/core/ui/lib/listwidgetwithdnd.py @@ -121,7 +121,7 @@ class ListWidgetWithDnD(QtWidgets.QListWidget): for file in listing: files.append(os.path.join(local_file, file)) Registry().execute('{mime_data}_dnd'.format(mime_data=self.mime_data_text), - {'files': files, 'target': self.itemAt(event.pos())}) + {'files': files}) else: event.ignore() diff --git a/openlp/plugins/images/lib/mediaitem.py b/openlp/plugins/images/lib/mediaitem.py index b436d2708..5eac4b3b5 100644 --- a/openlp/plugins/images/lib/mediaitem.py +++ b/openlp/plugins/images/lib/mediaitem.py @@ -364,7 +364,7 @@ class ImageMediaItem(MediaManagerItem): if validate_thumb(image.file_path, thumbnail_path): icon = build_icon(thumbnail_path) else: - icon = create_thumb(image.file_path, thumbnail_path) + icon = create_thumb(str(image.file_path), str(thumbnail_path)) item_name = QtWidgets.QTreeWidgetItem([file_name]) item_name.setText(0, file_name) item_name.setIcon(0, icon) @@ -388,6 +388,7 @@ class ImageMediaItem(MediaManagerItem): :param files: A List of strings containing the filenames of the files to be loaded :param target_group: The QTreeWidgetItem of the group that will be the parent of the added files """ + file_paths = [Path(file) for file in file_paths] self.application.set_normal_cursor() self.load_list(file_paths, target_group) last_dir = file_paths[0].parent From 98d5f0ec670940fc7b010f76220a8560a7c25642 Mon Sep 17 00:00:00 2001 From: Philip Ridout Date: Sun, 8 Oct 2017 19:38:56 +0100 Subject: [PATCH 02/22] fix 1660473, shamlessly ported from 2.4.5 --- openlp/core/ui/mainwindow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 25fe818ee..4a1200084 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -175,7 +175,7 @@ class Ui_MainWindow(object): triggers=self.service_manager_contents.on_load_service_clicked) self.file_save_item = create_action(main_window, 'fileSaveItem', icon=':/general/general_save.png', can_shortcuts=True, category=UiStrings().File, - triggers=self.service_manager_contents.save_file) + triggers=self.service_manager_contents.decide_save_method) self.file_save_as_item = create_action(main_window, 'fileSaveAsItem', can_shortcuts=True, category=UiStrings().File, triggers=self.service_manager_contents.save_file_as) From 71ad60d038f27747d691edafca9e956f7836b281 Mon Sep 17 00:00:00 2001 From: Philip Ridout Date: Sun, 8 Oct 2017 20:01:09 +0100 Subject: [PATCH 03/22] fixes #1660478 - Opening recent file does not prompt to save changes --- openlp/core/ui/servicemanager.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 153034e33..2bee2cae0 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -469,6 +469,12 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa Load a recent file as the service triggered by mainwindow recent service list. :param field: """ + if self.is_modified(): + result = self.save_modified_service() + if result == QtWidgets.QMessageBox.Cancel: + return False + elif result == QtWidgets.QMessageBox.Save: + self.decide_save_method() sender = self.sender() self.load_file(sender.data()) From 37da12affd0953d9824caf5e9bd43b4695af6256 Mon Sep 17 00:00:00 2001 From: Philip Ridout Date: Sun, 8 Oct 2017 20:29:54 +0100 Subject: [PATCH 04/22] fixes #1715125 - Missing .osz file extension on save service --- openlp/core/ui/servicemanager.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 2bee2cae0..42c8dea6d 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -713,18 +713,23 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa default_file_path = directory_path / default_file_path # SaveAs from osz to oszl is not valid as the files will be deleted on exit which is not sensible or usable in # the long term. + lite_filter = translate('OpenLP.ServiceManager', 'OpenLP Service Files - lite (*.oszl)') + packaged_filter = translate('OpenLP.ServiceManager', 'OpenLP Service Files (*.osz)') + if self._file_name.endswith('oszl') or self.service_has_all_original_files: file_path, filter_used = FileDialog.getSaveFileName( self.main_window, UiStrings().SaveService, default_file_path, - translate('OpenLP.ServiceManager', - 'OpenLP Service Files (*.osz);; OpenLP Service Files - lite (*.oszl)')) + '{packaged};; {lite}'.format(packaged=packaged_filter, lite=lite_filter)) else: file_path, filter_used = FileDialog.getSaveFileName( - self.main_window, UiStrings().SaveService, file_path, - translate('OpenLP.ServiceManager', 'OpenLP Service Files (*.osz);;')) + self.main_window, UiStrings().SaveService, default_file_path, + '{packaged};;'.format(packaged=packaged_filter)) if not file_path: return False - file_path.with_suffix('.osz') + if filter_used == lite_filter: + file_path = file_path.with_suffix('.oszl') + else: + file_path = file_path.with_suffix('.osz') self.set_file_name(file_path) self.decide_save_method() From 2be17b5c6fda2490fa5e44cd235a65ded29a3b45 Mon Sep 17 00:00:00 2001 From: Philip Ridout Date: Sun, 8 Oct 2017 20:41:07 +0100 Subject: [PATCH 05/22] fixes #1532193 - Typos in songusageplugin.py annother fix shamelessly ported from 2.4 --- openlp/core/common/settings.py | 6 ++++++ openlp/plugins/songusage/songusageplugin.py | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/openlp/core/common/settings.py b/openlp/core/common/settings.py index ca59d4e6f..48d8710a0 100644 --- a/openlp/core/common/settings.py +++ b/openlp/core/common/settings.py @@ -270,6 +270,12 @@ class Settings(QtCore.QSettings): ('media/last directory', 'media/last directory', [(str_to_path, None)]) ] + __setting_upgrade_3__ = [ + ('songuasge/db password', 'songusage/db password', []) + ('songuasge/db hostname', 'songusage/db hostname', []) + ('songuasge/db database', 'songusage/db database', []) + ] + @staticmethod def extend_default_settings(default_values): """ diff --git a/openlp/plugins/songusage/songusageplugin.py b/openlp/plugins/songusage/songusageplugin.py index d0c2f7fe7..8d5e08322 100644 --- a/openlp/plugins/songusage/songusageplugin.py +++ b/openlp/plugins/songusage/songusageplugin.py @@ -44,9 +44,9 @@ if QtCore.QDate().currentDate().month() < 9: __default_settings__ = { 'songusage/db type': 'sqlite', 'songusage/db username': '', - 'songuasge/db password': '', - 'songuasge/db hostname': '', - 'songuasge/db database': '', + 'songusage/db password': '', + 'songusage/db hostname': '', + 'songusage/db database': '', 'songusage/active': False, 'songusage/to date': QtCore.QDate(YEAR, 8, 31), 'songusage/from date': QtCore.QDate(YEAR - 1, 9, 1), From cecd2298a74ec36613eb7d719ea92d10f5f5dfd8 Mon Sep 17 00:00:00 2001 From: Philip Ridout Date: Sun, 8 Oct 2017 21:36:11 +0100 Subject: [PATCH 06/22] fixes #1660486 - Dragging item in service manager without changes triggeres 'unsaved' --- openlp/core/common/settings.py | 4 ++-- openlp/core/ui/servicemanager.py | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/openlp/core/common/settings.py b/openlp/core/common/settings.py index 48d8710a0..6f681b7d5 100644 --- a/openlp/core/common/settings.py +++ b/openlp/core/common/settings.py @@ -271,8 +271,8 @@ class Settings(QtCore.QSettings): ] __setting_upgrade_3__ = [ - ('songuasge/db password', 'songusage/db password', []) - ('songuasge/db hostname', 'songusage/db hostname', []) + ('songuasge/db password', 'songusage/db password', []), + ('songuasge/db hostname', 'songusage/db hostname', []), ('songuasge/db database', 'songusage/db database', []) ] diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 42c8dea6d..42a45cafd 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -1663,14 +1663,15 @@ class ServiceManager(OpenLPMixin, RegistryMixin, QtWidgets.QWidget, Ui_ServiceMa if start_pos == -1: return if item is None: - end_pos = len(self.service_items) + end_pos = len(self.service_items) - 1 else: end_pos = get_parent_item_data(item) - 1 service_item = self.service_items[start_pos] - self.service_items.remove(service_item) - self.service_items.insert(end_pos, service_item) - self.repaint_service_list(end_pos, child) - self.set_modified() + if start_pos != end_pos: + self.service_items.remove(service_item) + self.service_items.insert(end_pos, service_item) + self.repaint_service_list(end_pos, child) + self.set_modified() else: # we are not over anything so drop replace = False From 93e0a35489c5443317d37ace58a0135c7ddcb675 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Thu, 26 Oct 2017 13:33:22 -0700 Subject: [PATCH 07/22] Update Jenkins script to use python-jenkins --- scripts/jenkins_script.py | 118 ++++++++++++++++++++------------------ 1 file changed, 62 insertions(+), 56 deletions(-) diff --git a/scripts/jenkins_script.py b/scripts/jenkins_script.py index 9a0e9a4ec..8ce6af90d 100755 --- a/scripts/jenkins_script.py +++ b/scripts/jenkins_script.py @@ -31,25 +31,16 @@ You probably want to create an alias. Add this to your ~/.bashrc file and then l You can look up the token in the Branch-01-Pull job configuration or ask in IRC. """ - +import os import re -import sys import time -from optparse import OptionParser +from argparse import ArgumentParser from subprocess import Popen, PIPE -import warnings -from requests.exceptions import HTTPError from jenkins import Jenkins - JENKINS_URL = 'https://ci.openlp.io/' REPO_REGEX = r'(.*/+)(~.*)' -# Allows us to black list token. So when we change the token, we can display a proper message to the user. -OLD_TOKENS = [] - -# Disable the InsecureRequestWarning we get from urllib3, because we're not verifying our own self-signed certificate -warnings.simplefilter('ignore') class OpenLPJobs(object): @@ -85,13 +76,22 @@ class JenkinsTrigger(object): :param token: The token we need to trigger the build. If you do not have this token, ask in IRC. """ - def __init__(self, token): + def __init__(self, username, password, can_use_colour): """ Create the JenkinsTrigger instance. """ - self.token = token + self.build_numbers = {} + self.can_use_colour = can_use_colour and not os.name.startswith('nt') self.repo_name = get_repo_name() - self.jenkins_instance = Jenkins(JENKINS_URL) + self.server = Jenkins(JENKINS_URL, username=username, password=password) + + def fetch_build_numbers(self): + """ + Get the next build number from all the jobs + """ + for job_name in OpenLPJobs.Jobs: + job_info = self.server.get_job_info(job_name) + self.build_number[job_name] = job_info['nextBuildNumber'] def trigger_build(self): """ @@ -102,8 +102,7 @@ class JenkinsTrigger(object): # We just want the name (not the email). name = ' '.join(raw_output.decode().split()[:-1]) cause = 'Build triggered by %s (%s)' % (name, self.repo_name) - self.jenkins_instance.job(OpenLPJobs.Branch_Pull).build({'BRANCH_NAME': self.repo_name, 'cause': cause}, - token=self.token) + self.server.build_job(OpenLPJobs.Branch_Pull, {'BRANCH_NAME': self.repo_name, 'cause': cause}) def print_output(self): """ @@ -129,6 +128,20 @@ class JenkinsTrigger(object): # Open the url Popen(('xdg-open', url), stderr=PIPE) + def _get_build_info(self, job_name, build_number): + """ + Get the build info from the server. This method will check the queue and wait for the build. + """ + queue_info = self.server.get_queue_info() + tries = 0 + while queue_info and tries < 50: + tries += 1 + time.sleep(0.5) + queue_info = self.server.get_queue_info() + if tries >= 50: + raise Exception('Build has not started yet, it may be stuck in the queue.') + return self.server.get_build_info(job_name, build_number) + def __print_build_info(self, job_name): """ This helper method prints the job information of the given ``job_name`` @@ -136,21 +149,21 @@ class JenkinsTrigger(object): :param job_name: The name of the job we want the information from. For example *Branch-01-Pull*. Use the class variables from the :class:`OpenLPJobs` class. """ + build_info = self._get_build_info(job_name, self.build_number[job_name]) + print('{} ... '.format(build_info['url']), end='', flush=True) is_success = False - job = self.jenkins_instance.job(job_name) - while job.info['inQueue']: - time.sleep(1) - build = job.last_build - build.wait() - if build.info['result'] == 'SUCCESS': + while build_info['building'] is True: + time.sleep(0.5) + build_info = self.server.get_build_info(job_name, self.build_number[job_name]) + result_string = build_info['result'] + if self.can_use_colour and result_string == 'SUCCESS': # Make 'SUCCESS' green. - result_string = '%s%s%s' % (Colour.GREEN_START, build.info['result'], Colour.GREEN_END) + result_string = '%s%s%s' % (Colour.GREEN_START, result_string, Colour.GREEN_END) is_success = True - else: + elif self.can_use_colour: # Make 'FAILURE' red. - result_string = '%s%s%s' % (Colour.RED_START, build.info['result'], Colour.RED_END) - url = build.info['url'] - print('[%s] %s' % (result_string, url)) + result_string = '%s%s%s' % (Colour.RED_START, result_string, Colour.RED_END) + print('[{}]'.format(result_string)) return is_success @@ -186,36 +199,29 @@ def get_repo_name(): def main(): - usage = 'Usage: python %prog TOKEN [options]' + """ + Run the script + """ + parser = ArgumentParser() + parser.add_argument('-d', '--disable-output', action='store_false', default=True, help='Disable output') + parser.add_argument('-b', '--open-browser', action='store_true', default=False, + help='Opens the jenkins page in your browser') + parser.add_argument('-c', '--enable-colour', action='store_false', default=True, + help='Enable coloured output. Disabled on Windows') + parser.add_argument('-u', '--username', required=True, help='Your Jenkins username') + parser.add_argument('-p', '--password', required=True, help='Your Jenkins password or personal token') + args = parser.parse_args() - parser = OptionParser(usage=usage) - parser.add_option('-d', '--disable-output', dest='enable_output', action='store_false', default=True, - help='Disable output.') - parser.add_option('-b', '--open-browser', dest='open_browser', action='store_true', default=False, - help='Opens the jenkins page in your browser.') - options, args = parser.parse_args(sys.argv) - - if len(args) == 2: - if not get_repo_name(): - print('Not a branch. Have you pushed it to launchpad? Did you cd to the branch?') - return - token = args[-1] - if token in OLD_TOKENS: - print('Your token is not valid anymore. Get the most recent one.') - return - jenkins_trigger = JenkinsTrigger(token) - try: - jenkins_trigger.trigger_build() - except HTTPError: - print('Wrong token.') - return - # Open the browser before printing the output. - if options.open_browser: - jenkins_trigger.open_browser() - if options.enable_output: - jenkins_trigger.print_output() - else: - parser.print_help() + if not get_repo_name(): + print('Not a branch. Have you pushed it to launchpad? Did you cd to the branch?') + return + jenkins_trigger = JenkinsTrigger(username=args.username, password=args.password) + jenkins_trigger.trigger_build() + # Open the browser before printing the output. + if args.open_browser: + jenkins_trigger.open_browser() + if not args.disable_output: + jenkins_trigger.print_output() if __name__ == '__main__': From f6243f6e8828edc534d70be969420f673e41fa3f Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Thu, 26 Oct 2017 15:05:10 -0700 Subject: [PATCH 08/22] Fix some bugs, line up the statuses, provide some failure feedback, flip the colour option --- scripts/jenkins_script.py | 43 ++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/scripts/jenkins_script.py b/scripts/jenkins_script.py index 8ce6af90d..2d93d53d3 100755 --- a/scripts/jenkins_script.py +++ b/scripts/jenkins_script.py @@ -80,7 +80,7 @@ class JenkinsTrigger(object): """ Create the JenkinsTrigger instance. """ - self.build_numbers = {} + self.build_number = {} self.can_use_colour = can_use_colour and not os.name.startswith('nt') self.repo_name = get_repo_name() self.server = Jenkins(JENKINS_URL, username=username, password=password) @@ -102,6 +102,7 @@ class JenkinsTrigger(object): # We just want the name (not the email). name = ' '.join(raw_output.decode().split()[:-1]) cause = 'Build triggered by %s (%s)' % (name, self.repo_name) + self.fetch_build_numbers() self.server.build_job(OpenLPJobs.Branch_Pull, {'BRANCH_NAME': self.repo_name, 'cause': cause}) def print_output(self): @@ -117,7 +118,10 @@ class JenkinsTrigger(object): for job in OpenLPJobs.Jobs: if not self.__print_build_info(job): - print('Stopping after failure') + if self.current_build: + print('Stopping after failure, see {}console for more details'.format(self.current_build['url'])) + else: + print('Stopping after failure') break def open_browser(self): @@ -149,21 +153,22 @@ class JenkinsTrigger(object): :param job_name: The name of the job we want the information from. For example *Branch-01-Pull*. Use the class variables from the :class:`OpenLPJobs` class. """ - build_info = self._get_build_info(job_name, self.build_number[job_name]) - print('{} ... '.format(build_info['url']), end='', flush=True) + self.current_build = self._get_build_info(job_name, self.build_number[job_name]) + print('{:<60} [RUNNING]'.format(self.current_build['url']), end='', flush=True) is_success = False - while build_info['building'] is True: + while self.current_build['building'] is True: time.sleep(0.5) - build_info = self.server.get_build_info(job_name, self.build_number[job_name]) - result_string = build_info['result'] - if self.can_use_colour and result_string == 'SUCCESS': - # Make 'SUCCESS' green. - result_string = '%s%s%s' % (Colour.GREEN_START, result_string, Colour.GREEN_END) - is_success = True - elif self.can_use_colour: - # Make 'FAILURE' red. - result_string = '%s%s%s' % (Colour.RED_START, result_string, Colour.RED_END) - print('[{}]'.format(result_string)) + self.current_build = self.server.get_build_info(job_name, self.build_number[job_name]) + result_string = self.current_build['result'] + is_success = result_string == 'SUCCESS' + if self.can_use_colour: + if is_success: + # Make 'SUCCESS' green. + result_string = '{}{}{}'.format(Colour.GREEN_START, result_string, Colour.GREEN_END) + else: + # Make 'FAILURE' red. + result_string = '{}{}{}'.format(Colour.RED_START, result_string, Colour.RED_END) + print('\b\b\b\b\b\b\b\b\b[{:>7}]'.format(result_string)) return is_success @@ -203,11 +208,11 @@ def main(): Run the script """ parser = ArgumentParser() - parser.add_argument('-d', '--disable-output', action='store_false', default=True, help='Disable output') + parser.add_argument('-d', '--disable-output', action='store_true', default=False, help='Disable output') parser.add_argument('-b', '--open-browser', action='store_true', default=False, help='Opens the jenkins page in your browser') - parser.add_argument('-c', '--enable-colour', action='store_false', default=True, - help='Enable coloured output. Disabled on Windows') + parser.add_argument('-n', '--no-colour', action='store_true', default=False, + help='Disable coloured output (always disabled on Windows)') parser.add_argument('-u', '--username', required=True, help='Your Jenkins username') parser.add_argument('-p', '--password', required=True, help='Your Jenkins password or personal token') args = parser.parse_args() @@ -215,7 +220,7 @@ def main(): if not get_repo_name(): print('Not a branch. Have you pushed it to launchpad? Did you cd to the branch?') return - jenkins_trigger = JenkinsTrigger(username=args.username, password=args.password) + jenkins_trigger = JenkinsTrigger(args.username, args.password, not args.no_colour) jenkins_trigger.trigger_build() # Open the browser before printing the output. if args.open_browser: From 0d486d051448546c5758ebe2bc678435b5447b7c Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Thu, 26 Oct 2017 15:32:20 -0700 Subject: [PATCH 09/22] Updated the documentation in the file --- scripts/jenkins_script.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/scripts/jenkins_script.py b/scripts/jenkins_script.py index 2d93d53d3..05c589ddd 100755 --- a/scripts/jenkins_script.py +++ b/scripts/jenkins_script.py @@ -21,15 +21,24 @@ # Temple Place, Suite 330, Boston, MA 02111-1307 USA # ############################################################################### """ -This script helps to trigger builds of branches. To use it you have to install the jenkins-webapi package: +This script helps to trigger builds of branches. To use it you have to install the python-jenkins module. On Fedora +and Ubuntu/Debian, it is available as the ``python3-jenkins`` package:: - pip3 install jenkins-webapi + $ sudo dnf/apt install python3-jenkins -You probably want to create an alias. Add this to your ~/.bashrc file and then logout and login (to apply the alias): +To make it easier to run you may want to create a shell script or an alias. To create an alias, add this to your +``~/.bashrc`` (or ``~/.zshrc``) file and then log out and log back in again (to apply the alias):: - alias ci="python3 ./scripts/jenkins_script.py TOKEN" + alias ci="python3 /path/to/openlp_root/scripts/jenkins_script.py -u USERNAME -p PASSWORD" -You can look up the token in the Branch-01-Pull job configuration or ask in IRC. +To create a shell script, create the following file in a location in your ``$PATH`` (I called mine ``ci``):: + + #!/bin/bash + python3 /path/to/openlp_root/scripts/jenkins_script.py -u USERNAME -p PASSWORD + +``USERNAME`` is your Jenkins username, and ``PASSWORD`` is your Jenkins password or personal token. + +An older version of this script used to use a shared TOKEN, but this has been replaced with the username and password. """ import os import re @@ -154,7 +163,7 @@ class JenkinsTrigger(object): variables from the :class:`OpenLPJobs` class. """ self.current_build = self._get_build_info(job_name, self.build_number[job_name]) - print('{:<60} [RUNNING]'.format(self.current_build['url']), end='', flush=True) + print('{:<70} [RUNNING]'.format(self.current_build['url']), end='', flush=True) is_success = False while self.current_build['building'] is True: time.sleep(0.5) From 960ddedc6f08744f3585c28e4e66c55345c75b19 Mon Sep 17 00:00:00 2001 From: Phill Ridout Date: Sat, 28 Oct 2017 11:04:09 +0100 Subject: [PATCH 10/22] make tidy text part of core.\nRemove redundant (since py3) re.UNICODE flag Fixes: https://launchpad.net/bugs/1727517 --- openlp/core/common/__init__.py | 18 +++++++++++++-- openlp/core/common/i18n.py | 2 +- openlp/core/lib/__init__.py | 1 - openlp/core/lib/mediamanageritem.py | 2 +- openlp/core/ui/formattingtagcontroller.py | 2 +- openlp/plugins/bibles/forms/booknameform.py | 3 +-- openlp/plugins/bibles/lib/__init__.py | 6 ++--- openlp/plugins/bibles/lib/db.py | 3 +-- openlp/plugins/songs/forms/editsongform.py | 6 ++--- openlp/plugins/songs/lib/__init__.py | 5 ++-- .../plugins/songs/lib/importers/easyslides.py | 3 ++- .../plugins/songs/lib/importers/mediashout.py | 2 +- .../plugins/songs/lib/importers/openoffice.py | 4 ++-- .../plugins/songs/lib/importers/opensong.py | 3 ++- .../plugins/songs/lib/importers/songimport.py | 23 ++----------------- .../songs/lib/importers/songsoffellowship.py | 1 - openlp/plugins/songs/lib/openlyricsxml.py | 2 +- 17 files changed, 39 insertions(+), 47 deletions(-) diff --git a/openlp/core/common/__init__.py b/openlp/core/common/__init__.py index f8017fdbd..f4c22f490 100644 --- a/openlp/core/common/__init__.py +++ b/openlp/core/common/__init__.py @@ -43,9 +43,13 @@ log = logging.getLogger(__name__ + '.__init__') FIRST_CAMEL_REGEX = re.compile('(.)([A-Z][a-z]+)') SECOND_CAMEL_REGEX = re.compile('([a-z0-9])([A-Z])') -CONTROL_CHARS = re.compile(r'[\x00-\x1F\x7F-\x9F]', re.UNICODE) -INVALID_FILE_CHARS = re.compile(r'[\\/:\*\?"<>\|\+\[\]%]', re.UNICODE) +CONTROL_CHARS = re.compile(r'[\x00-\x1F\x7F-\x9F]') +INVALID_FILE_CHARS = re.compile(r'[\\/:\*\?"<>\|\+\[\]%]') IMAGES_FILTER = None +REPLACMENT_CHARS_MAP = str.maketrans({'\u2018': '\'', '\u2019': '\'', '\u201c': '"', '\u201d': '"', '\u2026': '...', + '\u2013': '-', '\u2014': '-', '\v': '\n\n', '\f': '\n\n'}) +NEW_LINE_REGEX = re.compile(r' ?(\r\n?|\n) ?') +WHITESPACE_REGEX = re.compile(r'[ \t]+') def trace_error_handler(logger): @@ -436,3 +440,13 @@ def get_file_encoding(file_path): return detector.result except OSError: log.exception('Error detecting file encoding') + +def normalize_str(irreg_str): + """ + + :param str irreg_str: + :return: + """ + irreg_str = irreg_str.translate(REPLACMENT_CHARS_MAP) + irreg_str = NEW_LINE_REGEX.sub('\n', irreg_str) + return WHITESPACE_REGEX.sub(' ', irreg_str) diff --git a/openlp/core/common/i18n.py b/openlp/core/common/i18n.py index 1f4357808..9149f3fe6 100644 --- a/openlp/core/common/i18n.py +++ b/openlp/core/common/i18n.py @@ -53,7 +53,7 @@ def translate(context, text, comment=None, qt_translate=QtCore.QCoreApplication. Language = namedtuple('Language', ['id', 'name', 'code']) ICU_COLLATOR = None -DIGITS_OR_NONDIGITS = re.compile(r'\d+|\D+', re.UNICODE) +DIGITS_OR_NONDIGITS = re.compile(r'\d+|\D+') LANGUAGES = sorted([ Language(1, translate('common.languages', '(Afan) Oromo', 'Language code: om'), 'om'), Language(2, translate('common.languages', 'Abkhazian', 'Language code: ab'), 'ab'), diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index 0f4078420..f78065774 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -38,7 +38,6 @@ log = logging.getLogger(__name__ + '.__init__') SLIMCHARS = 'fiíIÍjlĺľrtť.,;/ ()|"\'!:\\' - class ServiceItemContext(object): """ The context in which a Service Item is being generated diff --git a/openlp/core/lib/mediamanageritem.py b/openlp/core/lib/mediamanageritem.py index c650ad80e..cc884279c 100644 --- a/openlp/core/lib/mediamanageritem.py +++ b/openlp/core/lib/mediamanageritem.py @@ -92,7 +92,7 @@ class MediaManagerItem(QtWidgets.QWidget, RegistryProperties): Run some initial setup. This method is separate from __init__ in order to mock it out in tests. """ self.hide() - self.whitespace = re.compile(r'[\W_]+', re.UNICODE) + self.whitespace = re.compile(r'[\W_]+') visible_title = self.plugin.get_string(StringContent.VisibleName) self.title = str(visible_title['title']) Registry().register(self.plugin.name, self) diff --git a/openlp/core/ui/formattingtagcontroller.py b/openlp/core/ui/formattingtagcontroller.py index e92173fed..4b9d75fee 100644 --- a/openlp/core/ui/formattingtagcontroller.py +++ b/openlp/core/ui/formattingtagcontroller.py @@ -43,7 +43,7 @@ class FormattingTagController(object): r'(?P[^\s/!\?>]+)(?:\s+[^\s=]+="[^"]*")*\s*(?P/)?' r'|(?P!\[CDATA\[(?:(?!\]\]>).)*\]\])' r'|(?P\?(?:(?!\?>).)*\?)' - r'|(?P!--(?:(?!-->).)*--))>', re.UNICODE) + r'|(?P!--(?:(?!-->).)*--))>') self.html_regex = re.compile(r'^(?:[^<>]*%s)*[^<>]*$' % self.html_tag_regex.pattern) def pre_save(self): diff --git a/openlp/plugins/bibles/forms/booknameform.py b/openlp/plugins/bibles/forms/booknameform.py index f78559ce5..7c8a2c3cd 100644 --- a/openlp/plugins/bibles/forms/booknameform.py +++ b/openlp/plugins/bibles/forms/booknameform.py @@ -113,8 +113,7 @@ class BookNameForm(QDialog, Ui_BookNameDialog): cor_book = self.corresponding_combo_box.currentText() for character in '\\.^$*+?{}[]()': cor_book = cor_book.replace(character, '\\' + character) - books = [key for key in list(self.book_names.keys()) if re.match(cor_book, str(self.book_names[key]), - re.UNICODE)] + books = [key for key in list(self.book_names.keys()) if re.match(cor_book, str(self.book_names[key]))] books = [_f for _f in map(BiblesResourcesDB.get_book, books) if _f] if books: self.book_id = books[0]['id'] diff --git a/openlp/plugins/bibles/lib/__init__.py b/openlp/plugins/bibles/lib/__init__.py index 9247485c1..f9d93a43e 100644 --- a/openlp/plugins/bibles/lib/__init__.py +++ b/openlp/plugins/bibles/lib/__init__.py @@ -224,13 +224,13 @@ def update_reference_separators(): range_regex = '(?:(?P[0-9]+){sep_v})?' \ '(?P[0-9]+)(?P{sep_r}(?:(?:(?P' \ '[0-9]+){sep_v})?(?P[0-9]+)|{sep_e})?)?'.format_map(REFERENCE_SEPARATORS) - REFERENCE_MATCHES['range'] = re.compile(r'^\s*{range}\s*$'.format(range=range_regex), re.UNICODE) - REFERENCE_MATCHES['range_separator'] = re.compile(REFERENCE_SEPARATORS['sep_l'], re.UNICODE) + REFERENCE_MATCHES['range'] = re.compile(r'^\s*{range}\s*$'.format(range=range_regex)) + REFERENCE_MATCHES['range_separator'] = re.compile(REFERENCE_SEPARATORS['sep_l']) # full reference match: ((,(?!$)|(?=$)))+ REFERENCE_MATCHES['full'] = \ re.compile(r'^\s*(?!\s)(?P[\d]*[.]?[^\d\.]+)\.*(?(?:{range_regex}(?:{sep_l}(?!\s*$)|(?=\s*$)))+)\s*$'.format( - range_regex=range_regex, sep_l=REFERENCE_SEPARATORS['sep_l']), re.UNICODE) + range_regex=range_regex, sep_l=REFERENCE_SEPARATORS['sep_l'])) def get_reference_separator(separator_type): diff --git a/openlp/plugins/bibles/lib/db.py b/openlp/plugins/bibles/lib/db.py index bc8ce4150..995a9691a 100644 --- a/openlp/plugins/bibles/lib/db.py +++ b/openlp/plugins/bibles/lib/db.py @@ -307,8 +307,7 @@ class BibleDB(Manager): book_escaped = book for character in RESERVED_CHARACTERS: book_escaped = book_escaped.replace(character, '\\' + character) - regex_book = re.compile('\\s*{book}\\s*'.format(book='\\s*'.join(book_escaped.split())), - re.UNICODE | re.IGNORECASE) + regex_book = re.compile('\\s*{book}\\s*'.format(book='\\s*'.join(book_escaped.split())), re.IGNORECASE) if language_selection == LanguageSelection.Bible: db_book = self.get_book(book) if db_book: diff --git a/openlp/plugins/songs/forms/editsongform.py b/openlp/plugins/songs/forms/editsongform.py index fa475a63f..6e0772418 100644 --- a/openlp/plugins/songs/forms/editsongform.py +++ b/openlp/plugins/songs/forms/editsongform.py @@ -105,9 +105,9 @@ class EditSongForm(QtWidgets.QDialog, Ui_EditSongDialog, RegistryProperties): self.topics_list_view.setSortingEnabled(False) self.topics_list_view.setAlternatingRowColors(True) self.audio_list_widget.setAlternatingRowColors(True) - self.find_verse_split = re.compile('---\[\]---\n', re.UNICODE) - self.whitespace = re.compile(r'\W+', re.UNICODE) - self.find_tags = re.compile(u'\{/?\w+\}', re.UNICODE) + self.find_verse_split = re.compile('---\[\]---\n') + self.whitespace = re.compile(r'\W+') + self.find_tags = re.compile(r'\{/?\w+\}') def _load_objects(self, cls, combo, cache): """ diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index f88aa8678..74334ef0d 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -24,7 +24,6 @@ The :mod:`~openlp.plugins.songs.lib` module contains a number of library functio """ import logging -import os import re from PyQt5 import QtWidgets @@ -39,8 +38,8 @@ from openlp.plugins.songs.lib.ui import SongStrings log = logging.getLogger(__name__) -WHITESPACE = re.compile(r'[\W_]+', re.UNICODE) -APOSTROPHE = re.compile('[\'`’ʻ′]', re.UNICODE) +WHITESPACE = re.compile(r'[\W_]+') +APOSTROPHE = re.compile(r'[\'`’ʻ′]') # PATTERN will look for the next occurence of one of these symbols: # \controlword - optionally preceded by \*, optionally followed by a number # \'## - where ## is a pair of hex digits, representing a single character diff --git a/openlp/plugins/songs/lib/importers/easyslides.py b/openlp/plugins/songs/lib/importers/easyslides.py index a1ffb7b7c..6d717bdb4 100644 --- a/openlp/plugins/songs/lib/importers/easyslides.py +++ b/openlp/plugins/songs/lib/importers/easyslides.py @@ -25,6 +25,7 @@ import re from lxml import etree, objectify +from openlp.core.common import normalize_str from openlp.plugins.songs.lib import VerseType from openlp.plugins.songs.lib.importers.songimport import SongImport @@ -225,7 +226,7 @@ class EasySlidesImport(SongImport): verses[reg].setdefault(vt, {}) verses[reg][vt].setdefault(vn, {}) verses[reg][vt][vn].setdefault(inst, []) - verses[reg][vt][vn][inst].append(self.tidy_text(line)) + verses[reg][vt][vn][inst].append(normalize_str(line)) # done parsing versetags = [] # we use our_verse_order to ensure, we insert lyrics in the same order diff --git a/openlp/plugins/songs/lib/importers/mediashout.py b/openlp/plugins/songs/lib/importers/mediashout.py index 67cf0d0fb..9df9baa0f 100644 --- a/openlp/plugins/songs/lib/importers/mediashout.py +++ b/openlp/plugins/songs/lib/importers/mediashout.py @@ -101,7 +101,7 @@ class MediaShoutImport(SongImport): self.song_book_name = song.SongID for verse in verses: tag = VERSE_TAGS[verse.Type] + str(verse.Number) if verse.Type < len(VERSE_TAGS) else 'O' - self.add_verse(self.tidy_text(verse.Text), tag) + self.add_verse(verse.Text, tag) for order in verse_order: if order.Type < len(VERSE_TAGS): self.verse_order_list.append(VERSE_TAGS[order.Type] + str(order.Number)) diff --git a/openlp/plugins/songs/lib/importers/openoffice.py b/openlp/plugins/songs/lib/importers/openoffice.py index a097d8b85..f2a8b2147 100644 --- a/openlp/plugins/songs/lib/importers/openoffice.py +++ b/openlp/plugins/songs/lib/importers/openoffice.py @@ -24,7 +24,7 @@ import time from PyQt5 import QtCore -from openlp.core.common import is_win, get_uno_command, get_uno_instance +from openlp.core.common import get_uno_command, get_uno_instance, is_win, normalize_str from openlp.core.common.i18n import translate from .songimport import SongImport @@ -241,7 +241,7 @@ class OpenOfficeImport(SongImport): :param text: The text. """ - song_texts = self.tidy_text(text).split('\f') + song_texts = normalize_str(text).split('\f') self.set_defaults() for song_text in song_texts: if song_text.strip(): diff --git a/openlp/plugins/songs/lib/importers/opensong.py b/openlp/plugins/songs/lib/importers/opensong.py index e6924e7b2..6cd690562 100644 --- a/openlp/plugins/songs/lib/importers/opensong.py +++ b/openlp/plugins/songs/lib/importers/opensong.py @@ -25,6 +25,7 @@ import re from lxml import objectify from lxml.etree import Error, LxmlError +from openlp.core.common import normalize_str from openlp.core.common.i18n import translate from openlp.core.common.settings import Settings from openlp.plugins.songs.lib import VerseType @@ -262,7 +263,7 @@ class OpenSongImport(SongImport): post=this_line[offset + column:]) offset += len(chord) + 2 # Tidy text and remove the ____s from extended words - this_line = self.tidy_text(this_line) + this_line = normalize_str(this_line) this_line = this_line.replace('_', '') this_line = this_line.replace('||', '\n[---]\n') this_line = this_line.strip() diff --git a/openlp/plugins/songs/lib/importers/songimport.py b/openlp/plugins/songs/lib/importers/songimport.py index a67c17fe7..2bd8c0e56 100644 --- a/openlp/plugins/songs/lib/importers/songimport.py +++ b/openlp/plugins/songs/lib/importers/songimport.py @@ -25,6 +25,7 @@ import re from PyQt5 import QtCore +from openlp.core.common import normalize_str from openlp.core.common.applocation import AppLocation from openlp.core.common.i18n import translate from openlp.core.common.path import copyfile, create_paths @@ -130,26 +131,6 @@ class SongImport(QtCore.QObject): def register(self, import_wizard): self.import_wizard = import_wizard - def tidy_text(self, text): - """ - Get rid of some dodgy unicode and formatting characters we're not interested in. Some can be converted to ascii. - """ - text = text.replace('\u2018', '\'') - text = text.replace('\u2019', '\'') - text = text.replace('\u201c', '"') - text = text.replace('\u201d', '"') - text = text.replace('\u2026', '...') - text = text.replace('\u2013', '-') - text = text.replace('\u2014', '-') - # Replace vertical tab with 2 linebreaks - text = text.replace('\v', '\n\n') - # Replace form feed (page break) with 2 linebreaks - text = text.replace('\f', '\n\n') - # Remove surplus blank lines, spaces, trailing/leading spaces - text = re.sub(r'[ \t]+', ' ', text) - text = re.sub(r' ?(\r\n?|\n) ?', '\n', text) - return text - def process_song_text(self, text): """ Process the song text from import @@ -368,7 +349,7 @@ class SongImport(QtCore.QObject): verse_tag = VerseType.tags[VerseType.Other] 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) + sxml.add_verse_to_lyrics(verse_tag, verse_def[1:], normalize_str(verse_text), lang) song.lyrics = str(sxml.extract_xml(), 'utf-8') if not self.verse_order_list and self.verse_order_list_generated_useful: self.verse_order_list = self.verse_order_list_generated diff --git a/openlp/plugins/songs/lib/importers/songsoffellowship.py b/openlp/plugins/songs/lib/importers/songsoffellowship.py index 13e073cc1..bbba654c9 100644 --- a/openlp/plugins/songs/lib/importers/songsoffellowship.py +++ b/openlp/plugins/songs/lib/importers/songsoffellowship.py @@ -194,7 +194,6 @@ class SongsOfFellowshipImport(OpenOfficeImport): :param text_portion: A Piece of text """ text = text_portion.getString() - text = self.tidy_text(text) if text.strip() == '': return text if text_portion.CharWeight == BOLD: diff --git a/openlp/plugins/songs/lib/openlyricsxml.py b/openlp/plugins/songs/lib/openlyricsxml.py index 74d91068c..ef47fa77b 100644 --- a/openlp/plugins/songs/lib/openlyricsxml.py +++ b/openlp/plugins/songs/lib/openlyricsxml.py @@ -281,7 +281,7 @@ class OpenLyrics(object): # Process the formatting tags. # Have we any tags in song lyrics? tags_element = None - match = re.search('\{/?\w+\}', song.lyrics, re.UNICODE) + match = re.search(r'\{/?\w+\}', song.lyrics) if match: # Named 'format_' - 'format' is built-in function in Python. format_ = etree.SubElement(song_xml, 'format') From a268c4476b11fd9f6cb50bf1c1541419b637b236 Mon Sep 17 00:00:00 2001 From: Phill Ridout Date: Sat, 28 Oct 2017 19:58:34 +0100 Subject: [PATCH 11/22] Couple fixes for bugs caused by controll chars --- openlp/core/common/__init__.py | 8 ++++++-- openlp/core/widgets/edits.py | 12 ++++++++++- .../plugins/songs/lib/importers/zionworx.py | 20 +++++-------------- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/openlp/core/common/__init__.py b/openlp/core/common/__init__.py index f4c22f490..b7e579803 100644 --- a/openlp/core/common/__init__.py +++ b/openlp/core/common/__init__.py @@ -441,12 +441,16 @@ def get_file_encoding(file_path): except OSError: log.exception('Error detecting file encoding') + def normalize_str(irreg_str): """ + Normalize the supplied string. Remove unicode control chars and tidy up white space. - :param str irreg_str: - :return: + :param str irreg_str: The string to normalize. + :return: The normalized string + :rtype: str """ irreg_str = irreg_str.translate(REPLACMENT_CHARS_MAP) + irreg_str = CONTROL_CHARS.sub('', irreg_str) irreg_str = NEW_LINE_REGEX.sub('\n', irreg_str) return WHITESPACE_REGEX.sub(' ', irreg_str) diff --git a/openlp/core/widgets/edits.py b/openlp/core/widgets/edits.py index c2396810f..e64125833 100644 --- a/openlp/core/widgets/edits.py +++ b/openlp/core/widgets/edits.py @@ -27,6 +27,7 @@ import re from PyQt5 import QtCore, QtGui, QtWidgets +from openlp.core.common import CONTROL_CHARS from openlp.core.common.i18n import UiStrings, translate from openlp.core.common.path import Path, path_to_str, str_to_path from openlp.core.common.settings import Settings @@ -470,12 +471,21 @@ class SpellTextEdit(QtWidgets.QPlainTextEdit): cursor.insertText(html['start tag']) cursor.insertText(html['end tag']) + def insertFromMimeData(self, source): + """ + Reimplement `insertFromMimeData` so that we can remove any control characters + + :param QtCore.QMimeData source: The mime data to insert + :rtype: None + """ + self.insertPlainText(CONTROL_CHARS.sub('', source.text())) + class Highlighter(QtGui.QSyntaxHighlighter): """ Provides a text highlighter for pointing out spelling errors in text. """ - WORDS = r'(?iu)[\w\']+' + WORDS = r'(?i)[\w\']+' def __init__(self, *args): """ diff --git a/openlp/plugins/songs/lib/importers/zionworx.py b/openlp/plugins/songs/lib/importers/zionworx.py index 5cfc0576d..23817c31a 100644 --- a/openlp/plugins/songs/lib/importers/zionworx.py +++ b/openlp/plugins/songs/lib/importers/zionworx.py @@ -30,9 +30,6 @@ from openlp.plugins.songs.lib.importers.songimport import SongImport log = logging.getLogger(__name__) -# Used to strip control chars (except 10=LF, 13=CR) -CONTROL_CHARS_MAP = dict.fromkeys(list(range(10)) + [11, 12] + list(range(14, 32)) + [127]) - class ZionWorxImport(SongImport): """ @@ -95,12 +92,12 @@ class ZionWorxImport(SongImport): return self.set_defaults() try: - self.title = self._decode(record['Title1']) + self.title = record['Title1'] if record['Title2']: - self.alternate_title = self._decode(record['Title2']) - self.parse_author(self._decode(record['Writer'])) - self.add_copyright(self._decode(record['Copyright'])) - lyrics = self._decode(record['Lyrics']) + self.alternate_title = record['Title2'] + self.parse_author(record['Writer']) + self.add_copyright(record['Copyright']) + lyrics = record['Lyrics'] except UnicodeDecodeError as e: self.log_error(translate('SongsPlugin.ZionWorxImport', 'Record {index}').format(index=index), translate('SongsPlugin.ZionWorxImport', 'Decoding error: {error}').format(error=e)) @@ -122,10 +119,3 @@ class ZionWorxImport(SongImport): if not self.finish(): self.log_error(translate('SongsPlugin.ZionWorxImport', 'Record %d') % index + (': "' + title + '"' if title else '')) - - def _decode(self, str): - """ - Strips all control characters (except new lines). - """ - # ZionWorx has no option for setting the encoding for its songs, so we assume encoding is always the same. - return str.translate(CONTROL_CHARS_MAP) From 7697febb2a1f42977bf48fd7baf302c3b4b491b9 Mon Sep 17 00:00:00 2001 From: Phill Ridout Date: Thu, 2 Nov 2017 21:46:02 +0000 Subject: [PATCH 12/22] Fixes Bug #1661416 Fixes: https://launchpad.net/bugs/1661416 --- openlp/plugins/songusage/forms/songusagedetailform.py | 10 ++++++++-- openlp/plugins/songusage/songusageplugin.py | 9 +++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/openlp/plugins/songusage/forms/songusagedetailform.py b/openlp/plugins/songusage/forms/songusagedetailform.py index 147e26d10..dc3393c8d 100644 --- a/openlp/plugins/songusage/forms/songusagedetailform.py +++ b/openlp/plugins/songusage/forms/songusagedetailform.py @@ -54,8 +54,14 @@ class SongUsageDetailForm(QtWidgets.QDialog, Ui_SongUsageDetailDialog, RegistryP """ We need to set up the screen """ - self.from_date_calendar.setSelectedDate(Settings().value(self.plugin.settings_section + '/from date')) - self.to_date_calendar.setSelectedDate(Settings().value(self.plugin.settings_section + '/to date')) + to_date = Settings().value(self.plugin.settings_section + '/to date') + if not (isinstance(to_date, QtCore.QDate) and to_date.isValid()): + to_date = QtCore.QDate.currentDate() + from_date = Settings().value(self.plugin.settings_section + '/from date') + if not (isinstance(from_date, QtCore.QDate) and from_date.isValid()): + from_date = to_date.addYears(-1) + self.from_date_calendar.setSelectedDate(from_date) + self.to_date_calendar.setSelectedDate(to_date) self.report_path_edit.path = Settings().value(self.plugin.settings_section + '/last directory export') def on_report_path_edit_path_changed(self, file_path): diff --git a/openlp/plugins/songusage/songusageplugin.py b/openlp/plugins/songusage/songusageplugin.py index a49661143..79f21a8cf 100644 --- a/openlp/plugins/songusage/songusageplugin.py +++ b/openlp/plugins/songusage/songusageplugin.py @@ -38,10 +38,7 @@ from openlp.plugins.songusage.lib.db import init_schema, SongUsageItem log = logging.getLogger(__name__) -YEAR = QtCore.QDate().currentDate().year() -if QtCore.QDate().currentDate().month() < 9: - YEAR -= 1 - +TODAY = QtCore.QDate.currentDate() __default_settings__ = { 'songusage/db type': 'sqlite', @@ -50,8 +47,8 @@ __default_settings__ = { 'songusage/db hostname': '', 'songusage/db database': '', 'songusage/active': False, - 'songusage/to date': QtCore.QDate(YEAR, 8, 31), - 'songusage/from date': QtCore.QDate(YEAR - 1, 9, 1), + 'songusage/to date': TODAY, + 'songusage/from date': TODAY.addYears(-1), 'songusage/last directory export': None } From 94dd107abe38915412ac15fb26467cb9af03e6cd Mon Sep 17 00:00:00 2001 From: Phill Ridout Date: Fri, 3 Nov 2017 20:55:41 +0000 Subject: [PATCH 13/22] Changed merged errors Fixes: https://launchpad.net/bugs/1400415 --- openlp/core/common/__init__.py | 2 +- openlp/core/common/httputils.py | 8 ++++---- openlp/core/common/path.py | 2 +- openlp/core/lib/__init__.py | 2 +- openlp/core/ui/exceptionform.py | 2 +- openlp/core/ui/mainwindow.py | 2 +- openlp/core/ui/servicemanager.py | 8 ++++---- openlp/core/ui/thememanager.py | 6 +++--- openlp/core/version.py | 4 ++-- openlp/plugins/presentations/lib/pptviewcontroller.py | 2 +- tests/functional/openlp_core/common/test_httputils.py | 2 +- tests/functional/openlp_core/common/test_path.py | 8 ++++---- tests/functional/openlp_core/lib/test_lib.py | 2 +- tests/functional/openlp_core/ui/test_first_time.py | 2 +- .../presentations/test_presentationcontroller.py | 2 +- tests/utils/__init__.py | 2 +- 16 files changed, 28 insertions(+), 28 deletions(-) diff --git a/openlp/core/common/__init__.py b/openlp/core/common/__init__.py index b7e579803..d280cbde2 100644 --- a/openlp/core/common/__init__.py +++ b/openlp/core/common/__init__.py @@ -343,7 +343,7 @@ def delete_file(file_path): if file_path.exists(): file_path.unlink() return True - except (IOError, OSError): + except OSError: log.exception('Unable to delete file {file_path}'.format(file_path=file_path)) return False diff --git a/openlp/core/common/httputils.py b/openlp/core/common/httputils.py index 11ae7b563..21b778b80 100644 --- a/openlp/core/common/httputils.py +++ b/openlp/core/common/httputils.py @@ -97,8 +97,8 @@ def get_web_page(url, headers=None, update_openlp=False, proxies=None): response = requests.get(url, headers=headers, proxies=proxies, timeout=float(CONNECTION_TIMEOUT)) log.debug('Downloaded page {url}'.format(url=response.url)) break - except IOError: - # For now, catch IOError. All requests errors inherit from IOError + except OSError: + # For now, catch OSError. All requests errors inherit from OSError log.exception('Unable to connect to {url}'.format(url=url)) response = None if retries >= CONNECTION_RETRIES: @@ -127,7 +127,7 @@ def get_url_file_size(url): try: response = requests.head(url, timeout=float(CONNECTION_TIMEOUT), allow_redirects=True) return int(response.headers['Content-Length']) - except IOError: + except OSError: if retries > CONNECTION_RETRIES: raise ConnectionError('Unable to download {url}'.format(url=url)) else: @@ -173,7 +173,7 @@ def url_get_file(callback, url, file_path, sha256=None): file_path.unlink() return False break - except IOError: + except OSError: trace_error_handler(log) if retries > CONNECTION_RETRIES: if file_path.exists(): diff --git a/openlp/core/common/path.py b/openlp/core/common/path.py index 19e17470b..6b89acfb5 100644 --- a/openlp/core/common/path.py +++ b/openlp/core/common/path.py @@ -233,7 +233,7 @@ def create_paths(*paths, **kwargs): try: if not path.exists(): path.mkdir(parents=True) - except IOError: + except OSError: if not kwargs.get('do_not_log', False): log.exception('failed to check if directory exists or create directory') diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index f78065774..04d3b9e5e 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -103,7 +103,7 @@ def get_text_file_string(text_file_path): # no BOM was found file_handle.seek(0) content = file_handle.read() - except (IOError, UnicodeError): + except (OSError, UnicodeError): log.exception('Failed to open text file {text}'.format(text=text_file_path)) return content diff --git a/openlp/core/ui/exceptionform.py b/openlp/core/ui/exceptionform.py index 70fe2c416..45124dac8 100644 --- a/openlp/core/ui/exceptionform.py +++ b/openlp/core/ui/exceptionform.py @@ -155,7 +155,7 @@ class ExceptionForm(QtWidgets.QDialog, Ui_ExceptionDialog, RegistryProperties): try: with file_path.open('w') as report_file: report_file.write(report_text) - except IOError: + except OSError: log.exception('Failed to write crash report') def on_send_report_button_clicked(self): diff --git a/openlp/core/ui/mainwindow.py b/openlp/core/ui/mainwindow.py index 33cdc3301..c0e704afb 100644 --- a/openlp/core/ui/mainwindow.py +++ b/openlp/core/ui/mainwindow.py @@ -1367,7 +1367,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow, RegistryProperties): '- Please wait for copy to finish').format(path=self.new_data_path)) dir_util.copy_tree(str(old_data_path), str(self.new_data_path)) log.info('Copy successful') - except (IOError, os.error, DistutilsFileError) as why: + except (OSError, DistutilsFileError) as why: self.application.set_normal_cursor() log.exception('Data copy failed {err}'.format(err=str(why))) err_text = translate('OpenLP.MainWindow', diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 5dda18044..71c6a1147 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -609,7 +609,7 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi if not os.path.exists(save_file): shutil.copy(audio_from, save_file) zip_file.write(audio_from, audio_to) - except IOError: + except OSError: self.log_exception('Failed to save service to disk: {name}'.format(name=temp_file_name)) self.main_window.error_message(translate('OpenLP.ServiceManager', 'Error Saving File'), translate('OpenLP.ServiceManager', 'There was an error saving your file.')) @@ -670,7 +670,7 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi zip_file = zipfile.ZipFile(temp_file_name, 'w', zipfile.ZIP_STORED, True) # First we add service contents. zip_file.writestr(service_file_name, service_content) - except IOError: + except OSError: self.log_exception('Failed to save service to disk: {name}'.format(name=temp_file_name)) self.main_window.error_message(translate('OpenLP.ServiceManager', 'Error Saving File'), translate('OpenLP.ServiceManager', 'There was an error saving your file.')) @@ -802,11 +802,11 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi else: critical_error_message_box(message=translate('OpenLP.ServiceManager', 'File is not a valid service.')) self.log_error('File contains no service data') - except (IOError, NameError): + except (OSError, NameError): self.log_exception('Problem loading service file {name}'.format(name=file_name)) critical_error_message_box(message=translate('OpenLP.ServiceManager', 'File could not be opened because it is corrupt.')) - except zipfile.BadZipfile: + except zipfile.BadZipFile: if os.path.getsize(file_name) == 0: self.log_exception('Service file is zero sized: {name}'.format(name=file_name)) QtWidgets.QMessageBox.information(self, translate('OpenLP.ServiceManager', 'Empty File'), diff --git a/openlp/core/ui/thememanager.py b/openlp/core/ui/thememanager.py index 5b4c5cbb9..1b39e5fec 100644 --- a/openlp/core/ui/thememanager.py +++ b/openlp/core/ui/thememanager.py @@ -604,7 +604,7 @@ class ThemeManager(QtWidgets.QWidget, RegistryBase, Ui_ThemeManager, LogMixin, R else: with full_name.open('wb') as out_file: out_file.write(theme_zip.read(zipped_file)) - except (IOError, zipfile.BadZipfile): + except (OSError, zipfile.BadZipFile): self.log_exception('Importing theme from zip failed {name}'.format(name=file_path)) raise ValidationError except ValidationError: @@ -667,7 +667,7 @@ class ThemeManager(QtWidgets.QWidget, RegistryBase, Ui_ThemeManager, LogMixin, R theme_path = theme_dir / '{file_name}.json'.format(file_name=name) try: theme_path.write_text(theme_pretty) - except IOError: + except OSError: self.log_exception('Saving theme to file failed') if image_source_path and image_destination_path: if self.old_background_image_path and image_destination_path != self.old_background_image_path: @@ -675,7 +675,7 @@ class ThemeManager(QtWidgets.QWidget, RegistryBase, Ui_ThemeManager, LogMixin, R if image_source_path != image_destination_path: try: copyfile(image_source_path, image_destination_path) - except IOError: + except OSError: self.log_exception('Failed to save theme image') self.generate_and_save_image(name, theme) diff --git a/openlp/core/version.py b/openlp/core/version.py index 6d038a3d9..314c4865f 100644 --- a/openlp/core/version.py +++ b/openlp/core/version.py @@ -96,7 +96,7 @@ class VersionWorker(QtCore.QObject): remote_version = response.text log.debug('New version found: %s', remote_version) break - except IOError: + except OSError: log.exception('Unable to connect to OpenLP server to download version file') retries += 1 else: @@ -182,7 +182,7 @@ def get_version(): try: version_file = open(file_path, 'r') full_version = str(version_file.read()).rstrip() - except IOError: + except OSError: log.exception('Error in version file.') full_version = '0.0.0-bzr000' finally: diff --git a/openlp/plugins/presentations/lib/pptviewcontroller.py b/openlp/plugins/presentations/lib/pptviewcontroller.py index 0a403df37..ddabe07e1 100644 --- a/openlp/plugins/presentations/lib/pptviewcontroller.py +++ b/openlp/plugins/presentations/lib/pptviewcontroller.py @@ -70,7 +70,7 @@ class PptviewController(PresentationController): try: self.start_process() return self.process.CheckInstalled() - except WindowsError: + except OSError: return False def start_process(self): diff --git a/tests/functional/openlp_core/common/test_httputils.py b/tests/functional/openlp_core/common/test_httputils.py index e620fa04e..5e7a396b2 100644 --- a/tests/functional/openlp_core/common/test_httputils.py +++ b/tests/functional/openlp_core/common/test_httputils.py @@ -233,7 +233,7 @@ class TestHttpUtils(TestCase, TestMixin): Test socket timeout gets caught """ # GIVEN: Mocked urlopen to fake a network disconnect in the middle of a download - mocked_requests.get.side_effect = IOError + mocked_requests.get.side_effect = OSError # WHEN: Attempt to retrieve a file url_get_file(MagicMock(), url='http://localhost/test', file_path=Path(self.tempfile)) diff --git a/tests/functional/openlp_core/common/test_path.py b/tests/functional/openlp_core/common/test_path.py index 4b30bd2cb..2ec89771b 100644 --- a/tests/functional/openlp_core/common/test_path.py +++ b/tests/functional/openlp_core/common/test_path.py @@ -371,13 +371,13 @@ class TestPath(TestCase): @patch('openlp.core.common.path.log') def test_create_paths_dir_io_error(self, mocked_logger): """ - Test the create_paths() when an IOError is raised + Test the create_paths() when an OSError is raised """ # GIVEN: A `Path` to check with patched out mkdir and exists methods mocked_path = MagicMock() - mocked_path.exists.side_effect = IOError('Cannot make directory') + mocked_path.exists.side_effect = OSError('Cannot make directory') - # WHEN: An IOError is raised when checking the if the path exists. + # WHEN: An OSError is raised when checking the if the path exists. create_paths(mocked_path) # THEN: The Error should have been logged @@ -385,7 +385,7 @@ class TestPath(TestCase): def test_create_paths_dir_value_error(self): """ - Test the create_paths() when an error other than IOError is raised + Test the create_paths() when an error other than OSError is raised """ # GIVEN: A `Path` to check with patched out mkdir and exists methods mocked_path = MagicMock() diff --git a/tests/functional/openlp_core/lib/test_lib.py b/tests/functional/openlp_core/lib/test_lib.py index f2bfaf79c..1352b5da5 100644 --- a/tests/functional/openlp_core/lib/test_lib.py +++ b/tests/functional/openlp_core/lib/test_lib.py @@ -168,7 +168,7 @@ class TestLib(TestCase): patch.object(Path, 'open'): file_path = Path('testfile.txt') file_path.is_file.return_value = True - file_path.open.side_effect = IOError() + file_path.open.side_effect = OSError() # WHEN: get_text_file_string is called result = get_text_file_string(file_path) diff --git a/tests/functional/openlp_core/ui/test_first_time.py b/tests/functional/openlp_core/ui/test_first_time.py index eb9464375..2be5e1ad6 100644 --- a/tests/functional/openlp_core/ui/test_first_time.py +++ b/tests/functional/openlp_core/ui/test_first_time.py @@ -40,7 +40,7 @@ class TestFirstTimeWizard(TestMixin, TestCase): Test get_web_page will attempt CONNECTION_RETRIES+1 connections - bug 1409031 """ # GIVEN: Initial settings and mocks - mocked_requests.get.side_effect = IOError('Unable to connect') + mocked_requests.get.side_effect = OSError('Unable to connect') # WHEN: A webpage is requested try: diff --git a/tests/functional/openlp_plugins/presentations/test_presentationcontroller.py b/tests/functional/openlp_plugins/presentations/test_presentationcontroller.py index 30ab11561..a921ef81e 100644 --- a/tests/functional/openlp_plugins/presentations/test_presentationcontroller.py +++ b/tests/functional/openlp_plugins/presentations/test_presentationcontroller.py @@ -144,7 +144,7 @@ class TestPresentationController(TestCase): # GIVEN: A mocked open, get_thumbnail_folder and exists with patch('openlp.plugins.presentations.lib.presentationcontroller.Path.read_text') as mocked_read_text, \ patch(FOLDER_TO_PATCH) as mocked_get_thumbnail_folder: - mocked_read_text.side_effect = IOError() + mocked_read_text.side_effect = OSError() mocked_get_thumbnail_folder.return_value = Path('test') # WHEN: calling get_titles_and_notes diff --git a/tests/utils/__init__.py b/tests/utils/__init__.py index fd5aeccfd..dd4d78354 100644 --- a/tests/utils/__init__.py +++ b/tests/utils/__init__.py @@ -36,7 +36,7 @@ def convert_file_service_item(test_path, name, row=0): try: items = json.load(open_file) first_line = items[row] - except IOError: + except OSError: first_line = '' finally: open_file.close() From f307568cbbff54e390ed923dd277319634aa6738 Mon Sep 17 00:00:00 2001 From: Phill Ridout Date: Fri, 3 Nov 2017 22:52:24 +0000 Subject: [PATCH 14/22] Misc test fixes --- openlp/core/common/actions.py | 1 + openlp/core/ui/servicemanager.py | 2 +- tests/functional/openlp_core/common/test_actions.py | 1 + tests/functional/openlp_core/common/test_i18n.py | 2 +- tests/interfaces/openlp_core/ui/test_projectormanager.py | 2 +- tests/interfaces/openlp_core/ui/test_projectorsourceform.py | 2 +- tests/interfaces/openlp_core/ui/test_thememanager.py | 2 +- 7 files changed, 7 insertions(+), 5 deletions(-) diff --git a/openlp/core/common/actions.py b/openlp/core/common/actions.py index a5b417017..739aba4e3 100644 --- a/openlp/core/common/actions.py +++ b/openlp/core/common/actions.py @@ -366,6 +366,7 @@ class ActionList(object): continue if existing_action in affected_actions: return False + print(existing_action.shortcutContext()) if existing_action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]: return False elif action in self.get_all_child_objects(existing_action.parent()): diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index d13d7879d..f5a71934d 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -719,7 +719,7 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi 'OpenLP Service Files (*.osz);; OpenLP Service Files - lite (*.oszl)')) else: file_path, filter_used = FileDialog.getSaveFileName( - self.main_window, UiStrings().SaveService, file_path, + self.main_window, UiStrings().SaveService, default_file_path, translate('OpenLP.ServiceManager', 'OpenLP Service Files (*.osz);;')) if not file_path: return False diff --git a/tests/functional/openlp_core/common/test_actions.py b/tests/functional/openlp_core/common/test_actions.py index bd59d6577..57905654d 100644 --- a/tests/functional/openlp_core/common/test_actions.py +++ b/tests/functional/openlp_core/common/test_actions.py @@ -153,6 +153,7 @@ class TestActionList(TestCase, TestMixin): """ Prepare the tests """ + self.setup_application() self.action_list = ActionList.get_instance() self.build_settings() self.settings = Settings() diff --git a/tests/functional/openlp_core/common/test_i18n.py b/tests/functional/openlp_core/common/test_i18n.py index d6828fb6f..bffb819dc 100644 --- a/tests/functional/openlp_core/common/test_i18n.py +++ b/tests/functional/openlp_core/common/test_i18n.py @@ -155,7 +155,7 @@ def test_check_same_instance(): assert first_instance is second_instance, 'Two UiStrings objects should be the same instance' -def test_translate(self): +def test_translate(): """ Test the translate() function """ diff --git a/tests/interfaces/openlp_core/ui/test_projectormanager.py b/tests/interfaces/openlp_core/ui/test_projectormanager.py index ff95c4276..9184035b8 100644 --- a/tests/interfaces/openlp_core/ui/test_projectormanager.py +++ b/tests/interfaces/openlp_core/ui/test_projectormanager.py @@ -42,8 +42,8 @@ class TestProjectorManager(TestCase, TestMixin): """ Create the UI and setup necessary options """ - self.build_settings() self.setup_application() + self.build_settings() Registry.create() with patch('openlp.core.lib.projector.db.init_url') as mocked_init_url: if os.path.exists(TEST_DB): diff --git a/tests/interfaces/openlp_core/ui/test_projectorsourceform.py b/tests/interfaces/openlp_core/ui/test_projectorsourceform.py index 4b9e2f402..58094a17c 100644 --- a/tests/interfaces/openlp_core/ui/test_projectorsourceform.py +++ b/tests/interfaces/openlp_core/ui/test_projectorsourceform.py @@ -64,8 +64,8 @@ class ProjectorSourceFormTest(TestCase, TestMixin): Set up anything necessary for all tests """ mocked_init_url.return_value = 'sqlite:///{}'.format(TEST_DB) - self.build_settings() self.setup_application() + self.build_settings() Registry.create() # Do not try to recreate if we've already been created from a previous test if not hasattr(self, 'projectordb'): diff --git a/tests/interfaces/openlp_core/ui/test_thememanager.py b/tests/interfaces/openlp_core/ui/test_thememanager.py index 7f3927cf5..0808b12d0 100644 --- a/tests/interfaces/openlp_core/ui/test_thememanager.py +++ b/tests/interfaces/openlp_core/ui/test_thememanager.py @@ -41,8 +41,8 @@ class TestThemeManager(TestCase, TestMixin): """ Create the UI """ - self.build_settings() self.setup_application() + self.build_settings() Registry.create() self.theme_manager = ThemeManager() From 83eaad48ade4e3779dd199deeb856802bcad9768 Mon Sep 17 00:00:00 2001 From: Phill Ridout Date: Thu, 9 Nov 2017 19:11:37 +0000 Subject: [PATCH 15/22] Fix action test failure by removing un used actions --- openlp/core/common/actions.py | 1 - openlp/core/ui/servicemanager.py | 16 ++-------------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/openlp/core/common/actions.py b/openlp/core/common/actions.py index 739aba4e3..a5b417017 100644 --- a/openlp/core/common/actions.py +++ b/openlp/core/common/actions.py @@ -366,7 +366,6 @@ class ActionList(object): continue if existing_action in affected_actions: return False - print(existing_action.shortcutContext()) if existing_action.shortcutContext() in [QtCore.Qt.WindowShortcut, QtCore.Qt.ApplicationShortcut]: return False elif action in self.get_all_child_objects(existing_action.parent()): diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index f5a71934d..f3b107a50 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -193,18 +193,6 @@ class Ui_ServiceManager(object): text=translate('OpenLP.ServiceManager', 'Move to &bottom'), icon=':/services/service_bottom.png', tooltip=translate('OpenLP.ServiceManager', 'Move item to the end of the service.'), can_shortcuts=True, category=UiStrings().Service, triggers=self.on_service_end) - self.down_action = self.order_toolbar.add_toolbar_action( - 'down', - text=translate('OpenLP.ServiceManager', 'Move &down'), can_shortcuts=True, - tooltip=translate('OpenLP.ServiceManager', 'Moves the selection down the window.'), visible=False, - triggers=self.on_move_selection_down) - action_list.add_action(self.down_action) - self.up_action = self.order_toolbar.add_toolbar_action( - 'up', - text=translate('OpenLP.ServiceManager', 'Move up'), can_shortcuts=True, - tooltip=translate('OpenLP.ServiceManager', 'Moves the selection up the window.'), visible=False, - triggers=self.on_move_selection_up) - action_list.add_action(self.up_action) self.order_toolbar.addSeparator() self.delete_action = self.order_toolbar.add_toolbar_action( 'delete', can_shortcuts=True, @@ -300,8 +288,8 @@ class Ui_ServiceManager(object): self.theme_menu = QtWidgets.QMenu(translate('OpenLP.ServiceManager', '&Change Item Theme')) self.menu.addMenu(self.theme_menu) self.service_manager_list.addActions([self.move_down_action, self.move_up_action, self.make_live_action, - self.move_top_action, self.move_bottom_action, self.up_action, - self.down_action, self.expand_action, self.collapse_action]) + self.move_top_action, self.move_bottom_action, self.expand_action, + self.collapse_action]) Registry().register_function('theme_update_list', self.update_theme_list) Registry().register_function('config_screen_changed', self.regenerate_service_items) Registry().register_function('theme_update_global', self.theme_change) From 6d66cadb0ae683ceafa3329d4b1682d3818e161d Mon Sep 17 00:00:00 2001 From: Phill Ridout Date: Thu, 9 Nov 2017 19:15:31 +0000 Subject: [PATCH 16/22] head --- openlp/core/widgets/edits.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openlp/core/widgets/edits.py b/openlp/core/widgets/edits.py index e64125833..89310a713 100644 --- a/openlp/core/widgets/edits.py +++ b/openlp/core/widgets/edits.py @@ -242,7 +242,7 @@ class PathEdit(QtWidgets.QWidget): self.line_edit.editingFinished.connect(self.on_line_edit_editing_finished) self.update_button_tool_tips() - @property + @QtCore.pyqtProperty('QVariant') def path(self): """ A property getter method to return the selected path. @@ -350,7 +350,7 @@ class PathEdit(QtWidgets.QWidget): :rtype: None """ if self._path != path: - self.path = path + self._path = path self.pathChanged.emit(path) From 536a187fb9864dd9785eef8947d27959a1cc97c5 Mon Sep 17 00:00:00 2001 From: Phill Ridout Date: Thu, 9 Nov 2017 20:39:17 +0000 Subject: [PATCH 17/22] PEP8 --- openlp/core/lib/__init__.py | 1 + tests/functional/openlp_core/widgets/test_views.py | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index 04d3b9e5e..9bab13b71 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -38,6 +38,7 @@ log = logging.getLogger(__name__ + '.__init__') SLIMCHARS = 'fiíIÍjlĺľrtť.,;/ ()|"\'!:\\' + class ServiceItemContext(object): """ The context in which a Service Item is being generated diff --git a/tests/functional/openlp_core/widgets/test_views.py b/tests/functional/openlp_core/widgets/test_views.py index d931a5ef5..0fa028f11 100644 --- a/tests/functional/openlp_core/widgets/test_views.py +++ b/tests/functional/openlp_core/widgets/test_views.py @@ -627,4 +627,3 @@ class TestTreeWidgetWithDnD(TestCase): assert widget.allow_internal_dnd is False assert widget.indentation() == 0 assert widget.isAnimated() is True - From a408e3d74e3a069db96d9595332ff0a005370af0 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Thu, 9 Nov 2017 21:11:03 -0700 Subject: [PATCH 18/22] Fix some linting issues, and fix the test for newer versions of PyLint --- openlp/core/common/mixins.py | 14 ++++++++++++++ tests/utils/test_pylint.py | 14 +++++++++----- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/openlp/core/common/mixins.py b/openlp/core/common/mixins.py index 1bc6907a0..a07940e10 100644 --- a/openlp/core/common/mixins.py +++ b/openlp/core/common/mixins.py @@ -101,6 +101,20 @@ class RegistryProperties(object): """ This adds registry components to classes to use at run time. """ + _application = None + _plugin_manager = None + _image_manager = None + _media_controller = None + _service_manager = None + _preview_controller = None + _live_controller = None + _main_window = None + _renderer = None + _theme_manager = None + _settings_form = None + _alerts_manager = None + _projector_manager = None + @property def application(self): """ diff --git a/tests/utils/test_pylint.py b/tests/utils/test_pylint.py index 128c0741b..50ca64db6 100644 --- a/tests/utils/test_pylint.py +++ b/tests/utils/test_pylint.py @@ -58,17 +58,21 @@ class TestPylint(TestCase): # GIVEN: Some checks to disable and enable, and the pylint script disabled_checks = 'import-error,no-member' enabled_checks = 'missing-format-argument-key,unused-format-string-argument,bad-format-string' - if is_win() or 'arch' in platform.dist()[0].lower(): - pylint_script = 'pylint' - else: - pylint_script = 'pylint3' + pylint_kwargs = { + 'return_std': True + } + if version < '1.7.0': + if is_win() or 'arch' in platform.dist()[0].lower(): + pylint_kwargs.update({'script': 'pylint'}) + else: + pylint_kwargs.update({'script': 'pylint3'}) # WHEN: Running pylint (pylint_stdout, pylint_stderr) = \ lint.py_run('openlp --errors-only --disable={disabled} --enable={enabled} ' '--reports=no --output-format=parseable'.format(disabled=disabled_checks, enabled=enabled_checks), - return_std=True, script=pylint_script) + **pylint_kwargs) stdout = pylint_stdout.read() stderr = pylint_stderr.read() filtered_stdout = self._filter_tolerated_errors(stdout) From ac61fb5a4fff38a30c3bdd4fadff084112ca6d5b Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Fri, 10 Nov 2017 08:57:35 -0700 Subject: [PATCH 19/22] Make the heading line as long as the others --- scripts/jenkins_script.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/jenkins_script.py b/scripts/jenkins_script.py index 05c589ddd..706d808af 100755 --- a/scripts/jenkins_script.py +++ b/scripts/jenkins_script.py @@ -119,7 +119,7 @@ class JenkinsTrigger(object): Print the status information of the build triggered. """ print('Add this to your merge proposal:') - print('--------------------------------') + print('-' * 80) bzr = Popen(('bzr', 'revno'), stdout=PIPE, stderr=PIPE) raw_output, error = bzr.communicate() revno = raw_output.decode().strip() From a9692f83910b10ba75fbc4fdd0c329f0767580e7 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Fri, 10 Nov 2017 09:36:06 -0700 Subject: [PATCH 20/22] Print out the build info before the build starts with a WAITING status --- scripts/jenkins_script.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/scripts/jenkins_script.py b/scripts/jenkins_script.py index 706d808af..d0ba665b7 100755 --- a/scripts/jenkins_script.py +++ b/scripts/jenkins_script.py @@ -89,18 +89,18 @@ class JenkinsTrigger(object): """ Create the JenkinsTrigger instance. """ - self.build_number = {} + self.jobs = {} self.can_use_colour = can_use_colour and not os.name.startswith('nt') self.repo_name = get_repo_name() self.server = Jenkins(JENKINS_URL, username=username, password=password) - def fetch_build_numbers(self): + def fetch_jobs(self): """ - Get the next build number from all the jobs + Get the job info for all the jobs """ for job_name in OpenLPJobs.Jobs: job_info = self.server.get_job_info(job_name) - self.build_number[job_name] = job_info['nextBuildNumber'] + self.jobs[job_name] = job_info def trigger_build(self): """ @@ -111,7 +111,7 @@ class JenkinsTrigger(object): # We just want the name (not the email). name = ' '.join(raw_output.decode().split()[:-1]) cause = 'Build triggered by %s (%s)' % (name, self.repo_name) - self.fetch_build_numbers() + self.fetch_jobs() self.server.build_job(OpenLPJobs.Branch_Pull, {'BRANCH_NAME': self.repo_name, 'cause': cause}) def print_output(self): @@ -162,8 +162,10 @@ class JenkinsTrigger(object): :param job_name: The name of the job we want the information from. For example *Branch-01-Pull*. Use the class variables from the :class:`OpenLPJobs` class. """ - self.current_build = self._get_build_info(job_name, self.build_number[job_name]) - print('{:<70} [RUNNING]'.format(self.current_build['url']), end='', flush=True) + job = self.jobs[job_name] + print('{:<70} [WAITING]'.format(job['url'] + '/' + job['nextBuildNumber']), end='', flush=True) + self.current_build = self._get_build_info(job_name, job[job_name]['nextBuildNumber']) + print('\b\b\b\b\b\b\b\b\b[RUNNING]', end='', flush=True) is_success = False while self.current_build['building'] is True: time.sleep(0.5) From dd2d1002ce188a3e1cf094a79ddfa9bc3d9e1c4f Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Fri, 10 Nov 2017 10:51:42 -0700 Subject: [PATCH 21/22] Fix up a couple of issues, and move URL creation to where the job info is pulled --- scripts/jenkins_script.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/jenkins_script.py b/scripts/jenkins_script.py index d0ba665b7..a669de71e 100755 --- a/scripts/jenkins_script.py +++ b/scripts/jenkins_script.py @@ -101,6 +101,7 @@ class JenkinsTrigger(object): for job_name in OpenLPJobs.Jobs: job_info = self.server.get_job_info(job_name) self.jobs[job_name] = job_info + self.jobs[job_name]['nextBuildUrl'] = '{url}{nextBuildNumber}/'.format(**job_info) def trigger_build(self): """ @@ -163,13 +164,13 @@ class JenkinsTrigger(object): variables from the :class:`OpenLPJobs` class. """ job = self.jobs[job_name] - print('{:<70} [WAITING]'.format(job['url'] + '/' + job['nextBuildNumber']), end='', flush=True) - self.current_build = self._get_build_info(job_name, job[job_name]['nextBuildNumber']) + print('{:<70} [WAITING]'.format(job['nextBuildUrl']), end='', flush=True) + self.current_build = self._get_build_info(job_name, job['nextBuildNumber']) print('\b\b\b\b\b\b\b\b\b[RUNNING]', end='', flush=True) is_success = False while self.current_build['building'] is True: time.sleep(0.5) - self.current_build = self.server.get_build_info(job_name, self.build_number[job_name]) + self.current_build = self.server.get_build_info(job_name, job['nextBuildNumber']) result_string = self.current_build['result'] is_success = result_string == 'SUCCESS' if self.can_use_colour: From 1c760e44e5fe5be57e9bb921c61cbe2dfe3f253e Mon Sep 17 00:00:00 2001 From: Phill Ridout Date: Fri, 10 Nov 2017 22:50:04 +0000 Subject: [PATCH 22/22] Small modification to upgrade settings as per superflys request --- openlp/core/common/settings.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/openlp/core/common/settings.py b/openlp/core/common/settings.py index aa0e4a6f6..b98929138 100644 --- a/openlp/core/common/settings.py +++ b/openlp/core/common/settings.py @@ -255,10 +255,7 @@ class Settings(QtCore.QSettings): ('core/logo file', 'core/logo file', [(str_to_path, None)]), ('presentations/last directory', 'presentations/last directory', [(str_to_path, None)]), ('images/last directory', 'images/last directory', [(str_to_path, None)]), - ('media/last directory', 'media/last directory', [(str_to_path, None)]) - ] - - __setting_upgrade_3__ = [ + ('media/last directory', 'media/last directory', [(str_to_path, None)]), ('songuasge/db password', 'songusage/db password', []), ('songuasge/db hostname', 'songusage/db hostname', []), ('songuasge/db database', 'songusage/db database', [])