Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for qt6 (PyQt6 and PySide6) #237

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 39 additions & 14 deletions _pydev_bundle/pydev_monkey_qt.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def set_trace_in_qt():

def patch_qt(qt_support_mode):
'''
This method patches qt (PySide2, PySide, PyQt4, PyQt5) so that we have hooks to set the tracing for QThread.
This method patches qt (PySide6, PySide2, PySide, PyQt4, PyQt5, PyQt6) so that we have hooks to set the tracing for QThread.
'''
if not qt_support_mode:
return
Expand All @@ -43,24 +43,38 @@ def patch_qt(qt_support_mode):

patch_qt_on_import = None
try:
import PySide2 # @UnresolvedImport @UnusedImport
qt_support_mode = 'pyside2'
import PySide6 # @UnresolvedImport @UnusedImport
qt_support_mode = 'pyside6'
except:
try:
import Pyside # @UnresolvedImport @UnusedImport
qt_support_mode = 'pyside'
import PySide2 # @UnresolvedImport @UnusedImport
qt_support_mode = 'pyside2'
except:
try:
import PyQt5 # @UnresolvedImport @UnusedImport
qt_support_mode = 'pyqt5'
import Pyside # @UnresolvedImport @UnusedImport
qt_support_mode = 'pyside'
except:
try:
import PyQt4 # @UnresolvedImport @UnusedImport
qt_support_mode = 'pyqt4'
import PyQt6 # @UnresolvedImport @UnusedImport
qt_support_mode = 'pyqt6'
except:
return
try:
import PyQt5 # @UnresolvedImport @UnusedImport
qt_support_mode = 'pyqt5'
except:
try:
import PyQt4 # @UnresolvedImport @UnusedImport
qt_support_mode = 'pyqt4'
except:
return
if qt_support_mode == 'pyside6':
try:
import PySide6.QtCore # @UnresolvedImport
_internal_patch_qt(PySide6.QtCore, qt_support_mode)
except:
return

if qt_support_mode == 'pyside2':
elif qt_support_mode == 'pyside2':
try:
import PySide2.QtCore # @UnresolvedImport
_internal_patch_qt(PySide2.QtCore, qt_support_mode)
Expand All @@ -73,6 +87,13 @@ def patch_qt(qt_support_mode):
_internal_patch_qt(PySide.QtCore, qt_support_mode)
except:
return

elif qt_support_mode == 'pyqt6':
try:
import PyQt6.QtCore # @UnresolvedImport
_internal_patch_qt(PyQt6.QtCore)
except:
return

elif qt_support_mode == 'pyqt5':
try:
Expand Down Expand Up @@ -155,14 +176,14 @@ def __init__(self, thread, original_started):
QtCore.QObject.__init__(self)
self.thread = thread
self.original_started = original_started
if qt_support_mode in ('pyside', 'pyside2'):
if qt_support_mode in ('pyside', 'pyside2', 'pyside6'):
self._signal = original_started
else:
self._signal.connect(self._on_call)
self.original_started.connect(self._signal)

def connect(self, func, *args, **kwargs):
if qt_support_mode in ('pyside', 'pyside2'):
if qt_support_mode in ('pyside', 'pyside2', 'pyside6'):
return self._signal.connect(FuncWrapper(func), *args, **kwargs)
else:
return self._signal.connect(func, *args, **kwargs)
Expand Down Expand Up @@ -193,7 +214,11 @@ def __init__(self, *args, **kwargs):

def _exec_run(self):
set_trace_in_qt()
self.exec_()
# Qt6: exec_ is deprecated/removed
if hasattr(self, 'exec'):
self.exec()
else:
self.exec_()
return None

def _new_run(self):
Expand Down
4 changes: 2 additions & 2 deletions _pydevd_bundle/pydevd_command_line_handling.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,13 @@ def process_command_line(argv):
# The --qt-support is special because we want to keep backward compatibility:
# Previously, just passing '--qt-support' meant that we should use the auto-discovery mode
# whereas now, if --qt-support is passed, it should be passed as --qt-support=<mode>, where
# mode can be one of 'auto', 'none', 'pyqt5', 'pyqt4', 'pyside', 'pyside2'.
# mode can be one of 'auto', 'none', 'pyqt6', 'pyqt5', 'pyqt4', 'pyside', 'pyside2', 'pyside6'.
if argv[i] == '--qt-support':
setup['qt-support'] = 'auto'

elif argv[i].startswith('--qt-support='):
qt_support = argv[i][len('--qt-support='):]
valid_modes = ('none', 'auto', 'pyqt5', 'pyqt4', 'pyside', 'pyside2')
valid_modes = ('none', 'auto', 'pyqt6', 'pyqt5', 'pyqt4', 'pyside', 'pyside2', 'pyside6')
if qt_support not in valid_modes:
raise ValueError("qt-support mode invalid: " + qt_support)
if qt_support == 'none':
Expand Down
18 changes: 14 additions & 4 deletions tests_python/resources/_debugger_case_qthread1.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,18 @@
try:
from PySide import QtCore # @UnresolvedImport
except:
from PySide2 import QtCore # @UnresolvedImport
try:
from PySide2 import QtCore # @UnresolvedImport
except:
from PySide6 import QtCore # @UnresolvedImport
except:
try:
from PyQt4 import QtCore
from PyQt4 import QtCore # @UnresolvedImport
except:
from PyQt5 import QtCore
try:
from PyQt5 import QtCore # @UnresolvedImport
except:
from PyQt6 import QtCore # @UnresolvedImport

# Subclassing QThread
# http://doc.qt.nokia.com/latest/qthread.html
Expand All @@ -27,5 +33,9 @@ def run(self):
thread = AThread()
thread.finished.connect(app.exit)
thread.start()
app.exec_()
# Qt6: exec_ is deprecated/removed
if hasattr(app, 'exec'):
app.exec()
else:
app.exec_()
print('TEST SUCEEDED!')
18 changes: 14 additions & 4 deletions tests_python/resources/_debugger_case_qthread2.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,18 @@
try:
from PySide import QtCore # @UnresolvedImport
except:
from PySide2 import QtCore # @UnresolvedImport
try:
from PySide2 import QtCore # @UnresolvedImport
except:
from PySide6 import QtCore # @UnresolvedImport
except:
try:
from PyQt4 import QtCore
from PyQt4 import QtCore # @UnresolvedImport
except:
from PyQt5 import QtCore
try:
from PyQt5 import QtCore # @UnresolvedImport
except:
from PyQt6 import QtCore # @UnresolvedImport

# Subclassing QObject and using moveToThread
# http://labs.qt.nokia.com/2007/07/05/qthreads-no-longer-abstract/
Expand All @@ -36,5 +42,9 @@ def long_running(self):
objThread.started.connect(obj.long_running)
objThread.finished.connect(app.exit)
objThread.start()
app.exec_()
# Qt6: exec_ is deprecated/removed
if hasattr(app, 'exec'):
app.exec()
else:
app.exec_()
print('TEST SUCEEDED!')
18 changes: 14 additions & 4 deletions tests_python/resources/_debugger_case_qthread3.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,18 @@
try:
from PySide import QtCore # @UnresolvedImport
except:
from PySide2 import QtCore # @UnresolvedImport
try:
from PySide2 import QtCore # @UnresolvedImport
except:
from PySide6 import QtCore # @UnresolvedImport
except:
try:
from PyQt4 import QtCore
from PyQt4 import QtCore # @UnresolvedImport
except:
from PyQt5 import QtCore
try:
from PyQt5 import QtCore # @UnresolvedImport
except:
from PyQt6 import QtCore # @UnresolvedImport

# Using a QRunnable
# http://doc.qt.nokia.com/latest/qthreadpool.html
Expand All @@ -30,6 +36,10 @@ def run(self):
app = QtCore.QCoreApplication([])
runnable = Runnable()
QtCore.QThreadPool.globalInstance().start(runnable)
app.exec_()
# Qt6: exec_ is deprecated/removed
if hasattr(app, 'exec'):
app.exec()
else:
app.exec_()
QtCore.QThreadPool.globalInstance().waitForDone()
print('TEST SUCEEDED!')
22 changes: 16 additions & 6 deletions tests_python/resources/_debugger_case_qthread4.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
try:
from PySide import QtCore
try:
from PySide import QtCore # @UnresolvedImport
except:
try:
from PySide2 import QtCore # @UnresolvedImport
except:
from PySide6 import QtCore # @UnresolvedImport
except:
try:
from PySide2 import QtCore
from PyQt4 import QtCore # @UnresolvedImport
except:
try:
from PyQt4 import QtCore
from PyQt5 import QtCore # @UnresolvedImport
except:
from PyQt5 import QtCore
from PyQt6 import QtCore # @UnresolvedImport


class TestObject(QtCore.QObject):
Expand All @@ -30,7 +36,7 @@ def run(self):

def on_start():
print('On start called1')
print('On start called2')
print('On start called2') # break here


app = QtCore.QCoreApplication([])
Expand All @@ -43,5 +49,9 @@ def on_start():
some_thread.finished.connect(app.quit)

some_thread.start()
app.exec_()
# Qt6: exec_ is deprecated/removed
if hasattr(app, 'exec'):
app.exec()
else:
app.exec_()
print('TEST SUCEEDED!')
16 changes: 12 additions & 4 deletions tests_python/test_debugger.py
Original file line number Diff line number Diff line change
Expand Up @@ -1163,8 +1163,12 @@ def _has_qt():
from PySide import QtCore # @UnresolvedImport
return True
except:
from PySide2 import QtCore # @UnresolvedImport
return True
try:
from PySide2 import QtCore # @UnresolvedImport
return True
except:
from PySide6 import QtCore # @UnresolvedImport
return True
except:
try:
from PyQt4 import QtCore # @UnresolvedImport
Expand All @@ -1174,7 +1178,11 @@ def _has_qt():
from PyQt5 import QtCore # @UnresolvedImport
return True
except:
pass
try:
from PyQt6 import QtCore # @UnresolvedImport
return True
except:
pass
return False


Expand Down Expand Up @@ -1249,7 +1257,7 @@ def additional_output_checks(stdout, stderr):
if 'native Qt signal is not callable' in stderr:
raise AssertionError('Did not expect "native Qt signal is not callable" to be in stderr:\n%s' % (stderr,))

breakpoint_id = writer.write_add_breakpoint(28, 'on_start') # breakpoint on print('On start called2').
breakpoint_id = writer.write_add_breakpoint(writer.get_line_index_with_content('break here'), 'on_start') # breakpoint on print('On start called2').
writer.write_make_initial_run()

hit = writer.wait_for_breakpoint_hit()
Expand Down