From ab6d1e87f9b0a5fa29debbca3feb663e5998637c Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Thu, 31 Mar 2022 14:52:18 +0000 Subject: [PATCH] Handle PermissionError nicely --- openlp/core/common/handlers.py | 48 ++++++++++++++++++++ openlp/plugins/songs/forms/songimportform.py | 12 +++-- tests/openlp_core/common/test_handlers.py | 45 ++++++++++++++++++ 3 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 openlp/core/common/handlers.py create mode 100644 tests/openlp_core/common/test_handlers.py diff --git a/openlp/core/common/handlers.py b/openlp/core/common/handlers.py new file mode 100644 index 000000000..a0f2b86d0 --- /dev/null +++ b/openlp/core/common/handlers.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- + +########################################################################## +# OpenLP - Open Source Lyrics Projection # +# ---------------------------------------------------------------------- # +# Copyright (c) 2008-2022 OpenLP Developers # +# ---------------------------------------------------------------------- # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +########################################################################## +""" +Some exception handling functions +""" +import logging +from contextlib import contextmanager +from pathlib import Path +from typing import Optional + +from PyQt5 import QtWidgets + +from openlp.core.common.i18n import translate + + +log = logging.getLogger(__name__) + + +@contextmanager +def handle_permission_error(filepath: Path, parent: Optional[QtWidgets.QWidget] = None): + try: + yield + except PermissionError: + log.exception(f'Permission denied when accessing {filepath}') + QtWidgets.QMessageBox.critical( + parent, + translate('OpenLP.Handlers', 'Permission Error'), + translate('OpenLP.Handlers', 'There was a permissions error when trying to access ' + '{filename}').format(filename=filepath) + ) diff --git a/openlp/plugins/songs/forms/songimportform.py b/openlp/plugins/songs/forms/songimportform.py index 06380fa90..96542e0f1 100644 --- a/openlp/plugins/songs/forms/songimportform.py +++ b/openlp/plugins/songs/forms/songimportform.py @@ -25,6 +25,7 @@ import logging from PyQt5 import QtCore, QtWidgets, QtGui +from openlp.core.common.handlers import handle_permission_error from openlp.core.common.i18n import UiStrings, translate from openlp.core.common.mixins import RegistryProperties from openlp.core.lib.ui import critical_error_message_box @@ -496,9 +497,10 @@ class SongImportSourcePage(QtWidgets.QWizardPage): return True else: file_path = wizard.format_widgets[this_format]['path_edit'].path - if file_path: - if select_mode == SongFormatSelect.SingleFile and file_path.is_file(): - return True - elif select_mode == SongFormatSelect.SingleFolder and file_path.is_dir(): - return True + if file_path and file_path.exists(): + with handle_permission_error(file_path): + if select_mode == SongFormatSelect.SingleFile and file_path.is_file(): + return True + elif select_mode == SongFormatSelect.SingleFolder and file_path.is_dir(): + return True return False diff --git a/tests/openlp_core/common/test_handlers.py b/tests/openlp_core/common/test_handlers.py new file mode 100644 index 000000000..2f38fed2f --- /dev/null +++ b/tests/openlp_core/common/test_handlers.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- + +########################################################################## +# OpenLP - Open Source Lyrics Projection # +# ---------------------------------------------------------------------- # +# Copyright (c) 2008-2022 OpenLP Developers # +# ---------------------------------------------------------------------- # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +########################################################################## +""" +Test the exception handling functions +""" +from unittest.mock import patch + +from openlp.core.common.handlers import handle_permission_error + + +@patch('openlp.core.common.handlers.QtWidgets.QMessageBox') +def test_handle_permission_error(MockQMessageBox): + """Test the handle_permission_error() function to make sure it catches PermissionError""" + # GIVEN: A mocked QMessageBox class and a file path + file_path = 'mocked_file_path' + + # WHEN: the handle_permission_error() context manager is used + try: + with handle_permission_error(file_path): + raise PermissionError('Bad mojo') + except PermissionError: + assert False, 'PermissionError was not caught' + + MockQMessageBox.critical.assert_called_once_with( + None, 'Permission Error', + 'There was a permissions error when trying to access mocked_file_path' + )