From 28b7887f585e75f0decfe3177f004329358fc9d4 Mon Sep 17 00:00:00 2001 From: Julien Schueller Date: Tue, 12 Oct 2021 17:19:28 +0200 Subject: [PATCH] Nuke Qt4 support Closes #70 --- README.md | 9 +- qtpy/QtCore.py | 72 +----------- qtpy/QtDesigner.py | 4 +- qtpy/QtGui.py | 142 +---------------------- qtpy/QtHelp.py | 6 +- qtpy/QtMultimedia.py | 8 -- qtpy/QtNetwork.py | 6 +- qtpy/QtOpenGL.py | 7 +- qtpy/QtPrintSupport.py | 10 +- qtpy/QtSql.py | 7 +- qtpy/QtSvg.py | 7 +- qtpy/QtTest.py | 11 +- qtpy/QtWebEngineWidgets.py | 12 +- qtpy/QtWidgets.py | 115 +----------------- qtpy/QtXmlPatterns.py | 6 +- qtpy/__init__.py | 95 +-------------- qtpy/_patch/qcombobox.py | 101 ---------------- qtpy/compat.py | 64 ++-------- qtpy/tests/conftest.py | 16 +-- qtpy/tests/runtests.py | 2 +- qtpy/tests/test_main.py | 38 +----- qtpy/tests/test_patch_qcombobox.py | 107 ----------------- qtpy/tests/test_patch_qheaderview.py | 23 +--- qtpy/tests/test_qdesktopservice_split.py | 15 --- qtpy/tests/test_qtdesigner.py | 4 +- qtpy/tests/test_qtnetwork.py | 17 ++- qtpy/tests/test_qtxmlpatterns.py | 4 +- qtpy/tests/test_uic.py | 6 +- qtpy/uic.py | 15 +-- setup.py | 4 +- 30 files changed, 64 insertions(+), 869 deletions(-) delete mode 100644 qtpy/_patch/qcombobox.py delete mode 100644 qtpy/tests/test_patch_qcombobox.py diff --git a/README.md b/README.md index 3f6e46b7..59691109 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# QtPy: Abstraction layer for PyQt5/PyQt4/PySide2/PySide +# QtPy: Abstraction layer for PyQt5/PyQt6/PySide2/PySide6 [![license](https://img.shields.io/pypi/l/qtpy.svg)](./LICENSE) [![pypi version](https://img.shields.io/pypi/v/qtpy.svg)](https://pypi.org/project/QtPy/) @@ -18,7 +18,7 @@ **QtPy** is a small abstraction layer that lets you write applications using a single API call to either PyQt or PySide. -It provides support for PyQt5, PyQt4, PySide6, PySide2 and PySide using the Qt5 layout +It provides support for PyQt5, PyQt6, PySide6, PySide2 using the Qt5 layout (where the QtGui module has been split into QtGui and QtWidgets). Basically, you can write your code as if you were using PySide2 @@ -45,17 +45,16 @@ This project is released under the MIT license. ### Requirements -You need PyQt5, PyQt4, PySide2 or PySide installed in your system to make use +You need PyQt5, PyQt6, PySide2 or PySide6 installed in your system to make use of QtPy. If several of these packages are found, PyQt5 is used by default unless you set the `QT_API` environment variable. `QT_API` can take the following values: * `pyqt5` (to use PyQt5). -* `pyqt` or `pyqt4` (to use PyQt4). +* `pyqt6` (to use PyQt6). * `pyside6` (to use PySide6) * `pyside2` (to use PySide2) -* `pyside` (to use PySide). ### Installation diff --git a/qtpy/QtCore.py b/qtpy/QtCore.py index b353a0dc..a6142bf9 100644 --- a/qtpy/QtCore.py +++ b/qtpy/QtCore.py @@ -10,7 +10,7 @@ Provides QtCore classes and functions. """ -from . import PYQT6, PYQT5, PYSIDE2, PYSIDE6, PYQT4, PYSIDE, PythonQtError +from . import PYQT6, PYQT5, PYSIDE2, PYSIDE6, PythonQtError if PYQT6: from PyQt6.QtCore import * @@ -54,75 +54,5 @@ import PySide2.QtCore __version__ = PySide2.QtCore.__version__ -elif PYQT4: - from PyQt4.QtCore import * - # Those are things we inherited from Spyder that fix crazy crashes under - # some specific situations. (See #34) - from PyQt4.QtCore import QCoreApplication - from PyQt4.QtCore import Qt - from PyQt4.QtCore import pyqtSignal as Signal - from PyQt4.QtCore import pyqtBoundSignal as SignalInstance - from PyQt4.QtCore import pyqtSlot as Slot - from PyQt4.QtCore import pyqtProperty as Property - from PyQt4.QtGui import (QItemSelection, QItemSelectionModel, - QItemSelectionRange, QSortFilterProxyModel, - QStringListModel) - from PyQt4.QtCore import QT_VERSION_STR as __version__ - from PyQt4.QtCore import qInstallMsgHandler as qInstallMessageHandler - - # QDesktopServices has has been split into (QDesktopServices and - # QStandardPaths) in Qt5 - # This creates a dummy class that emulates QStandardPaths - from PyQt4.QtGui import QDesktopServices as _QDesktopServices - - class QStandardPaths(): - StandardLocation = _QDesktopServices.StandardLocation - displayName = _QDesktopServices.displayName - DesktopLocation = _QDesktopServices.DesktopLocation - DocumentsLocation = _QDesktopServices.DocumentsLocation - FontsLocation = _QDesktopServices.FontsLocation - ApplicationsLocation = _QDesktopServices.ApplicationsLocation - MusicLocation = _QDesktopServices.MusicLocation - MoviesLocation = _QDesktopServices.MoviesLocation - PicturesLocation = _QDesktopServices.PicturesLocation - TempLocation = _QDesktopServices.TempLocation - HomeLocation = _QDesktopServices.HomeLocation - DataLocation = _QDesktopServices.DataLocation - CacheLocation = _QDesktopServices.CacheLocation - writableLocation = _QDesktopServices.storageLocation - - # Those are imported from `import *` - del pyqtSignal, pyqtBoundSignal, pyqtSlot, pyqtProperty, QT_VERSION_STR, qInstallMsgHandler -elif PYSIDE: - from PySide.QtCore import * - from PySide.QtGui import (QItemSelection, QItemSelectionModel, - QItemSelectionRange, QSortFilterProxyModel, - QStringListModel) - from PySide.QtCore import qInstallMsgHandler as qInstallMessageHandler - del qInstallMsgHandler - - # QDesktopServices has has been split into (QDesktopServices and - # QStandardPaths) in Qt5 - # This creates a dummy class that emulates QStandardPaths - from PySide.QtGui import QDesktopServices as _QDesktopServices - - class QStandardPaths(): - StandardLocation = _QDesktopServices.StandardLocation - displayName = _QDesktopServices.displayName - DesktopLocation = _QDesktopServices.DesktopLocation - DocumentsLocation = _QDesktopServices.DocumentsLocation - FontsLocation = _QDesktopServices.FontsLocation - ApplicationsLocation = _QDesktopServices.ApplicationsLocation - MusicLocation = _QDesktopServices.MusicLocation - MoviesLocation = _QDesktopServices.MoviesLocation - PicturesLocation = _QDesktopServices.PicturesLocation - TempLocation = _QDesktopServices.TempLocation - HomeLocation = _QDesktopServices.HomeLocation - DataLocation = _QDesktopServices.DataLocation - CacheLocation = _QDesktopServices.CacheLocation - writableLocation = _QDesktopServices.storageLocation - - import PySide.QtCore - __version__ = PySide.QtCore.__version__ else: raise PythonQtError('No Qt bindings could be found') diff --git a/qtpy/QtDesigner.py b/qtpy/QtDesigner.py index 4aaafc81..04576785 100644 --- a/qtpy/QtDesigner.py +++ b/qtpy/QtDesigner.py @@ -9,12 +9,10 @@ Provides QtDesigner classes and functions. """ -from . import PYQT5, PYQT4, PythonQtError +from . import PYQT5, PythonQtError if PYQT5: from PyQt5.QtDesigner import * -elif PYQT4: - from PyQt4.QtDesigner import * else: raise PythonQtError('No Qt bindings could be found') diff --git a/qtpy/QtGui.py b/qtpy/QtGui.py index 90c074a4..62c0ee7c 100644 --- a/qtpy/QtGui.py +++ b/qtpy/QtGui.py @@ -8,13 +8,10 @@ """ Provides QtGui classes and functions. -.. warning:: Only PyQt4/PySide QtGui classes compatible with PyQt5.QtGui are - exposed here. Therefore, you need to treat/use this package as if it were - the ``PyQt5.QtGui`` module. """ import warnings -from . import PYQT6, PYQT5, PYQT4, PYSIDE, PYSIDE2, PYSIDE6, PythonQtError +from . import PYQT6, PYQT5, PYSIDE2, PYSIDE6, PythonQtError if PYQT6: @@ -26,142 +23,5 @@ elif PYSIDE6: from PySide6.QtGui import * QFontMetrics.width = QFontMetrics.horizontalAdvance - -elif PYQT4: - try: - # Older versions of PyQt4 do not provide these - from PyQt4.QtGui import (QGlyphRun, QMatrix2x2, QMatrix2x3, - QMatrix2x4, QMatrix3x2, QMatrix3x3, - QMatrix3x4, QMatrix4x2, QMatrix4x3, - QMatrix4x4, QTouchEvent, QQuaternion, - QRadialGradient, QRawFont, QStaticText, - QVector2D, QVector3D, QVector4D, - qFuzzyCompare) - except ImportError: - pass - try: - from PyQt4.Qt import QKeySequence, QTextCursor - except ImportError: - # In PyQt4-sip 4.19.13 QKeySequence and QTextCursor are in PyQt4.QtGui - from PyQt4.QtGui import QKeySequence, QTextCursor - from PyQt4.QtGui import (QAbstractTextDocumentLayout, QActionEvent, QBitmap, - QBrush, QClipboard, QCloseEvent, QColor, - QConicalGradient, QContextMenuEvent, QCursor, - QDoubleValidator, QDrag, - QDragEnterEvent, QDragLeaveEvent, QDragMoveEvent, - QDropEvent, QFileOpenEvent, QFocusEvent, QFont, - QFontDatabase, QFontInfo, QFontMetrics, - QFontMetricsF, QGradient, QHelpEvent, - QHideEvent, QHoverEvent, QIcon, QIconDragEvent, - QIconEngine, QImage, QImageIOHandler, QImageReader, - QImageWriter, QInputEvent, QInputMethodEvent, - QKeyEvent, QLinearGradient, - QMouseEvent, QMoveEvent, QMovie, - QPaintDevice, QPaintEngine, QPaintEngineState, - QPaintEvent, QPainter, QPainterPath, - QPainterPathStroker, QPalette, QPen, QPicture, - QPictureIO, QPixmap, QPixmapCache, QPolygon, - QPolygonF, QRegExpValidator, QRegion, QResizeEvent, - QSessionManager, QShortcutEvent, QShowEvent, - QStandardItem, QStandardItemModel, - QStatusTipEvent, QSyntaxHighlighter, QTabletEvent, - QTextBlock, QTextBlockFormat, QTextBlockGroup, - QTextBlockUserData, QTextCharFormat, - QTextDocument, QTextDocumentFragment, - QTextDocumentWriter, QTextFormat, QTextFragment, - QTextFrame, QTextFrameFormat, QTextImageFormat, - QTextInlineObject, QTextItem, QTextLayout, - QTextLength, QTextLine, QTextList, QTextListFormat, - QTextObject, QTextObjectInterface, QTextOption, - QTextTable, QTextTableCell, QTextTableCellFormat, - QTextTableFormat, QTransform, - QValidator, QWhatsThisClickedEvent, QWheelEvent, - QWindowStateChangeEvent, qAlpha, qBlue, - qGray, qGreen, qIsGray, qRed, qRgb, - qRgba, QIntValidator) - - # QDesktopServices has has been split into (QDesktopServices and - # QStandardPaths) in Qt5 - # It only exposes QDesktopServices that are still in pyqt5 - from PyQt4.QtGui import QDesktopServices as _QDesktopServices - - class QDesktopServices(): - openUrl = _QDesktopServices.openUrl - setUrlHandler = _QDesktopServices.setUrlHandler - unsetUrlHandler = _QDesktopServices.unsetUrlHandler - - def __getattr__(self, name): - attr = getattr(_QDesktopServices, name) - - new_name = name - if name == 'storageLocation': - new_name = 'writableLocation' - warnings.warn(("Warning QDesktopServices.{} is deprecated in Qt5" - "we recommend you use QDesktopServices.{} instead").format(name, new_name), - DeprecationWarning) - return attr - QDesktopServices = QDesktopServices() - -elif PYSIDE: - from PySide.QtGui import (QAbstractTextDocumentLayout, QActionEvent, QBitmap, - QBrush, QClipboard, QCloseEvent, QColor, - QConicalGradient, QContextMenuEvent, QCursor, - QDoubleValidator, QDrag, - QDragEnterEvent, QDragLeaveEvent, QDragMoveEvent, - QDropEvent, QFileOpenEvent, QFocusEvent, QFont, - QFontDatabase, QFontInfo, QFontMetrics, - QFontMetricsF, QGradient, QHelpEvent, - QHideEvent, QHoverEvent, QIcon, QIconDragEvent, - QIconEngine, QImage, QImageIOHandler, QImageReader, - QImageWriter, QInputEvent, QInputMethodEvent, - QKeyEvent, QKeySequence, QLinearGradient, - QMatrix2x2, QMatrix2x3, QMatrix2x4, QMatrix3x2, - QMatrix3x3, QMatrix3x4, QMatrix4x2, QMatrix4x3, - QMatrix4x4, QMouseEvent, QMoveEvent, QMovie, - QPaintDevice, QPaintEngine, QPaintEngineState, - QPaintEvent, QPainter, QPainterPath, - QPainterPathStroker, QPalette, QPen, QPicture, - QPictureIO, QPixmap, QPixmapCache, QPolygon, - QPolygonF, QQuaternion, QRadialGradient, - QRegExpValidator, QRegion, QResizeEvent, - QSessionManager, QShortcutEvent, QShowEvent, - QStandardItem, QStandardItemModel, - QStatusTipEvent, QSyntaxHighlighter, QTabletEvent, - QTextBlock, QTextBlockFormat, QTextBlockGroup, - QTextBlockUserData, QTextCharFormat, QTextCursor, - QTextDocument, QTextDocumentFragment, - QTextFormat, QTextFragment, - QTextFrame, QTextFrameFormat, QTextImageFormat, - QTextInlineObject, QTextItem, QTextLayout, - QTextLength, QTextLine, QTextList, QTextListFormat, - QTextObject, QTextObjectInterface, QTextOption, - QTextTable, QTextTableCell, QTextTableCellFormat, - QTextTableFormat, QTouchEvent, QTransform, - QValidator, QVector2D, QVector3D, QVector4D, - QWhatsThisClickedEvent, QWheelEvent, - QWindowStateChangeEvent, qAlpha, qBlue, - qGray, qGreen, qIsGray, qRed, qRgb, qRgba, - QIntValidator) - # QDesktopServices has has been split into (QDesktopServices and - # QStandardPaths) in Qt5 - # It only exposes QDesktopServices that are still in pyqt5 - from PySide.QtGui import QDesktopServices as _QDesktopServices - - class QDesktopServices(): - openUrl = _QDesktopServices.openUrl - setUrlHandler = _QDesktopServices.setUrlHandler - unsetUrlHandler = _QDesktopServices.unsetUrlHandler - - def __getattr__(self, name): - attr = getattr(_QDesktopServices, name) - - new_name = name - if name == 'storageLocation': - new_name = 'writableLocation' - warnings.warn(("Warning QDesktopServices.{} is deprecated in Qt5" - "we recommend you use QDesktopServices.{} instead").format(name, new_name), - DeprecationWarning) - return attr - QDesktopServices = QDesktopServices() else: raise PythonQtError('No Qt bindings could be found') diff --git a/qtpy/QtHelp.py b/qtpy/QtHelp.py index bbd44036..de06baf7 100644 --- a/qtpy/QtHelp.py +++ b/qtpy/QtHelp.py @@ -9,7 +9,7 @@ import warnings -from . import PYQT5, PYQT4, PYSIDE6, PYSIDE2, PYSIDE +from . import PYQT5, PYSIDE6, PYSIDE2 if PYQT5: from PyQt5.QtHelp import * @@ -17,7 +17,3 @@ from PySide6.QtHelp import * elif PYSIDE2: from PySide2.QtHelp import * -elif PYQT4: - from PyQt4.QtHelp import * -elif PYSIDE: - from PySide.QtHelp import * diff --git a/qtpy/QtMultimedia.py b/qtpy/QtMultimedia.py index 96d7e906..88cbdf10 100644 --- a/qtpy/QtMultimedia.py +++ b/qtpy/QtMultimedia.py @@ -1,8 +1,6 @@ import warnings from . import PYQT5 -from . import PYQT4 -from . import PYSIDE from . import PYSIDE2 from . import PYSIDE6 @@ -12,9 +10,3 @@ from PySide6.QtMultimedia import * elif PYSIDE2: from PySide2.QtMultimedia import * -elif PYQT4: - from PyQt4.QtMultimedia import * - from PyQt4.QtGui import QSound -elif PYSIDE: - from PySide.QtMultimedia import * - from PySide.QtGui import QSound diff --git a/qtpy/QtNetwork.py b/qtpy/QtNetwork.py index d8b6aa87..c1fcd588 100644 --- a/qtpy/QtNetwork.py +++ b/qtpy/QtNetwork.py @@ -10,7 +10,7 @@ Provides QtNetwork classes and functions. """ -from . import PYQT5, PYSIDE2, PYSIDE6, PYQT4, PYSIDE, PythonQtError +from . import PYQT5, PYSIDE2, PYSIDE6, PythonQtError if PYQT5: @@ -19,9 +19,5 @@ from PySide6.QtNetwork import * elif PYSIDE2: from PySide2.QtNetwork import * -elif PYQT4: - from PyQt4.QtNetwork import * -elif PYSIDE: - from PySide.QtNetwork import * else: raise PythonQtError('No Qt bindings could be found') diff --git a/qtpy/QtOpenGL.py b/qtpy/QtOpenGL.py index 5b3a80d7..aaa8cd2b 100644 --- a/qtpy/QtOpenGL.py +++ b/qtpy/QtOpenGL.py @@ -8,7 +8,7 @@ """Provides QtOpenGL classes and functions.""" # Local imports -from . import PYQT4, PYQT5, PYSIDE, PYSIDE2, PythonQtError +from . import PYQT5, PYSIDE2, PythonQtError if PYQT5: from PyQt5.QtOpenGL import * @@ -16,11 +16,6 @@ from PySide6.QtOpenGL import * elif PYSIDE2: from PySide2.QtOpenGL import * -elif PYQT4: - from PyQt4.QtOpenGL import * -elif PYSIDE: - from PySide.QtOpenGL import * else: raise PythonQtError('No Qt bindings could be found') -del PYQT4, PYQT5, PYSIDE, PYSIDE2 diff --git a/qtpy/QtPrintSupport.py b/qtpy/QtPrintSupport.py index d7f4ff10..872d8179 100644 --- a/qtpy/QtPrintSupport.py +++ b/qtpy/QtPrintSupport.py @@ -9,7 +9,7 @@ Provides QtPrintSupport classes and functions. """ -from . import PYQT5, PYQT4, PYSIDE6, PYSIDE2, PYSIDE, PythonQtError +from . import PYQT5, PYSIDE6, PYSIDE2, PythonQtError if PYQT5: @@ -18,13 +18,5 @@ from PySide6.QtPrintSupport import * elif PYSIDE2: from PySide2.QtPrintSupport import * -elif PYQT4: - from PyQt4.QtGui import (QAbstractPrintDialog, QPageSetupDialog, - QPrintDialog, QPrintEngine, QPrintPreviewDialog, - QPrintPreviewWidget, QPrinter, QPrinterInfo) -elif PYSIDE: - from PySide.QtGui import (QAbstractPrintDialog, QPageSetupDialog, - QPrintDialog, QPrintEngine, QPrintPreviewDialog, - QPrintPreviewWidget, QPrinter, QPrinterInfo) else: raise PythonQtError('No Qt bindings could be found') diff --git a/qtpy/QtSql.py b/qtpy/QtSql.py index 583e5cb0..0c8dcb3b 100644 --- a/qtpy/QtSql.py +++ b/qtpy/QtSql.py @@ -8,7 +8,7 @@ """Provides QtSql classes and functions.""" # Local imports -from . import PYQT5, PYSIDE6, PYSIDE2, PYQT4, PYSIDE, PythonQtError +from . import PYQT5, PYSIDE6, PYSIDE2, PythonQtError if PYQT5: from PyQt5.QtSql import * @@ -16,11 +16,6 @@ from PySide6.QtSql import * elif PYSIDE2: from PySide2.QtSql import * -elif PYQT4: - from PyQt4.QtSql import * -elif PYSIDE: - from PySide.QtSql import * else: raise PythonQtError('No Qt bindings could be found') -del PYQT4, PYQT5, PYSIDE, PYSIDE2 diff --git a/qtpy/QtSvg.py b/qtpy/QtSvg.py index ccc3fbd3..cb99e12c 100644 --- a/qtpy/QtSvg.py +++ b/qtpy/QtSvg.py @@ -8,7 +8,7 @@ """Provides QtSvg classes and functions.""" # Local imports -from . import PYQT4, PYSIDE6, PYSIDE2, PYQT5, PYQT6, PYSIDE, PythonQtError +from . import PYSIDE6, PYSIDE2, PYQT5, PYQT6, PythonQtError if PYQT6: from PyQt6.QtSvg import * @@ -18,11 +18,6 @@ from PySide6.QtSvg import * elif PYSIDE2: from PySide2.QtSvg import * -elif PYQT4: - from PyQt4.QtSvg import * -elif PYSIDE: - from PySide.QtSvg import * else: raise PythonQtError('No Qt bindings could be found') -del PYQT4, PYQT5, PYSIDE, PYSIDE2 diff --git a/qtpy/QtTest.py b/qtpy/QtTest.py index b86c174e..83ecb694 100644 --- a/qtpy/QtTest.py +++ b/qtpy/QtTest.py @@ -10,7 +10,7 @@ Provides QtTest and functions """ -from . import PYQT5, PYQT6, PYSIDE6, PYSIDE2, PYQT4, PYSIDE, PythonQtError +from . import PYQT5, PYQT6, PYSIDE6, PYSIDE2, PythonQtError if PYQT6: from PyQt6.QtTest import QTest @@ -20,14 +20,5 @@ from PySide6.QtTest import QTest elif PYSIDE2: from PySide2.QtTest import QTest -elif PYQT4: - from PyQt4.QtTest import QTest as OldQTest - - class QTest(OldQTest): - @staticmethod - def qWaitForWindowActive(QWidget): - OldQTest.qWaitForWindowShown(QWidget) -elif PYSIDE: - from PySide.QtTest import QTest else: raise PythonQtError('No Qt bindings could be found') diff --git a/qtpy/QtWebEngineWidgets.py b/qtpy/QtWebEngineWidgets.py index 20de297b..3b41b09a 100644 --- a/qtpy/QtWebEngineWidgets.py +++ b/qtpy/QtWebEngineWidgets.py @@ -10,7 +10,7 @@ Provides QtWebEngineWidgets classes and functions. """ -from . import PYQT5,PYSIDE2, PYSIDE6, PYQT4, PYSIDE, PythonQtError +from . import PYQT5, PYSIDE2, PYSIDE6, PythonQtError # To test if we are using WebEngine or WebKit @@ -40,15 +40,5 @@ from PySide2.QtWebEngineWidgets import QWebEngineSettings # Based on the work at https://github.com/spyder-ide/qtpy/pull/203 from PySide2.QtWebEngineWidgets import QWebEngineProfile -elif PYQT4: - from PyQt4.QtWebKit import QWebPage as QWebEnginePage - from PyQt4.QtWebKit import QWebView as QWebEngineView - from PyQt4.QtWebKit import QWebSettings as QWebEngineSettings - WEBENGINE = False -elif PYSIDE: - from PySide.QtWebKit import QWebPage as QWebEnginePage - from PySide.QtWebKit import QWebView as QWebEngineView - from PySide.QtWebKit import QWebSettings as QWebEngineSettings - WEBENGINE = False else: raise PythonQtError('No Qt bindings could be found') diff --git a/qtpy/QtWidgets.py b/qtpy/QtWidgets.py index 0dbb4a76..cd13d18e 100644 --- a/qtpy/QtWidgets.py +++ b/qtpy/QtWidgets.py @@ -8,13 +8,9 @@ """ Provides widget classes and functions. -.. warning:: Only PyQt4/PySide QtGui classes compatible with PyQt5.QtWidgets - are exposed here. Therefore, you need to treat/use this package as if it - were the ``PyQt5.QtWidgets`` module. """ -from . import PYQT5, PYQT6, PYSIDE2, PYQT4, PYSIDE, PYSIDE6, PythonQtError -from ._patch.qcombobox import patch_qcombobox +from . import PYQT5, PYQT6, PYSIDE2, PYSIDE6, PythonQtError from ._patch.qheaderview import introduce_renamed_methods_qheaderview if PYQT6: @@ -32,114 +28,5 @@ QPlainTextEdit.tabStopWidth = QPlainTextEdit.tabStopDistance elif PYSIDE2: from PySide2.QtWidgets import * -elif PYQT4: - from PyQt4.QtGui import * - QStyleOptionViewItem = QStyleOptionViewItemV4 - del QStyleOptionViewItemV4 - QStyleOptionFrame = QStyleOptionFrameV3 - del QStyleOptionFrameV3 - - # These objects belong to QtGui - try: - # Older versions of PyQt4 do not provide these - del (QGlyphRun, - QMatrix2x2, QMatrix2x3, QMatrix2x4, QMatrix3x2, QMatrix3x3, - QMatrix3x4, QMatrix4x2, QMatrix4x3, QMatrix4x4, - QQuaternion, QRadialGradient, QRawFont, QRegExpValidator, - QStaticText, QTouchEvent, QVector2D, QVector3D, QVector4D, - qFuzzyCompare) - except NameError: - pass - del (QAbstractTextDocumentLayout, QActionEvent, QBitmap, QBrush, QClipboard, - QCloseEvent, QColor, QConicalGradient, QContextMenuEvent, QCursor, - QDesktopServices, QDoubleValidator, QDrag, QDragEnterEvent, - QDragLeaveEvent, QDragMoveEvent, QDropEvent, QFileOpenEvent, - QFocusEvent, QFont, QFontDatabase, QFontInfo, QFontMetrics, - QFontMetricsF, QGradient, QHelpEvent, QHideEvent, - QHoverEvent, QIcon, QIconDragEvent, QIconEngine, QImage, - QImageIOHandler, QImageReader, QImageWriter, QInputEvent, - QInputMethodEvent, QKeyEvent, QKeySequence, QLinearGradient, - QMouseEvent, QMoveEvent, QMovie, QPaintDevice, QPaintEngine, - QPaintEngineState, QPaintEvent, QPainter, QPainterPath, - QPainterPathStroker, QPalette, QPen, QPicture, QPictureIO, QPixmap, - QPixmapCache, QPolygon, QPolygonF, - QRegion, QResizeEvent, QSessionManager, QShortcutEvent, QShowEvent, - QStandardItem, QStandardItemModel, QStatusTipEvent, - QSyntaxHighlighter, QTabletEvent, QTextBlock, QTextBlockFormat, - QTextBlockGroup, QTextBlockUserData, QTextCharFormat, QTextCursor, - QTextDocument, QTextDocumentFragment, QTextDocumentWriter, - QTextFormat, QTextFragment, QTextFrame, QTextFrameFormat, - QTextImageFormat, QTextInlineObject, QTextItem, QTextLayout, - QTextLength, QTextLine, QTextList, QTextListFormat, QTextObject, - QTextObjectInterface, QTextOption, QTextTable, QTextTableCell, - QTextTableCellFormat, QTextTableFormat, QTransform, - QValidator, QWhatsThisClickedEvent, - QWheelEvent, QWindowStateChangeEvent, qAlpha, qBlue, - qGray, qGreen, qIsGray, qRed, qRgb, qRgba, QIntValidator, - QStringListModel) - - # These objects belong to QtPrintSupport - del (QAbstractPrintDialog, QPageSetupDialog, QPrintDialog, QPrintEngine, - QPrintPreviewDialog, QPrintPreviewWidget, QPrinter, QPrinterInfo) - - # These objects belong to QtCore - del (QItemSelection, QItemSelectionModel, QItemSelectionRange, - QSortFilterProxyModel) - - # Patch QComboBox to allow Python objects to be passed to userData - patch_qcombobox(QComboBox) - - # QHeaderView: renamed methods - introduce_renamed_methods_qheaderview(QHeaderView) - -elif PYSIDE: - from PySide.QtGui import * - QStyleOptionViewItem = QStyleOptionViewItemV4 - del QStyleOptionViewItemV4 - - # These objects belong to QtGui - del (QAbstractTextDocumentLayout, QActionEvent, QBitmap, QBrush, QClipboard, - QCloseEvent, QColor, QConicalGradient, QContextMenuEvent, QCursor, - QDesktopServices, QDoubleValidator, QDrag, QDragEnterEvent, - QDragLeaveEvent, QDragMoveEvent, QDropEvent, QFileOpenEvent, - QFocusEvent, QFont, QFontDatabase, QFontInfo, QFontMetrics, - QFontMetricsF, QGradient, QHelpEvent, QHideEvent, - QHoverEvent, QIcon, QIconDragEvent, QIconEngine, QImage, - QImageIOHandler, QImageReader, QImageWriter, QInputEvent, - QInputMethodEvent, QKeyEvent, QKeySequence, QLinearGradient, - QMatrix2x2, QMatrix2x3, QMatrix2x4, QMatrix3x2, QMatrix3x3, - QMatrix3x4, QMatrix4x2, QMatrix4x3, QMatrix4x4, QMouseEvent, - QMoveEvent, QMovie, QPaintDevice, QPaintEngine, QPaintEngineState, - QPaintEvent, QPainter, QPainterPath, QPainterPathStroker, QPalette, - QPen, QPicture, QPictureIO, QPixmap, QPixmapCache, QPolygon, - QPolygonF, QQuaternion, QRadialGradient, QRegExpValidator, - QRegion, QResizeEvent, QSessionManager, QShortcutEvent, QShowEvent, - QStandardItem, QStandardItemModel, QStatusTipEvent, - QSyntaxHighlighter, QTabletEvent, QTextBlock, QTextBlockFormat, - QTextBlockGroup, QTextBlockUserData, QTextCharFormat, QTextCursor, - QTextDocument, QTextDocumentFragment, - QTextFormat, QTextFragment, QTextFrame, QTextFrameFormat, - QTextImageFormat, QTextInlineObject, QTextItem, QTextLayout, - QTextLength, QTextLine, QTextList, QTextListFormat, QTextObject, - QTextObjectInterface, QTextOption, QTextTable, QTextTableCell, - QTextTableCellFormat, QTextTableFormat, QTouchEvent, QTransform, - QValidator, QVector2D, QVector3D, QVector4D, QWhatsThisClickedEvent, - QWheelEvent, QWindowStateChangeEvent, qAlpha, qBlue, qGray, qGreen, - qIsGray, qRed, qRgb, qRgba, QIntValidator, QStringListModel) - - # These objects belong to QtPrintSupport - del (QAbstractPrintDialog, QPageSetupDialog, QPrintDialog, QPrintEngine, - QPrintPreviewDialog, QPrintPreviewWidget, QPrinter, QPrinterInfo) - - # These objects belong to QtCore - del (QItemSelection, QItemSelectionModel, QItemSelectionRange, - QSortFilterProxyModel) - - # Patch QComboBox to allow Python objects to be passed to userData - patch_qcombobox(QComboBox) - - # QHeaderView: renamed methods - introduce_renamed_methods_qheaderview(QHeaderView) - else: raise PythonQtError('No Qt bindings could be found') diff --git a/qtpy/QtXmlPatterns.py b/qtpy/QtXmlPatterns.py index b41e13df..3ab2661e 100644 --- a/qtpy/QtXmlPatterns.py +++ b/qtpy/QtXmlPatterns.py @@ -8,15 +8,11 @@ """Provides QtXmlPatterns classes and functions.""" # Local imports -from . import PYQT4, PYSIDE2, PYQT5, PYSIDE, PythonQtError +from . import PYSIDE2, PYQT5, PythonQtError if PYQT5: from PyQt5.QtXmlPatterns import * elif PYSIDE2: from PySide2.QtXmlPatterns import * -elif PYQT4: - from PyQt4.QtXmlPatterns import * -elif PYSIDE: - from PySide.QtXmlPatterns import * else: raise PythonQtError('No Qt bindings could be found') diff --git a/qtpy/__init__.py b/qtpy/__init__.py index ab0e9e51..fa62f8b2 100644 --- a/qtpy/__init__.py +++ b/qtpy/__init__.py @@ -13,7 +13,7 @@ If one of the APIs has already been imported, then it will be used. Otherwise, the shim will automatically select the first available API (PyQt5, PyQt6, -PySide2, PySide6, PyQt4 and finally PySide); in that case, you can force the use of one +PySide2 and PySide6); in that case, you can force the use of one specific bindings (e.g. if your application is using one specific bindings and you need to use library that use QtPy) by setting up the ``QT_API`` environment variable. @@ -53,28 +53,6 @@ >>> from qtpy import QtGui, QtWidgets, QtCore >>> print(QtWidgets.QWidget) -PyQt4 -===== - -Set the ``QT_API`` environment variable to 'pyqt' before importing any python -package:: - - >>> import os - >>> os.environ['QT_API'] = 'pyqt' - >>> from qtpy import QtGui, QtWidgets, QtCore - >>> print(QtWidgets.QWidget) - -PySide -====== - -Set the QT_API environment variable to 'pyside' before importing other -packages:: - - >>> import os - >>> os.environ['QT_API'] = 'pyside' - >>> from qtpy import QtGui, QtWidgets, QtCore - >>> print(QtWidgets.QWidget) - """ from distutils.version import LooseVersion @@ -106,15 +84,6 @@ class PythonQtWarning(Warning): PYQT6_API = ['pyqt6'] -# Names of the expected PyQt4 api -PYQT4_API = [ - 'pyqt', # name used in IPython.qt - 'pyqt4' # pyqode.qt original name -] - -# Names of the expected PySide api -PYSIDE_API = ['pyside'] - # Names of the expected PySide2 api PYSIDE2_API = ['pyside2'] @@ -129,11 +98,11 @@ class PythonQtWarning(Warning): API = os.environ[QT_API].lower() initial_api = API -assert API in (PYQT5_API + PYQT6_API + PYQT4_API + PYSIDE_API + PYSIDE2_API + PYSIDE6_API) +assert API in (PYQT5_API + PYQT6_API + PYSIDE2_API + PYSIDE6_API) is_old_pyqt = is_pyqt46 = False PYQT5 = True -PYQT4 = PYQT6 = PYSIDE = PYSIDE2 = PYSIDE6 = False +PYQT6 = PYSIDE2 = PYSIDE6 = False # When `FORCE_QT_API` is set, we disregard # any previously imported python bindings. @@ -146,11 +115,6 @@ class PythonQtWarning(Warning): API = initial_api if initial_api in PYSIDE6_API else 'pyside6' elif 'PySide2' in sys.modules: API = initial_api if initial_api in PYSIDE2_API else 'pyside2' - elif 'PyQt4' in sys.modules: - API = initial_api if initial_api in PYQT4_API else 'pyqt4' - elif 'PySide' in sys.modules: - API = initial_api if initial_api in PYSIDE_API else 'pyside' - if API in PYQT5_API: try: @@ -223,65 +187,18 @@ class PythonQtWarning(Warning): API = os.environ['QT_API'] = 'pyqt' -if API in PYQT4_API: - try: - import sip - try: - sip.setapi('QString', 2) - sip.setapi('QVariant', 2) - sip.setapi('QDate', 2) - sip.setapi('QDateTime', 2) - sip.setapi('QTextStream', 2) - sip.setapi('QTime', 2) - sip.setapi('QUrl', 2) - except (AttributeError, ValueError): - # PyQt < v4.6 - pass - try: - from PyQt4.Qt import PYQT_VERSION_STR as PYQT_VERSION # analysis:ignore - from PyQt4.Qt import QT_VERSION_STR as QT_VERSION # analysis:ignore - except ImportError: - # In PyQt4-sip 4.19.13 PYQT_VERSION_STR and QT_VERSION_STR are in PyQt4.QtCore - from PyQt4.QtCore import PYQT_VERSION_STR as PYQT_VERSION # analysis:ignore - from PyQt4.QtCore import QT_VERSION_STR as QT_VERSION # analysis:ignore - PYSIDE_VERSION = None - PYQT5 = False - PYQT4 = True - except ImportError: - API = os.environ['QT_API'] = 'pyside' - else: - is_old_pyqt = PYQT_VERSION.startswith(('4.4', '4.5', '4.6', '4.7')) - is_pyqt46 = PYQT_VERSION.startswith('4.6') - -if API in PYSIDE_API: - try: - from PySide import __version__ as PYSIDE_VERSION # analysis:ignore - from PySide.QtCore import __version__ as QT_VERSION # analysis:ignore - PYQT_VERSION = None - PYQT5 = PYSIDE2 = PYSIDE6 = False - PYSIDE = True - except ImportError: - raise PythonQtError('No Qt bindings could be found') - # If a correct API name is passed to QT_API and it could not be found, # switches to another and informs through the warning if API != initial_api and binding_specified: warnings.warn('Selected binding "{}" could not be found, ' 'using "{}"'.format(initial_api, API), RuntimeWarning) -API_NAME = {'pyqt6': 'PyQt6', 'pyqt5': 'PyQt5', 'pyqt': 'PyQt4', 'pyqt4': 'PyQt4', - 'pyside': 'PySide', 'pyside2':'PySide2', 'pyside6': 'PySide6'}[API] - -if PYQT4: - import sip - try: - API_NAME += (" (API v{0})".format(sip.getapi('QString'))) - except AttributeError: - pass +API_NAME = {'pyqt6': 'PyQt6', 'pyqt5': 'PyQt5', + 'pyside2':'PySide2', 'pyside6': 'PySide6'}[API] try: # QtDataVisualization backward compatibility (QtDataVisualization vs. QtDatavisualization) # Only available for Qt5 bindings > 5.9 on Windows from . import QtDataVisualization as QtDatavisualization except ImportError: - pass \ No newline at end of file + pass diff --git a/qtpy/_patch/qcombobox.py b/qtpy/_patch/qcombobox.py deleted file mode 100644 index d3e98bed..00000000 --- a/qtpy/_patch/qcombobox.py +++ /dev/null @@ -1,101 +0,0 @@ -# The code below, as well as the associated test were adapted from -# qt-helpers, which was released under a 3-Clause BSD license: -# -# Copyright (c) 2015, Chris Beaumont and Thomas Robitaille -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the -# distribution. -# * Neither the name of the Glue project nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -def patch_qcombobox(QComboBox): - """ - In PySide, using Python objects as userData in QComboBox causes - Segmentation faults under certain conditions. Even in cases where it - doesn't, findData does not work correctly. Likewise, findData also does not - work correctly with Python objects when using PyQt4. On the other hand, - PyQt5 deals with this case correctly. We therefore patch QComboBox when - using PyQt4 and PySide to avoid issues. - """ - - from ..QtGui import QIcon - from ..QtCore import Qt, QObject - - class userDataWrapper(): - """ - This class is used to wrap any userData object. If we don't do this, - then certain types of objects can cause segmentation faults or issues - depending on whether/how __getitem__ is defined. - """ - def __init__(self, data): - self.data = data - - _addItem = QComboBox.addItem - - def addItem(self, *args, **kwargs): - if len(args) == 3 or (not isinstance(args[0], QIcon) - and len(args) == 2): - args, kwargs['userData'] = args[:-1], args[-1] - if 'userData' in kwargs: - kwargs['userData'] = userDataWrapper(kwargs['userData']) - _addItem(self, *args, **kwargs) - - _insertItem = QComboBox.insertItem - - def insertItem(self, *args, **kwargs): - if len(args) == 4 or (not isinstance(args[1], QIcon) - and len(args) == 3): - args, kwargs['userData'] = args[:-1], args[-1] - if 'userData' in kwargs: - kwargs['userData'] = userDataWrapper(kwargs['userData']) - _insertItem(self, *args, **kwargs) - - _setItemData = QComboBox.setItemData - - def setItemData(self, index, value, role=Qt.UserRole): - value = userDataWrapper(value) - _setItemData(self, index, value, role=role) - - _itemData = QComboBox.itemData - - def itemData(self, index, role=Qt.UserRole): - userData = _itemData(self, index, role=role) - if isinstance(userData, userDataWrapper): - userData = userData.data - return userData - - def findData(self, value): - for i in range(self.count()): - if self.itemData(i) == value: - return i - return -1 - - QComboBox.addItem = addItem - QComboBox.insertItem = insertItem - QComboBox.setItemData = setItemData - QComboBox.itemData = itemData - QComboBox.findData = findData \ No newline at end of file diff --git a/qtpy/compat.py b/qtpy/compat.py index 949d8854..d90ed52b 100644 --- a/qtpy/compat.py +++ b/qtpy/compat.py @@ -10,7 +10,6 @@ from __future__ import print_function import sys -from . import PYQT4 from .QtWidgets import QFileDialog from .py3compat import Callable, is_text_string, to_text_string, TEXT_TYPES @@ -19,58 +18,17 @@ # QVariant conversion utilities # ============================================================================= PYQT_API_1 = False -if PYQT4: - import sip - try: - PYQT_API_1 = sip.getapi('QVariant') == 1 # PyQt API #1 - except AttributeError: - # PyQt =6.2 # assert QtWebEngineWidgets.QWebEnginePage is PySide6.QtWebEngineCore.QWebEnginePage -def assert_pyqt4(): - """ - Make sure that we are using PyQt4 - """ - import PyQt4 - assert QtCore.QEvent is PyQt4.QtCore.QEvent - assert QtGui.QPainter is PyQt4.QtGui.QPainter - assert QtWidgets.QWidget is PyQt4.QtGui.QWidget - assert QtWebEngineWidgets.QWebEnginePage is PyQt4.QtWebKit.QWebPage - - def assert_pyqt5(): """ Make sure that we are using PyQt5 @@ -80,11 +58,7 @@ def test_qt_api(): QT_API = os.environ.get('QT_API', '').lower() - if QT_API == 'pyside': - assert_pyside() - elif QT_API in ('pyqt', 'pyqt4'): - assert_pyqt4() - elif QT_API == 'pyqt5': + if QT_API == 'pyqt5': assert_pyqt5() elif QT_API == 'pyqt6': assert_pyqt6() @@ -96,16 +70,16 @@ def test_qt_api(): # If the tests are run locally, USE_QT_API and QT_API may not be # defined, but we still want to make sure qtpy is behaving sensibly. # We should then be loading, in order of decreasing preference, PyQt5, - # PyQt4, and PySide. + # PyQt6, and PySide2. try: import PyQt5 except ImportError: try: - import PyQt4 + import PyQt6 except ImportError: - import PySide - assert_pyside() + import PySide2 + assert_pyside2() else: - assert_pyqt4() + assert_pyqt6() else: assert_pyqt5() diff --git a/qtpy/tests/test_patch_qcombobox.py b/qtpy/tests/test_patch_qcombobox.py deleted file mode 100644 index 12536fac..00000000 --- a/qtpy/tests/test_patch_qcombobox.py +++ /dev/null @@ -1,107 +0,0 @@ -from __future__ import absolute_import - -import os -import sys - -import pytest - -from qtpy import PYQT5, PYSIDE2, PYSIDE6, QtGui, QtWidgets - -PY3 = sys.version[0] == "3" - - -def get_qapp(icon_path=None): - qapp = QtWidgets.QApplication.instance() - if qapp is None: - qapp = QtWidgets.QApplication(['']) - return qapp - - -class Data(object): - """ - Test class to store in userData. The __getitem__ is needed in order to - reproduce the segmentation fault. - """ - def __getitem__(self, item): - raise ValueError("Failing") - - -@pytest.mark.skipif(PY3 or PYSIDE2 or PYSIDE6, - reason="It segfaults in Python 3 and with PySide2/6") -def test_patched_qcombobox(): - """ - In PySide, using Python objects as userData in QComboBox causes - Segmentation faults under certain conditions. Even in cases where it - doesn't, findData does not work correctly. Likewise, findData also - does not work correctly with Python objects when using PyQt4. On the - other hand, PyQt5 deals with this case correctly. We therefore patch - QComboBox when using PyQt4 and PySide to avoid issues. - """ - - app = get_qapp() - - data1 = Data() - data2 = Data() - data3 = Data() - data4 = Data() - data5 = Data() - data6 = Data() - - icon1 = QtGui.QIcon() - icon2 = QtGui.QIcon() - - widget = QtWidgets.QComboBox() - widget.addItem('a', data1) - widget.insertItem(0, 'b', data2) - widget.addItem('c', data1) - widget.setItemData(2, data3) - widget.addItem(icon1, 'd', data4) - widget.insertItem(3, icon2, 'e', data5) - widget.addItem(icon1, 'f') - widget.insertItem(5, icon2, 'g') - - widget.show() - - assert widget.findData(data1) == 1 - assert widget.findData(data2) == 0 - assert widget.findData(data3) == 2 - assert widget.findData(data4) == 4 - assert widget.findData(data5) == 3 - assert widget.findData(data6) == -1 - - assert widget.itemData(0) == data2 - assert widget.itemData(1) == data1 - assert widget.itemData(2) == data3 - assert widget.itemData(3) == data5 - assert widget.itemData(4) == data4 - assert widget.itemData(5) is None - assert widget.itemData(6) is None - - assert widget.itemText(0) == 'b' - assert widget.itemText(1) == 'a' - assert widget.itemText(2) == 'c' - assert widget.itemText(3) == 'e' - assert widget.itemText(4) == 'd' - assert widget.itemText(5) == 'g' - assert widget.itemText(6) == 'f' - - -@pytest.mark.skipif(((PYSIDE2 or PYSIDE6 or PYQT5) - and os.environ.get('CI', None) is not None), - reason="It segfaults in our CIs with PYSIDE2/PYSIDE6 or PYQT5") -def test_model_item(): - """ - This is a regression test for an issue that caused the call to item(0) - below to trigger segmentation faults in PySide. The issue is - non-deterministic when running the call once, so we include a loop to make - sure that we trigger the fault. - """ - app = get_qapp() - combo = QtWidgets.QComboBox() - label_data = [('a', None)] - for iter in range(10000): - combo.clear() - for i, (label, data) in enumerate(label_data): - combo.addItem(label, userData=data) - model = combo.model() - model.item(0) diff --git a/qtpy/tests/test_patch_qheaderview.py b/qtpy/tests/test_patch_qheaderview.py index 17037f34..74df889d 100644 --- a/qtpy/tests/test_patch_qheaderview.py +++ b/qtpy/tests/test_patch_qheaderview.py @@ -3,7 +3,7 @@ import sys import pytest -from qtpy import PYSIDE, PYSIDE2, PYQT4 +from qtpy import PYSIDE2 from qtpy.QtWidgets import QApplication from qtpy.QtWidgets import QHeaderView from qtpy.QtCore import Qt @@ -46,11 +46,7 @@ class Model(QAbstractListModel): # test it assert isinstance(headerview.sectionsClickable(), bool) assert isinstance(headerview.sectionsMovable(), bool) - if PYSIDE: - assert isinstance(headerview.sectionResizeMode(0), - QHeaderView.ResizeMode) - else: - assert isinstance(headerview.sectionResizeMode(0), int) + assert isinstance(headerview.sectionResizeMode(0), int) headerview.setSectionsClickable(True) assert headerview.sectionsClickable() == True @@ -80,19 +76,4 @@ class Model(QAbstractListModel): headerview.setSectionResizeMode(0, QHeaderView.ResizeToContents) assert headerview.sectionResizeMode(0) == QHeaderView.ResizeToContents - # test that the old methods in Qt4 raise exceptions - if PYQT4 or PYSIDE: - with pytest.warns(UserWarning): - headerview.isClickable() - with pytest.warns(UserWarning): - headerview.isMovable() - with pytest.warns(UserWarning): - headerview.resizeMode(0) - with pytest.warns(UserWarning): - headerview.setClickable(True) - with pytest.warns(UserWarning): - headerview.setMovable(True) - with pytest.warns(UserWarning): - headerview.setResizeMode(0, QHeaderView.Interactive) - diff --git a/qtpy/tests/test_qdesktopservice_split.py b/qtpy/tests/test_qdesktopservice_split.py index 472f2df1..59e516aa 100644 --- a/qtpy/tests/test_qdesktopservice_split.py +++ b/qtpy/tests/test_qdesktopservice_split.py @@ -4,7 +4,6 @@ import pytest import warnings -from qtpy import PYQT4, PYSIDE def test_qstandarpath(): @@ -25,17 +24,3 @@ def test_qdesktopservice(): assert QDesktopServices.setUrlHandler is not None -@pytest.mark.skipif(not (PYQT4 or PYSIDE), reason="Warning is only raised in old bindings") -def test_qdesktopservice_qt4_pyside(): - from qtpy.QtGui import QDesktopServices - # Attributes from QStandardPaths should raise a warning when imported - # from QDesktopServices - with warnings.catch_warnings(record=True) as w: - # Cause all warnings to always be triggered. - warnings.simplefilter("always") - # Try to import QtHelp. - QDesktopServices.StandardLocation - - assert len(w) == 1 - assert issubclass(w[-1].category, DeprecationWarning) - assert "deprecated" in str(w[-1].message) diff --git a/qtpy/tests/test_qtdesigner.py b/qtpy/tests/test_qtdesigner.py index aa4bebe2..3497f733 100644 --- a/qtpy/tests/test_qtdesigner.py +++ b/qtpy/tests/test_qtdesigner.py @@ -1,9 +1,9 @@ from __future__ import absolute_import import pytest -from qtpy import PYSIDE6, PYSIDE2, PYSIDE +from qtpy import PYSIDE6, PYSIDE2 -@pytest.mark.skipif((PYSIDE6 or PYSIDE2 or PYSIDE), reason="QtDesigner is not avalaible in PySide/PySide2/PySide6") +@pytest.mark.skipif((PYSIDE6 or PYSIDE2), reason="QtDesigner is not avalaible in PySide2/PySide6") def test_qtdesigner(): from qtpy import QtDesigner """Test the qtpy.QtDesigner namespace""" diff --git a/qtpy/tests/test_qtnetwork.py b/qtpy/tests/test_qtnetwork.py index 8093fe29..d8079bdf 100644 --- a/qtpy/tests/test_qtnetwork.py +++ b/qtpy/tests/test_qtnetwork.py @@ -1,14 +1,14 @@ from __future__ import absolute_import import pytest -from qtpy import PYSIDE, PYSIDE2, PYSIDE6, QtNetwork +from qtpy import PYSIDE2, PYSIDE6, QtNetwork def test_qtnetwork(): """Test the qtpy.QtNetwork namespace""" assert QtNetwork.QAbstractNetworkCache is not None assert QtNetwork.QNetworkCacheMetaData is not None - if not PYSIDE and not PYSIDE2: + if not PYSIDE2: assert QtNetwork.QHttpMultiPart is not None assert QtNetwork.QHttpPart is not None assert QtNetwork.QNetworkAccessManager is not None @@ -35,10 +35,9 @@ def test_qtnetwork(): assert QtNetwork.QTcpServer is not None assert QtNetwork.QTcpSocket is not None assert QtNetwork.QUdpSocket is not None - if not PYSIDE: - assert QtNetwork.QSslCertificate is not None - assert QtNetwork.QSslCipher is not None - assert QtNetwork.QSslConfiguration is not None - assert QtNetwork.QSslError is not None - assert QtNetwork.QSslKey is not None - assert QtNetwork.QSslSocket is not None + assert QtNetwork.QSslCertificate is not None + assert QtNetwork.QSslCipher is not None + assert QtNetwork.QSslConfiguration is not None + assert QtNetwork.QSslError is not None + assert QtNetwork.QSslKey is not None + assert QtNetwork.QSslSocket is not None diff --git a/qtpy/tests/test_qtxmlpatterns.py b/qtpy/tests/test_qtxmlpatterns.py index 11ff2902..5b22d2de 100644 --- a/qtpy/tests/test_qtxmlpatterns.py +++ b/qtpy/tests/test_qtxmlpatterns.py @@ -1,7 +1,7 @@ from __future__ import absolute_import import pytest -from qtpy import PYSIDE2, PYSIDE6, PYSIDE +from qtpy import PYSIDE2, PYSIDE6 @pytest.mark.skipif(PYSIDE6, reason="not available with qt 6.0") def test_qtxmlpatterns(): @@ -11,7 +11,7 @@ def test_qtxmlpatterns(): assert QtXmlPatterns.QAbstractUriResolver is not None assert QtXmlPatterns.QAbstractXmlNodeModel is not None assert QtXmlPatterns.QAbstractXmlReceiver is not None - if not PYSIDE2 and not PYSIDE: + if not PYSIDE2: assert QtXmlPatterns.QSimpleXmlNodeModel is not None assert QtXmlPatterns.QSourceLocation is not None assert QtXmlPatterns.QXmlFormatter is not None diff --git a/qtpy/tests/test_uic.py b/qtpy/tests/test_uic.py index 5e0a32de..516d2a0e 100644 --- a/qtpy/tests/test_uic.py +++ b/qtpy/tests/test_uic.py @@ -3,10 +3,10 @@ import contextlib import pytest -from qtpy import PYQT5, PYSIDE6, PYSIDE2, PYSIDE, QtWidgets +from qtpy import PYQT5, PYSIDE6, PYSIDE2, QtWidgets from qtpy.QtWidgets import QComboBox -if PYSIDE2 or PYSIDE: +if PYSIDE2: pytest.importorskip("pyside2uic", reason="pyside2uic not installed") from qtpy import uic @@ -105,7 +105,7 @@ def test_load_ui_custom_auto(tmpdir): @pytest.mark.skipif(PYSIDE6, reason="unavailable") def test_load_full_uic(): - """Test that we load the full uic objects for PyQt5 and PyQt4.""" + """Test that we load the full uic objects for PyQt5.""" QT_API = os.environ.get('QT_API', '').lower() if QT_API.startswith('pyside'): assert hasattr(uic, 'loadUi') diff --git a/qtpy/uic.py b/qtpy/uic.py index 992a231b..4e2a15d2 100644 --- a/qtpy/uic.py +++ b/qtpy/uic.py @@ -1,6 +1,6 @@ import os -from . import PYSIDE, PYSIDE6, PYSIDE2, PYQT4, PYQT5, PYQT6 +from . import PYSIDE6, PYSIDE2, PYQT5, PYQT6 from .QtWidgets import QComboBox @@ -12,10 +12,6 @@ from PyQt5.uic import * -elif PYQT4: - - from PyQt4.uic import * - else: __all__ = ['loadUi', 'loadUiType'] @@ -82,14 +78,7 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. - if PYSIDE: - from PySide.QtCore import QMetaObject - from PySide.QtUiTools import QUiLoader - try: - from pysideuic import compileUi - except ImportError: - pass - elif PYSIDE6: + if PYSIDE6: from PySide6.QtCore import QMetaObject from PySide6.QtUiTools import QUiLoader elif PYSIDE2: diff --git a/setup.py b/setup.py index 696eb21e..3ae3e673 100644 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ version=version_ns['__version__'], packages=find_packages(exclude=['contrib', 'docs', 'tests*']), python_requires='>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*', - keywords=["qt PyQt4 PyQt5 PySide"], + keywords=["qt PyQt5 PyQt6 PySide2 PySide6"], url='https://github.com/spyder-ide/qtpy', license='MIT', author='Colin Duquesnoy and the Spyder Development Team', @@ -32,7 +32,7 @@ maintainer='Spyder Development Team and QtPy Contributors', maintainer_email='spyder.python@gmail.com', description='Provides an abstraction layer on top of the various Qt ' - 'bindings (PyQt5, PyQt4 and PySide) and additional custom ' + 'bindings (PyQt5/6 and PySide2/6) and additional custom ' 'QWidgets.', long_description=LONG_DESCRIPTION, long_description_content_type='text/markdown',