Skip to content

Commit

Permalink
Use original QgsMessageBar as base class [GispoCoding#26]
Browse files Browse the repository at this point in the history
  • Loading branch information
Joonalai committed Dec 15, 2023
1 parent 7a62f1e commit dadc2a7
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 25 deletions.
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ ban-relative-imports = "all"

[tool.ruff.per-file-ignores]
"src/pytest_qgis/pytest_qgis.py"=["PLR2004"] # TODO: Fix magic values. Remove this after.
"src/pytest_qgis/qgis_interface.py" = ["N802", "N803"]
"src/pytest_qgis/qgis_interface.py" = ["N802", "N803", "N815"]
"src/pytest_qgis/mock_qgis_classes.py" = ["N802", "N803"]
"tests/*" = [
"ANN001",
"ANN201",
Expand Down
95 changes: 77 additions & 18 deletions src/pytest_qgis/mock_qgis_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,37 +15,96 @@
#
# You should have received a copy of the GNU General Public License
# along with pytest-qgis. If not, see <https://www.gnu.org/licenses/>.


from typing import Dict, List
import typing

from qgis.core import Qgis
from qgis.PyQt.QtCore import QObject
from qgis.gui import QgsMessageBar as QgsMessageBarOriginal


class MockMessageBar(QObject):
class MockMessageBar(QgsMessageBarOriginal):
"""Mocked message bar to hold the messages."""

def __init__(self) -> None:
super().__init__()
self.messages: Dict[int, List[str]] = {
Qgis.Info: [],
Qgis.Warning: [],
Qgis.Critical: [],
Qgis.Success: [],
super().__init__(None)
self.messages: dict[int, list[str]] = {}
self._init_messages()

def _init_messages(self) -> None:
self.messages = {
Qgis.MessageLevel.Info: [],
Qgis.MessageLevel.Warning: [],
Qgis.MessageLevel.Critical: [],
Qgis.MessageLevel.Success: [],
}

def get_messages(self, level: int) -> List[str]:
def get_messages(self, level: int) -> list[str]:
"""Used to test which messages have been logged."""
return self.messages[level]

def pushMessage( # noqa: N802
def clear_messages(self) -> None:
"""Clear logged messages."""
self._init_messages()

@typing.overload
def pushMessage(
self,
title: str,
text: str,
level: int,
duration: int, # noqa: ARG002
text: typing.Optional[str] = None,
level: Qgis.MessageLevel = Qgis.MessageLevel.Info,
duration: int = -1,
) -> None:
...

@typing.overload
def pushMessage(
self,
title: typing.Optional[str] = None,
text: typing.Optional[str] = None,
level: Qgis.MessageLevel = Qgis.MessageLevel.Info,
duration: int = -1,
) -> None:
...

@typing.overload
def pushMessage( # noqa: PLR0913
self,
title: typing.Optional[str] = None,
text: typing.Optional[str] = None,
showMore: typing.Optional[str] = None,
level: Qgis.MessageLevel = Qgis.MessageLevel.Info,
duration: int = -1,
) -> None:
...

@typing.no_type_check
def pushMessage(
self,
*args: typing.Union[str, int],
**kwargs: dict[str, typing.Union[str, int]],
) -> None:
"""A mocked method for pushing a message to the bar."""
msg = f"{title}:{text}"
title = kwargs.get("title")
text = kwargs.get("text")
level = kwargs.get("level", Qgis.MessageLevel.Info)

length = len(args)
if length == 1 and not text:
text = args[0]
elif length == 1 and not title:
title = args[0]
elif length > 1 and isinstance(args[1], str):
# title, text, level, ...
title = args[0]
text = args[1]
if length > 2 and isinstance(args[2], int): # noqa: PLR2004
level = args[2]
elif length > 3 and isinstance(args[3], int): # noqa: PLR2004
level = args[3]
elif length > 1 and isinstance(args[1], int):
# text, level, ...
text = args[0]
level = args[1]
elif args and not text:
text = ", ".join(map(str, args))

msg = f"{title or 'no-title'}:{text}"
self.messages[level].append(msg)
2 changes: 2 additions & 0 deletions src/pytest_qgis/qgis_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
LOGGER = logging.getLogger("QGIS")


@typing.no_type_check # TODO: remove this later
class QgisInterface(QgisAbstractInterface):
"""
Class to expose QGIS objects and functions to plugins.
Expand Down Expand Up @@ -154,6 +155,7 @@ def newProject(self, promptToSaveFlag: bool = False) -> bool:
for relation in relation_manager.relations():
relation_manager.removeRelation(relation)
self._layers = []
self._messageBar.clear_messages()
self.newProjectCreated.emit()
return True

Expand Down
56 changes: 56 additions & 0 deletions tests/test_mock_qgis_classes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from typing import TYPE_CHECKING

import pytest
from qgis.core import Qgis

if TYPE_CHECKING:
from qgis.gui import QgisInterface


@pytest.mark.parametrize(
("args", "kwargs", "expected_level", "expected_message"),
[
(["text"], {}, Qgis.Info, "no-title:text"),
(["title"], {"text": "text"}, Qgis.MessageLevel.Info, "title:text"),
(
["text", Qgis.MessageLevel.Success],
{},
Qgis.MessageLevel.Success,
"no-title:text",
),
(
["title", "text", Qgis.MessageLevel.Warning, 20],
{},
Qgis.Warning,
"title:text",
),
(
["title", "text", "showMore", Qgis.MessageLevel.Warning, 20],
{},
Qgis.Warning,
"title:text",
),
(
[],
{
"title": "title",
"text": "text",
"showMore": "showMore",
"level": Qgis.MessageLevel.Warning,
"duration": 20,
},
Qgis.Warning,
"title:text",
),
],
)
def test_message_bar( # noqa: PLR0913
qgis_new_project: None,
qgis_iface: "QgisInterface",
args: list,
kwargs: dict,
expected_level: Qgis.MessageLevel,
expected_message: str,
):
qgis_iface.messageBar().pushMessage(*args, **kwargs)
assert qgis_iface.messageBar().messages.get(expected_level) == [expected_message]
7 changes: 1 addition & 6 deletions tests/test_pytest_qgis.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
# along with pytest-qgis. If not, see <https://www.gnu.org/licenses/>.

import pytest
from qgis.core import Qgis, QgsProcessing, QgsProject, QgsVectorLayer
from qgis.core import QgsProcessing, QgsProject, QgsVectorLayer
from qgis.PyQt.QtWidgets import QToolBar
from qgis.utils import iface

Expand Down Expand Up @@ -55,11 +55,6 @@ def test_qgis_new_project(qgis_new_project):
assert QgsProject.instance().mapLayers() == {}


def test_msg_bar(qgis_iface):
qgis_iface.messageBar().pushMessage("title", "text", Qgis.Info, 6)
assert qgis_iface.messageBar().messages.get(Qgis.Info) == ["title:text"]


def test_processing_providers(qgis_app, qgis_processing):
assert "qgis" in [
provider.id() for provider in qgis_app.processingRegistry().providers()
Expand Down

0 comments on commit dadc2a7

Please sign in to comment.