Repository: python-pillow/Pillow

Issue:
Import matplotlib qt4 backend after import PIL ImageQt when PyQt5 is installed causes exception
### What did you do?

```python
from PyQt4 import QtCore
from PIL.ImageQt import ImageQt
from matplotlib.backends.backend_qt4agg import (FigureCanvasQTAgg as FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
```

### What did you expect to happen?
Import PIL and matplotlib using PyQt4 (in an environment with PyQt5 also installed...)

### What actually happened?
RuntimeError: the PyQt5.QtCore and PyQt4.QtCore modules both wrap the QObject class

Note that this is related, to me, with issue #1939 (closed): https://github.com/python-pillow/Pillow/issues/1939

### What versions of Pillow and Python are you using?
Python 3.4.5
PIL 4.2.1
matplotlib 2.1.0

Please include **code** that reproduces the issue and whenever possible, an **image** that demonstrates the issue. Please upload images to GitHub, not to third-party file hosting sites. If necessary, add the image to a zip or tar archive.

The best reproductions are self-contained scripts with minimal dependencies. If you are using a framework such as plone, Django, or buildout, try to replicate the issue just using Pillow. 

```
Python 3.4.5 (default, May 29 2017, 15:17:55) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 
>>> import sys
>>> 
>>> 'PyQt4' in sys.modules
False
>>> 'PyQt5' in sys.modules
False
>>> 
>>> from PyQt4 import QtCore
>>> 'PyQt4' in sys.modules
True
>>> 'PyQt5' in sys.modules
False
>>> 
>>> from PIL.ImageQt import ImageQt
Imported PyQt4... OK!
>>> 
>>> 'PyQt4' in sys.modules
True
>>> 'PyQt5' in sys.modules
True
>>> 
>>> from matplotlib.backends.backend_qt4agg import (FigureCanvasQTAgg as FigureCanvas,
...     NavigationToolbar2QT as NavigationToolbar)
<module 'PyQt5' from '/usr/lib64/python3.4/site-packages/PyQt5/__init__.py'>
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python3.4/site-packages/matplotlib/backends/backend_qt4agg.py", line 10, in <module>
    from .backend_qt4 import (
  File "/usr/lib64/python3.4/site-packages/matplotlib/backends/backend_qt4.py", line 18, in <module>
    from .qt_compat import QtCore, QtWidgets, _getSaveFileName, __version__
  File "/usr/lib64/python3.4/site-packages/matplotlib/backends/qt_compat.py", line 153, in <module>
    from PyQt5 import QtCore, QtGui, QtWidgets
RuntimeError: the PyQt5.QtCore and PyQt4.QtCore modules both wrap the QObject class
>>> 
```
A try to fix it, is this (currently used in our production environment):

\# /usr/lib64/python3.4/site-packages/PIL/ImageQt.py

```python
(...)
import sys

from . import Image
from ._util import isPath
from io import BytesIO

qt_is_installed = True
qt_version = None
try:
    from PyQt5.QtGui import QImage, qRgba, QPixmap
    from PyQt5.QtCore import QBuffer, QIODevice
    qt_version = '5'
except (ImportError, RuntimeError):
    try:
        del sys.modules['PyQt5']
    except:
        pass

    try:
        from PyQt4.QtGui import QImage, qRgba, QPixmap
        from PyQt4.QtCore import QBuffer, QIODevice
        qt_version = '4'
    except (ImportError, RuntimeError):
        try:
            del sys.modules['PyQt4']
        except:
            pass

        try:
            from PySide.QtGui import QImage, qRgba, QPixmap
            from PySide.QtCore import QBuffer, QIODevice
            qt_version = 'side'
        except ImportError:
            qt_is_installed = False
(...)
```


Discussion:

Resolving patch:
diff --git a/src/PIL/ImageQt.py b/src/PIL/ImageQt.py
--- a/src/PIL/ImageQt.py
+++ b/src/PIL/ImageQt.py
@@ -19,25 +19,33 @@
 from . import Image
 from ._util import isPath, py3
 from io import BytesIO
-
-qt_is_installed = True
-qt_version = None
-try:
-    from PyQt5.QtGui import QImage, qRgba, QPixmap
-    from PyQt5.QtCore import QBuffer, QIODevice
-    qt_version = '5'
-except (ImportError, RuntimeError):
+import sys
+
+qt_versions = [
+    ['5', 'PyQt5'],
+    ['4', 'PyQt4'],
+    ['side', 'PySide']
+]
+# If a version has already been imported, attempt it first
+qt_versions.sort(key=lambda qt_version: qt_version[1] in sys.modules, reverse=True)
+for qt_version, qt_module in qt_versions:
     try:
-        from PyQt4.QtGui import QImage, qRgba, QPixmap
-        from PyQt4.QtCore import QBuffer, QIODevice
-        qt_version = '4'
-    except (ImportError, RuntimeError):
-        try:
+        if qt_module == 'PyQt5':
+            from PyQt5.QtGui import QImage, qRgba, QPixmap
+            from PyQt5.QtCore import QBuffer, QIODevice
+        elif qt_module == 'PyQt4':
+            from PyQt4.QtGui import QImage, qRgba, QPixmap
+            from PyQt4.QtCore import QBuffer, QIODevice
+        elif qt_module == 'PySide':
             from PySide.QtGui import QImage, qRgba, QPixmap
             from PySide.QtCore import QBuffer, QIODevice
-            qt_version = 'side'
-        except ImportError:
-            qt_is_installed = False
+    except (ImportError, RuntimeError):
+        continue
+    qt_is_installed = True
+    break
+else:
+    qt_is_installed = False
+    qt_version = None
 
 
 def rgb(r, g, b, a=255):


Test patch: