Skip to content

Commit

Permalink
Merge branch 'qt6-merge' into 'master'
Browse files Browse the repository at this point in the history
  • Loading branch information
karlch committed Aug 14, 2023
2 parents 4ea3f59 + 196f03f commit 7552d59
Show file tree
Hide file tree
Showing 95 changed files with 818 additions and 488 deletions.
8 changes: 6 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,16 @@ jobs:
toxenv: pyqt515-cov
- python: "3.11"
toxenv: pyqt515-piexif-cov
- python: "3.11"
toxenv: pyqt6-cov
- python: "3.11"
toxenv: lint
- python: "3.11"
toxenv: packaging
- python: "3.11"
toxenv: mypy
toxenv: mypy-pyqt5
- python: "3.11"
toxenv: mypy-pyqt6
fail-fast: false

steps:
Expand All @@ -51,7 +55,7 @@ jobs:
python-version: "${{ matrix.python }}"
- name: Install dependencies
run: |
sudo apt-get update && sudo apt-get install libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-xfixes0 libxcb-shape0
sudo apt-get install libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-xfixes0 libxcb-shape0 libegl1 libxcb-cursor0
python -m pip install --upgrade pip
pip install -r misc/requirements/requirements_tox.txt
- name: Install dependencies for pyexiv2
Expand Down
4 changes: 2 additions & 2 deletions .pydocstylerc
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[pydocstyle]
# Disabled:
# D101-105: Check for docstrings is handled by pylint.
# D100-105: Check for docstrings is handled by pylint.
# D107: Missing docstring in __init__, not always needed IMHO
# D202: No blank lines allowed after function docstring, false positives with decorators
# D402: First line should not be function's "signature", false positives
# D413: Multi-line docstring summary should start at the second line
# pep257: D203,D212,D213,D214,D215,D404,D405,D406,D407,D408,D409,D410,D411
ignore = D101,D102,D103,D105,D105,D107,D202,D203,D212,D213,D214,D215,D401,D402,D404,D405,D406,D407,D408,D409,D410,D411,D413
ignore = D100,D101,D102,D103,D105,D105,D107,D202,D203,D212,D213,D214,D215,D401,D402,D404,D405,D406,D407,D408,D409,D410,D411,D413
5 changes: 4 additions & 1 deletion .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ no-docstring-rgx=(^__|^main$|^test_|decorator|inside|^_on)
[FORMAT]
max-line-length=88
max-module-lines=1000
ignore-long-lines=(<?https?://|^# Copyright 201\d|# (pylint|flake8): disable=)
ignore-long-lines=(<?https?://|^# Copyright 201\d|# (pylint|flake8): disable=|# type: ignore)
expected-line-ending-format=LF

[SIMILARITIES]
Expand All @@ -58,3 +58,6 @@ max-args=10

[CLASSES]
valid-metaclass-classmethod-first-arg=cls

[TYPECHECK]
ignored-modules=PyQt5,PyQt6,PySide6
11 changes: 11 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@ All notable changes to vimiv are documented in this file.
v0.10.0 (unreleased)
--------------------

Added:
^^^^^^

* Support for PyQt6 and thus Qt6. The Qt version and wrapper can be selected with the
``QT_SELECT`` environment variable, using:

* ``5`` or ``PyQt5``: Use PyQt5.
* ``6`` or ``PyQt6``: Use PyQt6.
* ``PySide6``: Use PySide6 (Qt for Python). This is highly experimental and should be
used with care.

Fixed:
^^^^^^

Expand Down
21 changes: 21 additions & 0 deletions docs/documentation/hacking.rst
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,27 @@ And setup ``pre-commit`` using::

pre-commit install


Using Qt
--------

As vimiv supports multiple Qt versions and wrappers simultaneously, none should be
imported directly. Instead, use the corresponding import from ``vimiv.qt`` directly.

.. table:: How to import Qt modules
:widths: 50 50

======================================= ========================================
Good Bad
======================================= ========================================
``from vimiv.qt.core import QTimer`` ``from PyQt5.QtCore import QTimer``
``from vimiv.qt.core import Signal`` ``from PyQt5.QtCore import pyqtSignal``
``from vimiv.qt.core import Slot`` ``from PyQt5.QtCore import pyqtSlot``
``from vimiv.qt.widgets import QLabel`` ``from PyQt5.QtWidgets import QLabel``
``from vimiv.qt.gui import QPixmap`` ``from PyQt5.QtGui import QPixmap``
======================================= ========================================


.. _writing_plugins:

Writing Plugins
Expand Down
1 change: 0 additions & 1 deletion misc/requirements/requirements.txt

This file was deleted.

1 change: 1 addition & 0 deletions misc/requirements/requirements_pyqt5.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
PyQt5==5.15.7
1 change: 1 addition & 0 deletions misc/requirements/requirements_pyqt6.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
PyQt6==6.5.1
1 change: 1 addition & 0 deletions misc/requirements/requirements_pyside6.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
PySide6==6.4.1
7 changes: 7 additions & 0 deletions mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,10 @@ disallow_incomplete_defs = True
[mypy-vimiv.utils]
disallow_untyped_defs = False
disallow_incomplete_defs = False

# TODO re-think qt type checking
[mypy-vimiv.qt.*]
ignore_errors = True

[mypy-vimiv.qt]
ignore_errors = True
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ def read_from_init(name):

setuptools.setup(
python_requires=">=3.8",
install_requires=["PyQt5>=5.13.2"],
packages=setuptools.find_packages(),
ext_modules=[manipulate_module],
entry_points={"gui_scripts": ["vimiv = vimiv.startup:main"]},
Expand Down
4 changes: 2 additions & 2 deletions tests/end2end/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@

import logging

from PyQt5.QtGui import QPixmap

import pytest
import pytest_bdd as bdd

import mockdecorators

from vimiv.qt.gui import QPixmap

with mockdecorators.apply():
from vimiv import api, startup, utils
from vimiv.commands import runners
Expand Down
54 changes: 28 additions & 26 deletions tests/end2end/features/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
import os
import pathlib

from PyQt5.QtCore import Qt, QProcess, QTimer
from PyQt5.QtGui import QFocusEvent, QMouseEvent
from PyQt5.QtWidgets import QApplication

import pytest
import pytest_bdd as bdd

from vimiv.qt.core import Qt, QProcess, QTimer, QPointF
from vimiv.qt.gui import QFocusEvent, QMouseEvent
from vimiv.qt.widgets import QApplication

import vimiv.gui.library
import vimiv.gui.thumbnail
import vimiv.gui.mainwindow
Expand Down Expand Up @@ -124,10 +124,10 @@ def get_prompt():

def function(key):
keys = {
"y": Qt.Key_Y,
"n": Qt.Key_N,
"<return>": Qt.Key_Return,
"<escape>": Qt.Key_Escape,
"y": Qt.Key.Key_Y,
"n": Qt.Key.Key_N,
"<return>": Qt.Key.Key_Return,
"<escape>": Qt.Key.Key_Escape,
}
try:
qkey = keys[key]
Expand All @@ -149,22 +149,22 @@ def click_prompt_key():
def keypress(qtbot):
"""Fixture to press keys on a widget handling special keys appropriately."""
special_keys = {
"<escape>": Qt.Key_Escape,
"<return>": Qt.Key_Return,
"<space>": Qt.Key_Space,
"<backspace>": Qt.Key_Backspace,
"<escape>": Qt.Key.Key_Escape,
"<return>": Qt.Key.Key_Return,
"<space>": Qt.Key.Key_Space,
"<backspace>": Qt.Key.Key_Backspace,
}

def get_modifier(keys):
modifiers = {
"<ctrl>": Qt.ControlModifier,
"<alt>": Qt.AltModifier,
"<shift>": Qt.ShiftModifier,
"<ctrl>": Qt.KeyboardModifier.ControlModifier,
"<alt>": Qt.KeyboardModifier.AltModifier,
"<shift>": Qt.KeyboardModifier.ShiftModifier,
}
for name, key in modifiers.items():
if keys.startswith(name):
return key, keys.replace(name, "")
return Qt.NoModifier, keys
return Qt.KeyboardModifier.NoModifier, keys

def press_impl(widget, keys):
modifier, keys = get_modifier(keys)
Expand All @@ -187,22 +187,22 @@ def mousedrag(qtbot):
def drag(widget, *, start, diff):
end = start + diff

qtbot.mousePress(widget, Qt.LeftButton, pos=start)
qtbot.mousePress(widget, Qt.MouseButton.LeftButton, pos=start)

global_end = widget.mapToGlobal(end)
button = buttons = Qt.NoButton
button = buttons = Qt.MouseButton.NoButton
move_event = QMouseEvent(
QMouseEvent.MouseMove,
end,
global_end,
global_end,
QMouseEvent.Type.MouseMove,
QPointF(end),
QPointF(global_end),
QPointF(global_end),
button,
buttons,
Qt.NoModifier,
Qt.KeyboardModifier.NoModifier,
)
QApplication.sendEvent(widget, move_event)

qtbot.mouseRelease(widget, Qt.LeftButton, pos=end)
qtbot.mouseRelease(widget, Qt.MouseButton.LeftButton, pos=end)

return drag

Expand All @@ -222,7 +222,9 @@ def run_command(command, qtbot):

def external_finished():
state = external_runner.state()
assert state == QProcess.NotRunning, "external command timed out"
assert (
state == QProcess.ProcessState.NotRunning
), "external command timed out"

qtbot.waitUntil(external_finished, timeout=30000)

Expand Down Expand Up @@ -268,7 +270,7 @@ def focus_widget(image, library, widget_name):
raise KeyError(
f"Unknown widget '{widget_name}'. Currently supported: {', '.join(names)}"
)
event = QFocusEvent(QFocusEvent.FocusOut)
event = QFocusEvent(QFocusEvent.Type.FocusOut)
widget.focusOutEvent(event)


Expand Down
5 changes: 2 additions & 3 deletions tests/end2end/features/edit/test_crop_bdd.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@

import re

from PyQt5.QtCore import Qt, QPoint
from PyQt5.QtWidgets import QApplication

import pytest
import pytest_bdd as bdd

import vimiv.gui.crop_widget
from vimiv.qt.core import Qt, QPoint
from vimiv.qt.widgets import QApplication


bdd.scenarios("crop.feature")
Expand Down
4 changes: 2 additions & 2 deletions tests/end2end/features/image/test_gif_bdd.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ def movie(image):

@bdd.then("the animation should be playing")
def check_animation_playing(movie):
assert movie.state() == movie.Running
assert movie.state() == movie.MovieState.Running


@bdd.then("the animation should be paused")
def check_animation_paused(movie):
assert movie.state() == movie.Paused
assert movie.state() == movie.MovieState.Paused
4 changes: 2 additions & 2 deletions tests/end2end/features/image/test_imagescroll_bdd.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
# Copyright 2017-2023 Christian Karl (karlch) <karlch at protonmail dot com>
# License: GNU GPL v3, see the "LICENSE" and "AUTHORS" files for details.

from PyQt5.QtGui import QResizeEvent

import pytest_bdd as bdd

from vimiv.qt.gui import QResizeEvent


bdd.scenarios("imagescroll.feature")

Expand Down
22 changes: 12 additions & 10 deletions tests/end2end/features/misc/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
# Copyright 2017-2023 Christian Karl (karlch) <karlch at protonmail dot com>
# License: GNU GPL v3, see the "LICENSE" and "AUTHORS" files for details.

from PyQt5.QtGui import QGuiApplication, QClipboard

import pytest
import pytest_bdd as bdd

from vimiv.qt.gui import QGuiApplication, QClipboard


@pytest.fixture()
def clipboard():
Expand All @@ -17,39 +17,41 @@ def clipboard():

@bdd.then(bdd.parsers.parse("The clipboard should contain '{text}'"))
def check_clipboard(clipboard, text):
assert text in clipboard.text(mode=QClipboard.Clipboard)
assert text in clipboard.text(mode=QClipboard.Mode.Clipboard)


@bdd.then(bdd.parsers.parse("The primary selection should contain '{text}'"))
def check_primary(clipboard, text):
assert text in clipboard.text(mode=QClipboard.Selection)
assert text in clipboard.text(mode=QClipboard.Mode.Selection)


@bdd.then(bdd.parsers.parse("The clipboard should contain any image"))
def check_clipboard_image(clipboard, image):
assert not clipboard.pixmap(mode=QClipboard.Clipboard).toImage().isNull()
assert not clipboard.pixmap(mode=QClipboard.Mode.Clipboard).toImage().isNull()


@bdd.then(bdd.parsers.parse("The primary selection should contain any image"))
def check_primary_image(clipboard, image):
assert not clipboard.pixmap(mode=QClipboard.Selection).toImage().isNull()
assert not clipboard.pixmap(mode=QClipboard.Mode.Selection).toImage().isNull()


@bdd.then(bdd.parsers.parse("The clipboard should contain an image with width {width}"))
def check_clipboard_image_width(clipboard, width):
assert clipboard.pixmap(mode=QClipboard.Clipboard).size().width() == int(width)
assert clipboard.pixmap(mode=QClipboard.Mode.Clipboard).size().width() == int(width)


@bdd.then(
bdd.parsers.parse("The clipboard should contain an image with height {height}")
)
def check_clipboard_image_height(clipboard, height):
assert clipboard.pixmap(mode=QClipboard.Clipboard).size().height() == int(height)
assert clipboard.pixmap(mode=QClipboard.Mode.Clipboard).size().height() == int(
height
)


@bdd.then(bdd.parsers.parse("The clipboard should contain an image with size {size}"))
def check_clipboard_image_size(clipboard, size):
assert max(
clipboard.pixmap(mode=QClipboard.Clipboard).size().height(),
clipboard.pixmap(mode=QClipboard.Clipboard).size().width(),
clipboard.pixmap(mode=QClipboard.Mode.Clipboard).size().height(),
clipboard.pixmap(mode=QClipboard.Mode.Clipboard).size().width(),
) == int(size)
6 changes: 3 additions & 3 deletions tests/end2end/features/misc/test_clipboard_bdd.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@

import os

from PyQt5.QtGui import QClipboard

import pytest_bdd as bdd

from vimiv.qt.gui import QClipboard


bdd.scenarios("clipboard.feature")

Expand All @@ -23,4 +23,4 @@
)
def check_clipboard_abspath(clipboard, text):
text = os.path.abspath(text)
assert clipboard.text(mode=QClipboard.Clipboard) == text
assert clipboard.text(mode=QClipboard.Mode.Clipboard) == text
4 changes: 2 additions & 2 deletions tests/end2end/features/misc/test_symlink_bdd.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
# Copyright 2017-2023 Christian Karl (karlch) <karlch at protonmail dot com>
# License: GNU GPL v3, see the "LICENSE" and "AUTHORS" files for details.

from PyQt5.QtGui import QPixmap

import pytest_bdd as bdd

from vimiv.qt.gui import QPixmap

from vimiv import startup


Expand Down
Empty file.
Loading

0 comments on commit 7552d59

Please sign in to comment.