Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PyQt enums patch #352

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions Qt.py
Original file line number Diff line number Diff line change
Expand Up @@ -1800,6 +1800,30 @@ def __call__(self, *a, **kw):
raise NotImplementedError(self.__err)


def _pyqt_enums_patch():
"""Patch ``PyQt*`` Qt namespace enums to behave like ``PySide*``.

i.e. ``PyQt*`` only has Qt.Checked and Qt.CheckState, but not ``PySide*``
Qt.CheckState.Checked attribute or Qt.CheckState.values dictionary.
"""
qt_attrs = {
name: getattr(Qt.QtCore.Qt, name)
for name in dir(Qt.QtCore.Qt)
if not name.startswith("_")
}
Comment on lines +1810 to +1814
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one for example could (and likely is) pick up enums other than the 2 being fixed by this PR.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, it was the original intention to be able to capture all cases found, not just CheckState only. The description in the PR could probably do with a better wording to highlight it.


known_enums = set()
for attr_name, enum_class in qt_attrs.items():
j0yu marked this conversation as resolved.
Show resolved Hide resolved
if inspect.isclass(enum_class) and issubclass(enum_class, int):
j0yu marked this conversation as resolved.
Show resolved Hide resolved
known_enums.add(enum_class)
enum_class.values = {}

for attr_name, attr in qt_attrs.items():
if isinstance(attr, int) and attr.__class__ in known_enums:
attr.__class__.values[attr_name] = attr
setattr(attr.__class__, attr_name, attr)


def _install():
# Default order (customize order and content via QT_PREFERRED_BINDING)
default_order = ("PySide2", "PyQt5", "PySide", "PyQt4")
Expand Down Expand Up @@ -1915,6 +1939,12 @@ def _install():
if hasattr(Qt.QtCompat, 'loadUi'):
Qt.QtCompat.load_ui = Qt.QtCompat.loadUi

if Qt.__binding__.startswith("PyQt"):
if getattr(getattr(Qt, "QtCore", None), "Qt", None) is None:
_warn("Qt.QtCore.Qt not available. Not applying enums patch.")
else:
_pyqt_enums_patch()


_install()

Expand Down
39 changes: 39 additions & 0 deletions tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1159,3 +1159,42 @@ def test_multiple_preferred():
assert Qt.__binding__ == "PyQt4", (
"PyQt4 should have been picked, "
"instead got %s" % Qt.__binding__)

def test_pyqt_enums():
"""Check some known enums/flags mappings."""
from Qt import QtCore

class_attributes = { # Version agnostic flags and enums
"CheckState": ["Checked", "Unchecked", "PartiallyChecked"],
"Orientation": ["Horizontal", "Vertical"],
}
for class_name, attributes in class_attributes.items():
qt_class = getattr(QtCore.Qt, class_name)

values_path = "QtCore.Qt.{0}.{1}".format(class_name, "values")
assert hasattr(qt_class, "values"), (
"{0} should exist, but is missing".format(values_path))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is very hard to read

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I switched to %s notations in newest commits


cls_values = getattr(qt_class, "values", None)
assert cls_values and isinstance(cls_values, dict), (
"{0} should be a non-empty dictionary, "
"not {1}".format(values_path, cls_values))

for attr_name in attributes:
attr_path = "QtCore.Qt.{0}.{1}".format(class_name, attr_name)

assert hasattr(qt_class, attr_name), (
"{0} should exist, but is missing".format(attr_path))

value = getattr(qt_class, attr_name, None)
assert value is not None, (
"{0} shouldn't be None".format(attr_path))

assert attr_name in cls_values, (
"{0} key should exist in {1} "
"dict".format(attr_name, values_path))

cls_value = cls_values[attr_name]
assert value == cls_values[attr_name], (
"({0}) {1!r} != {2!r} ({3}[{4}])".format(
attr_path, value, cls_value, values_path, attr_name))
j0yu marked this conversation as resolved.
Show resolved Hide resolved