From 515b57c3c8a62632df04f7408ba4787bc21fa32a Mon Sep 17 00:00:00 2001 From: Martin Fitzpatrick Date: Thu, 4 Sep 2014 22:44:56 +0100 Subject: [PATCH 1/2] Fix handling of getSaveFileName to be consistent PyQt4 and PyQt5 handle getSaveFileName differently, returning either a filename or a filename,filter tuple respectively. PySide behaves as for PyQt5. This caused bug #3454 producing an 'format not supported' error as the tuple did not match any of the string types. This updates each API to return a tuple as per PyQt5 (following the principle of using the latest API as a target). For recent PyQt4 this means using getSaveFileNameAndFilter instead, for older PyQt4 we wrap the function to output a tuple. Figure saving has been tested on PySide, PyQt4 and PyQt5. --- lib/matplotlib/backends/backend_qt5.py | 2 +- lib/matplotlib/backends/qt_compat.py | 20 ++++++++------------ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/lib/matplotlib/backends/backend_qt5.py b/lib/matplotlib/backends/backend_qt5.py index b1bc794eb486..81f3ab05703a 100644 --- a/lib/matplotlib/backends/backend_qt5.py +++ b/lib/matplotlib/backends/backend_qt5.py @@ -715,7 +715,7 @@ def save_figure(self, *args): filters.append(filter) filters = ';;'.join(filters) - fname = _getSaveFileName(self.parent, "Choose a filename to save to", + fname, filter = _getSaveFileName(self.parent, "Choose a filename to save to", start, filters, selectedFilter) if fname: if startpath == '': diff --git a/lib/matplotlib/backends/qt_compat.py b/lib/matplotlib/backends/qt_compat.py index d65edbc4d2fd..39422025261d 100644 --- a/lib/matplotlib/backends/qt_compat.py +++ b/lib/matplotlib/backends/qt_compat.py @@ -78,21 +78,19 @@ try: if sip.getapi("QString") > 1: # Use new getSaveFileNameAndFilter() - _get_save = QtGui.QFileDialog.getSaveFileNameAndFilter + _getSaveFileName = QtGui.QFileDialog.getSaveFileNameAndFilter else: # Use old getSaveFileName() - _getSaveFileName = QtGui.QFileDialog.getSaveFileName + def _getSaveFileName(*args, **kwargs): + return QtGui.QFileDialog.getSaveFileName(*args, **kwargs), None + except (AttributeError, KeyError): # call to getapi() can fail in older versions of sip - _getSaveFileName = QtGui.QFileDialog.getSaveFileName + def _getSaveFileName(*args, **kwargs): + return QtGui.QFileDialog.getSaveFileName(*args, **kwargs), None else: # PyQt5 API - from PyQt5 import QtCore, QtGui, QtWidgets - - # Additional PyQt5 shimming to make it appear as for PyQt4 - - _get_save = QtWidgets.QFileDialog.getSaveFileName _getSaveFileName = QtWidgets.QFileDialog.getSaveFileName # Alias PyQt-specific functions for PySide compatibility. @@ -112,11 +110,8 @@ raise ImportError( "Matplotlib backend_qt4 and backend_qt4agg require PySide >=1.0.3") - _get_save = QtGui.QFileDialog.getSaveFileName + _getSaveFileName = QtGui.QFileDialog.getSaveFileName -if _getSaveFileName is None: - def _getSaveFileName(self, msg, start, filters, selectedFilter): - return _get_save(self, msg, start, filters, selectedFilter)[0] # Apply shim to Qt4 APIs to make them look like Qt5 if QT_API in (QT_API_PYQT, QT_API_PYQTv2, QT_API_PYSIDE): @@ -128,3 +123,4 @@ def _getSaveFileName(self, msg, start, filters, selectedFilter): ''' QtWidgets = QtGui + From c0fbfbd46571a8c5c414570a0ff618489a442835 Mon Sep 17 00:00:00 2001 From: Martin Fitzpatrick Date: Fri, 5 Sep 2014 09:09:57 +0100 Subject: [PATCH 2/2] Fix PEP8 compliance --- lib/matplotlib/backends/backend_qt5.py | 15 +++++++-------- lib/matplotlib/backends/qt_compat.py | 10 ++++++---- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/lib/matplotlib/backends/backend_qt5.py b/lib/matplotlib/backends/backend_qt5.py index 81f3ab05703a..72cad73b8f95 100644 --- a/lib/matplotlib/backends/backend_qt5.py +++ b/lib/matplotlib/backends/backend_qt5.py @@ -22,7 +22,6 @@ 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 @@ -184,6 +183,7 @@ class TimerQT(TimerBase): upon timer events. This list can be manipulated directly, or the functions add_callback and remove_callback can be used. ''' + def __init__(self, *args, **kwargs): TimerBase.__init__(self, *args, **kwargs) @@ -331,8 +331,8 @@ def resizeEvent(self, event): print('resize (%d x %d)' % (w, h)) print("FigureCanvasQt.resizeEvent(%d, %d)" % (w, h)) dpival = self.figure.dpi - winch = w/dpival - hinch = h/dpival + winch = w / dpival + hinch = h / dpival self.figure.set_size_inches(winch, hinch) FigureCanvasBase.resize_event(self) self.draw() @@ -551,9 +551,9 @@ def destroy(self, *args): self.window.destroyed.connect(self._widgetclosed) if self.toolbar: - self.toolbar.destroy() + self.toolbar.destroy() if DEBUG: - print("destroy figure manager") + print("destroy figure manager") self.window.close() def get_window_title(self): @@ -750,7 +750,7 @@ def __init__(self, targetfig, parent): self.slidertop.valueChanged.connect(self.sliderbottom.setMaximum) self.defaults = {} - for attr in ('left', 'bottom', 'right', 'top', 'wspace', 'hspace',): + for attr in ('left', 'bottom', 'right', 'top', 'wspace', 'hspace', ): self.defaults[attr] = getattr(self.targetfig.subplotpars, attr) slider = getattr(self, 'slider' + attr) slider.setMinimum(0) @@ -761,7 +761,7 @@ def __init__(self, targetfig, parent): self._setSliderPositions() def _setSliderPositions(self): - for attr in ('left', 'bottom', 'right', 'top', 'wspace', 'hspace',): + for attr in ('left', 'bottom', 'right', 'top', 'wspace', 'hspace', ): slider = getattr(self, 'slider' + attr) slider.setSliderPosition(int(self.defaults[attr] * 1000)) @@ -850,6 +850,5 @@ def exception_handler(type, value, tb): if len(msg): error_msg_qt(msg) - FigureCanvas = FigureCanvasQT FigureManager = FigureManagerQT diff --git a/lib/matplotlib/backends/qt_compat.py b/lib/matplotlib/backends/qt_compat.py index 39422025261d..21d85bba87c6 100644 --- a/lib/matplotlib/backends/qt_compat.py +++ b/lib/matplotlib/backends/qt_compat.py @@ -15,7 +15,6 @@ QT_API_PYQT5 = 'PyQt5' # use PyQt5 API; Version 2 with module shim ETS = dict(pyqt=QT_API_PYQTv2, pyside=QT_API_PYSIDE, pyqt5=QT_API_PYQT5) - # If the ETS QT_API environment variable is set, use it. Note that # ETS requires the version 2 of PyQt4, which is not the platform # default for Python 2.x. @@ -62,14 +61,14 @@ sip.setapi('QString', 2) except: res = 'QString API v2 specification failed. Defaulting to v1.' - verbose.report(cond+res, 'helpful') + verbose.report(cond + res, 'helpful') # condition has now been reported, no need to repeat it: cond = "" try: sip.setapi('QVariant', 2) except: res = 'QVariant API v2 specification failed. Defaulting to v1.' - verbose.report(cond+res, 'helpful') + verbose.report(cond + res, 'helpful') if QT_API in [QT_API_PYQT, QT_API_PYQTv2]: # PyQt4 API @@ -80,11 +79,15 @@ # Use new getSaveFileNameAndFilter() _getSaveFileName = QtGui.QFileDialog.getSaveFileNameAndFilter else: + + # Use old getSaveFileName() def _getSaveFileName(*args, **kwargs): return QtGui.QFileDialog.getSaveFileName(*args, **kwargs), None except (AttributeError, KeyError): + + # call to getapi() can fail in older versions of sip def _getSaveFileName(*args, **kwargs): return QtGui.QFileDialog.getSaveFileName(*args, **kwargs), None @@ -123,4 +126,3 @@ def _getSaveFileName(*args, **kwargs): ''' QtWidgets = QtGui -