Provides an abstraction layer on top of the various Qt bindings (PyQt5/6 and PySide2/6).
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Cross-binding compatibility functions for file dialogs, text processing, object lifecycle management, and QVariant handling that smooth over differences between Qt bindings and versions.
Utilities for handling text strings consistently across Python versions and Qt bindings.
def is_text_string(obj) -> bool:
"""
Return True if obj is a text string, False if it is anything else.
Args:
obj: Object to check
Returns:
bool: True if obj is a text string (str)
"""
def to_text_string(obj, encoding: str | None = None) -> str:
"""
Convert obj to (unicode) text string.
Args:
obj: Object to convert to string
encoding: Encoding to use if obj is bytes, defaults to None
Returns:
str: Text string representation of obj
"""
TEXT_TYPES: tuple[type, ...]
"""Tuple of text string types (str,)"""Usage example:
from qtpy.compat import is_text_string, to_text_string
data = "Hello World"
if is_text_string(data):
print("It's a string!")
# Convert various objects to text
text = to_text_string(42) # "42"
text = to_text_string(b"bytes", encoding="utf-8") # "bytes"Compatibility layer for QVariant differences between Qt bindings.
def to_qvariant(obj=None):
"""
Convert Python object to QVariant.
This is a transitional function from PyQt API#1 (QVariant exist)
to PyQt API#2 and PySide (QVariant does not exist).
Args:
obj: Python object to convert
Returns:
The object itself (no conversion needed in modern bindings)
"""
def from_qvariant(qobj=None, pytype=None):
"""
Convert QVariant object to Python object.
This is a transitional function from PyQt API #1 (QVariant exist)
to PyQt API #2 and PySide (QVariant does not exist).
Args:
qobj: QVariant object to convert
pytype: Python type hint (unused in modern bindings)
Returns:
The object itself (no conversion needed in modern bindings)
"""
PYQT_API_1: bool
"""Always False - legacy PyQt API compatibility flag"""Consistent file dialog interfaces that handle differences between Qt bindings and return types.
def getexistingdirectory(
parent=None,
caption: str = '',
basedir: str = '',
options=None
) -> str:
"""
Wrapper for QFileDialog.getExistingDirectory.
Args:
parent: Parent widget
caption: Dialog caption
basedir: Starting directory
options: Dialog options
Returns:
str: Selected directory path or empty string if cancelled
"""
def getopenfilename(
parent=None,
caption: str = '',
basedir: str = '',
filters: str = '',
selectedfilter: str = '',
options=None
) -> tuple[str, str]:
"""
Wrapper for QFileDialog.getOpenFileName.
Args:
parent: Parent widget
caption: Dialog caption
basedir: Starting directory
filters: File filters (e.g., "Images (*.png *.jpg);;All Files (*)")
selectedfilter: Initially selected filter
options: Dialog options
Returns:
tuple[str, str]: (selected_filename, selected_filter)
"""
def getopenfilenames(
parent=None,
caption: str = '',
basedir: str = '',
filters: str = '',
selectedfilter: str = '',
options=None
) -> tuple[list[str], str]:
"""
Wrapper for QFileDialog.getOpenFileNames.
Args:
parent: Parent widget
caption: Dialog caption
basedir: Starting directory
filters: File filters
selectedfilter: Initially selected filter
options: Dialog options
Returns:
tuple[list[str], str]: (selected_filenames, selected_filter)
"""
def getsavefilename(
parent=None,
caption: str = '',
basedir: str = '',
filters: str = '',
selectedfilter: str = '',
options=None
) -> tuple[str, str]:
"""
Wrapper for QFileDialog.getSaveFileName.
Args:
parent: Parent widget
caption: Dialog caption
basedir: Starting directory
filters: File filters
selectedfilter: Initially selected filter
options: Dialog options
Returns:
tuple[str, str]: (selected_filename, selected_filter)
"""Usage example:
from qtpy.compat import getopenfilename, getsavefilename, getexistingdirectory
from qtpy.QtWidgets import QApplication, QWidget
app = QApplication([])
parent = QWidget()
# Open file dialog
filename, filter_used = getopenfilename(
parent,
"Open File",
"",
"Python Files (*.py);;All Files (*)"
)
if filename:
print(f"Selected: {filename}")
# Save file dialog
filename, filter_used = getsavefilename(
parent,
"Save File",
"",
"Text Files (*.txt);;All Files (*)"
)
# Directory selection
directory = getexistingdirectory(parent, "Select Directory")Utilities for checking Qt object validity across different bindings.
def isalive(obj) -> bool:
"""
Wrapper for sip.isdeleted/shiboken.isValid to check if Qt object is alive.
Args:
obj: Qt object to check
Returns:
bool: True if the Qt object is still valid/alive, False if deleted
"""Usage example:
from qtpy.compat import isalive
from qtpy.QtWidgets import QWidget
widget = QWidget()
print(isalive(widget)) # True
widget.deleteLater()
# After event loop processes deletion
print(isalive(widget)) # FalseAll compatibility functions are available through the compat module:
# Import specific functions
from qtpy.compat import getopenfilename, isalive, to_text_string
# Import entire module
from qtpy import compat
filename, _ = compat.getopenfilename(None, "Open File")
is_valid = compat.isalive(some_widget)
text = compat.to_text_string(some_object)The compatibility module ensures consistent behavior across all supported Qt bindings:
This allows code to work identically whether using PyQt5, PyQt6, PySide2, or PySide6.
Install with Tessl CLI
npx tessl i tessl/pypi-qtpy