PY-23611 Support debugging for PySide2

This commit is contained in:
Andrey Lisin
2019-02-25 12:58:36 +03:00
parent d2ca86fc69
commit c0230a7f3b
8 changed files with 239 additions and 17 deletions
@@ -35,21 +35,31 @@ def patch_qt(qt_support_mode):
patch_qt_on_import = None
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 PyQt5 # @UnresolvedImport @UnusedImport
qt_support_mode = 'pyqt5'
except:
return
try:
import PyQt4 # @UnresolvedImport @UnusedImport
qt_support_mode = 'pyqt4'
except:
return
if qt_support_mode == 'pyside2':
try:
import PySide2.QtCore # @UnresolvedImport
_internal_patch_qt(PySide2.QtCore, qt_support_mode)
except:
return
if qt_support_mode == 'pyside':
elif qt_support_mode == 'pyside':
try:
import PySide.QtCore # @UnresolvedImport
_internal_patch_qt(PySide.QtCore, qt_support_mode)
@@ -134,14 +144,14 @@ def _internal_patch_qt(QtCore, qt_support_mode='auto'):
QtCore.QObject.__init__(self)
self.thread = thread
self.original_started = original_started
if qt_support_mode == 'pyside':
if qt_support_mode in ('pyside', 'pyside2'):
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 == 'pyside':
if qt_support_mode in ('pyside', 'pyside2'):
return self._signal.connect(FuncWrapper(func), *args, **kwargs)
else:
return self._signal.connect(func, *args, **kwargs)
@@ -111,13 +111,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'.
# mode can be one of 'auto', 'none', 'pyqt5', 'pyqt4', 'pyside', 'pyside2'.
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')
valid_modes = ('none', 'auto', 'pyqt5', 'pyqt4', 'pyside', 'pyside2')
if qt_support not in valid_modes:
raise ValueError("qt-support mode invalid: " + qt_support)
if qt_support == 'none':
+1 -1
View File
@@ -122,7 +122,7 @@ envs {
true)
if (Os.isFamily(Os.FAMILY_UNIX)) {
createPython("pyqt_env", "3.5.4", ["pyqt5==5.10.1"], "pyqt5", true)
createPython("qt_env", "3.7.2", ["pyqt5==5.12", "PySide2==5.12.1"], "qt", true)
}
@@ -40,7 +40,7 @@ public class PyDebuggerConfigurable implements SearchableConfigurable, Configura
private ActionLink myActionLink;
private JBTextField myAttachProcessFilter;
private JBLabel myAttachFilterLabel;
private final List<String> myPyQtBackendsList = Lists.newArrayList("Auto", "PyQt4", "PyQt5", "PySide");
private final List<String> myPyQtBackendsList = Lists.newArrayList("Auto", "PyQt4", "PyQt5", "PySide", "PySide2");
private final Project myProject;
+16
View File
@@ -0,0 +1,16 @@
from PySide2 import QtCore
import sys
class AThread(QtCore.QThread):
def run(self):
for i in range(3):
print("ping %d" % i)
app = QtCore.QCoreApplication([])
thread = AThread()
thread.finished.connect(app.exit)
thread.start()
sys.exit(app.exec_())
+23
View File
@@ -0,0 +1,23 @@
from PySide2 import QtCore
import sys
class SomeObject(QtCore.QObject):
finished = QtCore.Signal()
def longRunning(self):
for i in range(3):
print("ping %d" % i)
self.finished.emit()
app = QtCore.QCoreApplication([])
objThread = QtCore.QThread()
obj = SomeObject()
obj.moveToThread(objThread)
obj.finished.connect(objThread.quit)
objThread.started.connect(obj.longRunning)
objThread.finished.connect(app.exit)
objThread.start()
sys.exit(app.exec_())
+19
View File
@@ -0,0 +1,19 @@
from PySide2 import QtCore
import sys
class Runnable(QtCore.QRunnable):
def run(self):
app = QtCore.QCoreApplication.instance()
for i in range(3):
print("ping %d" % i)
app.quit()
app = QtCore.QCoreApplication([])
runnable = Runnable()
QtCore.QThreadPool.globalInstance().start(runnable)
sys.exit(app.exec_())
@@ -21,6 +21,7 @@ import com.jetbrains.env.ut.PyUnitTestProcessRunner;
import com.jetbrains.python.PythonHelpersLocator;
import com.jetbrains.python.console.pydev.PydevCompletionVariant;
import com.jetbrains.python.debugger.PyDebugValue;
import com.jetbrains.python.debugger.PyDebuggerOptionsProvider;
import com.jetbrains.python.debugger.PyExceptionBreakpointProperties;
import com.jetbrains.python.debugger.PyExceptionBreakpointType;
import com.jetbrains.python.debugger.settings.PyDebuggerSettings;
@@ -833,6 +834,12 @@ public class PythonDebuggerTest extends PyEnvTestCase {
@Override
public void before() {
toggleBreakpoint(getScriptName(), 8);
PyDebuggerOptionsProvider.getInstance(myFixture.getProject()).setPyQtBackend("pyqt5");
}
@Override
public void doFinally() {
PyDebuggerOptionsProvider.getInstance(myFixture.getProject()).setPyQtBackend("auto");
}
@Override
@@ -854,7 +861,7 @@ public class PythonDebuggerTest extends PyEnvTestCase {
@NotNull
@Override
public Set<String> getTags() {
return Sets.newHashSet("pyqt5");
return Sets.newHashSet("qt");
}
});
}
@@ -872,6 +879,12 @@ public class PythonDebuggerTest extends PyEnvTestCase {
@Override
public void before() {
toggleBreakpoint(getScriptName(), 10);
PyDebuggerOptionsProvider.getInstance(myFixture.getProject()).setPyQtBackend("pyqt5");
}
@Override
public void doFinally() {
PyDebuggerOptionsProvider.getInstance(myFixture.getProject()).setPyQtBackend("auto");
}
@Override
@@ -893,7 +906,7 @@ public class PythonDebuggerTest extends PyEnvTestCase {
@NotNull
@Override
public Set<String> getTags() {
return Sets.newHashSet("pyqt5");
return Sets.newHashSet("qt");
}
});
}
@@ -912,6 +925,12 @@ public class PythonDebuggerTest extends PyEnvTestCase {
@Override
public void before() {
toggleBreakpoint(getScriptName(), 9);
PyDebuggerOptionsProvider.getInstance(myFixture.getProject()).setPyQtBackend("pyqt5");
}
@Override
public void doFinally() {
PyDebuggerOptionsProvider.getInstance(myFixture.getProject()).setPyQtBackend("auto");
}
@Override
@@ -933,11 +952,146 @@ public class PythonDebuggerTest extends PyEnvTestCase {
@NotNull
@Override
public Set<String> getTags() {
return Sets.newHashSet("pyqt5");
return Sets.newHashSet("qt");
}
});
}
@Test
public void testPySide2QThreadInheritor() {
Assume.assumeFalse("Don't run under Windows", UsefulTestCase.IS_UNDER_TEAMCITY && SystemInfo.isWindows);
runPythonTest(new PyDebuggerTask("/debug", "test_pyside2_1.py") {
@Override
protected void init() {
setMultiprocessDebug(true);
}
@Override
public void before() {
toggleBreakpoint(getScriptName(), 8);
PyDebuggerOptionsProvider.getInstance(myFixture.getProject()).setPyQtBackend("pyside2");
}
@Override
public void doFinally() {
PyDebuggerOptionsProvider.getInstance(myFixture.getProject()).setPyQtBackend("auto");
}
@Override
public void testing() throws Exception {
waitForPause();
eval("i").hasValue("0");
resume();
waitForPause();
eval("i").hasValue("1");
resume();
}
@NotNull
@Override
public Set<String> getTags() {
return Sets.newHashSet("qt");
}
});
}
@Test
public void testPySide2MoveToThread() {
Assume.assumeFalse("Don't run under Windows", UsefulTestCase.IS_UNDER_TEAMCITY && SystemInfo.isWindows);
runPythonTest(new PyDebuggerTask("/debug", "test_pyside2_2.py") {
@Override
protected void init() {
setMultiprocessDebug(true);
}
@Override
public void before() {
toggleBreakpoint(getScriptName(), 10);
PyDebuggerOptionsProvider.getInstance(myFixture.getProject()).setPyQtBackend("pyside2");
}
@Override
public void doFinally() {
PyDebuggerOptionsProvider.getInstance(myFixture.getProject()).setPyQtBackend("auto");
}
@Override
public void testing() throws Exception {
waitForPause();
eval("i").hasValue("0");
resume();
waitForPause();
eval("i").hasValue("1");
resume();
}
@NotNull
@Override
public Set<String> getTags() {
return Sets.newHashSet("qt");
}
});
}
@Test
public void testPySide2QRunnableInheritor() {
Assume.assumeFalse("Don't run under Windows", UsefulTestCase.IS_UNDER_TEAMCITY && SystemInfo.isWindows);
runPythonTest(new PyDebuggerTask("/debug", "test_pyside2_3.py") {
@Override
protected void init() {
setMultiprocessDebug(true);
}
@Override
public void before() {
toggleBreakpoint(getScriptName(), 9);
PyDebuggerOptionsProvider.getInstance(myFixture.getProject()).setPyQtBackend("pyside2");
}
@Override
public void doFinally() {
PyDebuggerOptionsProvider.getInstance(myFixture.getProject()).setPyQtBackend("auto");
}
@Override
public void testing() throws Exception {
waitForPause();
eval("i").hasValue("0");
resume();
waitForPause();
eval("i").hasValue("1");
resume();
}
@NotNull
@Override
public Set<String> getTags() {
return Sets.newHashSet("qt");
}
});
}
@Test
public void testStepOverYieldFrom() {