diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_comm.py b/python/helpers/pydev/_pydevd_bundle/pydevd_comm.py index 70566d248c16..1c3f2a3ee69a 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_comm.py +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_comm.py @@ -139,6 +139,7 @@ CMD_STEP_INTO_MY_CODE = 144 CMD_GET_CONCURRENCY_EVENT = 145 CMD_SHOW_RETURN_VALUES = 146 CMD_INPUT_REQUESTED = 147 +CMD_GET_DESCRIPTION = 148 CMD_VERSION = 501 CMD_RETURN = 502 @@ -193,6 +194,7 @@ ID_TO_MEANING = { '145': 'CMD_GET_CONCURRENCY_EVENT', '146': 'CMD_SHOW_RETURN_VALUES', '147': 'CMD_INPUT_REQUESTED', + '148': 'CMD_GET_DESCRIPTION', '501': 'CMD_VERSION', '502': 'CMD_RETURN', @@ -700,6 +702,12 @@ class NetCommandFactory: except Exception: return self.make_error_message(seq, get_exception_traceback_str()) + def make_get_description_message(self, seq, payload): + try: + return NetCommand(CMD_GET_DESCRIPTION, seq, payload) + except Exception: + return self.make_error_message(seq, get_exception_traceback_str()) + def make_get_frame_message(self, seq, payload): try: return NetCommand(CMD_GET_FRAME, seq, payload) @@ -1135,6 +1143,36 @@ class InternalGetCompletions(InternalThreadCommand): cmd = dbg.cmd_factory.make_error_message(self.sequence, "Error evaluating expression " + exc) dbg.writer.add_command(cmd) + +# ======================================================================================================================= +# InternalGetDescription +# ======================================================================================================================= +class InternalGetDescription(InternalThreadCommand): + """ Fetch the variable description stub from the debug console + """ + + def __init__(self, seq, thread_id, frame_id, expression): + self.sequence = seq + self.thread_id = thread_id + self.frame_id = frame_id + self.expression = expression + + def do_it(self, dbg): + """ Get completions and write back to the client + """ + try: + frame = pydevd_vars.find_frame(self.thread_id, self.frame_id) + description = pydevd_console.get_description(frame, self.thread_id, self.frame_id, self.expression) + description = pydevd_vars.make_valid_xml_value(quote(description, '/>_= \t')) + description_xml = '' % description + cmd = dbg.cmd_factory.make_get_description_message(self.sequence, description_xml) + dbg.writer.add_command(cmd) + except: + exc = get_exception_traceback_str() + cmd = dbg.cmd_factory.make_error_message(self.sequence, "Error in fetching description" + exc) + dbg.writer.add_command(cmd) + + #======================================================================================================================= # InternalGetBreakpointException #======================================================================================================================= diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_console.py b/python/helpers/pydev/_pydevd_bundle/pydevd_console.py index d35cdc9df39d..b48daae2703a 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_console.py +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_console.py @@ -1,17 +1,17 @@ '''An helper file for the pydev debugger (REPL) console ''' -from code import InteractiveConsole import sys import traceback +from code import InteractiveConsole from _pydev_bundle import _pydev_completer -from _pydevd_bundle.pydevd_tracing import get_exception_traceback_str -from _pydevd_bundle.pydevd_vars import make_valid_xml_value -from _pydev_bundle.pydev_imports import Exec -from _pydevd_bundle.pydevd_io import IOBuf from _pydev_bundle.pydev_console_utils import BaseInterpreterInterface, BaseStdIn +from _pydev_bundle.pydev_imports import Exec from _pydev_bundle.pydev_override import overrides from _pydevd_bundle import pydevd_save_locals +from _pydevd_bundle.pydevd_io import IOBuf +from _pydevd_bundle.pydevd_tracing import get_exception_traceback_str +from _pydevd_bundle.pydevd_vars import make_valid_xml_value CONSOLE_OUTPUT = "output" CONSOLE_ERROR = "error" @@ -160,6 +160,12 @@ class DebugConsole(InteractiveConsole, BaseInterpreterInterface): except: self.showtraceback() + def get_namespace(self): + dbg_namespace = {} + dbg_namespace.update(self.frame.f_globals) + dbg_namespace.update(self.frame.f_locals) # locals later because it has precedence over the actual globals + return dbg_namespace + #======================================================================================================================= # InteractiveConsoleCache @@ -175,6 +181,7 @@ class InteractiveConsoleCache: def get_interactive_console(thread_id, frame_id, frame, console_message): """returns the global interactive console. interactive console should have been initialized by this time + :rtype: DebugConsole """ if InteractiveConsoleCache.thread_id == thread_id and InteractiveConsoleCache.frame_id == frame_id: return InteractiveConsoleCache.interactive_console_instance @@ -218,6 +225,16 @@ def execute_console_command(frame, thread_id, frame_id, line, buffer_output=True return console_message +def get_description(frame, thread_id, frame_id, expression): + console_message = ConsoleMessage() + interpreter = get_interactive_console(thread_id, frame_id, frame, console_message) + try: + interpreter.frame = frame + return interpreter.getDescription(expression) + finally: + interpreter.frame = None + + def get_completions(frame, act_tok): """ fetch all completions, create xml for the same return the completions xml diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_process_net_command.py b/python/helpers/pydev/_pydevd_bundle/pydevd_process_net_command.py index 2b7783cbe8ca..dec84ed73369 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_process_net_command.py +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_process_net_command.py @@ -16,11 +16,10 @@ from _pydevd_bundle.pydevd_comm import CMD_RUN, CMD_VERSION, CMD_LIST_THREADS, C CMD_SET_PY_EXCEPTION, CMD_GET_FILE_CONTENTS, CMD_SET_PROPERTY_TRACE, CMD_ADD_EXCEPTION_BREAK, \ CMD_REMOVE_EXCEPTION_BREAK, CMD_LOAD_SOURCE, CMD_ADD_DJANGO_EXCEPTION_BREAK, CMD_REMOVE_DJANGO_EXCEPTION_BREAK, \ CMD_EVALUATE_CONSOLE_EXPRESSION, InternalEvaluateConsoleExpression, InternalConsoleGetCompletions, \ - CMD_RUN_CUSTOM_OPERATION, InternalRunCustomOperation, CMD_IGNORE_THROWN_EXCEPTION_AT, CMD_ENABLE_DONT_TRACE,\ - CMD_SHOW_RETURN_VALUES, ID_TO_MEANING + CMD_RUN_CUSTOM_OPERATION, InternalRunCustomOperation, CMD_IGNORE_THROWN_EXCEPTION_AT, CMD_ENABLE_DONT_TRACE, \ + CMD_SHOW_RETURN_VALUES, ID_TO_MEANING, CMD_GET_DESCRIPTION, InternalGetDescription from _pydevd_bundle.pydevd_constants import get_thread_id, IS_PY3K, DebugInfoHolder, dict_contains, dict_keys, dict_pop, \ STATE_RUN -import pydevd_file_utils def process_net_command(py_db, cmd_id, seq, text): @@ -229,6 +228,14 @@ def process_net_command(py_db, cmd_id, seq, text): except: traceback.print_exc() + elif cmd_id == CMD_GET_DESCRIPTION: + try: + + thread_id, frame_id, expression = text.split('\t', 2) + int_cmd = InternalGetDescription(seq, thread_id, frame_id, expression) + py_db.post_internal_command(int_cmd, thread_id) + except: + traceback.print_exc() elif cmd_id == CMD_GET_FRAME: thread_id, frame_id, scope = text.split('\t', 2) diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java index 941e39343ba4..9090238a6a45 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/AbstractCommand.java @@ -30,7 +30,9 @@ public abstract class AbstractCommand { public static final int LOAD_SOURCE = 124; public static final int SMART_STEP_INTO = 128; public static final int EXIT = 129; - + public static final int GET_DESCRIPTION = 148; + + public static final int CALL_SIGNATURE_TRACE = 130; public static final int CMD_SET_PY_EXCEPTION = 131; @@ -52,6 +54,7 @@ public abstract class AbstractCommand { public static final int SHOW_RETURN_VALUES = 146; public static final int INPUT_REQUESTED = 147; + public static final int ERROR = 901; public static final int VERSION = 501; diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/GetDescriptionCommand.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/GetDescriptionCommand.java new file mode 100644 index 000000000000..ca216c7eb02e --- /dev/null +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/GetDescriptionCommand.java @@ -0,0 +1,47 @@ +package com.jetbrains.python.debugger.pydev; + +import com.jetbrains.python.debugger.PyDebugValue; +import com.jetbrains.python.debugger.PyDebuggerException; + +/** + * @author traff + */ +public class GetDescriptionCommand extends AbstractFrameCommand { + + private String myActionToken; + private String result = null; + + public GetDescriptionCommand(final RemoteDebugger debugger, String threadId, String frameId, final String myActionToken) { + super(debugger, GET_DESCRIPTION, threadId, frameId); + this.myActionToken = myActionToken; + } + + + @Override + public boolean isResponseExpected() { + return true; + } + + @Override + protected void processResponse(ProtocolFrame response) throws PyDebuggerException { + super.processResponse(response); + try { + PyDebugValue pyDebugValue = ProtocolParser.parseValue(response.getPayload(), getDebugger().getDebugProcess()); + result = pyDebugValue.getValue(); + } + catch (Exception e) { + throw new PyDebuggerException("cant obtain completions", e); + } + } + + + @Override + protected void buildPayload(Payload payload) { + super.buildPayload(payload); + payload.add(myActionToken); + } + + public String getResult() { + return result; + } +} diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/MultiProcessDebugger.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/MultiProcessDebugger.java index 042b455f3f1b..9b3231974b93 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/MultiProcessDebugger.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/MultiProcessDebugger.java @@ -518,6 +518,11 @@ public class MultiProcessDebugger implements ProcessDebugger { return debugger(threadId).getCompletions(threadId, frameId, prefix); } + @Override + public String getDescription(String threadId, String frameId, String cmd) { + return debugger(threadId).getDescription(threadId, frameId, cmd); + } + @Override public void addExceptionBreakpoint(ExceptionBreakpointCommandFactory factory) { for (RemoteDebugger d : allDebuggers()) { diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProcessDebugger.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProcessDebugger.java index 99c8908ab5c9..186dd53a569d 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProcessDebugger.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/ProcessDebugger.java @@ -87,6 +87,9 @@ public interface ProcessDebugger { List getCompletions(String threadId, String frameId, String prefix); + String getDescription(String threadId, String frameId, String cmd); + + void addExceptionBreakpoint(ExceptionBreakpointCommandFactory factory); void removeExceptionBreakpoint(ExceptionBreakpointCommandFactory factory); diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java index 457947dc9431..3149e42efa5e 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java @@ -761,6 +761,13 @@ public class RemoteDebugger implements ProcessDebugger { return command.getCompletions(); } + @Override + public String getDescription(String threadId, String frameId, String cmd) { + final GetDescriptionCommand command = new GetDescriptionCommand(this, threadId, frameId, cmd); + execute(command); + return command.getResult(); + } + @Override public void addExceptionBreakpoint(ExceptionBreakpointCommandFactory factory) { execute(factory.createAddCommand(this)); diff --git a/python/src/com/jetbrains/python/console/PythonDebugConsoleCommunication.java b/python/src/com/jetbrains/python/console/PythonDebugConsoleCommunication.java index 78ecbf99578b..f0a16fcb3b69 100644 --- a/python/src/com/jetbrains/python/console/PythonDebugConsoleCommunication.java +++ b/python/src/com/jetbrains/python/console/PythonDebugConsoleCommunication.java @@ -55,8 +55,8 @@ public class PythonDebugConsoleCommunication extends AbstractConsoleCommunicatio } @Override - public String getDescription(String text) { - return null; + public String getDescription(String refExpression) throws Exception { + return myDebugProcess.getDescription(refExpression); } @Override diff --git a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java index b252994c0e15..75023a3f24b6 100644 --- a/python/src/com/jetbrains/python/debugger/PyDebugProcess.java +++ b/python/src/com/jetbrains/python/debugger/PyDebugProcess.java @@ -902,6 +902,17 @@ public class PyDebugProcess extends XDebugProcess implements IPyDebugProcess, Pr return Lists.newArrayList(); } + @NotNull + public String getDescription(String prefix) throws Exception { + if (isConnected()) { + dropFrameCaches(); + final PyStackFrame frame = currentFrame(); + return myDebugger.getDescription(frame.getThreadId(), frame.getFrameId(), prefix); + } + return ""; + } + + @Override public void startNotified(ProcessEvent event) { }