diff --git a/python/pluginResources/messages/PyBundle.properties b/python/pluginResources/messages/PyBundle.properties index aed8bb51322b..242da19673fe 100644 --- a/python/pluginResources/messages/PyBundle.properties +++ b/python/pluginResources/messages/PyBundle.properties @@ -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: diff --git a/python/pydevSrc/src/com/jetbrains/python/debugger/pydev/ClientModeMultiProcessDebugger.java b/python/pydevSrc/src/com/jetbrains/python/debugger/pydev/ClientModeMultiProcessDebugger.java index af5b3a454ed6..7be2db0c2d8d 100644 --- a/python/pydevSrc/src/com/jetbrains/python/debugger/pydev/ClientModeMultiProcessDebugger.java +++ b/python/pydevSrc/src/com/jetbrains/python/debugger/pydev/ClientModeMultiProcessDebugger.java @@ -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 callback) { + public void loadReferrers(String threadId, + String frameId, + PyReferringObjectsValue var, + PyDebugCallback callback) { debugger(threadId).loadReferrers(threadId, frameId, var, callback); } diff --git a/python/pydevSrc/src/com/jetbrains/python/debugger/pydev/EvaluateCommand.java b/python/pydevSrc/src/com/jetbrains/python/debugger/pydev/EvaluateCommand.java index dbd78e3be075..0d3d524c94e0 100644 --- a/python/pydevSrc/src/com/jetbrains/python/debugger/pydev/EvaluateCommand.java +++ b/python/pydevSrc/src/com/jetbrains/python/debugger/pydev/EvaluateCommand.java @@ -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; } diff --git a/python/pydevSrc/src/com/jetbrains/python/debugger/pydev/MultiProcessDebugger.java b/python/pydevSrc/src/com/jetbrains/python/debugger/pydev/MultiProcessDebugger.java index bac52566fa8f..fefc35c7a2d6 100644 --- a/python/pydevSrc/src/com/jetbrains/python/debugger/pydev/MultiProcessDebugger.java +++ b/python/pydevSrc/src/com/jetbrains/python/debugger/pydev/MultiProcessDebugger.java @@ -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 callback) { + public void loadReferrers(String threadId, + String frameId, + PyReferringObjectsValue var, + PyDebugCallback callback) { debugger(threadId).loadReferrers(threadId, frameId, var, callback); } diff --git a/python/pydevSrc/src/com/jetbrains/python/debugger/pydev/ProcessDebugger.java b/python/pydevSrc/src/com/jetbrains/python/debugger/pydev/ProcessDebugger.java index c7afe6940696..72f9240d089b 100644 --- a/python/pydevSrc/src/com/jetbrains/python/debugger/pydev/ProcessDebugger.java +++ b/python/pydevSrc/src/com/jetbrains/python/debugger/pydev/ProcessDebugger.java @@ -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() { } } diff --git a/python/pydevSrc/src/com/jetbrains/python/debugger/pydev/RemoteDebugger.java b/python/pydevSrc/src/com/jetbrains/python/debugger/pydev/RemoteDebugger.java index 43d9176f3cd0..27cd3150e9ea 100644 --- a/python/pydevSrc/src/com/jetbrains/python/debugger/pydev/RemoteDebugger.java +++ b/python/pydevSrc/src/com/jetbrains/python/debugger/pydev/RemoteDebugger.java @@ -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 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 > void executeCommandSafely(@NotNull T command) { try { diff --git a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java index b6fa8c35f2c6..78e386a91828 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java +++ b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java @@ -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 callback) { diff --git a/python/src/com/jetbrains/python/debugger/PyDebuggerConfigurable.form b/python/src/com/jetbrains/python/debugger/PyDebuggerConfigurable.form index e5fede6b9413..c714f1b19f7e 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebuggerConfigurable.form +++ b/python/src/com/jetbrains/python/debugger/PyDebuggerConfigurable.form @@ -1,9 +1,9 @@
- + - + @@ -135,7 +135,7 @@ - + @@ -150,6 +150,18 @@ + + + + + + + + + + + + @@ -166,6 +178,15 @@ + + + + + + + + +
diff --git a/python/src/com/jetbrains/python/debugger/PyDebuggerConfigurable.java b/python/src/com/jetbrains/python/debugger/PyDebuggerConfigurable.java index 31557c0af46f..8c4867afd182 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebuggerConfigurable.java +++ b/python/src/com/jetbrains/python/debugger/PyDebuggerConfigurable.java @@ -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); } } diff --git a/python/src/com/jetbrains/python/debugger/PyDebuggerOptionsProvider.java b/python/src/com/jetbrains/python/debugger/PyDebuggerOptionsProvider.java index 6953c0673c5f..db2e86d80d0c 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebuggerOptionsProvider.java +++ b/python/src/com/jetbrains/python/debugger/PyDebuggerOptionsProvider.java @@ -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; + } }