PySide is intended to be compatible with PyQt's API #2 which was introduced with PyQt v4.6 (this is the default API for Python 3). So the first step to migrate from PyQt to PySide is to switch from API #1 to API #2, which means no more QString, QStringList or QVariant objects (replaced by Python objects):
For Spyder, I chose to deal with this transition period with the following solution. The idea is to be able to test alternatively (and without changing too much code) the three cases (PyQt API #1, PyQt API #2 and PySide) by implementing a transitional package that your code will import instead of importing directly PyQt or PySide. See for example the Spyder's Qt transitional package :
(in the rest of the code, all import PyQt4.QtGui statements are for example replaced by import spyderlib.qt.QtGui)
At first, I thought that the best solution was to migrate directly to PyQt API #2, hence breaking the compatibility with PyQt API #1 (it's hard to resist to the temptation of getting rid of QString and QVariant objects!). But then I realized that other projects using the Spyder's widgets (source code editor, array editor or dictionnary editor widgets) like guidata would be forced to perform this migration at the same time: this was not acceptable and would lead to maintain two different versions of Spyder, one compatible with API #1 (Spyder v2.1) and the other with API #2 (Spyder v2.2). So I'm now convinced that the best solution is to change the code to make it compatible with both APIs and this is quite easy to do (it's now done in v2.1): QString objects can be used implicitely and QVariant objects and methods may be replaced by simple conversion functions (see 'from_qvariant' and 'to_qvariant' in spyderlib's code):
Here is the example of the NumPy arrays editor widget which is compatible with PyQt API #1, API #2 and PySide:
Another difference between PyQt and PySide is the way the QFileDialog static methods are wrapped. In PyQt, getOpenFileName returns only the filename. With PySide, the same function returns a tuple containing the filename and the selected filter. So we have to deal with it and the best way is to write wrappers that ensure full compatibility with PyQt (API #1 and #2) and PySide. This is done here:
There are still a lot of bug to fix for Spyder to be fully compatible with PySide (only Spyder's light mode is running with PySide, with very minor bugs) but that's a great start!