[pycharm] PY-38965 Add debugger response timeout setting

GitOrigin-RevId: 9356bdfb3e7f72e9a6d93391989e68cfc0272e0f
This commit is contained in:
David Lysenko
2025-02-11 13:23:37 +00:00
committed by intellij-monorepo-bot
parent 290ba9eba8
commit d61687f0f6
10 changed files with 126 additions and 47 deletions
@@ -542,9 +542,9 @@ sdk.create.not.executable.does.not.exist.error=Executable does not exist
sdk.create.executable.directory.error=Path can't be a directory
sdk.create.tooltip.browse=Browse\u2026
sdk.create.custom.venv.install.fix.title=Install {0} {1}
sdk.create.custom.venv.run.error.message= Error Running {0}
sdk.create.custom.venv.run.error.message=Error Running {0}
sdk.create.custom.venv.progress.title.detect.executable=Detect executable
sdk.create.custom.existing.env.title ={0} env use
sdk.create.custom.existing.env.title={0} env use
sdk.create.targets.local=Local Machine
sdk.create.custom.virtualenv=Virtualenv
@@ -1051,6 +1051,7 @@ form.debugger.pyqt.compatible=PyQt compatible
form.debugger.run.debugger.in.server.mode=Run debugger in server mode
form.debugger.debugger.port=Debugger port:
form.debugger.remote.interpreter.docker.default.interpreter.path=python
form.debugger.response.timeout=Debugger evaluation response timeout (ms):
form.data.viewer.current.slice=Current slice
form.data.viewer.dialog.show.svn.map.table.header.column.format.title=Format
form.data.viewer.format=Format:
@@ -177,14 +177,20 @@ public class ClientModeMultiProcessDebugger implements ProcessDebugger {
}
@Override
public PyDebugValue evaluate(String threadId, String frameId, String expression, boolean execute) throws PyDebuggerException {
return debugger(threadId).evaluate(threadId, frameId, expression, execute);
public PyDebugValue evaluate(String threadId, String frameId, String expression, boolean execute, int evaluationTimeout)
throws PyDebuggerException {
return debugger(threadId).evaluate(threadId, frameId, expression, execute, evaluationTimeout);
}
@Override
public PyDebugValue evaluate(String threadId, String frameId, String expression, boolean execute, boolean trimResult)
public PyDebugValue evaluate(String threadId,
String frameId,
String expression,
boolean execute,
int evaluationTimeout,
boolean trimResult)
throws PyDebuggerException {
return debugger(threadId).evaluate(threadId, frameId, expression, execute, trimResult);
return debugger(threadId).evaluate(threadId, frameId, expression, execute, evaluationTimeout, trimResult);
}
@Override
@@ -201,7 +207,8 @@ public class ClientModeMultiProcessDebugger implements ProcessDebugger {
public @Nullable String execTableCommand(String threadId,
String frameId,
String command,
TableCommandType commandType, TableCommandParameters tableCommandParameters) throws PyDebuggerException {
TableCommandType commandType, TableCommandParameters tableCommandParameters)
throws PyDebuggerException {
return debugger(threadId).execTableCommand(threadId, frameId, command, commandType, tableCommandParameters);
}
@@ -235,7 +242,10 @@ public class ClientModeMultiProcessDebugger implements ProcessDebugger {
}
@Override
public void loadReferrers(String threadId, String frameId, PyReferringObjectsValue var, PyDebugCallback<? super XValueChildrenList> callback) {
public void loadReferrers(String threadId,
String frameId,
PyReferringObjectsValue var,
PyDebugCallback<? super XValueChildrenList> callback) {
debugger(threadId).loadReferrers(threadId, frameId, var, callback);
}
@@ -17,16 +17,18 @@ public class EvaluateCommand extends AbstractFrameCommand {
private final boolean myTrimResult;
private PyDebugValue myValue = null;
private final String myTempName;
private final int myEvaluationTimeout;
public EvaluateCommand(final RemoteDebugger debugger, final String threadId, final String frameId, final String expression,
final boolean execute, final boolean trimResult) {
final boolean execute, final boolean trimResult, final int evaluationTimeout) {
super(debugger, (execute ? EXECUTE : EVALUATE), threadId, frameId);
myExpression = expression;
myExecute = execute;
myDebugProcess = debugger.getDebugProcess();
myTrimResult = trimResult;
myTempName = myDebugProcess.canSaveToTemp(expression)? debugger.generateSaveTempName(threadId, frameId): "";
myTempName = myDebugProcess.canSaveToTemp(expression) ? debugger.generateSaveTempName(threadId, frameId) : "";
myEvaluationTimeout = evaluationTimeout;
}
@Override
@@ -50,6 +52,11 @@ public class EvaluateCommand extends AbstractFrameCommand {
}
}
@Override
protected long getResponseTimeout() {
return myEvaluationTimeout;
}
public PyDebugValue getValue() {
return myValue;
}
@@ -190,14 +190,20 @@ public class MultiProcessDebugger implements ProcessDebugger {
}
@Override
public PyDebugValue evaluate(String threadId, String frameId, String expression, boolean execute) throws PyDebuggerException {
return debugger(threadId).evaluate(threadId, frameId, expression, execute);
public PyDebugValue evaluate(String threadId, String frameId, String expression, boolean execute, int evaluationTimeout)
throws PyDebuggerException {
return debugger(threadId).evaluate(threadId, frameId, expression, execute, evaluationTimeout);
}
@Override
public PyDebugValue evaluate(String threadId, String frameId, String expression, boolean execute, boolean trimResult)
public PyDebugValue evaluate(String threadId,
String frameId,
String expression,
boolean execute,
int evaluationTimeout,
boolean trimResult)
throws PyDebuggerException {
return debugger(threadId).evaluate(threadId, frameId, expression, execute, trimResult);
return debugger(threadId).evaluate(threadId, frameId, expression, execute, evaluationTimeout, trimResult);
}
@Override
@@ -214,7 +220,8 @@ public class MultiProcessDebugger implements ProcessDebugger {
public @Nullable String execTableCommand(String threadId,
String frameId,
String command,
TableCommandType commandType, TableCommandParameters tableCommandParameters) throws PyDebuggerException {
TableCommandType commandType, TableCommandParameters tableCommandParameters)
throws PyDebuggerException {
return debugger(threadId).execTableCommand(threadId, frameId, command, commandType, tableCommandParameters);
}
@@ -248,7 +255,10 @@ public class MultiProcessDebugger implements ProcessDebugger {
}
@Override
public void loadReferrers(String threadId, String frameId, PyReferringObjectsValue var, PyDebugCallback<? super XValueChildrenList> callback) {
public void loadReferrers(String threadId,
String frameId,
PyReferringObjectsValue var,
PyDebugCallback<? super XValueChildrenList> callback) {
debugger(threadId).loadReferrers(threadId, frameId, var, callback);
}
@@ -23,12 +23,16 @@ public interface ProcessDebugger {
PyDebugValue evaluate(String threadId,
String frameId,
String expression, boolean execute) throws PyDebuggerException;
String expression,
boolean execute,
final int evaluationTimeout)
throws PyDebuggerException;
PyDebugValue evaluate(String threadId,
String frameId,
String expression,
boolean execute,
final int evaluationTimeout,
boolean trimResult)
throws PyDebuggerException;
@@ -151,5 +155,5 @@ public interface ProcessDebugger {
void suspendOtherThreads(PyThreadInfo thread);
default void interruptDebugConsole() {}
default void interruptDebugConsole() { }
}
@@ -147,21 +147,29 @@ public class RemoteDebugger implements ProcessDebugger {
}
@Override
public PyDebugValue evaluate(final String threadId,
final String frameId,
final String expression, final boolean execute) throws PyDebuggerException {
return evaluate(threadId, frameId, expression, execute, true);
public PyDebugValue evaluate(
final String threadId,
final String frameId,
final String expression,
final boolean execute,
final int evaluationTimeout
) throws PyDebuggerException {
return evaluate(threadId, frameId, expression, execute, evaluationTimeout, true);
}
@Override
public PyDebugValue evaluate(final String threadId,
final String frameId,
final String expression,
final boolean execute,
boolean trimResult)
throws PyDebuggerException {
return executeCommand(new EvaluateCommand(this, threadId, frameId, expression, execute, trimResult)).getValue();
public PyDebugValue evaluate(
final String threadId,
final String frameId,
final String expression,
final boolean execute,
final int evaluationTimeout,
boolean trimResult
) throws PyDebuggerException {
return executeCommand(
new EvaluateCommand(this, threadId, frameId, expression, execute, trimResult, evaluationTimeout)
).getValue();
}
@Override
@@ -325,7 +333,7 @@ public class RemoteDebugger implements ProcessDebugger {
final String expression = "del " + StringUtil.join(frameVars, ",");
final String wrappedExpression = String.format("try:\n %s\nexcept:\n pass", expression);
try {
evaluate(threadId, entry.getKey(), wrappedExpression, true);
evaluate(threadId, entry.getKey(), wrappedExpression, true, RESPONSE_TIMEOUT);
}
catch (PyDebuggerException e) {
LOG.error(e);
@@ -787,7 +795,6 @@ public class RemoteDebugger implements ProcessDebugger {
* If the command execution throws an exception and the debugger is in
* "connected" state then the exception is rethrown. If the debugger is not
* connected at this moment then the exception is ignored.
*
*/
private <T extends AbstractCommand<?>> T executeCommand(@NotNull T command) throws PyDebuggerException {
try {
@@ -808,7 +815,6 @@ public class RemoteDebugger implements ProcessDebugger {
* If the command execution throws an exception and the debugger is in
* "connected" state then the error is logged. If the debugger is not
* connected at this moment then the exception is ignored.
*
*/
private <T extends AbstractCommand<?>> void executeCommandSafely(@NotNull T command) {
try {
@@ -810,7 +810,9 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr
}
private PyDebugValue evaluate(String expression, boolean execute, PyStackFrame frame, boolean trimResult) throws PyDebuggerException {
return myDebugger.evaluate(frame.getThreadId(), frame.getFrameId(), expression, execute, trimResult);
PyDebuggerOptionsProvider settings = PyDebuggerOptionsProvider.getInstance(getProject());
return myDebugger.evaluate(frame.getThreadId(), frame.getFrameId(), expression, execute,
settings.getEvaluationResponseTimeout(), trimResult);
}
public void consoleExec(String command, PyDebugCallback<String> callback) {
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.jetbrains.python.debugger.PyDebuggerConfigurable">
<grid id="27dc6" binding="myMainPanel" layout-manager="GridLayoutManager" row-count="3" column-count="4" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="27dc6" binding="myMainPanel" layout-manager="GridLayoutManager" row-count="4" column-count="4" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="20" width="735" height="319"/>
<xy x="20" y="20" width="735" height="333"/>
</constraints>
<properties/>
<border type="none"/>
@@ -135,7 +135,7 @@
</grid>
<vspacer id="5915a">
<constraints>
<grid row="2" column="1" row-span="1" col-span="3" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
<grid row="3" column="1" row-span="1" col-span="3" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
</constraints>
</vspacer>
<component id="ffb0f" class="com.intellij.ui.components.JBLabel" binding="myAttachFilterLabel">
@@ -150,6 +150,18 @@
<html.disable class="java.lang.Boolean" value="false"/>
</clientProperties>
</component>
<component id="4a05c" class="com.intellij.ui.components.JBLabel" binding="myDebuggerEvaluationResponseTimeoutLabel" custom-create="true">
<constraints>
<grid row="2" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<labelFor value="79ca8"/>
<text resource-bundle="messages/PyBundle" key="form.debugger.response.timeout"/>
</properties>
<clientProperties>
<html.disable class="java.lang.Boolean" value="false"/>
</clientProperties>
</component>
<component id="79ca8" class="com.intellij.ui.components.JBTextField" binding="myAttachProcessFilter" default-binding="true">
<constraints>
<grid row="1" column="2" row-span="1" col-span="1" vsize-policy="3" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false">
@@ -166,6 +178,15 @@
<grid row="1" column="3" row-span="1" col-span="1" vsize-policy="1" hsize-policy="2" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
</hspacer>
<component id="fa84d" class="com.intellij.ui.JBIntSpinner" binding="myDebuggerEvaluationResponseTimeout" custom-create="true">
<constraints>
<grid row="2" column="2" row-span="1" col-span="1" vsize-policy="0" hsize-policy="2" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<max value="65535"/>
<min value="0"/>
</properties>
</component>
</children>
</grid>
</form>
@@ -43,6 +43,8 @@ public final class PyDebuggerConfigurable implements SearchableConfigurable, Con
private JBIntSpinner myDebuggerPort;
private JBCheckBox myRunDebuggerInServerMode;
private JPanel myDebuggerPortPanel;
private JBLabel myDebuggerEvaluationResponseTimeoutLabel;
private JBIntSpinner myDebuggerEvaluationResponseTimeout;
private enum PyQtBackend {
AUTO(PyBundle.messagePointer("python.debugger.qt.backend.auto")),
@@ -130,7 +132,8 @@ public final class PyDebuggerConfigurable implements SearchableConfigurable, Con
!StringUtil.toLowerCase((((PyQtBackend)myPyQtBackend.getSelectedItem()).name())).equals(settings.getPyQtBackend())) ||
myRunDebuggerInServerMode.isSelected() != settings.isRunDebuggerInServerMode() ||
myDebuggerPort.getNumber() != settings.getDebuggerPort() ||
!myAttachProcessFilter.getText().equals(settings.getAttachProcessFilter());
!myAttachProcessFilter.getText().equals(settings.getAttachProcessFilter()) ||
myDebuggerEvaluationResponseTimeout.getNumber() != settings.getEvaluationResponseTimeout();
}
@Override
@@ -151,6 +154,7 @@ public final class PyDebuggerConfigurable implements SearchableConfigurable, Con
settings.setDebuggerPort(myDebuggerPort.getNumber());
settings.setAttachProcessFilter(myAttachProcessFilter.getText());
settings.setEvaluationResponseTimeout(myDebuggerEvaluationResponseTimeout.getNumber());
}
@Override
@@ -165,6 +169,7 @@ public final class PyDebuggerConfigurable implements SearchableConfigurable, Con
myDebuggerPort.setNumber(settings.getDebuggerPort());
myRunDebuggerInServerMode.setSelected(settings.isRunDebuggerInServerMode());
myAttachProcessFilter.setText(settings.getAttachProcessFilter());
myDebuggerEvaluationResponseTimeout.setNumber(settings.getEvaluationResponseTimeout());
}
private void createUIComponents() {
@@ -175,15 +180,15 @@ public final class PyDebuggerConfigurable implements SearchableConfigurable, Con
PyBundle.message("debugger.warning.message")));
myActionLink = new ActionLink(PyBundle.message("form.debugger.clear.caches.action"), e -> {
boolean cleared = PySignatureCacheManager.getInstance(myProject).clearCache();
String message;
if (cleared) {
message = PyBundle.message("python.debugger.collection.signatures.deleted");
}
else {
message = PyBundle.message("python.debugger.nothing.to.delete");
}
Messages.showInfoMessage(myProject, message, PyBundle.message("debugger.delete.signature.cache"));
boolean cleared = PySignatureCacheManager.getInstance(myProject).clearCache();
String message;
if (cleared) {
message = PyBundle.message("python.debugger.collection.signatures.deleted");
}
else {
message = PyBundle.message("python.debugger.nothing.to.delete");
}
Messages.showInfoMessage(myProject, message, PyBundle.message("debugger.delete.signature.cache"));
});
myRunDebuggerInServerMode = new JBCheckBox();
@@ -197,5 +202,8 @@ public final class PyDebuggerConfigurable implements SearchableConfigurable, Con
myDebuggerPortLabel.setVisible(false);
myDebuggerPort.setVisible(false);
}
myDebuggerEvaluationResponseTimeoutLabel = new JBLabel(PyBundle.message("form.debugger.response.timeout"));
myDebuggerEvaluationResponseTimeout = new JBIntSpinner(0, 0, Integer.MAX_VALUE, 500);
}
}
@@ -42,6 +42,7 @@ public final class PyDebuggerOptionsProvider implements PersistentStateComponent
public boolean myRunDebuggerInServerMode = true;
public int myDebuggerPort = 29781;
public @NonNls String myAttachProcessFilter = "python";
public int myEvaluationResponseTimeout = 60_000;
}
@@ -86,8 +87,9 @@ public final class PyDebuggerOptionsProvider implements PersistentStateComponent
}
public String getPyQtBackend() {
if (StringUtil.toLowerCase(PyBundle.messagePointer("python.debugger.qt.backend.auto").get()).equals(myState.myPyQtBackend))
if (StringUtil.toLowerCase(PyBundle.messagePointer("python.debugger.qt.backend.auto").get()).equals(myState.myPyQtBackend)) {
return "auto";
}
return myState.myPyQtBackend;
}
@@ -118,5 +120,13 @@ public final class PyDebuggerOptionsProvider implements PersistentStateComponent
public void setAttachProcessFilter(String filter) {
myState.myAttachProcessFilter = filter;
}
public int getEvaluationResponseTimeout() {
return myState.myEvaluationResponseTimeout;
}
public void setEvaluationResponseTimeout(int timeout) {
myState.myEvaluationResponseTimeout = timeout;
}
}