{"id":2254,"library":"qtpy","title":"QtPy","description":"QtPy provides an abstraction layer on top of the various Qt bindings (PyQt5, PyQt6, PySide2, and PySide6), allowing developers to write Python GUI applications that can run with any of these backends without modifying code. It automatically detects and uses the available binding, or can be configured to prefer a specific one. The current version is 2.4.3, with a regular release cadence addressing compatibility and feature enhancements.","status":"active","version":"2.4.3","language":"en","source_language":"en","source_url":"https://github.com/spyder-ide/qtpy","tags":["qt","gui","abstraction","cross-platform","pyqt","pyside"],"install":[{"cmd":"pip install qtpy","lang":"bash","label":"Install QtPy (requires a Qt binding)"},{"cmd":"pip install qtpy[pyqt5] # or [pyqt6], [pyside2], [pyside6]","lang":"bash","label":"Install QtPy with a specific backend (example for PyQt5)"}],"dependencies":[{"reason":"One of the underlying Qt bindings is required by QtPy.","package":"PyQt5","optional":true},{"reason":"One of the underlying Qt bindings is required by QtPy.","package":"PyQt6","optional":true},{"reason":"One of the underlying Qt bindings is required by QtPy.","package":"PySide2","optional":true},{"reason":"One of the underlying Qt bindings is required by QtPy.","package":"PySide6","optional":true}],"imports":[{"note":"QtPy abstracts the specific binding. Import directly from `qtpy` to ensure cross-binding compatibility.","wrong":"from PyQt5 import QtWidgets","symbol":"QtWidgets","correct":"from qtpy import QtWidgets"},{"note":"Import `QtCore` for fundamental non-GUI classes.","symbol":"QtCore","correct":"from qtpy import QtCore"},{"note":"Import `QtGui` for GUI components not specific to widgets.","symbol":"QtGui","correct":"from qtpy import QtGui"}],"quickstart":{"code":"import sys\nimport os\nfrom qtpy import QtWidgets, QtCore\n\n# Optional: force a specific Qt API (e.g., 'PyQt5', 'PyQt6', 'PySide2', 'PySide6')\n# os.environ['QT_API'] = 'PyQt5'\n\n# Create the application object\napp = QtWidgets.QApplication(sys.argv)\n\n# Create a simple widget\nwidget = QtWidgets.QWidget()\nwidget.setWindowTitle('Hello QtPy!')\nwidget.setGeometry(300, 300, 300, 150)\n\nlayout = QtWidgets.QVBoxLayout()\nlabel = QtWidgets.QLabel('Welcome to QtPy!')\nbutton = QtWidgets.QPushButton('Click Me')\n\nlayout.addWidget(label)\nlayout.addWidget(button)\nwidget.setLayout(layout)\n\ndef on_button_click():\n    label.setText('Button clicked from ' + os.environ.get('QT_API', 'auto-detected') + '!')\n\nbutton.clicked.connect(on_button_click)\n\n# Show the widget\nwidget.show()\n\n# Start the event loop\nsys.exit(app.exec_())","lang":"python","description":"This quickstart demonstrates a basic QtPy application. It initializes a QApplication, creates a QWidget with a QLabel and QPushButton, sets up a simple layout, and connects a slot to the button's click signal. It highlights how to import modules from `qtpy` and also shows an optional environment variable `QT_API` that can be set to force a specific backend if multiple are installed."},"warnings":[{"fix":"Install your preferred Qt binding: `pip install PyQt6` or `pip install PySide6` etc. You can also install with QtPy extras: `pip install qtpy[pyqt6]`.","message":"QtPy does not install Qt bindings. You must explicitly install at least one binding (e.g., `PyQt5`, `PyQt6`, `PySide2`, or `PySide6`) for QtPy to function. If no binding is found, `QtBindingsNotFoundError` will be raised.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Consult Qt documentation for Qt6 migration guides. Review `qtpy`'s changelog for specific compatibility fixes. Be mindful of module paths and class availability.","message":"When migrating to Qt6 bindings (PyQt6/PySide6), be aware of significant changes in the underlying Qt framework. Modules or classes may have been moved (`QtGui.QScreen` to `QtWidgets.QScreen`) or removed (e.g., `QtWebEngineCore` vs `QtWebEngineWidgets` module structure, `QLibraryInfo.LibraryLocation` renamed to `LibraryPath`). While QtPy attempts to abstract these, some code adjustments might still be necessary.","severity":"breaking","affected_versions":"QtPy versions supporting Qt6 (>=2.0.0)"},{"fix":"Before importing `qtpy`, set `os.environ['QT_API'] = 'PySide6'` in your Python code or define the environment variable in your shell.","message":"If multiple Qt bindings are installed, QtPy follows a specific detection order (usually PyQt6, PySide6, PyQt5, PySide2). To force a specific binding, set the `QT_API` environment variable (e.g., `QT_API='PySide6'`).","severity":"gotcha","affected_versions":"All versions"},{"fix":"Be aware of the deprecation if you use `QSqlDatabase.exec()` directly. Consider updating your code to use newer, non-deprecated database interaction methods if available in PySide6.","message":"When using PySide6, `QSqlDatabase.exec()` raises a `DeprecationWarning` in Qt 6.5+. QtPy 2.4.3 and later ignore this warning by default to reduce noise, but the underlying API usage is still deprecated in PySide6.","severity":"deprecated","affected_versions":"QtPy >=2.4.3 (fix applied), PySide6 users"},{"fix":"Upgrade to QtPy 2.4.3 or newer. If upgrading is not immediately possible, carefully review `isinstance` checks involving these classes.","message":"Prior to QtPy 2.4.3, `isinstance` checks for `QMenu` and `QToolBar` (especially when dealing with wrapped objects or specific inheritance hierarchies) could fail unexpectedly, leading to runtime errors or incorrect behavior.","severity":"gotcha","affected_versions":"<2.4.3"}],"env_vars":null,"last_verified":"2026-04-09T00:00:00.000Z","next_check":"2026-07-08T00:00:00.000Z"}