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
PySide backend support #80
Changes from 8 commits
f73a1c9
fcdc78f
bd8658c
6844901
6ccb243
89f82f2
ecd7ffd
e13997d
039814b
aaaec76
4e7a8fc
a80b001
5c963ae
69e8d2d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,8 +11,12 @@ | |
from backend_agg import FigureCanvasAgg | ||
from backend_qt4 import QtCore, QtGui, FigureManagerQT, FigureCanvasQT,\ | ||
show, draw_if_interactive, backend_version, \ | ||
NavigationToolbar2QT | ||
NavigationToolbar2QT, QT_API, QT_API_PYSIDE | ||
|
||
if QT_API == QT_API_PYSIDE: | ||
class FigureCanvasAgg( FigureCanvasAgg, object ): | ||
pass | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See my note above re: new-style classes. |
||
DEBUG = False | ||
|
||
|
||
|
@@ -91,7 +95,7 @@ def paintEvent( self, e ): | |
else: | ||
stringBuffer = self.renderer._renderer.tostring_argb() | ||
|
||
qImage = QtGui.QImage(stringBuffer, self.renderer.width, | ||
qImage = QtGui.QImage(stringBuffer, self.renderer.width, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With ubuntu 11.4 (pyside 1.0.1 & qt4 4.7.2), I get a following exception. TypeError: 'PySide.QtGui.QImage' called with wrong argument types: Converting stringBuffer to a buffer object explicitly seem to solve the problem (both pyqt and pyside works), but i'm not sure if this behavior will depend on the pyside version.
We may need a same change at line 117. -JJ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a PySide bug fixed in 1.0.2 http://bugs.pyside.org/show_bug.cgi?id=489 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should probably add a version check against PySide then, since we know 1.0.2 is the minimum workable version. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good to know that this is a pyside bug. However, using explicit buffer call does any harm to matplotib w/ pyside v1.0.2? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. Wrapping with buffer makes it work in both versions. I was under the impression that mpl wasn't in the business of fixing bugs for specific versions of on specific platforms etc. In any case, there's another bug (819, see my opening comment) that wasn't fixed until 1.0.2 (try saving a figure). There is also an outstanding bug that prevents this backend working on mac (809) that won't be fixed until 1.0.3. I'd suggest that 1.0.3 should probably be the minimum supported version to keep things simple. In which case this can stay as is. Unless there is a good reason to want to wrap with buffer() in any case? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In my experience, mpl tries to broadly support as many versions of a library on as many platforms as feasible. I don't know if it's stated explicitly anywhere, but at least in my work environment, it is very important to support rather old and possibly buggy versions of core dependencies (e.g. GUI toolkits) for quite some time. Look at the GTK backend, for example, for a number of version-specific hacks that have been required over time. Eventually the idea is to prune that stuff out -- my own rule of thumb is to support at least as far back as whatever was in the (current release - 2) of RHEL. In this specific case, however, with PySide being so new and cutting edge to begin with, I think it's ok to require a minimum version and not add hacks for 1.0.x which were fairly ephemeral and not widely-used releases. But the version check is important because user's should understand it's breaking because of an old version of PySide and not some other reason. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was inclined to fix the buffer thing since pyside v1.0.1 is packaged for ubuntu, and this simple fix at least makes the backend usable. Anyhow, I agree with Michael and the current approach is okay. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, that's good then. As a side note, I was under the impression that Ubuntu was more or less the development platform for PySide. Every version of PySide is packaged for it within a few hours of release isn't it? |
||
self.renderer.height, | ||
QtGui.QImage.Format_ARGB32) | ||
p = QtGui.QPainter(self) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
""" A Qt API selector that can be used to switch between PyQt and PySide. | ||
""" | ||
|
||
import os | ||
|
||
# Available APIs. | ||
QT_API_PYQT = 'pyqt' | ||
QT_API_PYSIDE = 'pyside' | ||
|
||
# Use PyQt by default until PySide is stable. | ||
QT_API = os.environ.get('QT_API', QT_API_PYQT) | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was wondering if we shouldn't do PySide selection by adding a new backend type (Qt4Agg and PySideAgg would share a lot of code, but would be selected with matplotlib.use). However, then I saw that IPython is also using this method, and it would be nice to be compatible with that. Can we add a comment: Select PyQt4 or PySide using an environment variable, in the same way IPython does. |
||
if QT_API == QT_API_PYQT: | ||
from PyQt4 import QtCore, QtGui | ||
|
||
# Alias PyQt-specific functions for PySide compatibility. | ||
try: | ||
QtCore.Slot = QtCore.pyqtSlot | ||
except AttributeError: | ||
QtCore.Slot = pyqtSignature # Not a perfect match but | ||
# works in simple cases | ||
QtCore.Property = QtCore.pyqtProperty | ||
|
||
import sip | ||
try : | ||
if sip.getapi("QString") > 1 : | ||
# Use new getSaveFileNameAndFilter() | ||
_getSaveFileName = lambda self, msg, start, filters, \ | ||
selectedFilter : \ | ||
QtGui.QFileDialog.getSaveFileNameAndFilter( \ | ||
self, msg, start, filters, selectedFilter)[0] | ||
else : | ||
# Use old getSaveFileName() | ||
_getSaveFileName = QtGui.QFileDialog.getSaveFileName | ||
except (AttributeError, KeyError) : | ||
# call to getapi() can fail in older versions of sip | ||
# Use the old getSaveFileName() | ||
_getSaveFileName = QtGui.QFileDialog.getSaveFileName | ||
|
||
elif QT_API == QT_API_PYSIDE: | ||
from PySide import QtCore, QtGui | ||
|
||
# Alias PySide-specific function for PyQt compatibilty | ||
QtCore.pyqtProperty = QtCore.Property | ||
QtCore.pyqtSignature = QtCore.Slot # Not a perfect match but | ||
# works in simple cases | ||
|
||
_getSaveFileName = lambda self, msg, start, filters, selectedFilter : \ | ||
QtGui.QFileDialog.getSaveFileName(self, \ | ||
msg, start, filters, selectedFilter)[0] | ||
else: | ||
raise RuntimeError('Invalid Qt API %r, valid values are: %r or %r' % | ||
(QT_API, QT_API_PYQT, QT_API_PYSIDE)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I gather that PySide requires that its class bases are new-style classes? Why don't we just make these bases new-style classes (i.e. make the canonical FigureCanvasBase in backends.py inherit from object)? That doesn't seem to break anything for any of the other GUI backends and removes the need for this kludge.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All correct. If it doesn't break anything I'll make the change on Monday.