qt_for_kernel.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. """ Import Qt in a manner suitable for an IPython kernel.
  2. This is the import used for the `gui=qt` or `matplotlib=qt` initialization.
  3. Import Priority:
  4. if Qt has been imported anywhere else:
  5. use that
  6. if matplotlib has been imported and doesn't support v2 (<= 1.0.1):
  7. use PyQt4 @v1
  8. Next, ask QT_API env variable
  9. if QT_API not set:
  10. ask matplotlib what it's using. If Qt4Agg or Qt5Agg, then use the
  11. version matplotlib is configured with
  12. else: (matplotlib said nothing)
  13. # this is the default path - nobody told us anything
  14. try in this order:
  15. PyQt default version, PySide, PyQt5
  16. else:
  17. use what QT_API says
  18. Note that %gui's implementation will always set a `QT_API`, see
  19. `IPython.terminal.pt_inputhooks.get_inputhook_name_and_func`
  20. """
  21. # NOTE: This is no longer an external, third-party module, and should be
  22. # considered part of IPython. For compatibility however, it is being kept in
  23. # IPython/external.
  24. import os
  25. import sys
  26. from IPython.external.qt_loaders import (
  27. load_qt,
  28. loaded_api,
  29. enum_factory,
  30. # QT6
  31. QT_API_PYQT6,
  32. QT_API_PYSIDE6,
  33. # QT5
  34. QT_API_PYQT5,
  35. QT_API_PYSIDE2,
  36. # QT4
  37. QT_API_PYQT,
  38. QT_API_PYSIDE,
  39. # default
  40. QT_API_PYQT_DEFAULT,
  41. )
  42. _qt_apis = (
  43. # QT6
  44. QT_API_PYQT6,
  45. QT_API_PYSIDE6,
  46. # QT5
  47. QT_API_PYQT5,
  48. QT_API_PYSIDE2,
  49. # default
  50. QT_API_PYQT_DEFAULT,
  51. )
  52. def matplotlib_options(mpl):
  53. """Constraints placed on an imported matplotlib."""
  54. if mpl is None:
  55. return
  56. backend = mpl.rcParams.get('backend', None)
  57. if backend == 'Qt4Agg':
  58. mpqt = mpl.rcParams.get('backend.qt4', None)
  59. if mpqt is None:
  60. return None
  61. if mpqt.lower() == 'pyside':
  62. return [QT_API_PYSIDE]
  63. elif mpqt.lower() == 'pyqt4':
  64. return [QT_API_PYQT_DEFAULT]
  65. elif mpqt.lower() == 'pyqt4v2':
  66. return [QT_API_PYQT]
  67. raise ImportError("unhandled value for backend.qt4 from matplotlib: %r" %
  68. mpqt)
  69. elif backend == 'Qt5Agg':
  70. mpqt = mpl.rcParams.get('backend.qt5', None)
  71. if mpqt is None:
  72. return None
  73. if mpqt.lower() == 'pyqt5':
  74. return [QT_API_PYQT5]
  75. raise ImportError("unhandled value for backend.qt5 from matplotlib: %r" %
  76. mpqt)
  77. def get_options():
  78. """Return a list of acceptable QT APIs, in decreasing order of preference."""
  79. #already imported Qt somewhere. Use that
  80. loaded = loaded_api()
  81. if loaded is not None:
  82. return [loaded]
  83. mpl = sys.modules.get("matplotlib", None)
  84. if mpl is not None and tuple(mpl.__version__.split(".")) < ("1", "0", "2"):
  85. # 1.0.1 only supports PyQt4 v1
  86. return [QT_API_PYQT_DEFAULT]
  87. qt_api = os.environ.get('QT_API', None)
  88. if qt_api is None:
  89. #no ETS variable. Ask mpl, then use default fallback path
  90. return matplotlib_options(mpl) or [
  91. QT_API_PYQT_DEFAULT,
  92. QT_API_PYQT6,
  93. QT_API_PYSIDE6,
  94. QT_API_PYQT5,
  95. QT_API_PYSIDE2,
  96. ]
  97. elif qt_api not in _qt_apis:
  98. raise RuntimeError("Invalid Qt API %r, valid values are: %r" %
  99. (qt_api, ', '.join(_qt_apis)))
  100. else:
  101. return [qt_api]
  102. api_opts = get_options()
  103. QtCore, QtGui, QtSvg, QT_API = load_qt(api_opts)
  104. enum_helper = enum_factory(QT_API, QtCore)