Skip to content

Commit

Permalink
fix(mousepress): replace QTest mouse actions
Browse files Browse the repository at this point in the history
`QTest` mouse actions `mouseClick` and `mousePress` do not release
the mouse, causing `qtbot` to fail tests. Replace with `QtGui` mouse
events.

Fixes Issue pytest-dev#428
  • Loading branch information
adamgranthendry committed Jun 6, 2022
1 parent 0a21e15 commit b788e97
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 31 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ src/pytest_qt.egg-info
.coverage
/.cache
/.venv
.venv/
/.eggs
/.pytest_cache

# auto-generated by setuptools_scm
/src/pytestqt/_version.py

# Ignore vscode
.vscode/
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"esbonio.sphinx.confDir": "${workspaceFolder}\\docs\\source\\conf.py"
}
3 changes: 1 addition & 2 deletions src/pytestqt/qt_compat.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@
"""


from collections import namedtuple
import os
from collections import namedtuple

import pytest


VersionTuple = namedtuple("VersionTuple", "qt_api, qt_api_version, runtime, compiled")


Expand Down
108 changes: 84 additions & 24 deletions src/pytestqt/qtbot.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import contextlib
import weakref
import warnings
import weakref

from pytestqt.exceptions import TimeoutError
from pytestqt.qt_compat import qt_api
from pytestqt.wait_signal import (
SignalBlocker,
MultiSignalBlocker,
SignalEmittedSpy,
SignalEmittedError,
CallbackBlocker,
CallbackCalledTwiceError,
MultiSignalBlocker,
SignalBlocker,
SignalEmittedError,
SignalEmittedSpy,
)


Expand Down Expand Up @@ -636,25 +636,85 @@ def keyToAscii(key):
raise NotImplementedError("This method isn't available on PyQt5.")
qt_api.QtTest.QTest.keyToAscii(key)

@staticmethod
def mouseClick(*args, **kwargs):
qt_api.QtTest.QTest.mouseClick(*args, **kwargs)

@staticmethod
def mouseDClick(*args, **kwargs):
qt_api.QtTest.QTest.mouseDClick(*args, **kwargs)

@staticmethod
def mouseMove(*args, **kwargs):
qt_api.QtTest.QTest.mouseMove(*args, **kwargs)

@staticmethod
def mousePress(*args, **kwargs):
qt_api.QtTest.QTest.mousePress(*args, **kwargs)

@staticmethod
def mouseRelease(*args, **kwargs):
qt_api.QtTest.QTest.mouseRelease(*args, **kwargs)
def mouseClick(self, widget, button, pos=None, modifiers=None):
if pos is None:
pos = widget.rect().center()
self.mouseMove(widget, pos)
self.mousePress(widget, button, pos, modifiers)
self.mouseRelease(widget, button, pos, modifiers)

def mouseDClick(self, widget, button, pos=None, modifiers=None):
if pos is None:
pos = widget.rect().center()
self.mouseClick(widget, button, pos, modifiers)
self.mouseClick(widget, button, pos, modifiers)

def mouseDrag(self, widget, button, pos1, pos2, modifiers=None):
self.mouseMove(widget, pos1)
self.mousePress(widget, pos1, button, modifiers)
self.mouseMove(widget, pos2, button, modifiers)
self.mouseRelease(widget, pos2, button, modifiers)

def mouseMove(self, widget, pos, modifiers=None):
if isinstance(widget, qt_api.QtWidgets.QGraphicsView):
widget = widget.viewport()
if modifiers is None:
modifiers = qt_api.QtCore.Qt.KeyboardModifier.NoModifier
if isinstance(pos, qt_api.QtCore.QPoint):
pos = qt_api.QtCore.QPointF(pos) # PyQt6 requires `QPointF`
buttons = qt_api.QtCore.Qt.MouseButton.NoButton
# `QMouseEvent` does not accept keyword arguments. Results in `TypeError:
# not enough arguments`. Use positional instead.
event = qt_api.QtGui.QMouseEvent(
qt_api.QtCore.QEvent.Type.MouseMove,
pos,
qt_api.QtCore.Qt.MouseButton.NoButton,
buttons,
modifiers,
)
qt_api.QtWidgets.QApplication.sendEvent(widget, event)

def mousePress(self, widget, button, pos=None, modifiers=None):
if isinstance(widget, qt_api.QtWidgets.QGraphicsView):
widget = widget.viewport()
if modifiers is None:
modifiers = qt_api.QtCore.Qt.KeyboardModifier.NoModifier
if pos is None:
pos = widget.rect().center()
if isinstance(pos, qt_api.QtCore.QPoint):
pos = qt_api.QtCore.QPointF(pos) # PyQt6 requires `QPointF`
buttons = qt_api.QtCore.Qt.MouseButton.NoButton
# `QMouseEvent` does not accept keyword arguments. Results in `TypeError:
# not enough arguments`. Use positional instead.
event = qt_api.QtGui.QMouseEvent(
qt_api.QtCore.QEvent.Type.MouseButtonPress,
pos,
button,
buttons,
modifiers,
)
qt_api.QtWidgets.QApplication.sendEvent(widget, event)

def mouseRelease(self, widget, button, pos=None, modifiers=None):
if isinstance(widget, qt_api.QtWidgets.QGraphicsView):
widget = widget.viewport()
if modifiers is None:
modifiers = qt_api.QtCore.Qt.KeyboardModifier.NoModifier
if pos is None:
pos = widget.rect().center()
if isinstance(pos, qt_api.QtCore.QPoint):
pos = qt_api.QtCore.QPointF(pos) # PyQt6 requires `QPointF`
buttons = qt_api.QtCore.Qt.MouseButton.NoButton
# `QMouseEvent` does not accept keyword arguments. Results in `TypeError:
# not enough arguments`. Use positional instead.
event = qt_api.QtGui.QMouseEvent(
qt_api.QtCore.QEvent.Type.MouseButtonRelease,
pos,
button,
buttons,
modifiers,
)
qt_api.QtWidgets.QApplication.sendEvent(widget, event)


# provide easy access to exceptions to qtbot fixtures
Expand Down
11 changes: 6 additions & 5 deletions tests/test_basics.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import weakref

import pytest

from pytestqt import qt_compat
from pytestqt.qt_compat import qt_api

Expand Down Expand Up @@ -165,17 +164,19 @@ def extract(mouse_event):

event_recorder.registerEvent(qt_api.QtGui.QMouseEvent, extract)

qtbot.mousePress(event_recorder, qt_api.QtCore.Qt.MouseButton.LeftButton)
qtbot.mousePress(
widget=event_recorder, button=qt_api.QtCore.Qt.MouseButton.LeftButton
)
assert event_recorder.event_data == (
qt_api.QtCore.QEvent.Type.MouseButtonPress,
qt_api.QtCore.Qt.MouseButton.LeftButton,
qt_api.QtCore.Qt.KeyboardModifier.NoModifier,
)

qtbot.mousePress(
event_recorder,
qt_api.QtCore.Qt.MouseButton.RightButton,
qt_api.QtCore.Qt.KeyboardModifier.AltModifier,
widget=event_recorder,
button=qt_api.QtCore.Qt.MouseButton.RightButton,
modifiers=qt_api.QtCore.Qt.KeyboardModifier.AltModifier,
)
assert event_recorder.event_data == (
qt_api.QtCore.QEvent.Type.MouseButtonPress,
Expand Down

0 comments on commit b788e97

Please sign in to comment.