From 4c60022ac2a1f5eed8c6bb742c50e2063a20da74 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Fri, 17 Jun 2016 01:35:37 -0700 Subject: [PATCH 1/2] Drop conditional import of figureoptions. As far as I can tell, the only way the import of figureoptions could fail is under PyQt 4.3 or earlier (QFormLayout was introduced in Qt 4.4). PyQt 4.4 was released in 2008 and the oldest version still downloadable on SourceForge seems to be 4.9, so that seems safe... Also up the version requirement on PyQt. --- INSTALL | 2 +- doc/conf.py | 3 + lib/matplotlib/backends/backend_qt4.py | 5 -- lib/matplotlib/backends/backend_qt5.py | 56 +++++++++---------- .../backends/qt_editor/formlayout.py | 3 - 5 files changed, 30 insertions(+), 39 deletions(-) diff --git a/INSTALL b/INSTALL index 40e29470e793..aade12aab122 100644 --- a/INSTALL +++ b/INSTALL @@ -232,7 +232,7 @@ backends and the capabilities they provide. Versions 8.6.0 and 8.6.1 are known to have issues that may result in segfaults when closing multiple windows in the wrong order. -:term:`pyqt` 4.0 or later +:term:`pyqt` 4.4 or later The Qt4 widgets library python wrappers for the Qt4Agg backend :term:`pygtk` 2.4 or later diff --git a/doc/conf.py b/doc/conf.py index 6bef97d750cc..ced56039b5b9 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -319,6 +319,9 @@ class QWidget(object): class QMainWindow(object): pass + class QPushButton(object): + pass + class MySip(MagicMock): def getapi(*args): diff --git a/lib/matplotlib/backends/backend_qt4.py b/lib/matplotlib/backends/backend_qt4.py index b3d56a49fe6e..d19c0433be1b 100644 --- a/lib/matplotlib/backends/backend_qt4.py +++ b/lib/matplotlib/backends/backend_qt4.py @@ -22,12 +22,7 @@ from matplotlib._pylab_helpers import Gcf from matplotlib.figure import Figure - from matplotlib.widgets import SubplotTool -try: - import matplotlib.backends.qt_editor.figureoptions as figureoptions -except ImportError: - figureoptions = None from .qt_compat import QtCore, QtWidgets, _getSaveFileName, __version__ from matplotlib.backends.qt_editor.formsubplottool import UiSubplotTool diff --git a/lib/matplotlib/backends/backend_qt5.py b/lib/matplotlib/backends/backend_qt5.py index 6df325e7f169..876eb36bafac 100644 --- a/lib/matplotlib/backends/backend_qt5.py +++ b/lib/matplotlib/backends/backend_qt5.py @@ -23,10 +23,7 @@ from matplotlib.figure import Figure from matplotlib.widgets import SubplotTool -try: - import matplotlib.backends.qt_editor.figureoptions as figureoptions -except ImportError: - figureoptions = None +import matplotlib.backends.qt_editor.figureoptions as figureoptions from .qt_compat import (QtCore, QtGui, QtWidgets, _getSaveFileName, __version__, is_pyqt5) @@ -603,7 +600,7 @@ def _init_toolbar(self): a.setCheckable(True) if tooltip_text is not None: a.setToolTip(tooltip_text) - if figureoptions is not None and text == 'Subplots': + if text == 'Subplots': a = self.addAction(self._icon("qt4_editor_options.png"), 'Customize', self.edit_parameters) a.setToolTip('Edit axis, curve and image parameters') @@ -634,32 +631,31 @@ def _init_toolbar(self): self.layout().setSpacing(12) self.setMinimumHeight(48) - if figureoptions is not None: - def edit_parameters(self): - allaxes = self.canvas.figure.get_axes() - if not allaxes: - QtWidgets.QMessageBox.warning( - self.parent, "Error", "There are no axes to edit.") - return - if len(allaxes) == 1: - axes = allaxes[0] + def edit_parameters(self): + allaxes = self.canvas.figure.get_axes() + if not allaxes: + QtWidgets.QMessageBox.warning( + self.parent, "Error", "There are no axes to edit.") + return + if len(allaxes) == 1: + axes = allaxes[0] + else: + titles = [] + for axes in allaxes: + name = (axes.get_title() or + " - ".join(filter(None, [axes.get_xlabel(), + axes.get_ylabel()])) or + "".format( + type(axes).__name__, id(axes))) + titles.append(name) + item, ok = QtWidgets.QInputDialog.getItem( + self.parent, 'Customize', 'Select axes:', titles, 0, False) + if ok: + axes = allaxes[titles.index(six.text_type(item))] else: - titles = [] - for axes in allaxes: - name = (axes.get_title() or - " - ".join(filter(None, [axes.get_xlabel(), - axes.get_ylabel()])) or - "".format( - type(axes).__name__, id(axes))) - titles.append(name) - item, ok = QtWidgets.QInputDialog.getItem( - self.parent, 'Customize', 'Select axes:', titles, 0, False) - if ok: - axes = allaxes[titles.index(six.text_type(item))] - else: - return - - figureoptions.figure_edit(axes, self) + return + + figureoptions.figure_edit(axes, self) def _update_buttons_checked(self): # sync button checkstates to match active mode diff --git a/lib/matplotlib/backends/qt_editor/formlayout.py b/lib/matplotlib/backends/qt_editor/formlayout.py index a786a6105342..9acf9a207f32 100644 --- a/lib/matplotlib/backends/qt_editor/formlayout.py +++ b/lib/matplotlib/backends/qt_editor/formlayout.py @@ -54,10 +54,7 @@ from matplotlib.colors import is_color_like from matplotlib.colors import rgb2hex from matplotlib.colors import colorConverter - from matplotlib.backends.qt_compat import QtGui, QtWidgets, QtCore -if not hasattr(QtWidgets, 'QFormLayout'): - raise ImportError("Warning: formlayout requires PyQt4 >v4.3 or PySide") import datetime From a44839c7eb752e3679a8998dccc64ae42d6c3522 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Fri, 17 Jun 2016 12:32:47 -0700 Subject: [PATCH 2/2] Mock the entire PyQt4.QtGui classes API. --- doc/conf.py | 107 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 93 insertions(+), 14 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index ced56039b5b9..a77019ac64a0 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -307,20 +307,99 @@ class Frame(object): class MyPyQt4(MagicMock): class QtGui(object): - class QToolBar(object): - pass - - class QDialog(object): - pass - - class QWidget(object): - pass - - class QMainWindow(object): - pass - - class QPushButton(object): - pass + # PyQt4.QtGui public classes. + # Generated with + # textwrap.fill([name for name in dir(PyQt4.QtGui) + # if isinstance(getattr(PyQt4.QtGui, name), type)]) + _QtGui_public_classes = """\ + Display QAbstractButton QAbstractGraphicsShapeItem + QAbstractItemDelegate QAbstractItemView QAbstractPrintDialog + QAbstractProxyModel QAbstractScrollArea QAbstractSlider + QAbstractSpinBox QAbstractTextDocumentLayout QAction QActionEvent + QActionGroup QApplication QBitmap QBoxLayout QBrush QButtonGroup + QCalendarWidget QCheckBox QClipboard QCloseEvent QColor QColorDialog + QColumnView QComboBox QCommandLinkButton QCommonStyle QCompleter + QConicalGradient QContextMenuEvent QCursor QDataWidgetMapper QDateEdit + QDateTimeEdit QDesktopServices QDesktopWidget QDial QDialog + QDialogButtonBox QDirModel QDockWidget QDoubleSpinBox QDoubleValidator + QDrag QDragEnterEvent QDragLeaveEvent QDragMoveEvent QDropEvent + QErrorMessage QFileDialog QFileIconProvider QFileOpenEvent + QFileSystemModel QFocusEvent QFocusFrame QFont QFontComboBox + QFontDatabase QFontDialog QFontInfo QFontMetrics QFontMetricsF + QFormLayout QFrame QGesture QGestureEvent QGestureRecognizer QGlyphRun + QGradient QGraphicsAnchor QGraphicsAnchorLayout QGraphicsBlurEffect + QGraphicsColorizeEffect QGraphicsDropShadowEffect QGraphicsEffect + QGraphicsEllipseItem QGraphicsGridLayout QGraphicsItem + QGraphicsItemAnimation QGraphicsItemGroup QGraphicsLayout + QGraphicsLayoutItem QGraphicsLineItem QGraphicsLinearLayout + QGraphicsObject QGraphicsOpacityEffect QGraphicsPathItem + QGraphicsPixmapItem QGraphicsPolygonItem QGraphicsProxyWidget + QGraphicsRectItem QGraphicsRotation QGraphicsScale QGraphicsScene + QGraphicsSceneContextMenuEvent QGraphicsSceneDragDropEvent + QGraphicsSceneEvent QGraphicsSceneHelpEvent QGraphicsSceneHoverEvent + QGraphicsSceneMouseEvent QGraphicsSceneMoveEvent + QGraphicsSceneResizeEvent QGraphicsSceneWheelEvent + QGraphicsSimpleTextItem QGraphicsTextItem QGraphicsTransform + QGraphicsView QGraphicsWidget QGridLayout QGroupBox QHBoxLayout + QHeaderView QHelpEvent QHideEvent QHoverEvent QIcon QIconDragEvent + QIconEngine QIconEngineV2 QIdentityProxyModel QImage QImageIOHandler + QImageReader QImageWriter QInputContext QInputContextFactory + QInputDialog QInputEvent QInputMethodEvent QIntValidator QItemDelegate + QItemEditorCreatorBase QItemEditorFactory QItemSelection + QItemSelectionModel QItemSelectionRange QKeyEvent QKeyEventTransition + QKeySequence QLCDNumber QLabel QLayout QLayoutItem QLineEdit + QLinearGradient QListView QListWidget QListWidgetItem QMainWindow + QMatrix QMatrix2x2 QMatrix2x3 QMatrix2x4 QMatrix3x2 QMatrix3x3 + QMatrix3x4 QMatrix4x2 QMatrix4x3 QMatrix4x4 QMdiArea QMdiSubWindow + QMenu QMenuBar QMessageBox QMimeSource QMouseEvent + QMouseEventTransition QMoveEvent QMovie QPageSetupDialog QPaintDevice + QPaintEngine QPaintEngineState QPaintEvent QPainter QPainterPath + QPainterPathStroker QPalette QPanGesture QPen QPicture QPictureIO + QPinchGesture QPixmap QPixmapCache QPlainTextDocumentLayout + QPlainTextEdit QPolygon QPolygonF QPrintDialog QPrintEngine + QPrintPreviewDialog QPrintPreviewWidget QPrinter QPrinterInfo + QProgressBar QProgressDialog QProxyModel QPushButton QPyTextObject + QQuaternion QRadialGradient QRadioButton QRawFont QRegExpValidator + QRegion QResizeEvent QRubberBand QScrollArea QScrollBar + QSessionManager QShortcut QShortcutEvent QShowEvent QSizeGrip + QSizePolicy QSlider QSortFilterProxyModel QSound QSpacerItem QSpinBox + QSplashScreen QSplitter QSplitterHandle QStackedLayout QStackedWidget + QStandardItem QStandardItemModel QStaticText QStatusBar + QStatusTipEvent QStringListModel QStyle QStyleFactory QStyleHintReturn + QStyleHintReturnMask QStyleHintReturnVariant QStyleOption + QStyleOptionButton QStyleOptionComboBox QStyleOptionComplex + QStyleOptionDockWidget QStyleOptionDockWidgetV2 QStyleOptionFocusRect + QStyleOptionFrame QStyleOptionFrameV2 QStyleOptionFrameV3 + QStyleOptionGraphicsItem QStyleOptionGroupBox QStyleOptionHeader + QStyleOptionMenuItem QStyleOptionProgressBar QStyleOptionProgressBarV2 + QStyleOptionRubberBand QStyleOptionSizeGrip QStyleOptionSlider + QStyleOptionSpinBox QStyleOptionTab QStyleOptionTabBarBase + QStyleOptionTabBarBaseV2 QStyleOptionTabV2 QStyleOptionTabV3 + QStyleOptionTabWidgetFrame QStyleOptionTabWidgetFrameV2 + QStyleOptionTitleBar QStyleOptionToolBar QStyleOptionToolBox + QStyleOptionToolBoxV2 QStyleOptionToolButton QStyleOptionViewItem + QStyleOptionViewItemV2 QStyleOptionViewItemV3 QStyleOptionViewItemV4 + QStylePainter QStyledItemDelegate QSwipeGesture QSyntaxHighlighter + QSystemTrayIcon QTabBar QTabWidget QTableView QTableWidget + QTableWidgetItem QTableWidgetSelectionRange QTabletEvent + QTapAndHoldGesture QTapGesture QTextBlock QTextBlockFormat + QTextBlockGroup QTextBlockUserData QTextBrowser QTextCharFormat + QTextCursor QTextDocument QTextDocumentFragment QTextDocumentWriter + QTextEdit QTextFormat QTextFragment QTextFrame QTextFrameFormat + QTextImageFormat QTextInlineObject QTextItem QTextLayout QTextLength + QTextLine QTextList QTextListFormat QTextObject QTextObjectInterface + QTextOption QTextTable QTextTableCell QTextTableCellFormat + QTextTableFormat QTimeEdit QToolBar QToolBox QToolButton QToolTip + QTouchEvent QTransform QTreeView QTreeWidget QTreeWidgetItem + QTreeWidgetItemIterator QUndoCommand QUndoGroup QUndoStack QUndoView + QVBoxLayout QValidator QVector2D QVector3D QVector4D QWhatsThis + QWhatsThisClickedEvent QWheelEvent QWidget QWidgetAction QWidgetItem + QWindowStateChangeEvent QWizard QWizardPage QWorkspace + QX11EmbedContainer QX11EmbedWidget QX11Info + """ + for _name in _QtGui_public_classes.split(): + locals()[_name] = type(_name, (), {}) + del _name class MySip(MagicMock):