From b10aa241199b51386baefac393f262167ca86285 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Thu, 14 Feb 2019 22:19:26 +0100 Subject: [PATCH 01/18] Attempt to fix appveyor tests --- .../presentations/lib/impresscontroller.py | 1 + scripts/appveyor.yml | 7 +++++-- tests/functional/openlp_core/api/test_deploy.py | 16 ++++++++-------- tests/functional/openlp_core/common/test_path.py | 2 +- tests/utils/test_bzr_tags.py | 7 +++++-- 5 files changed, 20 insertions(+), 13 deletions(-) diff --git a/openlp/plugins/presentations/lib/impresscontroller.py b/openlp/plugins/presentations/lib/impresscontroller.py index d231acb05..1db6b9e68 100644 --- a/openlp/plugins/presentations/lib/impresscontroller.py +++ b/openlp/plugins/presentations/lib/impresscontroller.py @@ -46,6 +46,7 @@ from openlp.plugins.presentations.lib.presentationcontroller import Presentation if is_win(): from win32com.client import Dispatch import pywintypes + uno_available = False # Declare an empty exception to match the exception imported from UNO class ErrorCodeIOException(Exception): diff --git a/scripts/appveyor.yml b/scripts/appveyor.yml index 43f14e69d..3187a7b9f 100644 --- a/scripts/appveyor.yml +++ b/scripts/appveyor.yml @@ -1,5 +1,8 @@ version: OpenLP-win-ci-b{build} +image: + - Visual Studio 2017 + clone_script: - curl -L https://bazaar.launchpad.net/BRANCHPATH/tarball -o sourcecode.tar.gz - 7z e sourcecode.tar.gz @@ -11,7 +14,7 @@ environment: install: # Install dependencies from pypi - - "%PYTHON%\\python.exe -m pip install sqlalchemy alembic appdirs chardet beautifulsoup4 lxml Mako mysql-connector-python nose mock pyodbc psycopg2 pypiwin32 websockets asyncio waitress six webob requests QtAwesome PyQt5 pymediainfo" + - "%PYTHON%\\python.exe -m pip install sqlalchemy alembic appdirs chardet beautifulsoup4 lxml Mako mysql-connector-python pytest mock pyodbc psycopg2 pypiwin32 websockets asyncio waitress six webob requests QtAwesome PyQt5 pymediainfo" # Download and unpack mupdf - appveyor DownloadFile https://mupdf.com/downloads/archive/mupdf-1.14.0-windows.zip - 7z x mupdf-1.14.0-windows.zip @@ -27,7 +30,7 @@ build: off test_script: - cd openlp-branch # Run the tests - - "%PYTHON%\\python.exe -m nose -v tests" + - "%PYTHON%\\python.exe -m pytest -v tests" # Go back to the user root folder - cd.. diff --git a/tests/functional/openlp_core/api/test_deploy.py b/tests/functional/openlp_core/api/test_deploy.py index 784605034..75fc62cfb 100644 --- a/tests/functional/openlp_core/api/test_deploy.py +++ b/tests/functional/openlp_core/api/test_deploy.py @@ -15,13 +15,12 @@ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # # more details. # # # - - -# Temple Place, Suite 330, Boston, MA 02111-1307 USA # -############################################################################### -from tempfile import mkdtemp # You should have received a copy of the GNU General Public License along # # with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### +import os +from tempfile import mkdtemp from unittest import TestCase from unittest.mock import MagicMock, patch @@ -57,14 +56,15 @@ class TestRemoteDeploy(TestCase): # GIVEN: A new downloaded zip file mocked_zipfile = MagicMock() MockZipFile.return_value = mocked_zipfile - root_path = Path('/tmp/remotes') + root_path_str = '{sep}tmp{sep}remotes'.format(sep=os.sep) + root_path = Path(root_path_str) # WHEN: deploy_zipfile() is called deploy_zipfile(root_path, 'site.zip') # THEN: the zip file should have been extracted to the right location - MockZipFile.assert_called_once_with('/tmp/remotes/site.zip') - mocked_zipfile.extractall.assert_called_once_with('/tmp/remotes') + MockZipFile.assert_called_once_with(root_path_str + os.sep + 'site.zip') + mocked_zipfile.extractall.assert_called_once_with(root_path_str) @patch('openlp.core.api.deploy.Registry') @patch('openlp.core.api.deploy.get_web_page') diff --git a/tests/functional/openlp_core/common/test_path.py b/tests/functional/openlp_core/common/test_path.py index 7c0a34635..8695b58f1 100644 --- a/tests/functional/openlp_core/common/test_path.py +++ b/tests/functional/openlp_core/common/test_path.py @@ -324,7 +324,7 @@ class TestPath(TestCase): obj = path.json_object(extra=1, args=2) # THEN: A JSON decodable object should have been returned. - assert obj == {'__Path__': ('/', 'base', 'path', 'to', 'fi.le')} + assert obj == {'__Path__': (os.sep, 'base', 'path', 'to', 'fi.le')} def test_path_json_object_base_path(self): """ diff --git a/tests/utils/test_bzr_tags.py b/tests/utils/test_bzr_tags.py index e6c00f707..cd057ada4 100644 --- a/tests/utils/test_bzr_tags.py +++ b/tests/utils/test_bzr_tags.py @@ -24,7 +24,7 @@ Package to test for proper bzr tags. """ import os from subprocess import PIPE, Popen -from unittest import TestCase +from unittest import TestCase, SkipTest TAGS1 = {'1.9.0', '1.9.1', '1.9.2', '1.9.3', '1.9.4', '1.9.5', '1.9.6', '1.9.7', '1.9.8', '1.9.9', '1.9.10', @@ -42,7 +42,10 @@ class TestBzrTags(TestCase): path = os.path.dirname(__file__) # WHEN getting the branches tags - bzr = Popen(('bzr', 'tags', '--directory=' + path), stdout=PIPE) + try: + bzr = Popen(('bzr', 'tags', '--directory=' + path), stdout=PIPE) + except: + raise SkipTest('bzr is not installed') std_out = bzr.communicate()[0] count = len(TAGS1) tags = [line.decode('utf-8').split()[0] for line in std_out.splitlines()] From 7ec703a7d782eb6dca4c9df558d80a06930db0cf Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Fri, 15 Feb 2019 21:25:37 +0100 Subject: [PATCH 02/18] try out appveyor changes --- scripts/appveyor.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/appveyor.yml b/scripts/appveyor.yml index 3187a7b9f..e441af41b 100644 --- a/scripts/appveyor.yml +++ b/scripts/appveyor.yml @@ -18,7 +18,7 @@ install: # Download and unpack mupdf - appveyor DownloadFile https://mupdf.com/downloads/archive/mupdf-1.14.0-windows.zip - 7z x mupdf-1.14.0-windows.zip - - cp mupdf-1.14.0-windows/mupdf.exe openlp-branch/mupdf.exe + - cp mupdf-1.14.0-windows/mutool.exe openlp-branch/mutool.exe # Download and unpack mediainfo - appveyor DownloadFile https://mediaarea.net/download/binary/mediainfo/18.08.1/MediaInfo_CLI_18.08.1_Windows_i386.zip - mkdir MediaInfo @@ -52,7 +52,8 @@ after_test: # - curl -L -O http://downloads.sourceforge.net/project/portableapps/NSIS%20Portable/NSISPortable_3.0_English.paf.exe # - NSISPortable_3.0_English.paf.exe /S # Get the packaging code - - appveyor DownloadFile http://bazaar.launchpad.net/~openlp-core/openlp/packaging/tarball -FileName packaging.tar.gz + #- appveyor DownloadFile http://bazaar.launchpad.net/~openlp-core/openlp/packaging/tarball -FileName packaging.tar.gz + - appveyor DownloadFile http://bazaar.launchpad.net/~tomasgroth/openlp/packaging-webengine/tarball -FileName packaging.tar.gz - 7z e packaging.tar.gz - 7z x packaging.tar - mv ~openlp-core/openlp/packaging packaging From 85b40c50240dd1e3b019148f3a14b85ec4b0e244 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Fri, 15 Feb 2019 21:33:18 +0100 Subject: [PATCH 03/18] another try --- scripts/appveyor.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/appveyor.yml b/scripts/appveyor.yml index e441af41b..90473ebf7 100644 --- a/scripts/appveyor.yml +++ b/scripts/appveyor.yml @@ -56,7 +56,8 @@ after_test: - appveyor DownloadFile http://bazaar.launchpad.net/~tomasgroth/openlp/packaging-webengine/tarball -FileName packaging.tar.gz - 7z e packaging.tar.gz - 7z x packaging.tar - - mv ~openlp-core/openlp/packaging packaging + #- mv ~openlp-core/openlp/packaging packaging + - mv ~tomasgroth/openlp/packaging-webengine packaging # If this is trunk we should also build the manual - ps: >- If (BUILD_DOCS) { From 78263294c94c85029c3f178f21934b665700736d Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Fri, 15 Feb 2019 22:50:52 +0100 Subject: [PATCH 04/18] debug print --- scripts/appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/appveyor.yml b/scripts/appveyor.yml index 90473ebf7..91b2edc68 100644 --- a/scripts/appveyor.yml +++ b/scripts/appveyor.yml @@ -70,7 +70,7 @@ after_test: &"$env:PYTHON\python.exe" builders/windows-builder.py --skip-update -c windows/config-appveyor.ini -b ../openlp-branch -d ../documentation --portable --tag-override TAG } else { cd packaging - &"$env:PYTHON\python.exe" builders/windows-builder.py --skip-update --skip-translations -c windows/config-appveyor.ini -b ../openlp-branch --portable --tag-override TAG + &"$env:PYTHON\python.exe" builders/windows-builder.py -v --skip-update --skip-translations -c windows/config-appveyor.ini -b ../openlp-branch --portable --tag-override TAG } artifacts: From 2ab8b8ebec0fe82469dbf30f739ca33d797fb8ae Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Sat, 16 Feb 2019 22:24:44 +0100 Subject: [PATCH 05/18] remove link to dev branch --- scripts/appveyor.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/scripts/appveyor.yml b/scripts/appveyor.yml index 91b2edc68..26c9987d8 100644 --- a/scripts/appveyor.yml +++ b/scripts/appveyor.yml @@ -52,12 +52,10 @@ after_test: # - curl -L -O http://downloads.sourceforge.net/project/portableapps/NSIS%20Portable/NSISPortable_3.0_English.paf.exe # - NSISPortable_3.0_English.paf.exe /S # Get the packaging code - #- appveyor DownloadFile http://bazaar.launchpad.net/~openlp-core/openlp/packaging/tarball -FileName packaging.tar.gz - - appveyor DownloadFile http://bazaar.launchpad.net/~tomasgroth/openlp/packaging-webengine/tarball -FileName packaging.tar.gz + - appveyor DownloadFile http://bazaar.launchpad.net/~openlp-core/openlp/packaging/tarball -FileName packaging.tar.gz - 7z e packaging.tar.gz - 7z x packaging.tar - #- mv ~openlp-core/openlp/packaging packaging - - mv ~tomasgroth/openlp/packaging-webengine packaging + - mv ~openlp-core/openlp/packaging packaging # If this is trunk we should also build the manual - ps: >- If (BUILD_DOCS) { From 8de23cd980f6c1f6867ca542dd056ae9868e29a6 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Sun, 17 Feb 2019 21:23:47 +0100 Subject: [PATCH 06/18] Also install webengine. --- scripts/appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/appveyor.yml b/scripts/appveyor.yml index 26c9987d8..c1e7a006d 100644 --- a/scripts/appveyor.yml +++ b/scripts/appveyor.yml @@ -14,7 +14,7 @@ environment: install: # Install dependencies from pypi - - "%PYTHON%\\python.exe -m pip install sqlalchemy alembic appdirs chardet beautifulsoup4 lxml Mako mysql-connector-python pytest mock pyodbc psycopg2 pypiwin32 websockets asyncio waitress six webob requests QtAwesome PyQt5 pymediainfo" + - "%PYTHON%\\python.exe -m pip install sqlalchemy alembic appdirs chardet beautifulsoup4 lxml Mako mysql-connector-python pytest mock pyodbc psycopg2 pypiwin32 websockets asyncio waitress six webob requests QtAwesome PyQt5 PyQtWebEngine pymediainfo" # Download and unpack mupdf - appveyor DownloadFile https://mupdf.com/downloads/archive/mupdf-1.14.0-windows.zip - 7z x mupdf-1.14.0-windows.zip @@ -68,7 +68,7 @@ after_test: &"$env:PYTHON\python.exe" builders/windows-builder.py --skip-update -c windows/config-appveyor.ini -b ../openlp-branch -d ../documentation --portable --tag-override TAG } else { cd packaging - &"$env:PYTHON\python.exe" builders/windows-builder.py -v --skip-update --skip-translations -c windows/config-appveyor.ini -b ../openlp-branch --portable --tag-override TAG + &"$env:PYTHON\python.exe" builders/windows-builder.py --skip-update --skip-translations -c windows/config-appveyor.ini -b ../openlp-branch --portable --tag-override TAG } artifacts: From d7b543ef526f49cb74f8275f571899fc67cc33c1 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Sun, 17 Feb 2019 21:38:18 +0100 Subject: [PATCH 07/18] retry the test packaging branch --- scripts/appveyor.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/appveyor.yml b/scripts/appveyor.yml index c1e7a006d..5e8cf172d 100644 --- a/scripts/appveyor.yml +++ b/scripts/appveyor.yml @@ -52,10 +52,12 @@ after_test: # - curl -L -O http://downloads.sourceforge.net/project/portableapps/NSIS%20Portable/NSISPortable_3.0_English.paf.exe # - NSISPortable_3.0_English.paf.exe /S # Get the packaging code - - appveyor DownloadFile http://bazaar.launchpad.net/~openlp-core/openlp/packaging/tarball -FileName packaging.tar.gz + #- appveyor DownloadFile http://bazaar.launchpad.net/~openlp-core/openlp/packaging/tarball -FileName packaging.tar.gz + - appveyor DownloadFile http://bazaar.launchpad.net/~tomasgroth/openlp/packaging-webengine/tarball -FileName packaging.tar.gz - 7z e packaging.tar.gz - 7z x packaging.tar - - mv ~openlp-core/openlp/packaging packaging + #- mv ~openlp-core/openlp/packaging packaging + - mv ~tomasgroth/openlp/packaging-webengine packaging # If this is trunk we should also build the manual - ps: >- If (BUILD_DOCS) { From 0d6607087953f55be3e6fdfe633740423654b696 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 19 Feb 2019 21:46:31 +0100 Subject: [PATCH 08/18] build both 32 and 64 bit, and add debug print --- openlp/core/display/render.py | 1 + scripts/appveyor.yml | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/openlp/core/display/render.py b/openlp/core/display/render.py index 35f144ee8..acd2334c4 100644 --- a/openlp/core/display/render.py +++ b/openlp/core/display/render.py @@ -706,6 +706,7 @@ class Renderer(RegistryBase, LogMixin, RegistryProperties, DisplayWindow): else: # The remaining elements do not fit, thus reset the indexes, create a new list and continue. raw_list = raw_list[index + 1:] + print(raw_list) raw_list[0] = raw_tags + raw_list[0] html_list = html_list[index + 1:] html_list[0] = html_tags + html_list[0] diff --git a/scripts/appveyor.yml b/scripts/appveyor.yml index 5e8cf172d..9410159c8 100644 --- a/scripts/appveyor.yml +++ b/scripts/appveyor.yml @@ -10,7 +10,9 @@ clone_script: - mv BRANCHPATH openlp-branch environment: - PYTHON: C:\\Python37-x64 + matrix: + - PYTHON: C:\\Python37-x64 + - PYTHON: C:\\Python37 install: # Install dependencies from pypi From c241b28039cb2c1c985b1f84ed046cd560e12352 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Tue, 19 Feb 2019 22:38:44 +0100 Subject: [PATCH 09/18] put debug in the log --- openlp/core/display/render.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/core/display/render.py b/openlp/core/display/render.py index acd2334c4..06ce89283 100644 --- a/openlp/core/display/render.py +++ b/openlp/core/display/render.py @@ -706,7 +706,7 @@ class Renderer(RegistryBase, LogMixin, RegistryProperties, DisplayWindow): else: # The remaining elements do not fit, thus reset the indexes, create a new list and continue. raw_list = raw_list[index + 1:] - print(raw_list) + log.debug(raw_list) raw_list[0] = raw_tags + raw_list[0] html_list = html_list[index + 1:] html_list[0] = html_tags + html_list[0] From fb02d06a093230c9b5e30d0bea7abfaaf377abe1 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Wed, 27 Feb 2019 21:17:00 +0100 Subject: [PATCH 10/18] make the path of display web file work on frozen apps --- openlp/core/display/window.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/openlp/core/display/window.py b/openlp/core/display/window.py index d811de5b2..c0ef2a1ef 100644 --- a/openlp/core/display/window.py +++ b/openlp/core/display/window.py @@ -32,13 +32,11 @@ from PyQt5 import QtCore, QtWebChannel, QtWidgets from openlp.core.common.path import Path, path_to_str from openlp.core.common.settings import Settings from openlp.core.common.registry import Registry +from openlp.core.common.applocation import AppLocation from openlp.core.ui import HideMode from openlp.core.display.screens import ScreenList log = logging.getLogger(__name__) -DISPLAY_PATH = Path(__file__).parent / 'html' / 'display.html' -CHECKERBOARD_PATH = Path(__file__).parent / 'html' / 'checkerboard.png' -OPENLP_SPLASH_SCREEN_PATH = Path(__file__).parent / 'html' / 'openlp-splash-screen.png' class MediaWatcher(QtCore.QObject): @@ -126,7 +124,11 @@ class DisplayWindow(QtWidgets.QWidget): self.webview.page().setBackgroundColor(QtCore.Qt.transparent) self.layout.addWidget(self.webview) self.webview.loadFinished.connect(self.after_loaded) - self.set_url(QtCore.QUrl.fromLocalFile(path_to_str(DISPLAY_PATH))) + display_base_path = AppLocation.get_directory(AppLocation.AppDir) / 'core' / 'display' / 'html' + self.display_path = display_base_path / 'display.html' + self.checkerboard_path = display_base_path / 'checkerboard.png' + self.openlp_splash_screen_path = display_base_path / 'openlp-splash-screen.png' + self.set_url(QtCore.QUrl.fromLocalFile(path_to_str(self.display_path))) self.media_watcher = MediaWatcher(self) self.channel = QtWebChannel.QWebChannel(self) self.channel.registerObject('mediaWatcher', self.media_watcher) @@ -169,7 +171,7 @@ class DisplayWindow(QtWidgets.QWidget): bg_color = Settings().value('core/logo background color') image = Settings().value('core/logo file') if path_to_str(image).startswith(':'): - image = OPENLP_SPLASH_SCREEN_PATH + image = self.openlp_splash_screen_path image_uri = image.as_uri() self.run_javascript('Display.setStartupSplashScreen("{bg_color}", "{image}");'.format(bg_color=bg_color, image=image_uri)) @@ -329,7 +331,7 @@ class DisplayWindow(QtWidgets.QWidget): if theme.background_type == 'transparent' and not self.is_display: theme_copy = copy.deepcopy(theme) theme_copy.background_type = 'image' - theme_copy.background_filename = CHECKERBOARD_PATH + theme_copy.background_filename = self.checkerboard_path exported_theme = theme_copy.export_theme() else: exported_theme = theme.export_theme() From fd502f80dc3e8a2a77694c91e9d00b8d3845f662 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Mon, 4 Mar 2019 21:32:05 +0100 Subject: [PATCH 11/18] Use the normal packaging repo --- scripts/appveyor.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/scripts/appveyor.yml b/scripts/appveyor.yml index 9410159c8..fd9ffac73 100644 --- a/scripts/appveyor.yml +++ b/scripts/appveyor.yml @@ -54,12 +54,10 @@ after_test: # - curl -L -O http://downloads.sourceforge.net/project/portableapps/NSIS%20Portable/NSISPortable_3.0_English.paf.exe # - NSISPortable_3.0_English.paf.exe /S # Get the packaging code - #- appveyor DownloadFile http://bazaar.launchpad.net/~openlp-core/openlp/packaging/tarball -FileName packaging.tar.gz - - appveyor DownloadFile http://bazaar.launchpad.net/~tomasgroth/openlp/packaging-webengine/tarball -FileName packaging.tar.gz + - appveyor DownloadFile http://bazaar.launchpad.net/~openlp-core/openlp/packaging/tarball -FileName packaging.tar.gz - 7z e packaging.tar.gz - 7z x packaging.tar - #- mv ~openlp-core/openlp/packaging packaging - - mv ~tomasgroth/openlp/packaging-webengine packaging + - mv ~openlp-core/openlp/packaging packaging # If this is trunk we should also build the manual - ps: >- If (BUILD_DOCS) { From 2a6378f489b03fa58640babfbc9292812b1b226e Mon Sep 17 00:00:00 2001 From: Bob Luursema Date: Mon, 4 Mar 2019 21:37:11 +0100 Subject: [PATCH 12/18] Almost fixed bug 1800761 --- .bzrignore | 1 + openlp/plugins/songs/forms/songselectform.py | 5 ++-- openlp/plugins/songs/lib/songselect.py | 21 ++++++++++---- .../openlp_plugins/songs/test_songselect.py | 29 +++++++++++++------ 4 files changed, 39 insertions(+), 17 deletions(-) diff --git a/.bzrignore b/.bzrignore index f60d6cfff..2b43ce13a 100644 --- a/.bzrignore +++ b/.bzrignore @@ -7,6 +7,7 @@ cover .coverage coverage .directory +.vscode dist *.dll documentation/build/doctrees diff --git a/openlp/plugins/songs/forms/songselectform.py b/openlp/plugins/songs/forms/songselectform.py index d8b4db300..423f1f17c 100644 --- a/openlp/plugins/songs/forms/songselectform.py +++ b/openlp/plugins/songs/forms/songselectform.py @@ -263,8 +263,9 @@ class SongSelectForm(QtWidgets.QDialog, Ui_SongSelectDialog, RegistryProperties) self.login_progress_bar.setVisible(True) self.application.process_events() # Log the user in - if not self.song_select_importer.login( - self.username_edit.text(), self.password_edit.text(), self._update_login_progress): + subscription_level = self.song_select_importer.login( + self.username_edit.text(), self.password_edit.text(), self._update_login_progress) + if not subscription_level: QtWidgets.QMessageBox.critical( self, translate('SongsPlugin.SongSelectForm', 'Error Logging In'), diff --git a/openlp/plugins/songs/lib/songselect.py b/openlp/plugins/songs/lib/songselect.py index bde9b7bf9..01b9a635b 100644 --- a/openlp/plugins/songs/lib/songselect.py +++ b/openlp/plugins/songs/lib/songselect.py @@ -81,7 +81,7 @@ class SongSelectImport(object): :param username: SongSelect username :param password: SongSelect password :param callback: Method to notify of progress. - :return: True on success, False on failure. + :return: subscription level on success, None on failure. """ if callback: callback() @@ -115,11 +115,20 @@ class SongSelectImport(object): return False if callback: callback() - if posted_page.find('input', id='SearchText') is not None: - return True + if posted_page.find('input', id='SearchText') is not None or posted_page.find('div', id="select-organization") is not None: + try: + home_page = BeautifulSoup(self.opener.open(BASE_URL).read(), 'lxml') + except (TypeError, URLError) as error: + log.exception('Could not reach SongSelect, {error}'.format(error=error)) + subscription_element = home_page.find('div', {'class': 'subscriptionlevel'}) + if subscription_element is not None: + self.subscription_level = subscription_element.string.strip() + else: + self.subscription_level = 'premium' + return self.subscription_level else: log.debug(posted_page) - return False + return None def logout(self): """ @@ -128,7 +137,7 @@ class SongSelectImport(object): try: self.opener.open(LOGOUT_URL) except (TypeError, URLError) as error: - log.exception('Could not log of SongSelect, {error}'.format(error=error)) + log.exception('Could not log out of SongSelect, {error}'.format(error=error)) def search(self, search_text, max_results, callback=None): """ @@ -145,7 +154,7 @@ class SongSelectImport(object): 'PrimaryLanguage': '', 'Keys': '', 'Themes': '', - 'List': '', + 'List': '' if self.subscription_level == 'premium' else 'publicdomain', 'Sort': '', 'SearchText': search_text } diff --git a/tests/functional/openlp_plugins/songs/test_songselect.py b/tests/functional/openlp_plugins/songs/test_songselect.py index 1351faf51..4ef122c40 100644 --- a/tests/functional/openlp_plugins/songs/test_songselect.py +++ b/tests/functional/openlp_plugins/songs/test_songselect.py @@ -64,7 +64,7 @@ class TestSongSelectImport(TestCase, TestMixin): @patch('openlp.plugins.songs.lib.songselect.BeautifulSoup') def test_login_fails(self, MockedBeautifulSoup, mocked_build_opener): """ - Test that when logging in to SongSelect fails, the login method returns False + Test that when logging in to SongSelect fails, the login method returns None """ # GIVEN: A bunch of mocked out stuff and an importer object mocked_opener = MagicMock() @@ -80,12 +80,12 @@ class TestSongSelectImport(TestCase, TestMixin): # WHEN: The login method is called after being rigged to fail result = importer.login('username', 'password', mock_callback) - # THEN: callback was called 3 times, open was called twice, find was called twice, and False was returned + # THEN: callback was called 3 times, open was called twice, find was called twice, and None was returned assert 3 == mock_callback.call_count, 'callback should have been called 3 times' assert 2 == mocked_login_page.find.call_count, 'find should have been called twice' - assert 1 == mocked_posted_page.find.call_count, 'find should have been called once' + assert 2 == mocked_posted_page.find.call_count, 'find should have been called twice' assert 2 == mocked_opener.open.call_count, 'opener should have been called twice' - assert result is False, 'The login method should have returned False' + assert result is None, 'The login method should have returned None' @patch('openlp.plugins.songs.lib.songselect.build_opener') def test_login_except(self, mocked_build_opener): @@ -117,7 +117,11 @@ class TestSongSelectImport(TestCase, TestMixin): mocked_login_page.find.side_effect = [{'value': 'blah'}, None] mocked_posted_page = MagicMock() mocked_posted_page.find.return_value = MagicMock() - MockedBeautifulSoup.side_effect = [mocked_login_page, mocked_posted_page] + mocked_home_page = MagicMock() + mocked_return = MagicMock() + mocked_return.string = 'premium' + mocked_home_page.find.return_value = mocked_return + MockedBeautifulSoup.side_effect = [mocked_login_page, mocked_posted_page, mocked_home_page] mock_callback = MagicMock() importer = SongSelectImport(None) @@ -128,8 +132,8 @@ class TestSongSelectImport(TestCase, TestMixin): assert 3 == mock_callback.call_count, 'callback should have been called 3 times' assert 2 == mocked_login_page.find.call_count, 'find should have been called twice on the login page' assert 1 == mocked_posted_page.find.call_count, 'find should have been called once on the posted page' - assert 2 == mocked_opener.open.call_count, 'opener should have been called twice' - assert result is True, 'The login method should have returned True' + assert 3 == mocked_opener.open.call_count, 'opener should have been called 3 times' + assert result is 'premium', 'The login method should have returned the subscription level' @patch('openlp.plugins.songs.lib.songselect.build_opener') @patch('openlp.plugins.songs.lib.songselect.BeautifulSoup') @@ -146,7 +150,11 @@ class TestSongSelectImport(TestCase, TestMixin): mocked_login_page.find.side_effect = [{'value': 'blah'}, mocked_form] mocked_posted_page = MagicMock() mocked_posted_page.find.return_value = MagicMock() - MockedBeautifulSoup.side_effect = [mocked_login_page, mocked_posted_page] + mocked_home_page = MagicMock() + mocked_return = MagicMock() + mocked_return.string = 'premium' + mocked_home_page.find.return_value = mocked_return + MockedBeautifulSoup.side_effect = [mocked_login_page, mocked_posted_page, mocked_home_page] mock_callback = MagicMock() importer = SongSelectImport(None) @@ -158,7 +166,7 @@ class TestSongSelectImport(TestCase, TestMixin): assert 2 == mocked_login_page.find.call_count, 'find should have been called twice on the login page' assert 1 == mocked_posted_page.find.call_count, 'find should have been called once on the posted page' assert 'https://profile.ccli.com/do/login', mocked_opener.open.call_args_list[1][0][0] - assert result is True, 'The login method should have returned True' + assert result is 'premium', 'The login method should have returned the subscription level' @patch('openlp.plugins.songs.lib.songselect.build_opener') def test_logout(self, mocked_build_opener): @@ -191,6 +199,7 @@ class TestSongSelectImport(TestCase, TestMixin): MockedBeautifulSoup.return_value = mocked_results_page mock_callback = MagicMock() importer = SongSelectImport(None) + importer.subscription_level = 'premium' # WHEN: The login method is called after being rigged to fail results = importer.search('text', 1000, mock_callback) @@ -231,6 +240,7 @@ class TestSongSelectImport(TestCase, TestMixin): MockedBeautifulSoup.return_value = mocked_results_page mock_callback = MagicMock() importer = SongSelectImport(None) + importer.subscription_level = 'premium' # WHEN: The search method is called results = importer.search('text', 1000, mock_callback) @@ -282,6 +292,7 @@ class TestSongSelectImport(TestCase, TestMixin): MockedBeautifulSoup.return_value = mocked_results_page mock_callback = MagicMock() importer = SongSelectImport(None) + importer.subscription_level = 'premium' # WHEN: The search method is called results = importer.search('text', 2, mock_callback) From c68d6dc3de3c7165e43b8b666d179f64e18a0b30 Mon Sep 17 00:00:00 2001 From: Bob Luursema Date: Tue, 5 Mar 2019 21:55:37 +0100 Subject: [PATCH 13/18] Fixed bug 1800761 --- openlp/plugins/songs/forms/songselectform.py | 7 ++++++ openlp/plugins/songs/lib/songselect.py | 23 ++++++++++++++----- .../openlp_plugins/songs/test_songselect.py | 15 ++++-------- 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/openlp/plugins/songs/forms/songselectform.py b/openlp/plugins/songs/forms/songselectform.py index 423f1f17c..46d27e2af 100644 --- a/openlp/plugins/songs/forms/songselectform.py +++ b/openlp/plugins/songs/forms/songselectform.py @@ -273,6 +273,13 @@ class SongSelectForm(QtWidgets.QDialog, Ui_SongSelectDialog, RegistryProperties) 'There was a problem logging in, perhaps your username or password is incorrect?') ) else: + if subscription_level == 'Free': + QtWidgets.QMessageBox.information( + self, + translate('SongsPlugin.SongSelectForm', 'Free user'), + translate('SongsPlugin.SongSelectForm', + 'You logged in with a free account, the search will be limited to songs in the public domain.') + ) if self.save_password_checkbox.isChecked(): Settings().setValue(self.plugin.settings_section + '/songselect username', self.username_edit.text()) Settings().setValue(self.plugin.settings_section + '/songselect password', self.password_edit.text()) diff --git a/openlp/plugins/songs/lib/songselect.py b/openlp/plugins/songs/lib/songselect.py index 01b9a635b..5d5307cd9 100644 --- a/openlp/plugins/songs/lib/songselect.py +++ b/openlp/plugins/songs/lib/songselect.py @@ -115,20 +115,31 @@ class SongSelectImport(object): return False if callback: callback() - if posted_page.find('input', id='SearchText') is not None or posted_page.find('div', id="select-organization") is not None: + # Page if user is in an organization + if posted_page.find('input', id='SearchText') is not None: + self.subscription_level = self.find_subscription_level(posted_page) + return self.subscription_level + # Page if user is not in an organization + elif posted_page.find('div', id="select-organization") is not None: try: home_page = BeautifulSoup(self.opener.open(BASE_URL).read(), 'lxml') except (TypeError, URLError) as error: log.exception('Could not reach SongSelect, {error}'.format(error=error)) - subscription_element = home_page.find('div', {'class': 'subscriptionlevel'}) - if subscription_element is not None: - self.subscription_level = subscription_element.string.strip() - else: - self.subscription_level = 'premium' + self.subscription_level = self.find_subscription_level(home_page) return self.subscription_level else: log.debug(posted_page) return None + + def find_subscription_level(self, page): + scripts = page.find_all('script') + for tag in scripts: + if tag.string: + match = re.search("'Subscription': '(?P[^']+)", tag.string) + if match: + return match.group('subscription_level') + log.error('Could not determine SongSelect subscription level') + return 'unkown' def logout(self): """ diff --git a/tests/functional/openlp_plugins/songs/test_songselect.py b/tests/functional/openlp_plugins/songs/test_songselect.py index 4ef122c40..d12d84e46 100644 --- a/tests/functional/openlp_plugins/songs/test_songselect.py +++ b/tests/functional/openlp_plugins/songs/test_songselect.py @@ -117,11 +117,7 @@ class TestSongSelectImport(TestCase, TestMixin): mocked_login_page.find.side_effect = [{'value': 'blah'}, None] mocked_posted_page = MagicMock() mocked_posted_page.find.return_value = MagicMock() - mocked_home_page = MagicMock() - mocked_return = MagicMock() - mocked_return.string = 'premium' - mocked_home_page.find.return_value = mocked_return - MockedBeautifulSoup.side_effect = [mocked_login_page, mocked_posted_page, mocked_home_page] + MockedBeautifulSoup.side_effect = [mocked_login_page, mocked_posted_page] mock_callback = MagicMock() importer = SongSelectImport(None) @@ -132,8 +128,8 @@ class TestSongSelectImport(TestCase, TestMixin): assert 3 == mock_callback.call_count, 'callback should have been called 3 times' assert 2 == mocked_login_page.find.call_count, 'find should have been called twice on the login page' assert 1 == mocked_posted_page.find.call_count, 'find should have been called once on the posted page' - assert 3 == mocked_opener.open.call_count, 'opener should have been called 3 times' - assert result is 'premium', 'The login method should have returned the subscription level' + assert 2 == mocked_opener.open.call_count, 'opener should have been called twice' + assert result is 'unkown', 'The login method should have returned the subscription level' @patch('openlp.plugins.songs.lib.songselect.build_opener') @patch('openlp.plugins.songs.lib.songselect.BeautifulSoup') @@ -151,9 +147,6 @@ class TestSongSelectImport(TestCase, TestMixin): mocked_posted_page = MagicMock() mocked_posted_page.find.return_value = MagicMock() mocked_home_page = MagicMock() - mocked_return = MagicMock() - mocked_return.string = 'premium' - mocked_home_page.find.return_value = mocked_return MockedBeautifulSoup.side_effect = [mocked_login_page, mocked_posted_page, mocked_home_page] mock_callback = MagicMock() importer = SongSelectImport(None) @@ -166,7 +159,7 @@ class TestSongSelectImport(TestCase, TestMixin): assert 2 == mocked_login_page.find.call_count, 'find should have been called twice on the login page' assert 1 == mocked_posted_page.find.call_count, 'find should have been called once on the posted page' assert 'https://profile.ccli.com/do/login', mocked_opener.open.call_args_list[1][0][0] - assert result is 'premium', 'The login method should have returned the subscription level' + assert result is 'unkown', 'The login method should have returned the subscription level' @patch('openlp.plugins.songs.lib.songselect.build_opener') def test_logout(self, mocked_build_opener): From 40ceb07f18aa56a5d37e8495031aad2bcc98de01 Mon Sep 17 00:00:00 2001 From: Bob Luursema Date: Tue, 5 Mar 2019 22:02:49 +0100 Subject: [PATCH 14/18] Hotfix --- openlp/plugins/songs/lib/songselect.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/plugins/songs/lib/songselect.py b/openlp/plugins/songs/lib/songselect.py index 5d5307cd9..7aa1519a2 100644 --- a/openlp/plugins/songs/lib/songselect.py +++ b/openlp/plugins/songs/lib/songselect.py @@ -165,7 +165,7 @@ class SongSelectImport(object): 'PrimaryLanguage': '', 'Keys': '', 'Themes': '', - 'List': '' if self.subscription_level == 'premium' else 'publicdomain', + 'List': 'publicdomain' if self.subscription_level == 'Free' else '', 'Sort': '', 'SearchText': search_text } From 490f9bbe15b4f6d8c291449b5bfc1ff38d04418f Mon Sep 17 00:00:00 2001 From: Bob Luursema Date: Tue, 5 Mar 2019 22:21:12 +0100 Subject: [PATCH 15/18] Fix linting --- openlp/plugins/songs/forms/songselectform.py | 11 ++++++----- openlp/plugins/songs/lib/songselect.py | 4 ++-- .../openlp_plugins/songs/test_songselect.py | 4 ++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/openlp/plugins/songs/forms/songselectform.py b/openlp/plugins/songs/forms/songselectform.py index 46d27e2af..68e393a82 100644 --- a/openlp/plugins/songs/forms/songselectform.py +++ b/openlp/plugins/songs/forms/songselectform.py @@ -264,7 +264,7 @@ class SongSelectForm(QtWidgets.QDialog, Ui_SongSelectDialog, RegistryProperties) self.application.process_events() # Log the user in subscription_level = self.song_select_importer.login( - self.username_edit.text(), self.password_edit.text(), self._update_login_progress) + self.username_edit.text(), self.password_edit.text(), self._update_login_progress) if not subscription_level: QtWidgets.QMessageBox.critical( self, @@ -275,10 +275,11 @@ class SongSelectForm(QtWidgets.QDialog, Ui_SongSelectDialog, RegistryProperties) else: if subscription_level == 'Free': QtWidgets.QMessageBox.information( - self, - translate('SongsPlugin.SongSelectForm', 'Free user'), - translate('SongsPlugin.SongSelectForm', - 'You logged in with a free account, the search will be limited to songs in the public domain.') + self, + translate('SongsPlugin.SongSelectForm', 'Free user'), + translate('SongsPlugin.SongSelectForm', 'You logged in with a free account, ' + 'the search will be limited to songs ' + 'in the public domain.') ) if self.save_password_checkbox.isChecked(): Settings().setValue(self.plugin.settings_section + '/songselect username', self.username_edit.text()) diff --git a/openlp/plugins/songs/lib/songselect.py b/openlp/plugins/songs/lib/songselect.py index 7aa1519a2..71e093cb1 100644 --- a/openlp/plugins/songs/lib/songselect.py +++ b/openlp/plugins/songs/lib/songselect.py @@ -130,7 +130,7 @@ class SongSelectImport(object): else: log.debug(posted_page) return None - + def find_subscription_level(self, page): scripts = page.find_all('script') for tag in scripts: @@ -139,7 +139,7 @@ class SongSelectImport(object): if match: return match.group('subscription_level') log.error('Could not determine SongSelect subscription level') - return 'unkown' + return None def logout(self): """ diff --git a/tests/functional/openlp_plugins/songs/test_songselect.py b/tests/functional/openlp_plugins/songs/test_songselect.py index d12d84e46..1affd66c2 100644 --- a/tests/functional/openlp_plugins/songs/test_songselect.py +++ b/tests/functional/openlp_plugins/songs/test_songselect.py @@ -129,7 +129,7 @@ class TestSongSelectImport(TestCase, TestMixin): assert 2 == mocked_login_page.find.call_count, 'find should have been called twice on the login page' assert 1 == mocked_posted_page.find.call_count, 'find should have been called once on the posted page' assert 2 == mocked_opener.open.call_count, 'opener should have been called twice' - assert result is 'unkown', 'The login method should have returned the subscription level' + assert result is None, 'The login method should have returned the subscription level' @patch('openlp.plugins.songs.lib.songselect.build_opener') @patch('openlp.plugins.songs.lib.songselect.BeautifulSoup') @@ -159,7 +159,7 @@ class TestSongSelectImport(TestCase, TestMixin): assert 2 == mocked_login_page.find.call_count, 'find should have been called twice on the login page' assert 1 == mocked_posted_page.find.call_count, 'find should have been called once on the posted page' assert 'https://profile.ccli.com/do/login', mocked_opener.open.call_args_list[1][0][0] - assert result is 'unkown', 'The login method should have returned the subscription level' + assert result is None, 'The login method should have returned the subscription level' @patch('openlp.plugins.songs.lib.songselect.build_opener') def test_logout(self, mocked_build_opener): From b6a36f2324db7ae07a95ff52d6e5b60a50e94840 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Thu, 7 Mar 2019 20:23:04 +0100 Subject: [PATCH 16/18] pep8 fixes --- openlp/core/display/window.py | 2 +- tests/utils/test_bzr_tags.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openlp/core/display/window.py b/openlp/core/display/window.py index c0ef2a1ef..35442b5ed 100644 --- a/openlp/core/display/window.py +++ b/openlp/core/display/window.py @@ -29,7 +29,7 @@ import copy from PyQt5 import QtCore, QtWebChannel, QtWidgets -from openlp.core.common.path import Path, path_to_str +from openlp.core.common.path import path_to_str from openlp.core.common.settings import Settings from openlp.core.common.registry import Registry from openlp.core.common.applocation import AppLocation diff --git a/tests/utils/test_bzr_tags.py b/tests/utils/test_bzr_tags.py index cd057ada4..66b159c96 100644 --- a/tests/utils/test_bzr_tags.py +++ b/tests/utils/test_bzr_tags.py @@ -44,7 +44,7 @@ class TestBzrTags(TestCase): # WHEN getting the branches tags try: bzr = Popen(('bzr', 'tags', '--directory=' + path), stdout=PIPE) - except: + except Exception: raise SkipTest('bzr is not installed') std_out = bzr.communicate()[0] count = len(TAGS1) From cc4b8e42421d3569b123d317d4ee4899ffda0d77 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Fri, 8 Mar 2019 07:19:57 -0800 Subject: [PATCH 17/18] PJLink2 Update U --- openlp/core/projectors/db.py | 8 +++- openlp/core/projectors/manager.py | 41 ++++++------------- openlp/core/projectors/pjlink.py | 19 +++++++-- openlp/core/ui/icons.py | 12 ++++-- setup.cfg | 1 + .../openlp_core/lib/test_image_manager.py | 4 +- .../openlp_plugins/media/test_mediaplugin.py | 2 +- .../openlp_plugins/songs/test_lib.py | 2 +- .../songusage/test_songusage.py | 4 +- .../projectors/test_projector_db.py | 7 ++-- .../test_projector_pjlink_commands_01.py | 6 ++- 11 files changed, 59 insertions(+), 47 deletions(-) diff --git a/openlp/core/projectors/db.py b/openlp/core/projectors/db.py index ef233999b..9249f0b60 100644 --- a/openlp/core/projectors/db.py +++ b/openlp/core/projectors/db.py @@ -417,11 +417,17 @@ class ProjectorDB(Manager): value: (str) From ProjectorSource, Sources tables or PJLink default code list """ source_dict = {} + # Apparently, there was a change to the projector object. Test for which object has db id + if hasattr(projector, "id"): + chk = projector.id + elif hasattr(projector.entry, "id"): + chk = projector.entry.id + # Get default list first for key in projector.source_available: item = self.get_object_filtered(ProjectorSource, and_(ProjectorSource.code == key, - ProjectorSource.projector_id == projector.id)) + ProjectorSource.projector_id == chk)) if item is None: source_dict[key] = PJLINK_DEFAULT_CODES[key] else: diff --git a/openlp/core/projectors/manager.py b/openlp/core/projectors/manager.py index 966da08f8..9445c3f70 100644 --- a/openlp/core/projectors/manager.py +++ b/openlp/core/projectors/manager.py @@ -46,31 +46,10 @@ from openlp.core.projectors.sourceselectform import SourceSelectSingle, SourceSe from openlp.core.ui.icons import UiIcons from openlp.core.widgets.toolbar import OpenLPToolbar - log = logging.getLogger(__name__) log.debug('projectormanager loaded') -# Dict for matching projector status to display icon -STATUS_ICONS = { - S_NOT_CONNECTED: ':/projector/projector_item_disconnect.png', - S_CONNECTING: ':/projector/projector_item_connect.png', - S_CONNECTED: ':/projector/projector_off.png', - S_OFF: ':/projector/projector_off.png', - S_INITIALIZE: ':/projector/projector_off.png', - S_STANDBY: ':/projector/projector_off.png', - S_WARMUP: ':/projector/projector_warmup.png', - S_ON: ':/projector/projector_on.png', - S_COOLDOWN: ':/projector/projector_cooldown.png', - E_ERROR: ':/projector/projector_error.png', - E_NETWORK: ':/projector/projector_not_connected_error.png', - E_SOCKET_TIMEOUT: ':/projector/projector_not_connected_error.png', - E_AUTHENTICATION: ':/projector/projector_not_connected_error.png', - E_UNKNOWN_SOCKET_ERROR: ':/projector/projector_not_connected_error.png', - E_NOT_CONNECTED: ':/projector/projector_not_connected_error.png' -} - - class UiProjectorManager(object): """ UI part of the Projector Manager @@ -122,7 +101,7 @@ class UiProjectorManager(object): self.one_toolbar.add_toolbar_action('connect_projector', text=translate('OpenLP.ProjectorManager', 'Connect to selected projector.'), - icon=UiIcons().projector_connect, + icon=UiIcons().projector_select_connect, tooltip=translate('OpenLP.ProjectorManager', 'Connect to selected projector.'), triggers=self.on_connect_projector) @@ -136,7 +115,7 @@ class UiProjectorManager(object): self.one_toolbar.add_toolbar_action('disconnect_projector', text=translate('OpenLP.ProjectorManager', 'Disconnect from selected projectors'), - icon=UiIcons().projector_disconnect, + icon=UiIcons().projector_select_disconnect, tooltip=translate('OpenLP.ProjectorManager', 'Disconnect from selected projector.'), triggers=self.on_disconnect_projector) @@ -151,7 +130,7 @@ class UiProjectorManager(object): self.one_toolbar.add_toolbar_action('poweron_projector', text=translate('OpenLP.ProjectorManager', 'Power on selected projector'), - icon=UiIcons().projector_on, + icon=UiIcons().projector_power_on, tooltip=translate('OpenLP.ProjectorManager', 'Power on selected projector.'), triggers=self.on_poweron_projector) @@ -164,7 +143,7 @@ class UiProjectorManager(object): triggers=self.on_poweron_projector) self.one_toolbar.add_toolbar_action('poweroff_projector', text=translate('OpenLP.ProjectorManager', 'Standby selected projector'), - icon=UiIcons().projector_off, + icon=UiIcons().projector_power_off, tooltip=translate('OpenLP.ProjectorManager', 'Put selected projector in standby.'), triggers=self.on_poweroff_projector) @@ -309,7 +288,7 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM S_INITIALIZE: UiIcons().projector_on, S_STANDBY: UiIcons().projector_off, S_WARMUP: UiIcons().projector_warmup, - S_ON: UiIcons().projector_off, + S_ON: UiIcons().projector_on, S_COOLDOWN: UiIcons().projector_cooldown, E_ERROR: UiIcons().projector_error, E_NETWORK: UiIcons().error, @@ -505,7 +484,8 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM projector = list_item.data(QtCore.Qt.UserRole) try: projector.link.connect_to_host() - except Exception: + except Exception as e: + print(e) continue def on_delete_projector(self, opt=None): @@ -880,6 +860,7 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM """ Update the icons when the selected projectors change """ + log.debug('update_icons(): Checking for selected projector items in list') count = len(self.projector_list_widget.selectedItems()) projector = None if count == 0: @@ -900,6 +881,7 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM self.get_toolbar_item('blank_projector_multiple', hidden=True) self.get_toolbar_item('show_projector_multiple', hidden=True) elif count == 1: + log.debug('update_icons(): Found one item selected') projector = self.projector_list_widget.selectedItems()[0].data(QtCore.Qt.UserRole) connected = QSOCKET_STATE[projector.link.state()] == S_CONNECTED power = projector.link.power == S_ON @@ -910,12 +892,14 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM self.get_toolbar_item('blank_projector_multiple', hidden=True) self.get_toolbar_item('show_projector_multiple', hidden=True) if connected: + log.debug('update_icons(): Updating icons for connected state') self.get_toolbar_item('view_projector', enabled=True) self.get_toolbar_item('source_view_projector', - enabled=connected and power and projector.link.source_available is not None) + enabled=projector.link.source_available is not None and connected and power) self.get_toolbar_item('edit_projector', hidden=True) self.get_toolbar_item('delete_projector', hidden=True) else: + log.debug('update_icons(): Updating for not connected state') self.get_toolbar_item('view_projector', hidden=True) self.get_toolbar_item('source_view_projector', hidden=True) self.get_toolbar_item('edit_projector', enabled=True) @@ -931,6 +915,7 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM self.get_toolbar_item('blank_projector', enabled=False) self.get_toolbar_item('show_projector', enabled=False) else: + log.debug('update_icons(): Updating for multiple items selected') self.get_toolbar_item('edit_projector', enabled=False) self.get_toolbar_item('delete_projector', enabled=False) self.get_toolbar_item('view_projector', hidden=True) diff --git a/openlp/core/projectors/pjlink.py b/openlp/core/projectors/pjlink.py index 02d6c444b..524bc8c3c 100644 --- a/openlp/core/projectors/pjlink.py +++ b/openlp/core/projectors/pjlink.py @@ -528,8 +528,9 @@ class PJLinkCommands(object): sources.append(source) sources.sort() self.source_available = sources - log.debug('({ip}) Setting projector sources_available to "{data}"'.format(ip=self.entry.name, - data=self.source_available)) + log.debug('({ip}) Setting projector source_available to "{data}"'.format(ip=self.entry.name, + data=self.source_available)) + self.projectorUpdateIcons.emit() return def process_lamp(self, data): @@ -886,6 +887,9 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands): elif status >= S_NOT_CONNECTED and status in QSOCKET_STATE: # Socket connection status update self.status_connect = status + # Check if we need to update error state as well + if self.error_status != S_OK and status != S_NOT_CONNECTED: + self.error_status = S_OK elif status >= S_NOT_CONNECTED and status in PROJECTOR_STATE: # Only affects the projector status self.projector_status = status @@ -905,7 +909,14 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands): message=status_message if msg is None else msg)) # Now that we logged extra information for debugging, broadcast the original change/message - (code, message) = self._get_status(status) + # Check for connection errors first + if self.error_status != S_OK: + log.debug('({ip}) Signalling error code'.format(ip=self.entry.name)) + (code, message) = self._get_status(self.error_status) + status = self.error_status + else: + log.debug('({ip}) Signalling status code'.format(ip=self.entry.name)) + (code, message) = self._get_status(status) if msg is not None: message = msg elif message is None: @@ -953,7 +964,7 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands): log.error('({ip}) Invalid initial packet received - closing socket'.format(ip=self.entry.name)) return self.disconnect_from_host() # Convert the initial login prompt with the expected PJLink normal command format for processing - log.debug('({ip}) check_login(): Formatting initial connection prompt' + log.debug('({ip}) check_login(): Formatting initial connection prompt ' 'to PJLink packet'.format(ip=self.entry.name)) return self.get_data('{start}{clss}{data}'.format(start=PJLINK_PREFIX, clss='1', diff --git a/openlp/core/ui/icons.py b/openlp/core/ui/icons.py index 5aa157e9f..0e83a01d8 100644 --- a/openlp/core/ui/icons.py +++ b/openlp/core/ui/icons.py @@ -117,13 +117,17 @@ class UiIcons(object): 'presentation': {'icon': 'fa.bar-chart'}, 'preview': {'icon': 'fa.laptop'}, 'projector': {'icon': 'op.video'}, - 'projector_connect': {'icon': 'fa.plug'}, + 'projector_connect': {'icon': 'fa.plug'}, # Projector connect 'projector_cooldown': {'icon': 'fa.video-camera', 'attr': 'blue'}, - 'projector_disconnect': {'icon': 'fa.plug', 'attr': 'lightGray'}, + 'projector_disconnect': {'icon': 'fa.plug', 'attr': 'lightGray'}, # Projector disconnect 'projector_error': {'icon': 'fa.video-camera', 'attr': 'red'}, 'projector_hdmi': {'icon': 'op.hdmi'}, - 'projector_off': {'icon': 'fa.video-camera', 'attr': 'black'}, - 'projector_on': {'icon': 'fa.video-camera', 'attr': 'green'}, + 'projector_power_off': {'icon': 'fa.video-camera', 'attr': 'red'}, # Toolbar power off + 'projector_power_on': {'icon': 'fa.video-camera', 'attr': 'green'}, # Toolbar power on + 'projector_off': {'icon': 'fa.video-camera', 'attr': 'black'}, # Projector off + 'projector_on': {'icon': 'fa.video-camera', 'attr': 'green'}, # Projector on + 'projector_select_connect': {'icon': 'fa.plug', 'attr': 'green'}, # Toolbar connect + 'projector_select_disconnect': {'icon': 'fa.plug', 'attr': 'red'}, # Toolbar disconnect 'projector_warmup': {'icon': 'fa.video-camera', 'attr': 'yellow'}, 'picture': {'icon': 'fa.picture-o'}, 'print': {'icon': 'fa.print'}, diff --git a/setup.cfg b/setup.cfg index 71cd36460..5b443dcf7 100644 --- a/setup.cfg +++ b/setup.cfg @@ -9,6 +9,7 @@ ignore = E402,E722,W503,W504 [flake8] exclude=resources.py,vlc.py +max-line-length = 120 ignore = E402,W503,W504,D [pycodestyle] diff --git a/tests/functional/openlp_core/lib/test_image_manager.py b/tests/functional/openlp_core/lib/test_image_manager.py index 33207f69b..9cb77ece9 100644 --- a/tests/functional/openlp_core/lib/test_image_manager.py +++ b/tests/functional/openlp_core/lib/test_image_manager.py @@ -178,7 +178,7 @@ class TestImageManager(TestCase, TestMixin): # THEN a KeyError is thrown with self.assertRaises(KeyError) as context: self.image_manager.get_image(TEST_PATH, 'church1.jpg') - assert context.exception is not '', 'KeyError exception should have been thrown for missing image' + assert context.exception != '', 'KeyError exception should have been thrown for missing image' @patch('openlp.core.lib.imagemanager.run_thread') def test_different_dimension_image(self, mocked_run_thread): @@ -211,7 +211,7 @@ class TestImageManager(TestCase, TestMixin): # WHEN: calling with correct image, but wrong dimensions with self.assertRaises(KeyError) as context: self.image_manager.get_image(full_path, 'church.jpg', 120, 120) - assert context.exception is not '', 'KeyError exception should have been thrown for missing dimension' + assert context.exception != '', 'KeyError exception should have been thrown for missing dimension' @patch('openlp.core.lib.imagemanager.resize_image') @patch('openlp.core.lib.imagemanager.image_to_byte') diff --git a/tests/functional/openlp_plugins/media/test_mediaplugin.py b/tests/functional/openlp_plugins/media/test_mediaplugin.py index eabf35aa0..d5bfcac0b 100644 --- a/tests/functional/openlp_plugins/media/test_mediaplugin.py +++ b/tests/functional/openlp_plugins/media/test_mediaplugin.py @@ -57,4 +57,4 @@ class MediaPluginTest(TestCase, TestMixin): # THEN: about() should return a string object assert isinstance(MediaPlugin.about(), str) # THEN: about() should return a non-empty string - assert len(MediaPlugin.about()) is not 0 + assert len(MediaPlugin.about()) != 0 diff --git a/tests/functional/openlp_plugins/songs/test_lib.py b/tests/functional/openlp_plugins/songs/test_lib.py index eedbe85c7..e9c657df3 100644 --- a/tests/functional/openlp_plugins/songs/test_lib.py +++ b/tests/functional/openlp_plugins/songs/test_lib.py @@ -199,7 +199,7 @@ class TestLib(TestCase): result = _remove_typos(diff) # THEN: There should be no typos in the middle anymore. The remaining equals should have been merged. - assert len(result) is 1, 'The result should contain only one element.' + assert len(result) == 1, 'The result should contain only one element.' assert result[0][0] == 'equal', 'The result should contain an equal element.' assert result[0][1] == 0, 'The start indices should be kept.' assert result[0][2] == 22, 'The stop indices should be kept.' diff --git a/tests/functional/openlp_plugins/songusage/test_songusage.py b/tests/functional/openlp_plugins/songusage/test_songusage.py index 03847a601..e80c31c03 100644 --- a/tests/functional/openlp_plugins/songusage/test_songusage.py +++ b/tests/functional/openlp_plugins/songusage/test_songusage.py @@ -45,8 +45,8 @@ class TestSongUsage(TestCase): # THEN: about() should return a string object assert isinstance(SongUsagePlugin.about(), str) # THEN: about() should return a non-empty string - assert len(SongUsagePlugin.about()) is not 0 - assert len(SongUsagePlugin.about()) is not 0 + assert len(SongUsagePlugin.about()) != 0 + assert len(SongUsagePlugin.about()) != 0 @patch('openlp.plugins.songusage.songusageplugin.Manager') def test_song_usage_init(self, MockedManager): diff --git a/tests/openlp_core/projectors/test_projector_db.py b/tests/openlp_core/projectors/test_projector_db.py index ae25e011c..bc5899aeb 100644 --- a/tests/openlp_core/projectors/test_projector_db.py +++ b/tests/openlp_core/projectors/test_projector_db.py @@ -134,6 +134,7 @@ class TestProjectorDB(TestCase, TestMixin): """ Set up anything necessary for all tests """ + self.tmp_folder = mkdtemp(prefix='openlp_') # Create a test app to keep from segfaulting Registry.create() self.registry = Registry() @@ -153,11 +154,11 @@ class TestProjectorDB(TestCase, TestMixin): patch('openlp.core.ui.mainwindow.ThemeManager'), \ patch('openlp.core.ui.mainwindow.ProjectorManager'), \ patch('openlp.core.ui.mainwindow.websockets.WebSocketServer'), \ - patch('openlp.core.ui.mainwindow.server.HttpServer'): + patch('openlp.core.ui.mainwindow.server.HttpServer'), \ + patch('openlp.core.state.State.list_plugins') as mock_plugins: + mock_plugins.return_value = [] self.main_window = MainWindow() - # Create a temporary database directory and database - self.tmp_folder = mkdtemp(prefix='openlp_') tmpdb_url = 'sqlite:///{db}'.format(db=os.path.join(self.tmp_folder, TEST_DB)) mocked_init_url.return_value = tmpdb_url self.projector = ProjectorDB() diff --git a/tests/openlp_core/projectors/test_projector_pjlink_commands_01.py b/tests/openlp_core/projectors/test_projector_pjlink_commands_01.py index a03e84db5..361b5c4bb 100644 --- a/tests/openlp_core/projectors/test_projector_pjlink_commands_01.py +++ b/tests/openlp_core/projectors/test_projector_pjlink_commands_01.py @@ -452,12 +452,16 @@ class TestPJLinkCommands(TestCase): """ Test saving video source available information """ + # GIVEN: Test object with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log: pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True) pjlink.source_available = [] - log_debug_calls = [call('({ip}) Setting projector sources_available to ' + log_debug_calls = [call('({ip}) reset_information() connect status is ' + 'S_NOT_CONNECTED'.format(ip=pjlink.name)), + call('({ip}) Setting projector source_available to ' '"[\'11\', \'12\', \'21\', \'22\', \'31\', \'32\']"'.format(ip=pjlink.name))] + chk_data = '21 12 11 22 32 31' # Although they should already be sorted, use unsorted to verify method chk_test = ['11', '12', '21', '22', '31', '32'] From eb8864f5696fb5d3e24940bce71f5fda92a42ef2 Mon Sep 17 00:00:00 2001 From: Ken Roberts Date: Fri, 8 Mar 2019 19:53:20 -0800 Subject: [PATCH 18/18] Minor cleanups --- openlp/core/projectors/manager.py | 3 +-- openlp/core/projectors/pjlink.py | 4 ++-- openlp/core/ui/advancedtab.py | 4 ++-- openlp/core/ui/themestab.py | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/openlp/core/projectors/manager.py b/openlp/core/projectors/manager.py index 9445c3f70..c8c01401e 100644 --- a/openlp/core/projectors/manager.py +++ b/openlp/core/projectors/manager.py @@ -484,8 +484,7 @@ class ProjectorManager(QtWidgets.QWidget, RegistryBase, UiProjectorManager, LogM projector = list_item.data(QtCore.Qt.UserRole) try: projector.link.connect_to_host() - except Exception as e: - print(e) + except Exception: continue def on_delete_projector(self, opt=None): diff --git a/openlp/core/projectors/pjlink.py b/openlp/core/projectors/pjlink.py index 524bc8c3c..24f1b04ed 100644 --- a/openlp/core/projectors/pjlink.py +++ b/openlp/core/projectors/pjlink.py @@ -912,11 +912,11 @@ class PJLink(QtNetwork.QTcpSocket, PJLinkCommands): # Check for connection errors first if self.error_status != S_OK: log.debug('({ip}) Signalling error code'.format(ip=self.entry.name)) - (code, message) = self._get_status(self.error_status) + code, message = self._get_status(self.error_status) status = self.error_status else: log.debug('({ip}) Signalling status code'.format(ip=self.entry.name)) - (code, message) = self._get_status(status) + code, message = self._get_status(status) if msg is not None: message = msg elif message is None: diff --git a/openlp/core/ui/advancedtab.py b/openlp/core/ui/advancedtab.py index 3627e8f45..33909bdc2 100644 --- a/openlp/core/ui/advancedtab.py +++ b/openlp/core/ui/advancedtab.py @@ -455,7 +455,7 @@ class AdvancedTab(SettingsTab): Service Name options changed """ self.service_name_day.setEnabled(default_service_enabled) - time_enabled = default_service_enabled and self.service_name_day.currentIndex() is not 7 + time_enabled = default_service_enabled and self.service_name_day.currentIndex() != 7 self.service_name_time.setEnabled(time_enabled) self.service_name_edit.setEnabled(default_service_enabled) self.service_name_revert_button.setEnabled(default_service_enabled) @@ -497,7 +497,7 @@ class AdvancedTab(SettingsTab): """ React to the day of the service name changing. """ - self.service_name_time.setEnabled(service_day is not 7) + self.service_name_time.setEnabled(service_day != 7) self.update_service_name_example(None) def on_service_name_revert_button_clicked(self): diff --git a/openlp/core/ui/themestab.py b/openlp/core/ui/themestab.py index d1998ccca..ee87b79d0 100644 --- a/openlp/core/ui/themestab.py +++ b/openlp/core/ui/themestab.py @@ -206,7 +206,7 @@ class ThemesTab(SettingsTab): find_and_set_in_combo_box(self.default_combo_box, self.global_theme) # self.renderer.set_global_theme() self.renderer.set_theme_level(self.theme_level) - if self.global_theme is not '': + if self.global_theme != '': self._preview_global_theme() def _preview_global_theme(self):