|
1 | 1 | # -*- coding: utf-8 -*- |
| 2 | +# |
| 3 | +# Copyright © 2014-2015 Colin Duquesnoy |
| 4 | +# |
| 5 | +# Licensed under the terms of the MIT License |
| 6 | +# (see LICENSE.txt for details) |
| 7 | + |
2 | 8 | """ |
3 | | -**QtPyqt** is a shim over the various qt bindings. It is used to write |
| 9 | +**QtPy** is a shim over the various qt bindings. It is used to write |
4 | 10 | qt bindings indenpendent library or application. |
5 | 11 |
|
6 | 12 | The shim will automatically select the first available API (PyQt5, PyQt4 and |
7 | 13 | finally PySide). |
8 | 14 |
|
9 | 15 | You can force the use of one specific bindings (e.g. if your application is |
10 | | -using one specific bindings and you need to use library that use pyqode.qt) by |
11 | | -setting up the `QT_API` environment variable. |
| 16 | +using one specific bindings and you need to use library that use QtPy) by |
| 17 | +setting up the ``QT_API`` environment variable. |
12 | 18 |
|
13 | 19 | PyQt5 |
14 | 20 | ===== |
15 | 21 |
|
16 | 22 | For pyqt5, you don't have to set anything as it will be used automatically:: |
17 | | - >>> from qtpy import QtGui, QtWidgets, QtCore |
| 23 | +
|
| 24 | + >>> from pyqode.qt import QtGui, QtWidgets, QtCore |
18 | 25 | >>> print(QtWidgets.QWidget) |
19 | 26 |
|
20 | | -""" |
21 | 27 |
|
| 28 | +PyQt4 |
| 29 | +===== |
22 | 30 |
|
23 | | -import os |
| 31 | +Set the ``QT_API`` environment variable to 'PyQt4' (case insensitive) before |
| 32 | +importing any python package:: |
24 | 33 |
|
25 | | -__version__ = '1.0.1' |
| 34 | + >>> import os |
| 35 | + >>> os.environ['QT_API'] = 'PyQt4' |
| 36 | + >>> from pyqode.qt import QtGui, QtWidgets, QtCore |
| 37 | + >>> print(QtWidgets.QWidget) |
26 | 38 |
|
27 | 39 |
|
28 | | -os.environ.setdefault('QT_API', 'pyqt') |
29 | | -assert os.environ['QT_API'] in ('pyqt5', 'pyqt', 'pyside') |
| 40 | +.. warning:: This requires to set the SIP api to version 2 (for strings and |
| 41 | + covariants). If you're using python2 you have to make sure the correct sip |
| 42 | + api is set before importing any PyQt4 module (pyqode.qt can take care of |
| 43 | + that for you but it must be imported before any PyQt4 module). |
30 | 44 |
|
31 | | -API = os.environ['QT_API'] |
32 | | -API_NAME = {'pyqt5': 'PyQt5', 'pyqt': 'PyQt4', 'pyside': 'PySide'}[API] |
33 | 45 |
|
34 | | -PYQT5 = False |
| 46 | +PySide |
| 47 | +====== |
35 | 48 |
|
36 | | -if API == 'pyqt5': |
37 | | - try: |
38 | | - from PyQt5.QtCore import PYQT_VERSION_STR as __version__ |
39 | | - is_old_pyqt = False |
40 | | - is_pyqt46 = False |
41 | | - PYQT5 = True |
42 | | - except ImportError: |
43 | | - pass |
44 | | -elif API == 'pyqt': |
45 | | - # QtPy 1.0 is compatible with both #1 and #2 PyQt API, |
46 | | - # but to avoid issues with IPython and other Qt plugins |
47 | | - # we choose to support only API #2 |
48 | | - import sip |
49 | | - try: |
50 | | - sip.setapi('QString', 2) |
51 | | - sip.setapi('QVariant', 2) |
52 | | - except AttributeError: |
53 | | - # PyQt < v4.6. The actual check is done by requirements.check_qt() |
54 | | - # call from spyder.py |
55 | | - pass |
| 49 | +Set the QT_API environment variable to 'PySide' (case insensitive) before |
| 50 | +importing pyqode:: |
56 | 51 |
|
| 52 | + >>> import os |
| 53 | + >>> os.environ['QT_API'] = 'PySide' |
| 54 | + >>> from pyqode.qt import QtGui, QtWidgets, QtCore |
| 55 | + >>> print(QtWidgets.QWidget) |
| 56 | +
|
| 57 | +""" |
| 58 | + |
| 59 | +import os |
| 60 | +import sys |
| 61 | +import logging |
| 62 | + |
| 63 | +__version__ = '1.0.1' |
| 64 | + |
| 65 | +#: Qt API environment variable name |
| 66 | +QT_API = 'QT_API' |
| 67 | +#: names of the expected PyQt5 api |
| 68 | +PYQT5_API = ['pyqt5'] |
| 69 | +#: names of the expected PyQt4 api |
| 70 | +PYQT4_API = [ |
| 71 | + 'pyqt', # name used in IPython.qt |
| 72 | + 'pyqt4' # pyqode.qt original name |
| 73 | +] |
| 74 | +#: names of the expected PySide api |
| 75 | +PYSIDE_API = ['pyside'] |
| 76 | + |
| 77 | + |
| 78 | +class PythonQtError(Exception): |
| 79 | + |
| 80 | + """ |
| 81 | + Error raise if no bindings could be selected |
| 82 | + """ |
| 83 | + pass |
| 84 | + |
| 85 | + |
| 86 | +def setup_apiv2(): |
| 87 | + """ |
| 88 | + Setup apiv2 when using PyQt4 and Python2. |
| 89 | + """ |
| 90 | + # setup PyQt api to version 2 |
| 91 | + if sys.version_info[0] == 2: |
| 92 | + logging.getLogger(__name__).debug( |
| 93 | + 'setting up SIP API to version 2') |
| 94 | + import sip |
| 95 | + try: |
| 96 | + sip.setapi("QString", 2) |
| 97 | + sip.setapi("QVariant", 2) |
| 98 | + except ValueError: |
| 99 | + logging.getLogger(__name__).critical( |
| 100 | + "failed to set up sip api to version 2 for PyQt4") |
| 101 | + raise ImportError('PyQt4') |
| 102 | + |
| 103 | + |
| 104 | +def autodetect(): |
| 105 | + """ |
| 106 | + Auto-detects and use the first available QT_API by importing them in the |
| 107 | + following order: |
| 108 | +
|
| 109 | + 1) PyQt5 |
| 110 | + 2) PyQt4 |
| 111 | + 3) PySide |
| 112 | + """ |
| 113 | + logging.getLogger(__name__).debug('auto-detecting QT_API') |
57 | 114 | try: |
58 | | - from PyQt4.QtCore import PYQT_VERSION_STR as __version__ # analysis:ignore |
| 115 | + logging.getLogger(__name__).debug('trying PyQt5') |
| 116 | + import PyQt5 |
| 117 | + os.environ[QT_API] = PYQT5_API[0] |
| 118 | + logging.getLogger(__name__).debug('imported PyQt5') |
59 | 119 | except ImportError: |
60 | | - # Switching to PySide |
61 | | - API = os.environ['QT_API'] = 'pyside' |
62 | | - API_NAME = 'PySide' |
63 | | - else: |
64 | | - is_old_pyqt = __version__.startswith(('4.4', '4.5', '4.6', '4.7')) |
65 | | - is_pyqt46 = __version__.startswith('4.6') |
66 | | - import sip |
67 | 120 | try: |
68 | | - API_NAME += (" (API v%d)" % sip.getapi('QString')) |
69 | | - except AttributeError: |
70 | | - pass |
71 | | - |
72 | | - |
73 | | -if API == 'pyside': |
| 121 | + logging.getLogger(__name__).debug('trying PyQt4') |
| 122 | + setup_apiv2() |
| 123 | + import PyQt4 |
| 124 | + os.environ[QT_API] = PYQT4_API[0] |
| 125 | + logging.getLogger(__name__).debug('imported PyQt4') |
| 126 | + except ImportError: |
| 127 | + try: |
| 128 | + logging.getLogger(__name__).debug('trying PySide') |
| 129 | + import PySide |
| 130 | + os.environ[QT_API] = PYSIDE_API[0] |
| 131 | + logging.getLogger(__name__).debug('imported PySide') |
| 132 | + except ImportError: |
| 133 | + raise PythonQtError('No Qt bindings could be found') |
| 134 | + |
| 135 | + |
| 136 | +if QT_API in os.environ: |
| 137 | + # check if the selected QT_API is available |
74 | 138 | try: |
75 | | - from PySide import __version__ # analysis:ignore |
| 139 | + if os.environ[QT_API].lower() in PYQT5_API: |
| 140 | + logging.getLogger(__name__).debug('importing PyQt5') |
| 141 | + import PyQt5 |
| 142 | + os.environ[QT_API] = PYQT5_API[0] |
| 143 | + logging.getLogger(__name__).debug('imported PyQt5') |
| 144 | + elif os.environ[QT_API].lower() in PYQT4_API: |
| 145 | + logging.getLogger(__name__).debug('importing PyQt4') |
| 146 | + setup_apiv2() |
| 147 | + import PyQt4 |
| 148 | + os.environ[QT_API] = PYQT4_API[0] |
| 149 | + logging.getLogger(__name__).debug('imported PyQt4') |
| 150 | + elif os.environ[QT_API].lower() in PYSIDE_API: |
| 151 | + logging.getLogger(__name__).debug('importing PySide') |
| 152 | + import PySide |
| 153 | + os.environ[QT_API] = PYSIDE_API[0] |
| 154 | + logging.getLogger(__name__).debug('imported PySide') |
76 | 155 | except ImportError: |
77 | | - raise ImportError("QtPy requires PySide or PyQt to be installed") |
78 | | - else: |
79 | | - is_old_pyqt = is_pyqt46 = False |
| 156 | + logging.getLogger(__name__).warning( |
| 157 | + 'failed to import the selected QT_API: %s', |
| 158 | + os.environ[QT_API]) |
| 159 | + # use the auto-detected API if possible |
| 160 | + autodetect() |
| 161 | +else: |
| 162 | + # user did not select a qt api, let's perform auto-detection |
| 163 | + autodetect() |
| 164 | + |
| 165 | + |
| 166 | +logging.getLogger(__name__).info('using %s' % os.environ[QT_API]) |
80 | 167 |
|
0 commit comments