Skip to content

Commit

Permalink
PR: Improve enum to flags aliasing for PyQt6 and PySide6 > 6.3 and `Q…
Browse files Browse the repository at this point in the history
…FileDialog` static methods kwarg compatibility (#449)
  • Loading branch information
ccordoba12 authored Aug 24, 2023
2 parents b5a8bb6 + 335687d commit 6ae5759
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 32 deletions.
13 changes: 10 additions & 3 deletions qtpy/QtCore.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
"""Provides QtCore classes and functions."""
from typing import TYPE_CHECKING

from . import PYQT6, PYQT5, PYSIDE2, PYSIDE6
from packaging.version import parse

from . import PYQT6, PYQT5, PYSIDE2, PYSIDE6, QT_VERSION as _qt_version
from ._utils import possibly_static_exec, possibly_static_exec_

if PYQT5:
Expand Down Expand Up @@ -69,10 +71,11 @@
# Alias for MiddleButton removed in PyQt6 but available in PyQt5, PySide2 and PySide6
Qt.MidButton = Qt.MiddleButton

# Add removed definition for `Qt.ItemFlags` as an alias of `Qt.ItemFlag` as PySide6 does.
# Add removed definition for `Qt.ItemFlags` as an alias of `Qt.ItemFlag`
# passing as default value 0 in the same way PySide6 6.5+ does.
# Note that for PyQt5 and PySide2 those definitions are two different classes
# (one is the flag definition and the other the enum definition)
Qt.ItemFlags = Qt.ItemFlag
Qt.ItemFlags = lambda value=0: Qt.ItemFlag(value)

elif PYSIDE2:
from PySide2.QtCore import *
Expand Down Expand Up @@ -117,6 +120,10 @@
QThread.exec_ = lambda self, *args, **kwargs: self.exec(*args, **kwargs)
QTextStreamManipulator.exec_ = lambda self, *args, **kwargs: self.exec(*args, **kwargs)

# Passing as default value 0 in the same way PySide6 6.3.2 does for the `Qt.ItemFlags` definition.
if parse(_qt_version) > parse('6.3'):
Qt.ItemFlags = lambda value=0: Qt.ItemFlag(value)

# For issue #153 and updated for issue #305
if PYQT5 or PYQT6:
QDate.toPython = lambda self, *args, **kwargs: self.toPyDate(*args, **kwargs)
Expand Down
70 changes: 42 additions & 28 deletions qtpy/QtWidgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@
# -----------------------------------------------------------------------------

"""Provides widget classes and functions."""
from functools import partialmethod, wraps
from functools import partialmethod

from packaging.version import parse

from . import PYQT5, PYQT6, PYSIDE2, PYSIDE6, QT_VERSION as _qt_version
from ._utils import add_action, possibly_static_exec, getattr_missing_optional_dep
from ._utils import (
add_action,
possibly_static_exec,
getattr_missing_optional_dep,
static_method_kwargs_wrapper
)


_missing_optional_names = {}
Expand All @@ -23,22 +28,6 @@ def __getattr__(name):
raise getattr_missing_optional_dep(
name, module_name=__name__, optional_names=_missing_optional_names)

def _dir_to_directory(func):
@wraps(func)
def _dir_to_directory_(*args, **kwargs):
if "dir" in kwargs:
kwargs["directory"] = kwargs.pop("dir")
return func(*args, **kwargs)
return _dir_to_directory_

def _directory_to_dir(func):
@wraps(func)
def _directory_to_dir_(*args, **kwargs):
if "directory" in kwargs:
kwargs["dir"] = kwargs.pop("directory")
return func(*args, **kwargs)
return _directory_to_dir_


if PYQT5:
from PyQt5.QtWidgets import *
Expand Down Expand Up @@ -71,8 +60,11 @@ def _directory_to_dir_(*args, **kwargs):
QMenu.exec_ = lambda *args, **kwargs: possibly_static_exec(QMenu, *args, **kwargs)
QLineEdit.getTextMargins = lambda self: (self.textMargins().left(), self.textMargins().top(), self.textMargins().right(), self.textMargins().bottom())

# Map missing flags definitions
QFileDialog.Options = QFileDialog.Option
# Add removed definition for `QFileDialog.Options` as an alias of `QFileDialog.Option`
# passing as default value 0 in the same way PySide6 6.5+ does.
# Note that for PyQt5 and PySide2 those definitions are two different classes
# (one is the flag definition and the other the enum definition)
QFileDialog.Options = lambda value=0: QFileDialog.Option(value)

# Allow unscoped access for enums inside the QtWidgets module
from .enums_compat import promote_enums
Expand Down Expand Up @@ -108,17 +100,39 @@ def _directory_to_dir_(*args, **kwargs):
QDialog.exec_ = lambda self, *args, **kwargs: self.exec(*args, **kwargs)
QMenu.exec_ = lambda *args, **kwargs: possibly_static_exec(QMenu, *args, **kwargs)

# Passing as default value 0 in the same way PySide6 < 6.3.2 does for the `QFileDialog.Options` definition.
if parse(_qt_version) > parse('6.3'):
QFileDialog.Options = lambda value=0: QFileDialog.Option(value)


if PYSIDE2 or PYSIDE6:
QFileDialog.getExistingDirectory = _directory_to_dir(QFileDialog.getExistingDirectory)
QFileDialog.getOpenFileName = _directory_to_dir(QFileDialog.getOpenFileName)
QFileDialog.getOpenFileNames = _directory_to_dir(QFileDialog.getOpenFileNames)
QFileDialog.getSaveFileName = _directory_to_dir(QFileDialog.getSaveFileName)
# Make PySide2/6 `QFileDialog` static methods accept the `directory` kwarg as `dir`
QFileDialog.getExistingDirectory = static_method_kwargs_wrapper(
QFileDialog.getExistingDirectory, "directory", "dir"
)
QFileDialog.getOpenFileName = static_method_kwargs_wrapper(
QFileDialog.getOpenFileName, "directory", "dir"
)
QFileDialog.getOpenFileNames = static_method_kwargs_wrapper(
QFileDialog.getOpenFileNames, "directory", "dir"
)
QFileDialog.getSaveFileName = static_method_kwargs_wrapper(
QFileDialog.getSaveFileName, "directory", "dir"
)
else:
QFileDialog.getExistingDirectory = _dir_to_directory(QFileDialog.getExistingDirectory)
QFileDialog.getOpenFileName = _dir_to_directory(QFileDialog.getOpenFileName)
QFileDialog.getOpenFileNames = _dir_to_directory(QFileDialog.getOpenFileNames)
QFileDialog.getSaveFileName = _dir_to_directory(QFileDialog.getSaveFileName)
# Make PyQt5/6 `QFileDialog` static methods accept the `dir` kwarg as `directory`
QFileDialog.getExistingDirectory = static_method_kwargs_wrapper(
QFileDialog.getExistingDirectory, "dir", "directory"
)
QFileDialog.getOpenFileName = static_method_kwargs_wrapper(
QFileDialog.getOpenFileName, "dir", "directory"
)
QFileDialog.getOpenFileNames = static_method_kwargs_wrapper(
QFileDialog.getOpenFileNames, "dir", "directory"
)
QFileDialog.getSaveFileName = static_method_kwargs_wrapper(
QFileDialog.getSaveFileName, "dir", "directory"
)

# Make `addAction` compatible with Qt6 >= 6.3
if PYQT5 or PYSIDE2 or parse(_qt_version) < parse('6.3'):
Expand Down
16 changes: 16 additions & 0 deletions qtpy/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
# -----------------------------------------------------------------------------

"""Provides utility functions for use by QtPy itself."""
from functools import wraps

import qtpy

Expand Down Expand Up @@ -112,3 +113,18 @@ def add_action(self, *args, old_add_action):
return old_add_action(self, *args)
return action
return old_add_action(self, *args)


def static_method_kwargs_wrapper(func, from_kwarg_name, to_kwarg_name):
"""
Helper function to manage `from_kwarg_name` to `to_kwarg_name` kwargs name changes in static methods.
Makes static methods accept the `from_kwarg_name` kwarg as `to_kwarg_name`.
"""
@staticmethod
@wraps(func)
def _from_kwarg_name_to_kwarg_name_(*args, **kwargs):
if from_kwarg_name in kwargs:
kwargs[to_kwarg_name] = kwargs.pop(from_kwarg_name)
return func(*args, **kwargs)
return _from_kwarg_name_to_kwarg_name_
1 change: 1 addition & 0 deletions qtpy/tests/test_qtcore.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,3 +179,4 @@ def test_itemflags_typedef():
Test existence of `QFlags<ItemFlag>` typedef `ItemFlags` that was removed from PyQt6
"""
assert QtCore.Qt.ItemFlags is not None
assert QtCore.Qt.ItemFlags() == QtCore.Qt.ItemFlag(0)
3 changes: 2 additions & 1 deletion qtpy/tests/test_qtwidgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,4 +236,5 @@ def test_qfiledialog_flags_typedef():
"""
Test existence of `QFlags<Option>` typedef `Options` that was removed from PyQt6
"""
assert QtWidgets.QFileDialog.Options is not None
assert QtWidgets.QFileDialog.Options is not None
assert QtWidgets.QFileDialog.Options() == QtWidgets.QFileDialog.Option(0)

0 comments on commit 6ae5759

Please sign in to comment.