Index: README.md
==================================================================
--- README.md
+++ README.md
@@ -88,11 +88,11 @@
These external libraries are used in the code. They can be installed from PyPI.
- `platformdirs`
- `ijson`
- `pint`
-- `PyQt5`
+- `PySide6`
- `delegateto`
- `PyHamcrest`
- `cx_Freeze` (Stand-alone bundles only. Used by the installer for Windows®-based platforms.)
### System libraries
Index: build_MTGProxyPrinter_packages.bat
==================================================================
--- build_MTGProxyPrinter_packages.bat
+++ build_MTGProxyPrinter_packages.bat
@@ -1,10 +1,10 @@
:: Generate an application bundle using cx_Freeze
:: Create or activate the build environment
-IF EXIST "venv" (
- call venv\Scripts\activate.bat
+IF EXIST "venv-PySide6" (
+ call venv-PySide6\Scripts\activate.bat
) ELSE (
call create_development_environment.bat
)
:: Create a platform-dependent, portable build in the build directory
Index: build_MTGProxyPrinter_packages.sh
==================================================================
--- build_MTGProxyPrinter_packages.sh
+++ build_MTGProxyPrinter_packages.sh
@@ -1,7 +1,7 @@
#!/bin/bash
-ENVIRONMENT_NAME="venv"
+ENVIRONMENT_NAME="venv-PySide6"
# Generate an application bundle using cx_Freeze for Linux.
if [ ! -e "${ENVIRONMENT_NAME}" ]; then
./create_development_environment.sh
fi
Index: create_development_environment.bat
==================================================================
--- create_development_environment.bat
+++ create_development_environment.bat
@@ -1,8 +1,8 @@
-python -m venv venv
+python -m venv venv-PySide6
-call venv\Scripts\activate.bat
+call venv-PySide6\Scripts\activate.bat
python -m pip install --upgrade pip
python -m pip install wheel
python -m pip install "pip-tools >= 7"
python -m piptools compile -o requirements.txt pyproject.toml
Index: create_development_environment.sh
==================================================================
--- create_development_environment.sh
+++ create_development_environment.sh
@@ -1,7 +1,7 @@
#!/bin/bash
-ENVIRONMENT_NAME="venv"
+ENVIRONMENT_NAME="venv-PySide6"
if [ -e "${ENVIRONMENT_NAME}" ]; then
echo "Removing already existing virtual environment."
rm -r "${ENVIRONMENT_NAME}"
fi
Index: doc/ThirdPartyLicenses.md
==================================================================
--- doc/ThirdPartyLicenses.md
+++ doc/ThirdPartyLicenses.md
@@ -509,19 +509,16 @@
permanent authorization for you to choose that version for the
Library.
-# PyQt5
-
-Copyright (c) [Riverbank Computing Limited](https://www.riverbankcomputing.com/).
-
-The included copy is licensed under the terms of the
-GNU General Public License version 3 as published by the Free Software Foundation.
-
-See LICENSE.md (when viewing from the source code archive) or the License tab in the
-MTGProxyPrinter About dialog for details.
+# Qt6, PySide6
+
+Qt and PySide6 are available under the GNU Lesser General Public License version 3.
+
+The Qt Toolkit is Copyright (C) 2018 The Qt Company Ltd. and other contributors.
+Contact: https://www.qt.io/licensing/
# cx_Freeze
Index: mtg_proxy_printer/__main__.py
==================================================================
--- mtg_proxy_printer/__main__.py
+++ mtg_proxy_printer/__main__.py
@@ -18,12 +18,11 @@
import os
import platform
import sys
-from PyQt5.QtCore import Qt, QTimer
-from PyQt5.QtWidgets import QApplication
+from PySide6.QtCore import QTimer
import mtg_proxy_printer.app_dirs
from mtg_proxy_printer.argument_parser import parse_args
import mtg_proxy_printer.logger
from mtg_proxy_printer.application import Application
@@ -58,22 +57,19 @@
global _app
arguments = parse_args()
mtg_proxy_printer.app_dirs.migrate_from_old_appdirs()
mtg_proxy_printer.logger.configure_root_logger()
handle_ssl_certificates()
- # According to https://doc.qt.io/qt-5/qt.html#ApplicationAttribute-enum,
- # Qt.AA_EnableHighDpiScaling has to be set prior to creating the QApplication instance
- QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
_app = Application(arguments, sys.argv)
if arguments.test_exit_on_launch:
logger.info("Skipping startup tasks, because immediate application exit was requested.")
QTimer.singleShot(0, _app.main_window.on_action_quit_triggered)
else:
logger.debug("Enqueueing startup tasks.")
_app.enqueue_startup_tasks(arguments)
logger.debug("Initialisation done. Starting event loop.")
- _app.exec_()
+ _app.exec()
logger.debug("Left event loop.")
if __name__ == "__main__":
main()
Index: mtg_proxy_printer/application.py
==================================================================
--- mtg_proxy_printer/application.py
+++ mtg_proxy_printer/application.py
@@ -21,13 +21,13 @@
import shutil
import sys
from tempfile import mkdtemp
import typing
-from PyQt5.QtCore import pyqtSlot as Slot, Qt, QTimer, QStringListModel, QThreadPool, QTranslator, QLocale, QLibraryInfo
-from PyQt5.QtWidgets import QApplication
-from PyQt5.QtGui import QIcon
+from PySide6.QtCore import Slot, QTimer, QStringListModel, QThreadPool, QTranslator, QLocale, QLibraryInfo
+from PySide6.QtWidgets import QApplication
+from PySide6.QtGui import QIcon
from mtg_proxy_printer.argument_parser import Namespace
from mtg_proxy_printer import meta_data
import mtg_proxy_printer.model.carddb
import mtg_proxy_printer.carddb_migrations
@@ -56,17 +56,18 @@
def __init__(self, args: Namespace, argv: typing.List[str] = None):
if argv is None:
argv = sys.argv
logger.info(f"Starting MTGProxyPrinter version {meta_data.__version__}")
- if not os.getenv("QT_QPA_PLUGIN") and "-platform" not in argv and platform.system() == "Windows":
- logger.info("Running on Windows without explicit platform override. Enabling dark mode rendering.")
- # The explicit set platform and parameters overwrite the environment, so set these options iff neither
- # present as parameters nor environment variables.
- argv.append("-platform")
- argv.append("windows:darkmode=1")
super().__init__(argv)
+ # Note: The sub-expression '"-style" not in argv' breaks, if "-style" is passed as a value for another
+ # argument or as a positional argument.
+ # (For example, if the user wants to load a document with file name "-style" via command line argument.)
+ if platform.system() == "Windows" and "-style" not in argv and not os.getenv("QT_STYLE_OVERRIDE"):
+ logger.info("Running on Windows without explicit style set. Use 'fusion', which supports dark mode.")
+ # Set a dark-mode compatible style, if on Windows and the user does not override the style.
+ self.setStyle("fusion")
# Used by the with_database_write_lock decorator to not start un-frozen,
# waiting tasks when the application is about to exit
self.should_run = True
self.args = args
self._setup_translations()
@@ -219,11 +220,11 @@
f"Possible display languages are: {locale.uiLanguages()}")
path = ":" if mtg_proxy_printer.ui.common.HAS_COMPILED_RESOURCES \
else str(pathlib.Path(mtg_proxy_printer.__file__).parent / "resources")
path += "/translations"
logger.debug(f"Locale search path is '{path}'")
- self._load_translator(locale, "qtbase", QLibraryInfo.location(QLibraryInfo.LibraryLocation.TranslationsPath))
+ self._load_translator(locale, "qtbase", QLibraryInfo.location(QLibraryInfo.LibraryPath.TranslationsPath))
self._load_translator(locale, "mtgproxyprinter", path)
def _load_translator(self, locale: QLocale, component: str, path: str):
translator = QTranslator(self)
if translator.load(locale, component, '_', path):
@@ -256,12 +257,10 @@
QIcon.setThemeSearchPaths(theme_search_paths)
QIcon.setThemeName("breeze")
else:
logger.debug(f"Using system-provided icon theme '{fallback_icon_theme}'")
- self.setAttribute(Qt.AA_UseHighDpiPixmaps)
-
@Slot()
def quit(self):
logger.info("About to exit.")
self.should_run = False
self.main_window.hide()
Index: mtg_proxy_printer/card_info_downloader.py
==================================================================
--- mtg_proxy_printer/card_info_downloader.py
+++ mtg_proxy_printer/card_info_downloader.py
@@ -26,11 +26,11 @@
import urllib.error
import urllib.parse
import urllib.request
import ijson
-from PyQt5.QtCore import pyqtSignal as Signal, QObject, Qt, QThreadPool
+from PySide6.QtCore import Signal, QObject, Qt, QThreadPool
from mtg_proxy_printer.downloader_base import DownloaderBase
from mtg_proxy_printer.model.carddb import CardDatabase, SCHEMA_NAME, with_database_write_lock
from mtg_proxy_printer.sqlite_helpers import cached_dedent
from mtg_proxy_printer.printing_filter_updater import PrintingFilterUpdater
Index: mtg_proxy_printer/carddb_migrations.py
==================================================================
--- mtg_proxy_printer/carddb_migrations.py
+++ mtg_proxy_printer/carddb_migrations.py
@@ -30,11 +30,11 @@
import urllib.error
import urllib.parse
from textwrap import dedent
from typing import List, Dict, Union, Tuple, Any, Generator, Callable
-from PyQt5.QtCore import QCoreApplication, Qt
+from PySide6.QtCore import QCoreApplication, Qt
try:
from typing import LiteralString
except AttributeError:
from typing_extensions import LiteralString
Index: mtg_proxy_printer/decklist_downloader.py
==================================================================
--- mtg_proxy_printer/decklist_downloader.py
+++ mtg_proxy_printer/decklist_downloader.py
@@ -26,11 +26,11 @@
import platform
import re
import typing
import ijson
-from PyQt5.QtGui import QValidator
+from PySide6.QtGui import QValidator
from mtg_proxy_printer.downloader_base import DownloaderBase
from mtg_proxy_printer.decklist_parser.common import ParserBase
from mtg_proxy_printer.decklist_parser.csv_parsers import ScryfallCSVParser, TappedOutCSVParser
from mtg_proxy_printer.decklist_parser.re_parsers import MTGArenaParser, MagicWorkstationDeckDataFormatParser, \
Index: mtg_proxy_printer/decklist_parser/common.py
==================================================================
--- mtg_proxy_printer/decklist_parser/common.py
+++ mtg_proxy_printer/decklist_parser/common.py
@@ -14,11 +14,11 @@
# along with this program. If not, see .
from abc import abstractmethod
import typing
-from PyQt5.QtCore import QObject, pyqtSignal as Signal
+from PySide6.QtCore import QObject, Signal
from mtg_proxy_printer.model.carddb import Card, CardDatabase, CardIdentificationData
from mtg_proxy_printer.model.imagedb import ImageDatabase
import mtg_proxy_printer.settings
from mtg_proxy_printer.logger import get_logger
Index: mtg_proxy_printer/decklist_parser/csv_parsers.py
==================================================================
--- mtg_proxy_printer/decklist_parser/csv_parsers.py
+++ mtg_proxy_printer/decklist_parser/csv_parsers.py
@@ -16,11 +16,11 @@
import abc
import collections
import csv
import typing
-from PyQt5.QtCore import QObject, QCoreApplication
+from PySide6.QtCore import QObject, QCoreApplication
from mtg_proxy_printer.model.carddb import Card, CardDatabase, CardIdentificationData
from mtg_proxy_printer.model.imagedb import ImageDatabase
from .common import ParsedDeck, ParserBase
Index: mtg_proxy_printer/decklist_parser/re_parsers.py
==================================================================
--- mtg_proxy_printer/decklist_parser/re_parsers.py
+++ mtg_proxy_printer/decklist_parser/re_parsers.py
@@ -15,11 +15,11 @@
import copy
from collections import Counter
import re
import typing
-from PyQt5.QtCore import QObject, QCoreApplication
+from PySide6.QtCore import QObject, QCoreApplication
from mtg_proxy_printer.decklist_parser.common import ParsedDeck, ParserBase
from mtg_proxy_printer.model.carddb import Card, CardDatabase, CardIdentificationData
from mtg_proxy_printer.model.imagedb import ImageDatabase
from mtg_proxy_printer.logger import get_logger
@@ -172,13 +172,14 @@
class MagicWorkstationDeckDataFormatParser(GenericRegularExpressionDeckParser):
@staticmethod
def supported_file_types() -> typing.Dict[str, typing.List[str]]:
return {
- QCoreApplication.translate(
- "MagicWorkstationDeckDataFormatParser", "Magic Workstation Deck Data Format"): ["mwDeck"],
- }
+ QCoreApplication.translate(
+ "MagicWorkstationDeckDataFormatParser", "Magic Workstation Deck Data Format"): ["mwDeck"],
+ }
+
PREFIXES_TO_SKIP = frozenset({"//"})
def __init__(self, card_db: CardDatabase, image_db: ImageDatabase, parent: QObject = None):
super().__init__(
card_db, image_db,
@@ -251,13 +252,14 @@
@staticmethod
def supported_file_types() -> typing.Dict[str, typing.List[str]]:
return {
QCoreApplication.translate("XMageParser", "XMage Deck file"): ["dck"],
- }
+ }
+
PREFIXES_TO_SKIP = frozenset(("NAME", "LAYOUT"))
def __init__(self, card_db: CardDatabase, image_db: ImageDatabase, parent: QObject = None):
super().__init__(
card_db, image_db,
re.compile(r"(SB: )?(?P\d+) \[(?P\w+):(?P[^]]+)] (?P.+)"), parent
)
Index: mtg_proxy_printer/document_controller/_interface.py
==================================================================
--- mtg_proxy_printer/document_controller/_interface.py
+++ mtg_proxy_printer/document_controller/_interface.py
@@ -17,11 +17,11 @@
from functools import partial
import itertools
import operator
import typing
-from PyQt5.QtCore import QCoreApplication
+from PySide6.QtCore import QCoreApplication
from mtg_proxy_printer.units_and_sizes import StringList
if typing.TYPE_CHECKING:
from mtg_proxy_printer.model.document import Document
Index: mtg_proxy_printer/document_controller/move_cards.py
==================================================================
--- mtg_proxy_printer/document_controller/move_cards.py
+++ mtg_proxy_printer/document_controller/move_cards.py
@@ -15,11 +15,11 @@
import functools
import itertools
import typing
-from PyQt5.QtCore import QModelIndex
+from PySide6.QtCore import QModelIndex
from ._interface import DocumentAction, IllegalStateError, Self
from mtg_proxy_printer.logger import get_logger
if typing.TYPE_CHECKING:
Index: mtg_proxy_printer/document_controller/replace_card.py
==================================================================
--- mtg_proxy_printer/document_controller/replace_card.py
+++ mtg_proxy_printer/document_controller/replace_card.py
@@ -14,11 +14,11 @@
# along with this program. If not, see .
import functools
import typing
-from PyQt5.QtCore import Qt
+from PySide6.QtCore import Qt
from mtg_proxy_printer.model.carddb import Card
from mtg_proxy_printer.model.card_list import PageColumns
if typing.TYPE_CHECKING:
from mtg_proxy_printer.model.document_page import CardContainer
Index: mtg_proxy_printer/document_controller/shuffle_document.py
==================================================================
--- mtg_proxy_printer/document_controller/shuffle_document.py
+++ mtg_proxy_printer/document_controller/shuffle_document.py
@@ -20,11 +20,11 @@
# Compatibility with Py 3.8
from secrets import token_bytes as randbytes
import typing
-from PyQt5.QtCore import Qt, QModelIndex
+from PySide6.QtCore import Qt, QModelIndex
from ._interface import DocumentAction, IllegalStateError, Self
from mtg_proxy_printer.model.carddb import Card
from mtg_proxy_printer.model.card_list import PageColumns
from mtg_proxy_printer.model.document_page import CardContainer
Index: mtg_proxy_printer/downloader_base.py
==================================================================
--- mtg_proxy_printer/downloader_base.py
+++ mtg_proxy_printer/downloader_base.py
@@ -13,11 +13,11 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import gzip
-from PyQt5.QtCore import QObject, pyqtSignal as Signal
+from PySide6.QtCore import QObject, Signal
import mtg_proxy_printer.http_file
from mtg_proxy_printer.logger import get_logger
logger = get_logger(__name__)
del get_logger
Index: mtg_proxy_printer/http_file.py
==================================================================
--- mtg_proxy_printer/http_file.py
+++ mtg_proxy_printer/http_file.py
@@ -24,11 +24,11 @@
import typing
from typing import List, Optional, Dict
import urllib.error
import urllib.request
-from PyQt5.QtCore import QObject, pyqtSignal as Signal
+from PySide6.QtCore import QObject, Signal
import delegateto
from mtg_proxy_printer.meta_data import USER_AGENT
from mtg_proxy_printer.logger import get_logger
Index: mtg_proxy_printer/meta_data.py
==================================================================
--- mtg_proxy_printer/meta_data.py
+++ mtg_proxy_printer/meta_data.py
@@ -12,11 +12,11 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
PROGRAMNAME = "MTGProxyPrinter"
-__version__ = "0.29.1"
+__version__ = "0.29.1+PySide6"
COPYRIGHT = "(C) 2020-2024 Thomas Hess"
HOME_PAGE = "https://chiselapp.com/user/luziferius/repository/MTGProxyPrinter"
DOWNLOAD_WEB_PAGE = f"{HOME_PAGE}/uv/download.html"
USER_AGENT = f"{PROGRAMNAME}/{__version__} ({HOME_PAGE})"
Index: mtg_proxy_printer/metered_file.py
==================================================================
--- mtg_proxy_printer/metered_file.py
+++ mtg_proxy_printer/metered_file.py
@@ -15,11 +15,11 @@
from typing import Iterable, List, Optional, BinaryIO, Union
from io import BufferedIOBase
-from PyQt5.QtCore import QObject, pyqtSignal as Signal
+from PySide6.QtCore import QObject, Signal
from delegateto import delegate
from mtg_proxy_printer.logger import get_logger
logger = get_logger(__name__)
Index: mtg_proxy_printer/missing_images_manager.py
==================================================================
--- mtg_proxy_printer/missing_images_manager.py
+++ mtg_proxy_printer/missing_images_manager.py
@@ -13,11 +13,11 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import typing
-from PyQt5.QtCore import QObject, pyqtSignal as Signal, pyqtSlot as Slot
+from PySide6.QtCore import QObject, Signal, Slot
from mtg_proxy_printer.model.document import Document
from mtg_proxy_printer.logger import get_logger
logger = get_logger(__name__)
del get_logger
Index: mtg_proxy_printer/model/card_list.py
==================================================================
--- mtg_proxy_printer/model/card_list.py
+++ mtg_proxy_printer/model/card_list.py
@@ -15,12 +15,12 @@
import enum
import itertools
import typing
-from PyQt5.QtCore import QAbstractTableModel, QModelIndex, Qt, pyqtSlot as Slot, pyqtSignal as Signal, QItemSelection
-from PyQt5.QtGui import QIcon
+from PySide6.QtCore import QAbstractTableModel, QModelIndex, Qt, Slot, Signal, QItemSelection
+from PySide6.QtGui import QIcon
from mtg_proxy_printer.model.carddb import Card, CardIdentificationData, CardDatabase, AnyCardType
from mtg_proxy_printer.logger import get_logger
logger = get_logger(__name__)
@@ -97,11 +97,11 @@
if role == ItemDataRole.ToolTipRole:
return self.tr("Beware: Potentially oversized card!\nThis card may not fit in your deck.")
elif role == ItemDataRole.DecorationRole:
return self._oversized_icon
- def flags(self, index: QModelIndex) -> Qt.ItemFlags:
+ def flags(self, index: QModelIndex) -> ItemFlag:
flags = super().flags(index)
if index.column() in self.EDITABLE_COLUMNS:
flags |= ItemFlag.ItemIsEditable
return flags
Index: mtg_proxy_printer/model/carddb.py
==================================================================
--- mtg_proxy_printer/model/carddb.py
+++ mtg_proxy_printer/model/carddb.py
@@ -22,13 +22,13 @@
import pathlib
import sqlite3
import threading
import typing
-from PyQt5.QtWidgets import QApplication
-from PyQt5.QtGui import QPixmap, QColor, QTransform, QPainter, QColorConstants
-from PyQt5.QtCore import Qt, QPoint, QRect, QSize, QPointF, QObject, pyqtSignal as Signal, pyqtSlot as Slot
+from PySide6.QtWidgets import QApplication
+from PySide6.QtGui import QPixmap, QColor, QTransform, QPainter, QColorConstants
+from PySide6.QtCore import Qt, QPoint, QRect, QSize, QPointF, QObject, Signal, Slot
if typing.TYPE_CHECKING:
from mtg_proxy_printer.model.imagedb import CacheContent
import mtg_proxy_printer.app_dirs
@@ -150,11 +150,11 @@
round(self.image_file.width() * corner.value[0]),
round(self.image_file.height() * corner.value[1])),
QSize(10, 10)
))
average_color = sample_area.scaled(
- 1, 1, transformMode=Qt.TransformationMode.SmoothTransformation).toImage().pixelColor(0, 0)
+ 1, 1, mode=Qt.TransformationMode.SmoothTransformation).toImage().pixelColor(0, 0)
return average_color
def display_string(self):
return f'"{self.name}" [{self.set.code.upper()}:{self.collector_number}]'
@@ -227,11 +227,11 @@
vertical_scaling_factor = card_size.width() / card_size.height()
horizontal_scaling_factor = card_size.height()/(card_size.width()*2)
combined_image = QPixmap(card_size)
combined_image.fill(QColor.fromRgb(255, 255, 255, 0)) # Fill with fully transparent white
painter = QPainter(combined_image)
- painter.setRenderHints(RenderHint.SmoothPixmapTransform | RenderHint.HighQualityAntialiasing)
+ painter.setRenderHints(RenderHint.SmoothPixmapTransform | RenderHint.Antialiasing)
transformation = QTransform()
transformation.rotate(90)
transformation.scale(horizontal_scaling_factor, vertical_scaling_factor)
painter.setTransform(transformation)
painter.drawPixmap(QPointF(card_size.width(), -card_size.height()), self.back.image_file)
Index: mtg_proxy_printer/model/document.py
==================================================================
--- mtg_proxy_printer/model/document.py
+++ mtg_proxy_printer/model/document.py
@@ -21,11 +21,11 @@
import pathlib
import sys
import textwrap
import typing
-from PyQt5.QtCore import QAbstractItemModel, QModelIndex, Qt, pyqtSlot as Slot, pyqtSignal as Signal, \
+from PySide6.QtCore import QAbstractItemModel, QModelIndex, Qt, Slot, Signal, \
QPersistentModelIndex
import mtg_proxy_printer.sqlite_helpers
from mtg_proxy_printer.model.document_page import CardContainer, Page, PageList
from mtg_proxy_printer.units_and_sizes import PageType
Index: mtg_proxy_printer/model/document_loader.py
==================================================================
--- mtg_proxy_printer/model/document_loader.py
+++ mtg_proxy_printer/model/document_loader.py
@@ -24,12 +24,12 @@
import textwrap
import typing
from unittest.mock import patch
import pint
-from PyQt5.QtGui import QPageLayout, QPageSize
-from PyQt5.QtCore import QObject, pyqtSignal as Signal, QThreadPool, QMarginsF, QSizeF, Qt
+from PySide6.QtGui import QPageLayout, QPageSize
+from PySide6.QtCore import QObject, Signal, QThreadPool, QMarginsF, QSizeF, Qt
from hamcrest import assert_that, all_of, instance_of, greater_than_or_equal_to, matches_regexp, is_in, \
has_properties, is_, any_of
try:
from hamcrest import contains_exactly
Index: mtg_proxy_printer/model/imagedb.py
==================================================================
--- mtg_proxy_printer/model/imagedb.py
+++ mtg_proxy_printer/model/imagedb.py
@@ -24,12 +24,12 @@
import string
import threading
import typing
import urllib.error
-from PyQt5.QtCore import QObject, pyqtSignal as Signal, pyqtSlot as Slot, QModelIndex, Qt, QThreadPool
-from PyQt5.QtGui import QPixmap, QColorConstants
+from PySide6.QtCore import QObject, Signal, Slot, QModelIndex, Qt, QThreadPool
+from PySide6.QtGui import QPixmap, QColorConstants
if typing.TYPE_CHECKING:
from mtg_proxy_printer.model.document import Document
from mtg_proxy_printer.model.carddb import with_database_write_lock
Index: mtg_proxy_printer/model/string_list.py
==================================================================
--- mtg_proxy_printer/model/string_list.py
+++ mtg_proxy_printer/model/string_list.py
@@ -13,11 +13,11 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import typing
-from PyQt5.QtCore import QAbstractListModel, Qt, QObject, QModelIndex
+from PySide6.QtCore import QAbstractListModel, Qt, QObject, QModelIndex
from mtg_proxy_printer.model.carddb import MTGSet
__all__ = [
Index: mtg_proxy_printer/natsort.py
==================================================================
--- mtg_proxy_printer/natsort.py
+++ mtg_proxy_printer/natsort.py
@@ -18,11 +18,11 @@
"""
import re
import typing
-from PyQt5.QtCore import QSortFilterProxyModel, QModelIndex
+from PySide6.QtCore import QSortFilterProxyModel, QModelIndex
__all__ = [
"natural_sorted",
"str_less_than",
"NaturallySortedSortFilterProxyModel",
Index: mtg_proxy_printer/print.py
==================================================================
--- mtg_proxy_printer/print.py
+++ mtg_proxy_printer/print.py
@@ -14,13 +14,13 @@
# along with this program. If not, see .
import math
from pathlib import Path
-from PyQt5.QtCore import QObject, QMarginsF, QSizeF, pyqtSlot as Slot, QPersistentModelIndex
-from PyQt5.QtGui import QPainter, QPdfWriter, QPageSize
-from PyQt5.QtPrintSupport import QPrinter
+from PySide6.QtCore import QObject, QMarginsF, QSizeF, Slot, QPersistentModelIndex
+from PySide6.QtGui import QPainter, QPdfWriter, QPageSize
+from PySide6.QtPrintSupport import QPrinter
import mtg_proxy_printer.meta_data
from mtg_proxy_printer.settings import settings
from mtg_proxy_printer.model.document import Document
from mtg_proxy_printer.model.document_loader import PageLayoutSettings
@@ -61,11 +61,10 @@
f"orientation={page_layout.orientation()}, "
f"margins={layout.margin_left, layout.margin_top, layout.margin_right, layout.margin_bottom}")
# magnitude returns a float by default, so round to int to avoid a TypeError
printer.setResolution(round(mtg_proxy_printer.units_and_sizes.RESOLUTION.magnitude))
# Disable duplex printing by default
- printer.setDoubleSidedPrinting(False)
printer.setDuplex(QPrinter.DuplexMode.DuplexNone)
printer.setOutputFormat(QPrinter.OutputFormat.NativeFormat)
if RenderMode.IMPLICIT_MARGINS not in renderer.render_mode:
printer.setFullPage(True)
return printer
Index: mtg_proxy_printer/printing_filter_updater.py
==================================================================
--- mtg_proxy_printer/printing_filter_updater.py
+++ mtg_proxy_printer/printing_filter_updater.py
@@ -14,11 +14,11 @@
# along with this program. If not, see .
import sqlite3
import typing
-from PyQt5.QtCore import QObject, pyqtSignal as Signal, Qt, QCoreApplication
+from PySide6.QtCore import QObject, Signal, Qt, QCoreApplication
import mtg_proxy_printer.settings
if typing.TYPE_CHECKING:
from mtg_proxy_printer.model.carddb import CardDatabase
from mtg_proxy_printer.ui.main_window import MainWindow
Index: mtg_proxy_printer/resources/ui/central_widget/columnar.ui
==================================================================
--- mtg_proxy_printer/resources/ui/central_widget/columnar.ui
+++ mtg_proxy_printer/resources/ui/central_widget/columnar.ui
@@ -24,11 +24,11 @@
false
- QPainter::Antialiasing|QPainter::HighQualityAntialiasing
+ QPainter::Antialiasing
-
Index: mtg_proxy_printer/resources/ui/central_widget/grouped.ui
==================================================================
--- mtg_proxy_printer/resources/ui/central_widget/grouped.ui
+++ mtg_proxy_printer/resources/ui/central_widget/grouped.ui
@@ -24,11 +24,11 @@
false
- QPainter::Antialiasing|QPainter::HighQualityAntialiasing
+ QPainter::Antialiasing
-
Index: mtg_proxy_printer/resources/ui/document_settings_dialog.ui
==================================================================
--- mtg_proxy_printer/resources/ui/document_settings_dialog.ui
+++ mtg_proxy_printer/resources/ui/document_settings_dialog.ui
@@ -1,17 +1,9 @@
DocumentSettingsDialog
-
-
- 0
- 0
- 501
- 300
-
-
Set Document settings
-
@@ -42,34 +34,14 @@
button_box
accepted()
DocumentSettingsDialog
accept()
-
-
- 248
- 254
-
-
- 157
- 274
-
-
button_box
rejected()
DocumentSettingsDialog
reject()
-
-
- 316
- 260
-
-
- 286
- 274
-
-
Index: mtg_proxy_printer/runner.py
==================================================================
--- mtg_proxy_printer/runner.py
+++ mtg_proxy_printer/runner.py
@@ -13,11 +13,11 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import typing
-from PyQt5.QtCore import QRunnable, QObject, pyqtSignal as Signal
+from PySide6.QtCore import QRunnable, QObject, Signal
from mtg_proxy_printer.logger import get_logger
logger = get_logger(__name__)
del get_logger
Index: mtg_proxy_printer/settings.py
==================================================================
--- mtg_proxy_printer/settings.py
+++ mtg_proxy_printer/settings.py
@@ -19,11 +19,11 @@
import re
import typing
import tokenize
import pint
-from PyQt5.QtCore import QStandardPaths
+from PySide6.QtCore import QStandardPaths
import mtg_proxy_printer.app_dirs
import mtg_proxy_printer.meta_data
import mtg_proxy_printer.natsort
from mtg_proxy_printer.units_and_sizes import CardSizes, ConfigParser, SectionProxy, unit_registry, T, QuantityT, UnitT
Index: mtg_proxy_printer/ui/add_card.py
==================================================================
--- mtg_proxy_printer/ui/add_card.py
+++ mtg_proxy_printer/ui/add_card.py
@@ -13,13 +13,13 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
from typing import Union, Type, Optional
-from PyQt5.QtCore import QStringListModel, pyqtSlot as Slot, pyqtSignal as Signal, Qt, QItemSelectionModel, QItemSelection
-from PyQt5.QtWidgets import QWidget, QDialogButtonBox
-from PyQt5.QtGui import QIcon
+from PySide6.QtCore import QStringListModel, Slot, Signal, Qt, QItemSelectionModel, QItemSelection
+from PySide6.QtWidgets import QWidget, QDialogButtonBox
+from PySide6.QtGui import QIcon
from mtg_proxy_printer.document_controller.card_actions import ActionAddCard
import mtg_proxy_printer.model.string_list
import mtg_proxy_printer.model.carddb
import mtg_proxy_printer.model.document
Index: mtg_proxy_printer/ui/cache_cleanup_wizard.py
==================================================================
--- mtg_proxy_printer/ui/cache_cleanup_wizard.py
+++ mtg_proxy_printer/ui/cache_cleanup_wizard.py
@@ -19,13 +19,13 @@
import functools
import math
import pathlib
import typing
-from PyQt5.QtCore import QAbstractTableModel, Qt, QModelIndex, QObject, QBuffer, QIODevice, QItemSelectionModel, QSize
-from PyQt5.QtGui import QIcon, QPixmap
-from PyQt5.QtWidgets import QWidget, QWizard, QWizardPage
+from PySide6.QtCore import QAbstractTableModel, Qt, QModelIndex, QObject, QBuffer, QIODevice, QItemSelectionModel, QSize
+from PySide6.QtGui import QIcon, QPixmap
+from PySide6.QtWidgets import QWidget, QWizard, QWizardPage
import mtg_proxy_printer.settings
from mtg_proxy_printer.natsort import NaturallySortedSortFilterProxyModel
from mtg_proxy_printer.model.carddb import CardDatabase, Card, MTGSet
from mtg_proxy_printer.model.imagedb import ImageDatabase, CacheContent as ImageCacheContent, ImageKey
@@ -61,11 +61,11 @@
source.width() // scaling_factor, source.height() // scaling_factor,
Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation)
buffer = QBuffer()
buffer.open(QIODevice.OpenModeFlag.WriteOnly)
pixmap.save(buffer, "PNG", quality=100)
- image = buffer.data().toBase64().data().decode()
+ image = buffer.data().toBase64().toStdString()
card_name = f'{card_name}
' if card_name else ""
tooltip_text = f'{card_name}'
return tooltip_text
Index: mtg_proxy_printer/ui/central_widget.py
==================================================================
--- mtg_proxy_printer/ui/central_widget.py
+++ mtg_proxy_printer/ui/central_widget.py
@@ -17,14 +17,14 @@
import math
import operator
import pathlib
from typing import Union, Type, Optional
-from PyQt5.QtCore import pyqtSignal as Signal, pyqtSlot as Slot, QPersistentModelIndex, QItemSelectionModel, \
+from PySide6.QtCore import Signal, Slot, QPersistentModelIndex, QItemSelectionModel, \
QModelIndex, QPoint, Qt
-from PyQt5.QtGui import QIcon
-from PyQt5.QtWidgets import QWidget, QAction, QMenu, QInputDialog, QFileDialog
+from PySide6.QtGui import QIcon, QAction
+from PySide6.QtWidgets import QWidget, QMenu, QInputDialog, QFileDialog
import mtg_proxy_printer.app_dirs
import mtg_proxy_printer.settings
from mtg_proxy_printer.model.card_list import PageColumns
from mtg_proxy_printer.model.document import Document
Index: mtg_proxy_printer/ui/common.py
==================================================================
--- mtg_proxy_printer/ui/common.py
+++ mtg_proxy_printer/ui/common.py
@@ -15,15 +15,14 @@
import pathlib
import platform
import typing
-from PyQt5.QtCore import QFile, QUrl, QObject, QSize, QCoreApplication
-from PyQt5.QtWidgets import QLabel, QWizard, QWidget, QGraphicsColorizeEffect, QTextEdit
-from PyQt5.QtGui import QIcon
-# noinspection PyUnresolvedReferences
-from PyQt5 import uic
+from PySide6.QtCore import QFile, QUrl, QObject, QSize, QCoreApplication
+from PySide6.QtWidgets import QLabel, QWizard, QWidget, QGraphicsColorizeEffect, QTextEdit
+from PySide6.QtGui import QIcon
+from PySide6.QtUiTools import loadUiType
from mtg_proxy_printer.logger import get_logger
logger = get_logger(__name__)
del get_logger
@@ -92,22 +91,24 @@
label.setText(f"""{display_text:s}""")
def load_ui_from_file(name: str):
"""
- Returns the Ui class type from uic.loadUiType(), loading the ui file with the given name.
-
+ Returns the Ui class type as returned by PySide6.QtUiTools.loadUiType(), loading the ui file with the given name.
:param name: Path to the UI file
:return: class implementing the requested Ui
:raises FileNotFoundError: If the given ui file does not exist
"""
file_path = f"{RESOURCE_PATH_PREFIX}/ui/{name}.ui"
if not QFile.exists(file_path):
error_message = f"UI file not found: {file_path}"
logger.error(error_message)
raise FileNotFoundError(error_message)
- base_type, _ = uic.loadUiType(file_path, from_imports=True)
+ try:
+ base_type, _ = loadUiType(file_path)
+ except TypeError as e:
+ raise RuntimeError(f"Ui compilation failed for path {file_path}") from e
return base_type
def load_icon(name: str) -> QIcon:
file_path = f"{RESOURCE_PATH_PREFIX}/icons/{name}"
if not QFile.exists(file_path):
Index: mtg_proxy_printer/ui/compiled_resources.pyi
==================================================================
--- mtg_proxy_printer/ui/compiled_resources.pyi
+++ mtg_proxy_printer/ui/compiled_resources.pyi
@@ -12,11 +12,11 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
"""
-Declares the interface created by the PyQt5 resource compiler.
+Declares the interface created by the PySide6 resource compiler.
This is only used for type hinting.
"""
import typing
Index: mtg_proxy_printer/ui/deck_import_wizard.py
==================================================================
--- mtg_proxy_printer/ui/deck_import_wizard.py
+++ mtg_proxy_printer/ui/deck_import_wizard.py
@@ -20,14 +20,15 @@
import re
import typing
import urllib.error
import urllib.parse
-from PyQt5.QtCore import pyqtSlot as Slot, pyqtSignal as Signal, pyqtProperty as Property, QStringListModel, Qt, \
+from PySide6.QtCore import Slot, Signal, Property, QStringListModel, Qt, SIGNAL, \
QItemSelection, QSize, QUrl
-from PyQt5.QtGui import QValidator, QIcon, QDesktopServices
-from PyQt5.QtWidgets import QWizard, QFileDialog, QMessageBox, QWizardPage, QWidget, QRadioButton
+from PySide6.QtGui import QValidator, QIcon, QDesktopServices
+from PySide6.QtWidgets import QWizard, QFileDialog, QMessageBox, QWizardPage, QWidget, QRadioButton
+
from mtg_proxy_printer.units_and_sizes import SectionProxy
import mtg_proxy_printer.settings
from mtg_proxy_printer.decklist_parser import re_parsers, common, csv_parsers
from mtg_proxy_printer.decklist_downloader import IsIdentifyingDeckUrlValidator, AVAILABLE_DOWNLOADERS, \
@@ -118,18 +119,18 @@
self.deck_list_url_validator.validate(text)[0] == State.Acceptable))
supported_sites = "\n".join((downloader.APPLICABLE_WEBSITES for downloader in AVAILABLE_DOWNLOADERS.values()))
ui.deck_list_download_url_line_edit.setToolTip(
self.tr("Supported websites:\n{supported_sites}").format(supported_sites=supported_sites))
ui.translate_deck_list_target_language.setModel(language_model)
- self.registerField("deck_list*", ui.deck_list, "plainText", ui.deck_list.textChanged)
+ self.registerField("deck_list*", ui.deck_list)
self.registerField("print-guessing-enable", ui.print_guessing_enable)
self.registerField("print-guessing-prefer-already-downloaded", ui.print_guessing_prefer_already_downloaded)
self.registerField("translate-deck-list-enable", ui.translate_deck_list_enable)
- self.registerField("deck-list-downloaded", self, "deck_list_downloader", self.deck_list_downloader_changed)
+ self.registerField("deck-list-downloaded", self, "deck_list_downloader", "deck_list_downloader_changed(str)")
self.registerField(
"translate-deck-list-target-language", ui.translate_deck_list_target_language,
- "currentText", ui.translate_deck_list_target_language.currentTextChanged
+ "currentText", "currentTextChanged(str)"
)
logger.info(f"Created {self.__class__.__name__} instance.")
@Property(str, notify=deck_list_downloader_changed)
@@ -605,10 +606,11 @@
}
def __init__(self, card_db: CardDatabase, image_db: ImageDatabase,
language_model: QStringListModel, parent: QWidget = None, flags=Qt.WindowFlags()):
super().__init__(QSize(1000, 600), parent, flags)
+ self.setDefaultProperty("QPlainTextEdit", "plainText", SIGNAL("textChanged()"))
self.card_db = card_db
self.select_deck_parser_page = SelectDeckParserPage(card_db, image_db, self)
self.load_list_page = LoadListPage(language_model, self)
self.summary_page = SummaryPage(card_db, self)
self.addPage(self.load_list_page)
Index: mtg_proxy_printer/ui/dialogs.py
==================================================================
--- mtg_proxy_printer/ui/dialogs.py
+++ mtg_proxy_printer/ui/dialogs.py
@@ -15,14 +15,14 @@
import typing
import pathlib
import sys
-from PyQt5.QtCore import QFile, pyqtSlot as Slot, QThreadPool, QObject, QEvent, Qt
-from PyQt5.QtWidgets import QFileDialog, QWidget, QTextBrowser, QDialogButtonBox, QDialog
-from PyQt5.QtGui import QIcon
-from PyQt5.QtPrintSupport import QPrintPreviewDialog, QPrintDialog, QPrinter
+from PySide6.QtCore import QFile, Slot, QThreadPool, QObject, QEvent, Qt
+from PySide6.QtWidgets import QFileDialog, QWidget, QTextBrowser, QDialogButtonBox, QDialog
+from PySide6.QtGui import QIcon
+from PySide6.QtPrintSupport import QPrintPreviewDialog, QPrintDialog, QPrinter
import mtg_proxy_printer.app_dirs
from mtg_proxy_printer.model.carddb import Card, CardDatabase
import mtg_proxy_printer.model.document
import mtg_proxy_printer.model.imagedb
@@ -247,11 +247,11 @@
def _set_text_browser_with_markdown_file_content(self, file_path: str, text_browser: QTextBrowser):
file = QFile(file_path, self)
file.open(QFile.OpenModeFlag.ReadOnly)
try:
- content = file.readAll().data().decode("utf-8")
+ content = file.readAll().toStdString()
finally:
file.close()
text_browser.setMarkdown(content)
@@ -367,7 +367,7 @@
self.document.apply(action)
logger.debug("Saving settings in the document done.")
def clear_highlight(self):
"""Clears all GUI widget highlights."""
- for item in self.findChildren((QWidget,), options=Qt.FindChildOption.FindChildrenRecursively): # type: QWidget
+ for item in self.findChildren(QWidget, options=Qt.FindChildOption.FindChildrenRecursively): # type: QWidget
item.setGraphicsEffect(None)
Index: mtg_proxy_printer/ui/item_delegates.py
==================================================================
--- mtg_proxy_printer/ui/item_delegates.py
+++ mtg_proxy_printer/ui/item_delegates.py
@@ -12,12 +12,12 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import typing
-from PyQt5.QtCore import QModelIndex, Qt, QAbstractItemModel, QSortFilterProxyModel
-from PyQt5.QtWidgets import QStyledItemDelegate, QWidget, QStyleOptionViewItem, QComboBox
+from PySide6.QtCore import QModelIndex, Qt, QAbstractItemModel, QSortFilterProxyModel
+from PySide6.QtWidgets import QStyledItemDelegate, QWidget, QStyleOptionViewItem, QComboBox
from mtg_proxy_printer.model.carddb import Card
from mtg_proxy_printer.model.card_list import PageColumns
from mtg_proxy_printer.model.document import Document
from mtg_proxy_printer.logger import get_logger
Index: mtg_proxy_printer/ui/main_window.py
==================================================================
--- mtg_proxy_printer/ui/main_window.py
+++ mtg_proxy_printer/ui/main_window.py
@@ -14,14 +14,15 @@
# along with this program. If not, see .
import pathlib
import typing
-from PyQt5.QtCore import pyqtSlot as Slot, pyqtSignal as Signal, QStringListModel, QUrl, Qt, QSize
-from PyQt5.QtGui import QCloseEvent, QKeySequence, QDesktopServices, QDragEnterEvent, QDropEvent, QPixmap
-from PyQt5.QtWidgets import QApplication, QMessageBox, QAction, QWidget, QMainWindow, QDialog
+from PySide6.QtCore import Slot, Signal, QStringListModel, QUrl, Qt, QSize
+from PySide6.QtGui import QCloseEvent, QKeySequence, QAction, QDesktopServices, QDragEnterEvent, QDropEvent, QPixmap
+from PySide6.QtWidgets import QApplication, QMessageBox, QWidget, QMainWindow, QDialog
+from PySide6.QtPrintSupport import QPrintDialog
from mtg_proxy_printer.missing_images_manager import MissingImagesManager
from mtg_proxy_printer.card_info_downloader import CardInfoDownloader
from mtg_proxy_printer.model.carddb import CardDatabase, Card, MTGSet
from mtg_proxy_printer.model.imagedb import ImageDatabase
@@ -123,11 +124,10 @@
]
for action, shortcut in actions_with_shortcuts:
action.setShortcut(shortcut)
def _setup_central_widget(self):
- self.setCentralWidget(self.ui.central_widget)
self.ui.central_widget.set_data(self.document, self.card_database, self.image_db)
def _setup_loading_state_connections(self):
for widget_or_action in self._get_widgets_and_actions_disabled_in_loading_state():
self.loading_state_changed.connect(widget_or_action.setDisabled)
@@ -264,11 +264,12 @@
"This is passed as the {action} when asking the user about compacting the document if that can save pages")
if self._ask_user_about_compacting_document(action_str) == StandardButton.Cancel:
return
self.current_dialog = PrintDialog(self.document, self)
self.current_dialog.finished.connect(self.on_dialog_finished)
- self.missing_images_manager.obtain_missing_images(self.current_dialog.open)
+ # Use the QDialog base class open() method, because QPrintDialog.open() performs additional, unwanted actions.
+ self.missing_images_manager.obtain_missing_images(super(QPrintDialog, self.current_dialog).open)
@Slot()
def on_action_print_preview_triggered(self):
logger.info(f"User views the print preview.")
action_str = self.tr(
@@ -332,11 +333,11 @@
"This program requires downloading additional card data from Scryfall to operate the card search.\n"
"Download the required data from Scryfall now?\n"
"Without the data, you can only print custom cards by drag&dropping "
"the image files onto the main window."),
StandardButton.Yes | StandardButton.No, StandardButton.Yes) == StandardButton.Yes:
- self.ui.action_download_card_data.trigger()
+ self.card_data_downloader.import_from_api()
@Slot()
def on_action_save_document_triggered(self):
logger.debug("User clicked on Save")
if self.document.save_file_path is None:
@@ -427,11 +428,11 @@
"There are %n new printings available on Scryfall. Update the local data now?",
"", estimated_card_count),
StandardButton.Yes | StandardButton.No, StandardButton.Yes
) == StandardButton.Yes:
logger.info("User agreed to update the card data from Scryfall. Performing update")
- self.ui.action_download_card_data.trigger()
+ self.card_data_downloader.import_from_api()
else:
# If the user declines to perform the update now, allow them to perform it later by enabling the action.
self.ui.action_download_card_data.setEnabled(True)
def ask_user_about_application_update_policy(self):
@@ -517,8 +518,8 @@
for url in mime_data.urls():
pixmap = QPixmap(url.toLocalFile())
if not pixmap.isNull():
if pixmap.width() != width or pixmap.height() != height:
new_size = QSize(width, height)
- pixmap = pixmap.scaled(new_size, transformMode=TransformationMode.SmoothTransformation)
+ pixmap = pixmap.scaled(new_size, mode=TransformationMode.SmoothTransformation)
result.append(pixmap)
return result
Index: mtg_proxy_printer/ui/page_config_container.py
==================================================================
--- mtg_proxy_printer/ui/page_config_container.py
+++ mtg_proxy_printer/ui/page_config_container.py
@@ -13,11 +13,11 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
from functools import partial
-from PyQt5.QtWidgets import QWidget
+from PySide6.QtWidgets import QWidget
from mtg_proxy_printer.ui.common import load_ui_from_file
from mtg_proxy_printer.logger import get_logger
try:
Index: mtg_proxy_printer/ui/page_config_preview_area.py
==================================================================
--- mtg_proxy_printer/ui/page_config_preview_area.py
+++ mtg_proxy_printer/ui/page_config_preview_area.py
@@ -14,12 +14,13 @@
# along with this program. If not, see .
import enum
from unittest.mock import MagicMock
-from PyQt5.QtCore import pyqtSlot as Slot, QPersistentModelIndex
-from PyQt5.QtGui import QColorConstants, QPainter, QPixmap
+from PySide6.QtCore import Slot, QPersistentModelIndex
+from PySide6.QtGui import QColorConstants, QPainter, QPixmap
+from PySide6.QtWidgets import QWidget
from mtg_proxy_printer.document_controller.page_actions import ActionNewPage
from mtg_proxy_printer.document_controller.card_actions import ActionAddCard, ActionRemoveCards
from mtg_proxy_printer.model.document_loader import PageLayoutSettings
from mtg_proxy_printer.units_and_sizes import CardSizes, CardSize
@@ -27,12 +28,10 @@
from mtg_proxy_printer.model.document import Document
from mtg_proxy_printer.model.carddb import Card, MTGSet
from mtg_proxy_printer.ui.common import load_ui_from_file
from mtg_proxy_printer.logger import get_logger
-from PyQt5.QtWidgets import QWidget
-
try:
from mtg_proxy_printer.ui.generated.page_config_preview_area import Ui_PageConfigPreviewArea
except ModuleNotFoundError:
Ui_PageConfigPreviewArea = load_ui_from_file("page_config_preview_area")
Index: mtg_proxy_printer/ui/page_config_widget.py
==================================================================
--- mtg_proxy_printer/ui/page_config_widget.py
+++ mtg_proxy_printer/ui/page_config_widget.py
@@ -16,12 +16,12 @@
import functools
from functools import partial
import math
import typing
-from PyQt5.QtCore import pyqtSlot as Slot, Qt, pyqtSignal as Signal
-from PyQt5.QtWidgets import QGroupBox, QWidget, QDoubleSpinBox, QCheckBox, QLineEdit
+from PySide6.QtCore import Slot, Qt, Signal
+from PySide6.QtWidgets import QGroupBox, QWidget, QDoubleSpinBox, QCheckBox, QLineEdit
import mtg_proxy_printer.settings
from mtg_proxy_printer.ui.common import load_ui_from_file, BlockedSignals, highlight_widget
from mtg_proxy_printer.model.document_loader import PageLayoutSettings
from mtg_proxy_printer.units_and_sizes import CardSizes, PageType, unit_registry, ConfigParser, QuantityT
@@ -60,19 +60,19 @@
layout_key = spinbox.objectName()
spinbox.valueChanged[float].connect(
partial(self.set_numerical_page_layout_item, page_layout, layout_key, "mm"))
spinbox.valueChanged[float].connect(self.validate_paper_size_settings)
spinbox.valueChanged[float].connect(self.on_page_layout_setting_changed)
- spinbox.valueChanged[float].connect(partial(self.page_layout_changed.emit, page_layout))
+ spinbox.valueChanged[float].connect(lambda: self.page_layout_changed.emit(page_layout))
for checkbox, _ in self._get_boolean_settings_widgets():
layout_key = checkbox.objectName()
checkbox.stateChanged.connect(partial(self.set_boolean_page_layout_item, page_layout, layout_key))
- checkbox.stateChanged.connect(partial(self.page_layout_changed.emit, page_layout))
+ checkbox.stateChanged.connect(lambda: self.page_layout_changed.emit(page_layout))
ui.document_name.textChanged.connect(partial(setattr, page_layout, "document_name"))
- ui.document_name.textChanged.connect(partial(self.page_layout_changed.emit, page_layout))
+ ui.document_name.textChanged.connect(lambda: self.page_layout_changed.emit(page_layout))
return page_layout
@staticmethod
def set_numerical_page_layout_item(page_layout: PageLayoutSettings, layout_key: str, unit: str, value: float):
# Implementation note: This call is placed here, because stuffing it into a lambda defined within a while loop
@@ -87,11 +87,14 @@
# Implementation note: This call is placed here, because stuffing it into a lambda defined within a while loop
# somehow uses the wrong references and will set the attribute that was processed last in the loop.
# This method can be used via functools.partial to reduce the signature to (CheckState) -> None,
# which can be connected to the stateChanged signal just fine.
# Also, functools.partial does not exhibit the same issue as the lambda expression shows.
- setattr(page_layout, layout_key, value == CheckState.Checked)
+ #
+ # PySide6 maps the QCheckBox check states to proper Python enums, but the stateChanged Qt signal carries raw
+ # integers. To get the integers for comparison, the lambdas below require accessing the CheckState enum values.
+ setattr(page_layout, layout_key, value == CheckState.Checked.value)
@Slot()
def on_page_layout_setting_changed(self):
"""
Recomputes and updates the page capacity display, whenever any page layout widget changes.
Index: mtg_proxy_printer/ui/page_renderer.py
==================================================================
--- mtg_proxy_printer/ui/page_renderer.py
+++ mtg_proxy_printer/ui/page_renderer.py
@@ -15,13 +15,14 @@
import enum
import typing
from functools import partial
-from PyQt5.QtCore import Qt, QEvent
-from PyQt5.QtWidgets import QGraphicsView, QWidget, QAction
-from PyQt5.QtGui import QWheelEvent, QKeySequence, QPalette, QResizeEvent
+from PySide6.QtCore import Qt, QEvent
+from PySide6.QtWidgets import QGraphicsView, QWidget
+from PySide6.QtGui import QWheelEvent, QKeySequence, QPalette, QResizeEvent, QAction
+
from mtg_proxy_printer.model.document import Document
from mtg_proxy_printer.logger import get_logger
from mtg_proxy_printer.ui.page_scene import RenderMode, PageScene
Index: mtg_proxy_printer/ui/page_scene.py
==================================================================
--- mtg_proxy_printer/ui/page_scene.py
+++ mtg_proxy_printer/ui/page_scene.py
@@ -2,14 +2,14 @@
import enum
import functools
import itertools
import typing
-from PyQt5.QtCore import Qt, QSizeF, QPointF, QRectF, pyqtSignal as Signal, QObject, pyqtSlot as Slot, \
+from PySide6.QtCore import Qt, QSizeF, QPointF, QRectF, Signal, QObject, Slot, \
QPersistentModelIndex, QModelIndex, QRect, QPoint, QSize
-from PyQt5.QtGui import QPen, QColorConstants, QBrush, QColor, QPalette, QFontMetrics, QPixmap, QTransform, QPolygonF
-from PyQt5.QtWidgets import QGraphicsItemGroup, QGraphicsItem, QGraphicsPixmapItem, QGraphicsRectItem, \
+from PySide6.QtGui import QPen, QColorConstants, QBrush, QColor, QPalette, QFontMetrics, QPixmap, QTransform, QPolygonF
+from PySide6.QtWidgets import QGraphicsItemGroup, QGraphicsItem, QGraphicsPixmapItem, QGraphicsRectItem, \
QGraphicsLineItem, QGraphicsSimpleTextItem, QGraphicsScene, QGraphicsPolygonItem
from mtg_proxy_printer.model.card_list import PageColumns
from mtg_proxy_printer.model.carddb import Card, CardCorner
from mtg_proxy_printer.model.document import Document
Index: mtg_proxy_printer/ui/printing_filter_widgets.py
==================================================================
--- mtg_proxy_printer/ui/printing_filter_widgets.py
+++ mtg_proxy_printer/ui/printing_filter_widgets.py
@@ -16,13 +16,13 @@
import abc
from functools import partial
from typing import List, Tuple
-from PyQt5.QtCore import QUrl
-from PyQt5.QtGui import QDesktopServices
-from PyQt5.QtWidgets import QGroupBox, QWidget, QCheckBox, QPushButton
+from PySide6.QtCore import QUrl
+from PySide6.QtGui import QDesktopServices
+from PySide6.QtWidgets import QGroupBox, QWidget, QCheckBox, QPushButton
from mtg_proxy_printer.units_and_sizes import ConfigParser, SectionProxy
from mtg_proxy_printer.ui.common import highlight_widget
try:
Index: mtg_proxy_printer/ui/progress_bar.py
==================================================================
--- mtg_proxy_printer/ui/progress_bar.py
+++ mtg_proxy_printer/ui/progress_bar.py
@@ -11,12 +11,12 @@
# 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 .
-from PyQt5.QtCore import pyqtSlot as Slot, Qt
-from PyQt5.QtWidgets import QWidget, QLabel, QProgressBar
+from PySide6.QtCore import Slot, Qt
+from PySide6.QtWidgets import QWidget, QLabel, QProgressBar
try:
from mtg_proxy_printer.ui.generated.progress_bar import Ui_ProgressBar
except ModuleNotFoundError:
from mtg_proxy_printer.ui.common import load_ui_from_file
Index: mtg_proxy_printer/ui/settings_window.py
==================================================================
--- mtg_proxy_printer/ui/settings_window.py
+++ mtg_proxy_printer/ui/settings_window.py
@@ -15,13 +15,13 @@
import pathlib
import typing
from functools import partial
-from PyQt5.QtCore import QStringListModel, pyqtSignal as Signal, Qt, QItemSelectionModel, QEvent, QObject, QTimer
-from PyQt5.QtWidgets import QDialogButtonBox, QMessageBox, QWidget, QDialog
-from PyQt5.QtGui import QIcon, QStandardItemModel, QResizeEvent
+from PySide6.QtCore import QStringListModel, Signal, Qt, QItemSelectionModel, QEvent, QObject, QTimer
+from PySide6.QtWidgets import QDialogButtonBox, QMessageBox, QWidget, QDialog
+from PySide6.QtGui import QIcon, QStandardItemModel, QResizeEvent
import mtg_proxy_printer.app_dirs
from mtg_proxy_printer.units_and_sizes import ConfigParser
from mtg_proxy_printer.model.document import Document
from mtg_proxy_printer.document_controller import DocumentAction
Index: mtg_proxy_printer/ui/settings_window_pages.py
==================================================================
--- mtg_proxy_printer/ui/settings_window_pages.py
+++ mtg_proxy_printer/ui/settings_window_pages.py
@@ -17,13 +17,13 @@
from functools import partial
import pathlib
import typing
from abc import abstractmethod
-from PyQt5.QtCore import pyqtSignal as Signal, pyqtSlot as Slot, QUrl, QStandardPaths, QStringListModel, Qt, QThreadPool
-from PyQt5.QtGui import QDesktopServices, QStandardItem, QIcon
-from PyQt5.QtWidgets import QWidget, QCheckBox, QFileDialog, QMessageBox, QApplication, QLineEdit
+from PySide6.QtCore import Signal, Slot, QUrl, QStandardPaths, QStringListModel, Qt, QThreadPool
+from PySide6.QtGui import QDesktopServices, QStandardItem, QIcon
+from PySide6.QtWidgets import QWidget, QCheckBox, QFileDialog, QMessageBox, QApplication, QLineEdit
import mtg_proxy_printer.app_dirs
import mtg_proxy_printer.settings
from mtg_proxy_printer.printing_filter_updater import PrintingFilterUpdater
from mtg_proxy_printer.logger import get_logger
@@ -67,11 +67,10 @@
class PageMetadata(typing.NamedTuple):
text: str
icon_name: OptStr
tooltip: OptStr = None
-
class Page(QWidget):
"""The base class for settings page widgets. Defines the API used by the settings window"""
def display_item(self) -> typing.Sequence[QStandardItem]:
data = self.display_metadata()
@@ -104,11 +103,11 @@
"""Highlights GUI widgets with a state different from the given settings"""
pass
def clear_highlight(self):
"""Clears all GUI widget highlights."""
- for item in self.findChildren((QWidget,), options=Qt.FindChildOption.FindChildrenRecursively): # type: QWidget
+ for item in self.findChildren(QWidget, options=Qt.FindChildOption.FindChildrenRecursively): # type: QWidget
item.setGraphicsEffect(None)
class DebugSettingsPage(Page):
Index: mtg_proxy_printer/units_and_sizes.py
==================================================================
--- mtg_proxy_printer/units_and_sizes.py
+++ mtg_proxy_printer/units_and_sizes.py
@@ -26,11 +26,11 @@
import pint
try:
from pint.facets.plain.registry import QuantityT, UnitT
except ImportError: # Compatibility with Pint 0.21 for Python 3.8 support
QuantityT = UnitT = typing.Any
-from PyQt5.QtCore import QSize
+from PySide6.QtCore import QSize
def _setup_units() -> typing.Tuple[pint.UnitRegistry, QuantityT]:
registry = pint.UnitRegistry()
resolution = registry.parse_expression("300dots/inch")
Index: mtg_proxy_printer/update_checker.py
==================================================================
--- mtg_proxy_printer/update_checker.py
+++ mtg_proxy_printer/update_checker.py
@@ -19,11 +19,11 @@
import typing
import urllib.parse
import urllib.error
import ijson
-from PyQt5.QtCore import QObject, pyqtSignal as Signal, QThreadPool
+from PySide6.QtCore import QObject, Signal, QThreadPool
from mtg_proxy_printer.argument_parser import Namespace
import mtg_proxy_printer.meta_data
from mtg_proxy_printer import settings
from mtg_proxy_printer.model.carddb import CardDatabase
Index: pyproject.toml
==================================================================
--- pyproject.toml
+++ pyproject.toml
@@ -31,11 +31,11 @@
# ijson adds full compatibility with Python 3.11 in version 3.2 (3.1 is really slow on Py3.11).
# and Python 3.12 support in 3.2.1. Require newer versions on those Python versions to avoid
# falling back to the slow pure Python backend.
dependencies = [
"platformdirs >= 2.6.0",
- "PyQt5",
+ "PySide6_Essentials >= 6.7.0",
"ijson >= 3.1.0; python_version < '3.11'",
"ijson >= 3.2.0; python_version >= '3.11'",
"ijson >= 3.2.1; python_version >= '3.12'",
"pint < 0.22; python_version < '3.9'", # 0.22 dropped Py 3.8 support, thus Win7 support
"pint >= 0.22; python_version >= '3.9'", # Requires 0.22 for the QuantityT and UnitT types
@@ -55,21 +55,15 @@
"pytest",
"pytest-cov",
"pytest-timeout",
"pytest-qt >= 2.0",
"tox >= 4.0",
- "PySide2; platform_system == 'Windows' and python_version < '3.12'", # Used for lrelease: Compiling translations
- "PySide6_Essentials; platform_system == 'Windows' and python_version >= '3.12'", # Used for lrelease: Compiling translations
"pillow; platform_system == 'Windows'", # Used to convert the app icon to .ico
]
package = [
"build",
- # cx_Freeze 7.2 seems to somehow break loading the compiled Qt resources, but only for PyQt5.
- # Limit to 7.1 for now, until a fix is found
- "cx_Freeze >= 6.11.1, < 7.2; platform.python_implementation == 'CPython'",
- "PySide2; platform_system == 'Windows' and python_version < '3.12'", # Used for lrelease: Compiling translations
- "PySide6_Essentials; platform_system == 'Windows' and python_version >= '3.12'", # Used for lrelease: Compiling translations
+ "cx_Freeze >= 6.11.1; platform.python_implementation == 'CPython'",
"pillow; platform_system == 'Windows'", # Used to convert the app icon to .ico
]
[project.urls]
@@ -104,10 +98,10 @@
[build-system]
requires = [
"setuptools >=61",
"wheel",
- "PyQt5",
+ "PySide6_Essentials >= 6.7.0",
"build",
"tox >= 4.0",
]
build-backend = "setuptools.build_meta"
Index: run_tests.bat
==================================================================
--- run_tests.bat
+++ run_tests.bat
@@ -1,10 +1,10 @@
:: Runs the unit tests
:: Create or activate the build environment
-IF EXIST "venv" (
- call venv\Scripts\activate.bat
+IF EXIST "venv-PySide6" (
+ call venv-PySide6\Scripts\activate.bat
) ELSE (
call create_development_environment.bat
)
tox run
Index: run_tests.sh
==================================================================
--- run_tests.sh
+++ run_tests.sh
@@ -1,5 +1,5 @@
#!/bin/bash
-source venv/bin/activate
+source venv-PySide6/bin/activate
tox run
deactivate
Index: scripts/clean_windows_build.bat
==================================================================
--- scripts/clean_windows_build.bat
+++ scripts/clean_windows_build.bat
@@ -1,105 +1,69 @@
-:: Copyright (C) 2022-2023 Thomas Hess
-::
-:: 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 .
-
-
-:: Cleanup various items that bloat the application bundle. Mostly related to unused PyQt5 and Qt5 components
-if "%1%"=="" (
- pushd build\exe*
-) else (
- pushd "%1"
-)
-
-rmdir /S /Q PyQt5.uic.widget-plugins
-
-pushd lib
-del ijson\backends\python*.dll
-
-
-pushd PyQt5
-:: All DLLs here are also in Qt5\bin\
-del *.dll
-del QtRemoteObjects.pyd QtSerialPort.pyd QtSensors.pyd QtNetwork.pyd QtXml.pyd QtXmlPatterns.pyd pyrcc.pyd
-
-:: The sip bindings aren't used at runtime
-rmdir /S /Q bindings
-
-pushd Qt5
-
-:: Unused Qsci
-rmdir /S /Q qsci
-
-:: Unused Qml bindings
-rmdir /S /Q qml
-
-
-:: Unused DLLs
-pushd bin
-del d3dcompiler_47.dll libEGL.dll libGLESv2.dll opengl32sw.dll Qt5Bluetooth.dll Qt5DBus.dll Qt5Designer.dll Qt5Help.dll
-del Qt5Location.dll Qt5Multimedia.dll Qt5MultimediaWidgets.dll Qt5Network.dll Qt5Nfc.dll Qt5OpenGL.dll Qt5Positioning.dll
-del Qt5PositioningQuick.dll Qt5Qml.dll Qt5QmlModels.dll Qt5QmlWorkerScript.dll Qt5Quick.dll Qt5Quick3D.dll
-del Qt5Quick3DAssetImport.dll Qt5Quick3DRender.dll Qt5Quick3DRuntimeRender.dll Qt5Quick3DUtils.dll Qt5QuickControls2.dll
-del Qt5QuickParticles.dll Qt5QuickShapes.dll Qt5QuickTemplates2.dll Qt5QuickTest.dll Qt5QuickWidgets.dll Qt5RemoteObjects.dll
-del Qt5Sensors.dll Qt5SerialPort.dll Qt5Sql.dll Qt5Test.dll Qt5WebChannel.dll
-del Qt5WebSockets.dll Qt5WebView.dll Qt5XmlPatterns.dll
-del libcrypto-1_1-x64.dll libssl-1_1-x64.dll
-popd
-
-
-:: Unused plugins
-pushd plugins
-
-:: Remove duplicated Qt5 base DLLs
-FOR %%G IN ( printsupport platforms imageformats styles
-) DO del %%G\Qt5*.dll
-
-
-FOR %%G IN (
- assetimporters audio geometryloaders geoservices mediaservice playlistformats
- position renderers sceneparsers sensorgestures sensors sqldrivers texttospeech webview
-) DO rmdir /S /Q %%G
-popd
-
-
-:: Unused translations (of unused modules)
-pushd translations
-del qtxmlpatterns_*.qm
-del qtconnectivity_*.qm
-del qtdeclarative_*.qm
-del qtlocation_*.qm
-del qtmultimedia_*.qm
-del qtquickcontrols_*.qm
-del qtquickcontrols2_*.qm
-del qtserialport_*.qm
-del qtwebsockets_*.qm
-popd
-
-:: leave Qt5
-popd
-
-:: Unused extension modules
-del *.pyi
-del QAxContainer.pyd QtBluetooth.pyd QtDBus.pyd QtDesigner.pyd QtHelp.pyd QtLocation.pyd QtMultimedia.pyd QtMultimediaWidgets.pyd
-del QtOpenGL.pyd QtNfc.pyd QtPositioning.pyd QtQml.pyd QtQuick.pyd QtQuick3D.pyd QtQuickWidgets.pyd
-del QtRemoteObjects.pydQtSensors.pydQtSerialPort.pyd QtSql.pyd QtTest.pyd QtTextToSpeech.pyd QtWebChannel.pyd
-del QtWebSockets.pyd _QOpenGLFunctions_2_0.pyd _QOpenGLFunctions_2_1.pyd _QOpenGLFunctions_4_1_Core.pyd
-
-:: leave PyQt5
-popd
-:: leave lib
-popd
-::leave build directory
-popd
-
-
+:: Copyright (C) 2022-2023 Thomas Hess
+::
+:: 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 .
+
+if "%1%"=="" (
+ pushd build\exe*
+) else (
+ pushd "%1"
+)
+
+pushd lib
+
+pushd PySide6
+
+:: Don't need the executables, like Qt6 Designer, etc.
+:: Delete all typing stubs
+del *.exe *.pyi
+
+:: Remove unused components. Each consists of a pair of QtComponent.pyd and Qt6Component.dll
+del Q*tSerialPort* Qt*DBus* Qt*Designer* Qt*JsonRpc* Qt*Labs* Qt*LanguageServer* Qt*Network*
+del Qt*Qml* Qt*Quick* Qt*RemoteObjects* Qt*Sensors* Qt*Sql* Qt*Test* Qt*WebChannel*
+del Qt*Bluetooth* Qt*Charts* Qt*Concurrent* Qt*DataVisualization* Qt*Graphs* Qt*HttpServer*
+del Qt*Nfc* Qt*Positioning* Qt*Scxml* Qt*SerialBus* Qt*SerialPort* Qt*ShaderTools*
+del Qt*StateMachine* Qt*Test* Qt*TextToSpeech* Qt*Web* Qt*3D*
+del Qt*Help* Qt*Multimedia* Qt*Xml*
+
+:: Unused audio/video codec DLLs
+del avformat-*.dll avutil-*.dll swresample-*.dll swscale-*.dll
+:: Unused OpenGL bindings. The Qt6OpenGL DLLs are required and thus not removed
+del QtOpenGL.pyd QtOpenGLWidgets.pyd opengl32sw.dll
+
+
+pushd translations
+:: Remove translations for unused/removed components
+del assistant* designer* linguist* qtdeclarative*
+
+:: leave translations
+popd
+
+pushd plugins
+del /Q /S tls
+
+:: leave plugins
+popd
+
+:: leave PySide6
+popd
+
+
+del shiboken6\shiboken6*.lib
+del email\architecture.rst
+
+:: leave lib
+popd
+::leave build directory
+popd
+
+
Index: scripts/compile_resources.py
==================================================================
--- scripts/compile_resources.py
+++ scripts/compile_resources.py
@@ -71,20 +71,19 @@
iterable = iter(iterable)
return list(iter(lambda: tuple(itertools.islice(iterable, chunk_size)), ()))
def compile():
- command = ("pyrcc5", "-compress", "9", str(SOURCES_PATH)) # noqa # "pyrcc5" is a program name, not a typo
+ command = ("pyside6-rcc", "--compress", "9", "--generator", "python", str(SOURCES_PATH))
compiled = subprocess.check_output(command, universal_newlines=True) # type: str
# The resource compiler outputs > 15000 lines with extremely low line length.
# Reduce the file size by removing a good percentage of those line breaks
blocks = compiled.split("\\\n")
chunks = split_iterable(blocks, 7)
joined_chunks = ("".join(items) for items in chunks)
compiled = "\\\n".join(joined_chunks)
TARGET_PATH.write_text(compiled, "utf-8")
-
def clean():
TARGET_PATH.unlink(missing_ok=True)
Index: scripts/compile_ui_files.py
==================================================================
--- scripts/compile_ui_files.py
+++ scripts/compile_ui_files.py
@@ -23,19 +23,17 @@
to provide type hinting and autocompletion for the Ui classes defined by the UI files.
"""
import argparse
import ast
-import io
import itertools
import textwrap
from pathlib import Path
import shutil
+import subprocess
from typing import Tuple, NamedTuple, TypeVar, Iterable, Union, Type, List, Any, Dict, Set
-import PyQt5.uic
-
SOURCE_ROOT = Path(__file__).parent.parent # Checkout root directory
MAIN_PACKAGE = SOURCE_ROOT / "mtg_proxy_printer"
UI_SOURCE_PATH = MAIN_PACKAGE / "resources/ui" # UI files live here
TARGET_PATH = MAIN_PACKAGE / "ui/generated" # Package containing generated modules/type hinting stubs
T = TypeVar("T")
@@ -74,10 +72,16 @@
def type_filter(any_: Iterable[Any], types: Union[Type[T], Tuple[Type[T], ...]]) -> Iterable[T]:
return filter(lambda x: isinstance(x, types), any_)
+
+def create_python_package(location: Path, /):
+ """Creates an empty Python package at the given Path"""
+ location.mkdir(parents=True, exist_ok=True)
+ (location/"__init__.py").touch(exist_ok=True)
+
def compile_ui_files(args: Namespace, target_path: Path = TARGET_PATH, source_path: Path = UI_SOURCE_PATH):
"""
Compiles all UI files found in source_path to Python types, storing results in target_path.
@@ -84,32 +88,16 @@
Recursively finds UI files under source_path, replicates the found directory tree as a Python package hierarchy and
populates it with the compiled Ui types.
"""
if args.purge_existing and target_path.is_dir():
shutil.rmtree(target_path)
-
- source_path = source_path.resolve()
- target_path.mkdir(exist_ok=True)
-
- def map_to_output(directory, file_name):
- dir_path = Path(directory).relative_to(source_path)
- return target_path/dir_path, file_name
- import functools
- PyQt5.uic.open = functools.partial(open, encoding="utf-8")
- PyQt5.uic.compileUiDir(str(source_path), recurse=True, map=map_to_output)
create_python_package(target_path)
-
-
-def create_python_package(target_dir: Path):
- """
- Creates an empty __init__.py file in target_dir and each subdirectory, recursively.
- This marks these directories as proper Python packages.
- """
- (target_dir/"__init__.py").touch(exist_ok=True)
- for entry in target_dir.rglob("*"):
- if entry.is_dir():
- (entry/"__init__.py").touch(exist_ok=True)
+ for ui_file in source_path.rglob("*.ui"):
+ compiled = compile_ui_file(ui_file)
+ parent_dir = (target_path/ui_file.relative_to(source_path)).parent
+ create_python_package(parent_dir)
+ (parent_dir/f"{ui_file.stem}.py").write_text(compiled, "utf-8")
def create_ui_type_stubs(args: Namespace, target_path: Path = TARGET_PATH, source_path: Path = UI_SOURCE_PATH):
"""
Creates type hinting stubs for all UI files found in source_path, storing results in target_path.
@@ -118,17 +106,17 @@
populates it with the created type hints.
"""
if args.purge_existing and target_path.is_dir():
shutil.rmtree(target_path)
class_registry = build_class_registry(MAIN_PACKAGE)
+ create_python_package(target_path)
for ui_file in source_path.rglob("*.ui"):
compiled = compile_ui_file(ui_file)
stub = generate_stub(compiled, ui_file, class_registry)
parent_dir = (target_path/ui_file.relative_to(source_path)).parent
- parent_dir.mkdir(exist_ok=True)
+ create_python_package(parent_dir)
(parent_dir/f"{ui_file.stem}.pyi").write_text(stub, "utf-8")
- create_python_package(target_path)
def build_class_registry(package_path: Path) -> ClassRegistry:
"""Scan the source tree for classes and build a dict from class name to import path"""
result: ClassRegistry = {}
@@ -139,16 +127,15 @@
result[class_def.name] = ast.ImportFrom(module_path, [ast.alias(class_def.name)])
return result
def compile_ui_file(path: Path) -> str:
- buffer = io.StringIO()
try:
- PyQt5.uic.compileUi(path, buffer, from_imports=True)
+ command = ("pyside6-uic", "--generator", "python", str(path))
except Exception as e:
raise RuntimeError(f"Compilation failed for file {path}") from e
- return buffer.getvalue()
+ return subprocess.check_output(command, encoding="utf-8")
def generate_stub(compiled_ui: str, ui_file: Path, class_registry: ClassRegistry) -> str:
root_node = ast.parse(compiled_ui)
header = f"# Automatically generated type hinting stub for '{ui_file.name}'. Do not modify."
@@ -213,26 +200,17 @@
def get_assignments(function_body: List[ast.stmt]) -> List[Assignment]:
return [
Assignment(
assignment.targets[0].attr,
- get_assignment_type(assignment)
+ assignment.value.func.id
)
for assignment
in type_filter(function_body, ast.Assign)
if hasattr(assignment.targets[0], "attr") # Filter out local variables
]
-
-def get_assignment_type(assignment: ast.Assign):
- func = assignment.value.func
- if isinstance(func, ast.Attribute):
- return f"{func.value.id}.{func.attr}" # Qualified name: module.ClassName()
- elif isinstance(func, ast.Name):
- return func.id
- raise NotImplementedError("Unknown assignment type")
-
def get_function_stub(function_body: ast.FunctionDef, found_class_uses: UsedClasses):
for index, arg in enumerate(function_body.args.args):
if arg.arg == "self":
continue
Index: scripts/update_translations.py
==================================================================
--- scripts/update_translations.py
+++ scripts/update_translations.py
@@ -18,11 +18,10 @@
"""
Management script for application translations
"""
import argparse
-import itertools
import pathlib
import re
import subprocess
from typing import Callable, NamedTuple
@@ -29,11 +28,10 @@
# Mapping between source locales, as provided by Crowdin, and the target, as expected/loaded by Qt.
# TODO: Investigate, how systems behave in locales requiring the country as disambiguation, like en or zh.
LOCALES = {
"de-DE": "de",
-# "en-GB": "en_GB",
"en-US": "en_US",
"es-ES": "es",
"fr-FR": "fr",
"it-IT": "it",
"ja-JP": "ja",
@@ -51,10 +49,11 @@
re.search(
r'"source":\s*"(?P.+)",',
crowdin_yml_path.read_text("utf-8")
)["path"]
)
+
class Namespace(NamedTuple):
"""Mock namespace for type hinting"""
command: Callable[["Namespace"], None]
@@ -87,29 +86,18 @@
raise RuntimeError("The required Crowdin CLI client is not installed in the PATH, exiting.") from e
def register_new_raw_strings():
TRANSLATIONS_DIR.mkdir(parents=True, exist_ok=True)
- # PyQt5
- package = pathlib.Path("mtg_proxy_printer")
- files = list(itertools.chain(package.rglob("*.py"), package.rglob("*.ui")))
- subprocess.call([
- "pylupdate5",
- "-noobsolete", "-verbose",
- *files,
- "-ts", SOURCES_PATH
- ])
- ''' PySide6
subprocess.call([
"pyside6-lupdate",
"-source-language", "en_US",
"-recursive", "-no-obsolete",
"-extensions", "py,ui",
"mtg_proxy_printer",
"-ts", SOURCES_PATH
])
- '''
def upload_raw_strings(args: Namespace):
"""Updates the sources .ts from code, then uploads it to the Crowdin API"""
register_new_raw_strings()
@@ -137,15 +125,14 @@
except FileNotFoundError:
print("lrelease not found on PATH. Falling back to the executable supplied by PySide2.")
import sys
exe = pathlib.Path(sys.executable)
venv = exe.parent.parent
- lrelease5 = venv / "Lib" / "site-packages" / "PySide2" / "lrelease.exe"
lrelease6 = venv / "Lib" / "site-packages" / "PySide6" / "lrelease.exe"
- if not lrelease5.is_file() and not lrelease6.is_file():
+ if not lrelease6.is_file():
raise RuntimeError("No fallback lrelease executable found")
- return lrelease5 if lrelease5.is_file() else lrelease6
+ return lrelease6
else:
return "lrelease"
def compile_translations(args: Namespace):
Index: setup_cx_freeze.py
==================================================================
--- setup_cx_freeze.py
+++ setup_cx_freeze.py
@@ -41,57 +41,46 @@
base = "Win32GUI" if sys.platform == "win32" else None
excludes = [
f"{main_package}.resources", # Do not include the raw resources as individual files
"distutils",
+ "ijson.benchmark", # Ignore the benchmark script added after ijson 3.2.3
+ "importlib_metadata",
"lib2to3",
"pep517",
- "pytest",
+ "pint.testsuite", # Ignore the internal test suite
"pydoc_data",
+ "pytest",
+ "sqlite3.test", # Ignore the internal test suite
"tkinter",
"toml",
- "sqlite3.test", # Ignore the internal test suite
- "pint.testsuite", # Ignore the internal test suite
- "ijson.benchmark", # Ignore the benchmark script added after ijson 3.2.3
- "importlib_metadata",
-
- # All unused PyQt components
- "PyQt5.QtXmlPatterns",
- "PyQt5.QtNfc",
- "PyQt5.QtQml",
- "PyQt5.QtSql",
- "PyQt5.Qt3DAnimation",
- "PyQt5.Qt3DCore",
- "PyQt5.Qt3DExtras",
- "PyQt5.Qt3DInput",
- "PyQt5.Qt3DLogic",
- "PyQt5.Qt3DRender",
- "PyQt5.QtBluetooth",
- "PyQt5.QtChart",
- "PyQt5.QtDataVisualisation",
- "PyQt5.QtLocation",
- "PyQt5.QtMultimedia",
- "PyQt5.QtMultimediaWidgets",
- "PyQt5.QtNetwork",
- "PyQt5.QtNetworkAuth",
- "PyQt5.QtOpenGL",
- "PyQt5.QtPositioning",
- "PyQt5.QtPurchasing",
- "PyQt5.QtQuick",
- "PyQt5.QtQuickWidgets",
- "PyQt5.QtRemoteObjects",
- "PyQt5.QtSensors",
- "PyQt5.QtSerialPort",
- "PyQt5.QtTest",
- "PyQt5.QtWebChannel",
- "PyQt5.QtWebEngine",
- "PyQt5.QtWebEngineCore",
- "PyQt5.QtWebEngineWidgets",
- "PyQt5.QtWebKit",
- "PyQt5.QtWebKitWidgets",
- "PyQt5.QtWebSockets",
- "PyQt5.uic.port_v2",
+ # Empty package with readme and download scripts
+ "ctypes.test",
+ # Unused PySide6 components
+ "PySide6.glue",
+ "PySide6.include",
+ "PySide6.metatypes",
+ "PySide6.plugins.assetimporters",
+ "PySide6.plugins.canbus",
+ "PySide6.plugins.designer",
+ "PySide6.plugins.geometryloaders",
+ "PySide6.plugins.geoservices",
+ "PySide6.plugins.multimedia",
+ "PySide6.plugins.networkinformation",
+ "PySide6.plugins.position",
+ "PySide6.plugins.qmltooling",
+ "PySide6.plugins.scxmldatamodel",
+ "PySide6.plugins.sensors",
+ "PySide6.plugins.sqldrivers", # Use Python native sqlite3 module instead
+ "PySide6.plugins.tls",
+ "PySide6.qml",
+ "PySide6.QtAsyncio",
+ "PySide6.resources",
+ "PySide6.scripts",
+ "PySide6.support",
+ "PySide6.translations.qtwebengine_locales",
+ "PySide6.typesystems",
]
if sys.platform == "win32":
excludes += [
"platformdirs.android",
Index: tests/conftest.py
==================================================================
--- tests/conftest.py
+++ tests/conftest.py
@@ -20,11 +20,11 @@
import itertools
import sqlite3
import unittest.mock
from pathlib import Path
-from PyQt5.QtGui import QColorConstants, QPixmap
+from PySide6.QtGui import QColorConstants, QPixmap
import pytest
import mtg_proxy_printer.sqlite_helpers
import mtg_proxy_printer.settings
from mtg_proxy_printer.printing_filter_updater import PrintingFilterUpdater
@@ -55,11 +55,11 @@
db.execute("PRAGMA reverse_unordered_selects = TRUE")
return db
@pytest.fixture
-def image_db(tmp_path: Path):
+def image_db(qtbot, tmp_path: Path):
image_db = ImageDatabase(tmp_path)
regular_width, regular_height = image_db.blank_image.width(), image_db.blank_image.height()
for scryfall_id, is_front in itertools.product(
["0000579f-7b35-4ed3-b44c-db2a538066fe", "b3b87bfc-f97f-4734-94f6-e3e2f335fc4d"], [True, False]):
# Regular card images
@@ -71,21 +71,19 @@
key = ImageKey(scryfall_id, True, True)
image_db.loaded_images[key] = image_db.blank_image.scaled(regular_height, regular_width*2)
image_db.images_on_disk.add(key)
yield image_db
- image_db.__dict__.clear()
@pytest.fixture
def document(qtbot, card_db: CardDatabase, image_db: ImageDatabase) -> Document:
fill_card_database_with_json_cards(qtbot, card_db, [
"regular_english_card", "oversized_card", "english_double_faced_card"])
document = Document(card_db, image_db)
document.loader.db = card_db.db
yield document
- document.__dict__.clear()
@pytest.fixture
def document_light(qtbot) -> Document:
mock_card_db = unittest.mock.NonCallableMagicMock()
@@ -95,6 +93,5 @@
mock_card_db.db = mtg_proxy_printer.sqlite_helpers.create_in_memory_database(
"carddb", CardDatabase.MIN_SUPPORTED_SQLITE_VERSION, check_same_thread=False)
document = Document(mock_card_db, mock_image_db)
document.loader.db = mock_card_db.db
yield document
- document.__dict__.clear()
Index: tests/document_controller/test_action_move_cards.py
==================================================================
--- tests/document_controller/test_action_move_cards.py
+++ tests/document_controller/test_action_move_cards.py
@@ -16,11 +16,11 @@
from functools import partial
import pytest
from hamcrest import *
-from PyQt5.QtCore import QModelIndex
+from PySide6.QtCore import QModelIndex
from mtg_proxy_printer.model.document_page import PageType
from mtg_proxy_printer.document_controller import IllegalStateError
from mtg_proxy_printer.document_controller.page_actions import ActionNewPage
from mtg_proxy_printer.document_controller.move_cards import ActionMoveCards
Index: tests/document_controller/test_action_remove_page.py
==================================================================
--- tests/document_controller/test_action_remove_page.py
+++ tests/document_controller/test_action_remove_page.py
@@ -14,11 +14,11 @@
# along with this program. If not, see .
from functools import partial
from hamcrest import *
-from PyQt5.QtCore import QModelIndex
+from PySide6.QtCore import QModelIndex
from mtg_proxy_printer.model.document_page import Page
from mtg_proxy_printer.document_controller import IllegalStateError
from mtg_proxy_printer.document_controller.page_actions import ActionRemovePage
Index: tests/test___main__.py
==================================================================
--- tests/test___main__.py
+++ tests/test___main__.py
@@ -43,11 +43,11 @@
def main_mocks():
with patch("mtg_proxy_printer.__main__.mtg_proxy_printer.logger.configure_root_logger") as configure_root_logger, \
patch.multiple(
"mtg_proxy_printer.__main__",
_app=DEFAULT, Application=DEFAULT, handle_ssl_certificates=DEFAULT,
- parse_args=DEFAULT, QTimer=DEFAULT, logger=DEFAULT, QApplication=DEFAULT) as mocks:
+ parse_args=DEFAULT, QTimer=DEFAULT, logger=DEFAULT) as mocks:
mocks["configure_root_logger"] = configure_root_logger
yield mocks
mocks.clear()
@@ -79,11 +79,11 @@
main_mocks["configure_root_logger"].assert_called_once()
def test_main_calls_exec_on_application_instance(main_mocks):
mtg_proxy_printer.__main__.main()
- main_mocks["Application"]().exec_.assert_called_once()
+ main_mocks["Application"]().exec.assert_called_once()
def test_enqueues_startup_tasks_on_regular_launch(main_mocks):
main_mocks["parse_args"].return_value = Namespace(test_exit_on_launch=False)
mtg_proxy_printer.__main__.main()
Index: tests/test_card_list.py
==================================================================
--- tests/test_card_list.py
+++ tests/test_card_list.py
@@ -17,11 +17,11 @@
import typing
from hamcrest import *
import pytest
from pytestqt.qtbot import QtBot
-from PyQt5.QtCore import QItemSelectionModel
+from PySide6.QtCore import QItemSelectionModel
from mtg_proxy_printer.model.carddb import CardDatabase, CardIdentificationData
from mtg_proxy_printer.model.card_list import CardListModel
from tests.helpers import fill_card_database_with_json_cards
Index: tests/test_carddb.py
==================================================================
--- tests/test_carddb.py
+++ tests/test_carddb.py
@@ -198,12 +198,11 @@
"english_double_faced_art_series_card",
"Flowerfoot_Swordmaster_card",
"Flowerfoot_Swordmaster_token",
],
)
- yield card_db
- card_db.__dict__.clear()
+ return card_db
def generate_test_cases_for_test_translate_card_name():
"""Yields tuples with card data, target language and expected result."""
# Same-language identity translation
Index: tests/test_check_card_rendering.py
==================================================================
--- tests/test_check_card_rendering.py
+++ tests/test_check_card_rendering.py
@@ -14,11 +14,11 @@
# along with this program. If not, see .
import pytest
from hamcrest import *
from pytestqt.qtbot import QtBot
-from PyQt5.QtGui import QPixmap, QColorConstants
+from PySide6.QtGui import QPixmap, QColorConstants
from mtg_proxy_printer.model.carddb import Card, CheckCard, MTGSet
from mtg_proxy_printer.units_and_sizes import CardSizes
Index: tests/test_document.py
==================================================================
--- tests/test_document.py
+++ tests/test_document.py
@@ -18,12 +18,13 @@
import pathlib
import typing
import unittest.mock
import textwrap
-from PyQt5.QtCore import Qt
-from PyQt5.QtGui import QPixmap
+from PySide6.QtCore import Qt
+from PySide6.QtGui import QPixmap
+
from hamcrest import *
from hamcrest import contains_exactly
import pytest
from pytestqt.qtbot import QtBot
@@ -360,12 +361,11 @@
margin_top=20*mm, margin_bottom=19*mm, margin_left=18*mm, margin_right=17*mm,
row_spacing=3*mm, column_spacing=2*mm, card_bleed=1*mm,
draw_cut_markers=True, draw_sharp_corners=False,
)
document.apply(ActionEditDocumentSettings(custom_layout))
- yield document
- document.__dict__.clear()
+ return document
def test_document_reset_clears_modified_page_layout(qtbot: QtBot, document_custom_layout: Document):
default_layout = PageLayoutSettings.create_from_settings()
assert_that(
Index: tests/test_image_db.py
==================================================================
--- tests/test_image_db.py
+++ tests/test_image_db.py
@@ -13,12 +13,12 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import io
-from PyQt5.QtCore import QBuffer, QIODevice
-from PyQt5.QtGui import QPixmap
+from PySide6.QtCore import QBuffer, QIODevice
+from PySide6.QtGui import QPixmap
from hamcrest import *
from pytestqt.qtbot import QtBot
from mtg_proxy_printer.model.imagedb import ImageDatabase, ImageKey
@@ -53,6 +53,5 @@
assert_that((image_db.db_path / keys[1].format_relative_path()).is_file(), is_(True))
assert_that((image_db.db_path / keys[0].format_relative_path()).parent.is_dir(), is_(True))
image_db.delete_disk_cache_entries([keys[1]])
assert_that((image_db.db_path / keys[1].format_relative_path()).is_file(), is_(False))
assert_that((image_db.db_path / keys[0].format_relative_path()).parent.is_dir(), is_(False))
-
Index: tests/test_known_card_image_model.py
==================================================================
--- tests/test_known_card_image_model.py
+++ tests/test_known_card_image_model.py
@@ -18,11 +18,11 @@
"""
import pathlib
import typing
-from PyQt5.QtCore import Qt
+from PySide6.QtCore import Qt
import pytest
from hamcrest import *
from mtg_proxy_printer.ui.cache_cleanup_wizard import KnownCardImageModel, KnownCardColumns
from mtg_proxy_printer.model.carddb import CardDatabase
@@ -50,11 +50,10 @@
front_image.parent.mkdir(parents=True)
back_image.parent.mkdir(parents=True)
image_db.blank_image.save(str(front_image), "PNG")
image_db.blank_image.save(str(back_image), "PNG")
yield Environment(card_db, image_db, front_image, back_image)
- image_db.__dict__.clear()
@pytest.mark.parametrize("is_hidden", [True, False])
@pytest.mark.parametrize("is_front", [True, False])
def test_add_row_identifies_low_resolution_images(environment: Environment, is_front: bool, is_hidden: bool):
Index: tests/test_page_layout_settings.py
==================================================================
--- tests/test_page_layout_settings.py
+++ tests/test_page_layout_settings.py
@@ -19,12 +19,12 @@
import mtg_proxy_printer.model.document
import mtg_proxy_printer.model.document_loader
from mtg_proxy_printer.units_and_sizes import PageType, QuantityT, UnitT, unit_registry, StrDict
from mtg_proxy_printer.ui.page_scene import RenderMode
-from PyQt5.QtGui import QPageLayout, QPageSize
-from PyQt5.QtCore import QMarginsF
+from PySide6.QtGui import QPageLayout, QPageSize
+from PySide6.QtCore import QMarginsF
import pytest
from hamcrest import *
PageLayoutSettings = mtg_proxy_printer.model.document_loader.PageLayoutSettings
from tests.hasgetter import has_getters
Index: tests/ui/settings/test_card_filter_widgets.py
==================================================================
--- tests/ui/settings/test_card_filter_widgets.py
+++ tests/ui/settings/test_card_filter_widgets.py
@@ -14,11 +14,11 @@
# along with this program. If not, see .
import typing
from unittest.mock import patch
-from PyQt5.QtWidgets import QCheckBox
+from PySide6.QtWidgets import QCheckBox
import pytest
from hamcrest import *
from mtg_proxy_printer.units_and_sizes import SectionProxy
import mtg_proxy_printer.settings
Index: tests/ui/settings/test_initial_page_selection.py
==================================================================
--- tests/ui/settings/test_initial_page_selection.py
+++ tests/ui/settings/test_initial_page_selection.py
@@ -11,11 +11,11 @@
# 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 .
-from PyQt5.QtCore import QStringListModel
+from PySide6.QtCore import QStringListModel
from hamcrest import *
from pytestqt.qtbot import QtBot
from mtg_proxy_printer.ui.settings_window import SettingsWindow
Index: tests/ui/test_add_card.py
==================================================================
--- tests/ui/test_add_card.py
+++ tests/ui/test_add_card.py
@@ -17,12 +17,12 @@
import pytest
from hamcrest import *
from pytestqt.qtbot import QtBot
-from PyQt5.QtCore import Qt, QPoint, QRect, QItemSelectionModel
-from PyQt5.QtWidgets import QDialogButtonBox
+from PySide6.QtCore import Qt, QPoint, QRect, QItemSelectionModel
+from PySide6.QtWidgets import QDialogButtonBox
from mtg_proxy_printer.model.carddb import CardDatabase, CardIdentificationData
from mtg_proxy_printer.ui.add_card import HorizontalAddCardWidget, VerticalAddCardWidget
from tests.helpers import fill_card_database_with_json_card
@@ -44,13 +44,18 @@
expected_card_identification_data = CardIdentificationData(
"en", "Clearwater Pathway", "aznr", "25"
)
qtbot.add_widget(add_card_widget := widget_class())
add_card_widget.set_card_database(card_db)
- add_card_widget.ui.copies_input.setValue(1)
+ add_card_widget.card_name_filter_updated("") # Populate the card name list
+ add_card_widget.ui.card_name_list.setSelection(QRect(1, 1, 1, 1), ClearAndSelect)
+ qtbot.mouseClick(add_card_widget.ui.card_name_list, LeftButton, pos=QPoint(10, 10))
+ ok_button = add_card_widget.ui.button_box.button(StandardButton.Ok)
+ qtbot.mouseClick(ok_button, LeftButton, pos=QPoint(10, 10))
add_card_widget.ui.card_name_list.setSelection(QRect(1, 1, 1, 1), ClearAndSelect)
qtbot.mouseClick(add_card_widget.ui.card_name_list, LeftButton, pos=QPoint(10, 10))
qtbot.wait(10)
qtbot.mouseClick(
add_card_widget.ui.button_box.button(StandardButton.Ok), LeftButton
)
+ add_card_widget.ui.copies_input.setValue(1)
assert_that(add_card_widget._read_card_data_from_ui(), is_(equal_to(expected_card_identification_data)))
Index: tests/ui/test_card_item.py
==================================================================
--- tests/ui/test_card_item.py
+++ tests/ui/test_card_item.py
@@ -13,13 +13,13 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
from hamcrest import *
import pytest
-from PyQt5.QtCore import QSize
-from PyQt5.QtGui import QColorConstants, QPixmap, QImage, QPainter, QColor
-from PyQt5.QtWidgets import QGraphicsItem, QGraphicsScene
+from PySide6.QtCore import QSize
+from PySide6.QtGui import QColorConstants, QPixmap, QImage, QPainter, QColor
+from PySide6.QtWidgets import QGraphicsItem, QGraphicsScene
from mtg_proxy_printer.ui.page_scene import CardItem
from tests.document_controller.helpers import append_new_card_in_page
from tests.hasgetter import has_getter
Index: tests/ui/test_central_widget.py
==================================================================
--- tests/ui/test_central_widget.py
+++ tests/ui/test_central_widget.py
@@ -16,11 +16,12 @@
from pathlib import PurePath
from unittest.mock import NonCallableMagicMock, patch
import pytest
from pytestqt.qtbot import QtBot
-from PyQt5.QtCore import Qt
+from PySide6.QtCore import Qt
+
from hamcrest import *
from mtg_proxy_printer.model.document_page import Page
from mtg_proxy_printer.model.carddb import Card, MTGSet, CheckCard
from mtg_proxy_printer.document_controller.card_actions import ActionAddCard
Index: tests/ui/test_deck_import_wizard.py
==================================================================
--- tests/ui/test_deck_import_wizard.py
+++ tests/ui/test_deck_import_wizard.py
@@ -20,13 +20,13 @@
from hamcrest import *
from pytestqt.qtbot import QtBot
import pytest
-from PyQt5.QtCore import QStringListModel, Qt, QPoint, QObject
-from PyQt5.QtWidgets import QCheckBox, QWizard, QTableView, QComboBox, QLineEdit
-from PyQt5.QtTest import QTest
+from PySide6.QtCore import QStringListModel, Qt, QPoint, QObject
+from PySide6.QtWidgets import QCheckBox, QWizard, QTableView, QComboBox, QLineEdit
+from PySide6.QtTest import QTest
import mtg_proxy_printer.settings
from mtg_proxy_printer.model.carddb import CardDatabase, CardIdentificationData, CardList
from mtg_proxy_printer.ui.deck_import_wizard import DeckImportWizard
from mtg_proxy_printer.decklist_parser.re_parsers import MTGOnlineParser, MTGArenaParser, \
Index: tests/ui/test_item_delegate.py
==================================================================
--- tests/ui/test_item_delegate.py
+++ tests/ui/test_item_delegate.py
@@ -15,11 +15,11 @@
from collections import Counter
import itertools
from unittest.mock import NonCallableMagicMock
-from PyQt5.QtWidgets import QComboBox
+from PySide6.QtWidgets import QComboBox
import pytest
from hamcrest import *
from mtg_proxy_printer.document_controller.card_actions import ActionAddCard
from mtg_proxy_printer.model.carddb import CardDatabase, Card, MTGSet
Index: tests/ui/test_main_window.py
==================================================================
--- tests/ui/test_main_window.py
+++ tests/ui/test_main_window.py
@@ -15,13 +15,12 @@
import dataclasses
import pathlib
import unittest.mock
-
-from PyQt5.QtCore import QStringListModel, QThreadPool
-from PyQt5.QtWidgets import QMessageBox
+from PySide6.QtCore import QStringListModel, QThreadPool
+from PySide6.QtWidgets import QMessageBox
from pytestqt.qtbot import QtBot
from hamcrest import *
import pytest
import mtg_proxy_printer.http_file
@@ -60,12 +59,10 @@
qtbot.add_widget(main_window)
with qtbot.wait_exposed(main_window, timeout=1000):
main_window.show()
yield main_window
main_window.hide()
- del cid
- main_window.__dict__.clear()
def test_main_window_hides_progress_bar_after_downloading_image_during_load(
qtbot: QtBot, main_window: MainWindow):
with unittest.mock.patch.object( # Mock all HTTP-specific I/O calls
@@ -142,11 +139,10 @@
unittest.mock.patch.object(QThreadPool.globalInstance(), "start") as thread_pool_start, \
qtbot.assertNotEmitted(main_window.loading_state_changed):
main_window.show_card_data_update_available_message_box(10000)
thread_pool_start.assert_not_called()
import_from_api.assert_not_called()
- assert_that(ui.action_download_card_data.isEnabled(), is_(True))
def test_accepting_card_data_update_offer_results_in_performed_action(qtbot: QtBot, main_window: MainWindow):
ui = main_window.ui
ui.action_download_card_data.setEnabled(True)
@@ -155,11 +151,10 @@
"question", return_value=StandardButton.Yes) as message_box, \
unittest.mock.patch.object(QThreadPool.globalInstance(), "start") as thread_pool_start:
main_window.show_card_data_update_available_message_box(10000)
message_box.assert_called_once()
thread_pool_start.assert_called_once()
- assert_that(ui.action_download_card_data.isEnabled(), is_(False))
def test_action_download_card_data_is_enabled_after_network_error(qtbot: QtBot, main_window: MainWindow):
ui = main_window.ui
ui.action_download_card_data.setEnabled(False)
Index: tests/ui/test_page_config_container.py
==================================================================
--- tests/ui/test_page_config_container.py
+++ tests/ui/test_page_config_container.py
@@ -11,11 +11,11 @@
# 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 .
-from PyQt5.QtWidgets import QCheckBox, QDoubleSpinBox, QLineEdit
+from PySide6.QtWidgets import QCheckBox, QDoubleSpinBox, QLineEdit
import pytest
from pytestqt.qtbot import QtBot
from hamcrest import *
Index: tests/ui/test_page_config_dialog.py
==================================================================
--- tests/ui/test_page_config_dialog.py
+++ tests/ui/test_page_config_dialog.py
@@ -13,11 +13,11 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
import pytest
-from PyQt5.QtWidgets import QDialogButtonBox
+from PySide6.QtWidgets import QDialogButtonBox
from mtg_proxy_printer.ui.dialogs import DocumentSettingsDialog
StandardButton = QDialogButtonBox.StandardButton
def test__init__(qtbot, document_light):
Index: tests/ui/test_page_config_widget.py
==================================================================
--- tests/ui/test_page_config_widget.py
+++ tests/ui/test_page_config_widget.py
@@ -14,11 +14,11 @@
# along with this program. If not, see .
from unittest.mock import patch
import pint
-from PyQt5.QtWidgets import QDoubleSpinBox, QCheckBox, QLineEdit
+from PySide6.QtWidgets import QDoubleSpinBox, QCheckBox, QLineEdit
from hamcrest import *
import pytest
from pytestqt.qtbot import QtBot
@@ -120,10 +120,11 @@
line_edit: QLineEdit = getattr(ui, attribute_name)
new_value = "Test"
with qtbot.waitSignals([line_edit.textChanged, widget.page_layout_changed], timeout=100):
line_edit.setText(new_value)
assert_that(widget.page_layout, has_property(attribute_name, equal_to(new_value)))
+
ZeroMarginsSettings = {
"paper-height": "297 mm",
"paper-width": "210 mm",
Index: tests/ui/test_page_renderer.py
==================================================================
--- tests/ui/test_page_renderer.py
+++ tests/ui/test_page_renderer.py
@@ -15,12 +15,12 @@
from unittest.mock import patch
import pytest
from hamcrest import *
-from PyQt5.QtCore import QEvent
-from PyQt5.QtWidgets import QAction
+from PySide6.QtCore import QEvent
+from PySide6.QtGui import QAction
from mtg_proxy_printer.ui.page_renderer import PageRenderer, ZoomDirection
PATH_PREFIX = "mtg_proxy_printer.ui.page_renderer."
@@ -52,6 +52,6 @@
@pytest.mark.parametrize("zoom_action, direction", [
("zoom_in_action", ZoomDirection.IN), ("zoom_out_action", ZoomDirection.OUT)])
def test_renderer_zoom_action_triggers_zoom(renderer: PageRenderer, zoom_action: str, direction: ZoomDirection):
action: QAction = getattr(renderer, zoom_action)
action.trigger()
- renderer._perform_zoom_step.assert_called_once_with(direction, False)
+ renderer._perform_zoom_step.assert_called_once_with(direction)
Index: tests/ui/test_page_scene.py
==================================================================
--- tests/ui/test_page_scene.py
+++ tests/ui/test_page_scene.py
@@ -21,13 +21,13 @@
from math import ceil
from hamcrest import *
import pytest
-from PyQt5.QtWidgets import QGraphicsPixmapItem, QGraphicsLineItem
-from PyQt5.QtGui import QPalette, QColorConstants, QPixmap, QImage, QColor, QPainter
-from PyQt5.QtCore import QPoint
+from PySide6.QtWidgets import QGraphicsPixmapItem, QGraphicsLineItem
+from PySide6.QtGui import QPalette, QColorConstants, QPixmap, QImage, QColor, QPainter
+from PySide6.QtCore import QPoint
from mtg_proxy_printer.units_and_sizes import PageType, CardSizes, CardSize, UnitT, unit_registry, QuantityT
from mtg_proxy_printer.ui.page_scene import RenderMode, PageScene
from mtg_proxy_printer.document_controller.card_actions import ActionAddCard, ActionRemoveCards
from mtg_proxy_printer.document_controller.compact_document import ActionCompactDocument
Index: tests/ui/test_progress_bar.py
==================================================================
--- tests/ui/test_progress_bar.py
+++ tests/ui/test_progress_bar.py
@@ -13,11 +13,11 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
from hamcrest import *
import pytest
-from PyQt5.QtWidgets import QWidget
+from PySide6.QtWidgets import QWidget
from pytestqt.qtbot import QtBot
from mtg_proxy_printer.ui.progress_bar import ProgressBar
from tests.hasgetter import has_getters