diff --git a/python/helpers/pydev/pydev_ipython_console.py b/python/helpers/pydev/pydev_ipython_console.py index 2175c02d2cca..dca3b4dc53ee 100644 --- a/python/helpers/pydev/pydev_ipython_console.py +++ b/python/helpers/pydev/pydev_ipython_console.py @@ -31,7 +31,7 @@ class InterpreterInterface(BaseInterpreterInterface): self.interpreter = PyDevFrontEnd() self._input_error_printed = False self.notification_succeeded = False - self.notification_tries = 0; + self.notification_tries = 0 self.notification_max_tries = 3 self.notify_about_magic() @@ -101,11 +101,9 @@ class InterpreterInterface(BaseInterpreterInterface): traceback.print_exc() return [] - def close(self): sys.exit(0) - def ipython_editor(self, file, line): server = self.get_server() diff --git a/python/helpers/pydev/pydevconsole.py b/python/helpers/pydev/pydevconsole.py index c747c1c41af4..d42726ba458c 100644 --- a/python/helpers/pydev/pydevconsole.py +++ b/python/helpers/pydev/pydevconsole.py @@ -3,10 +3,14 @@ try: except ImportError: from pydevconsole_code_for_ironpython import InteractiveConsole +from code import compile_command +from code import InteractiveInterpreter + import os import sys from pydevd_constants import USE_LIB_COPY +from pydevd_utils import * if USE_LIB_COPY: import _pydev_threading as threading @@ -18,6 +22,12 @@ import fix_getpass fix_getpass.fixGetpass() import pydevd_xml +import pydevd_vars + +try: + from pydevd_exec import Exec +except: + from pydevd_exec2 import Exec try: if USE_LIB_COPY: @@ -171,6 +181,21 @@ class InterpreterInterface(BaseInterpreterInterface): xml += "" return xml + + def getVariable(self, attributes): + xml = "" + valDict = pydevd_vars.resolveVar(self.namespace, attributes) + if valDict is None: + valDict = {} + + keys = valDict.keys() + + for k in keys: + xml += pydevd_vars.varToXML(valDict[k], to_string(k)) + + xml += "" + + return xml def close(self): sys.exit(0) @@ -274,6 +299,7 @@ def start_server(host, port, interpreter): server.register_function(interpreter.execLine) server.register_function(interpreter.getCompletions) server.register_function(interpreter.getFrame) + server.register_function(interpreter.getVariable) server.register_function(interpreter.getDescription) server.register_function(interpreter.close) server.register_function(interpreter.interrupt) @@ -332,7 +358,7 @@ def get_completions(text, token, globals, locals): return interpreterInterface.getCompletions(text, token) -def get_frame(globals, locals): +def get_frame(): return interpreterInterface.getFrame() def exec_expression(expression, globals, locals): @@ -363,6 +389,65 @@ def read_line(s): return ret +# Debugger integration + +class ConsoleWriter(InteractiveInterpreter): + skip = 0 + + def __init__(self, locals=None): + InteractiveInterpreter.__init__(self, locals) + + def write(self, data): + #if (data.find("global_vars") == -1 and data.find("pydevd") == -1): + if self.skip > 0: + self.skip -= 1 + else: + if data == "Traceback (most recent call last):\n": + self.skip = 1 + sys.stderr.write(data) + +def consoleExec(thread_id, frame_id, expression): + """returns 'False' in case expression is partialy correct + """ + frame = pydevd_vars.findFrame(thread_id, frame_id) + + expression = str(expression.replace('@LINE@', '\n')) + + #Not using frame.f_globals because of https://sourceforge.net/tracker2/?func=detail&aid=2541355&group_id=85796&atid=577329 + #(Names not resolved in generator expression in method) + #See message: http://mail.python.org/pipermail/python-list/2009-January/526522.html + updated_globals = {} + updated_globals.update(frame.f_globals) + updated_globals.update(frame.f_locals) #locals later because it has precedence over the actual globals + + if IPYTHON: + return exec_expression(expression, updated_globals, frame.f_locals) + + interpreter = ConsoleWriter() + + try: + code = compile_command(expression) + except (OverflowError, SyntaxError, ValueError): + # Case 1 + interpreter.showsyntaxerror() + return False + + if code is None: + # Case 2 + return True + + #Case 3 + + try: + Exec(code, updated_globals, frame.f_locals) + + except SystemExit: + raise + except: + interpreter.showtraceback() + + return False + #======================================================================================================================= # main #======================================================================================================================= diff --git a/python/helpers/pydev/pydevd_comm.py b/python/helpers/pydev/pydevd_comm.py index 015a71241dd7..592a96900c73 100644 --- a/python/helpers/pydev/pydevd_comm.py +++ b/python/helpers/pydev/pydevd_comm.py @@ -905,7 +905,7 @@ class InternalConsoleExec(InternalThreadCommand): thread.start_new_thread = thread._original_start_new_thread #don't trace new threads created by console command thread.start_new = thread._original_start_new_thread - result = pydevd_vars.consoleExec(self.thread_id, self.frame_id, self.expression) + result = pydevconsole.consoleExec(self.thread_id, self.frame_id, self.expression) xml = "" xml += pydevd_vars.varToXML(result, "") xml += "" diff --git a/python/helpers/pydev/pydevd_vars.py b/python/helpers/pydev/pydevd_vars.py index a4d2b8a6e228..b8f95fc62a24 100644 --- a/python/helpers/pydev/pydevd_vars.py +++ b/python/helpers/pydev/pydevd_vars.py @@ -5,9 +5,7 @@ import pickle from django_frame import DjangoTemplateFrame from pydevd_constants import * #@UnusedWildImport from types import * #@UnusedWildImport -from code import compile_command -from code import InteractiveInterpreter -import pydevconsole + from pydevd_xml import * try: @@ -54,9 +52,6 @@ if USE_PSYCO_OPTIMIZATION: if hasattr(sys, 'exc_clear'): #jython does not have it sys.exc_clear() #don't keep the traceback -- clients don't want to see it - - - def iterFrames(initialFrame): """NO-YIELD VERSION: Iterates through all the frames starting at the specified frame (which will be the first returned item)""" #cannot use yield @@ -161,6 +156,7 @@ def resolveCompoundVariable(thread_id, frame_id, scope, attrs): return {} attrList = attrs.split('\t') + if scope == "GLOBAL": var = frame.f_globals del attrList[0] # globals are special, and they get a single dummy unused attribute @@ -181,6 +177,22 @@ def resolveCompoundVariable(thread_id, frame_id, scope, attrs): return resolver.getDictionary(var) except: traceback.print_exc() + + +def resolveVar(var, attrs): + attrList = attrs.split('\t') + + for k in attrList: + type, _typeName, resolver = getType(var) + + var = resolver.resolve(var, k) + + try: + type, _typeName, resolver = getType(var) + return resolver.getDictionary(var) + except: + traceback.print_exc() + def evaluateExpression(thread_id, frame_id, expression, doExec): """returns the result of the evaluated expression @@ -241,64 +253,6 @@ def evaluateExpression(thread_id, frame_id, expression, doExec): del updated_globals del frame -class ConsoleWriter(InteractiveInterpreter): - skip = 0 - - def __init__(self, locals=None): - InteractiveInterpreter.__init__(self, locals) - - def write(self, data): - #if (data.find("global_vars") == -1 and data.find("pydevd") == -1): - if self.skip > 0: - self.skip -= 1 - else: - if data == "Traceback (most recent call last):\n": - self.skip = 1 - sys.stderr.write(data) - -def consoleExec(thread_id, frame_id, expression): - """returns 'False' in case expression is partialy correct - """ - frame = findFrame(thread_id, frame_id) - - expression = str(expression.replace('@LINE@', '\n')) - - #Not using frame.f_globals because of https://sourceforge.net/tracker2/?func=detail&aid=2541355&group_id=85796&atid=577329 - #(Names not resolved in generator expression in method) - #See message: http://mail.python.org/pipermail/python-list/2009-January/526522.html - updated_globals = {} - updated_globals.update(frame.f_globals) - updated_globals.update(frame.f_locals) #locals later because it has precedence over the actual globals - - if pydevconsole.IPYTHON: - return pydevconsole.exec_expression(expression, updated_globals, frame.f_locals) - - interpreter = ConsoleWriter() - - try: - code = compile_command(expression) - except (OverflowError, SyntaxError, ValueError): - # Case 1 - interpreter.showsyntaxerror() - return False - - if code is None: - # Case 2 - return True - - #Case 3 - - try: - Exec(code, updated_globals, frame.f_locals) - - except SystemExit: - raise - except: - interpreter.showtraceback() - - return False - - def changeAttrExpression(thread_id, frame_id, attr, expression): """Changes some attribute in a given frame. @note: it will not (currently) work if we're not in the topmost frame (that's a python diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/GetVariableCommand.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/GetVariableCommand.java index cff939d6b659..ef4bd12059d7 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/GetVariableCommand.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/GetVariableCommand.java @@ -8,11 +8,19 @@ public class GetVariableCommand extends GetFrameCommand { private final String myVariableName; private final PyDebugValue myParent; - public GetVariableCommand(final RemoteDebugger debugger, final String threadId, final String frameId, final String variableName, - PyDebugValue parent) { + public GetVariableCommand(final RemoteDebugger debugger, final String threadId, final String frameId, PyDebugValue var) { super(debugger, GET_VARIABLE, threadId, frameId); - myVariableName = variableName; - myParent = parent; + myVariableName = composeName(var); + myParent = var; + } + + public static String composeName(final PyDebugValue var) { + final StringBuilder sb = new StringBuilder(var.getTempName()); + PyDebugValue p = var; + while ((p = p.getParent()) != null) { + sb.insert(0, '\t').insert(0, p.getTempName()); + } + return sb.toString(); } @Override diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java index d0c04ab5b80a..a3eb50fc3453 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java @@ -143,7 +143,7 @@ public class RemoteDebugger implements ProcessDebugger { @Override public XValueChildrenList loadVariable(final String threadId, final String frameId, final PyDebugValue var) throws PyDebuggerException { setTempVariable(threadId, frameId, var); - final GetVariableCommand command = new GetVariableCommand(this, threadId, frameId, composeName(var), var); + final GetVariableCommand command = new GetVariableCommand(this, threadId, frameId, var); command.execute(); return command.getVariables(); } @@ -182,15 +182,6 @@ public class RemoteDebugger implements ProcessDebugger { myTempVars.clear(); } - private static String composeName(final PyDebugValue var) { - final StringBuilder sb = new StringBuilder(var.getTempName()); - PyDebugValue p = var; - while ((p = p.getParent()) != null) { - sb.insert(0, '\t').insert(0, p.getTempName()); - } - return sb.toString(); - } - // todo: change variable in lists doesn't work - either fix in pydevd or format var name appropriately private void setTempVariable(final String threadId, final String frameId, final PyDebugValue var) { final PyDebugValue topVar = var.getTopParent(); diff --git a/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java b/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java index 0bea2b9267a3..c741f73aa81f 100644 --- a/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java +++ b/python/src/com/jetbrains/python/console/PydevConsoleCommunication.java @@ -18,8 +18,9 @@ import com.jetbrains.python.console.parsing.PythonConsoleData; import com.jetbrains.python.console.pydev.*; import com.jetbrains.python.debugger.PyDebugValue; import com.jetbrains.python.debugger.PyDebuggerException; -import com.jetbrains.python.debugger.PyEvaluator; +import com.jetbrains.python.debugger.PyFrameAccessor; import com.jetbrains.python.debugger.PydevXmlUtils; +import com.jetbrains.python.debugger.pydev.GetVariableCommand; import com.jetbrains.python.debugger.pydev.ProtocolParser; import org.apache.xmlrpc.WebServer; import org.apache.xmlrpc.XmlRpcException; @@ -38,12 +39,13 @@ import java.util.Vector; * @author Fabio */ public class PydevConsoleCommunication extends AbstractConsoleCommunication implements IScriptConsoleCommunication, XmlRpcHandler, - PyEvaluator { + PyFrameAccessor { private static final String EXEC_LINE = "execLine"; private static final String GET_COMPLETIONS = "getCompletions"; private static final String GET_DESCRIPTION = "getDescription"; private static final String GET_FRAME = "getFrame"; + private static final String GET_VARIABLE = "getVariable"; private static final String HANDSHAKE = "handshake"; private static final String CLOSE = "close"; /** @@ -431,19 +433,43 @@ public class PydevConsoleCommunication extends AbstractConsoleCommunication impl try { Object ret = myClient.execute(GET_FRAME, new Object[]{}); if (ret instanceof String) { - final List values = ProtocolParser.parseValues((String)ret); - XValueChildrenList list = new XValueChildrenList(values.size()); - for (PyDebugValue v: values) { - list.add(v.getName(), v); - } - return list; + return parseVars((String)ret, null); } } catch (XmlRpcException e) { throw new PyDebuggerException("Get frame from console failed", e); } } - //list.add("X", new PyDebugValue("X", "int", "1000000", false, false)); return new XValueChildrenList(); } + + private XValueChildrenList parseVars(String ret, PyDebugValue parent) throws PyDebuggerException { + final List values = ProtocolParser.parseValues(ret, this); + XValueChildrenList list = new XValueChildrenList(values.size()); + for (PyDebugValue v : values) { + list.add(v.getName(), parent != null ? v.setParent(parent) : v); + } + return list; + } + + @Override + public XValueChildrenList loadVariable(PyDebugValue var) throws PyDebuggerException { + if (myClient != null) { + try { + Object ret = myClient.execute(GET_VARIABLE, new Object[]{GetVariableCommand.composeName(var)}); + if (ret instanceof String) { + return parseVars((String)ret, var); + } + } + catch (XmlRpcException e) { + throw new PyDebuggerException("Get variable from console failed", e); + } + } + return new XValueChildrenList(); + } + + @Override + public void changeVariable(PyDebugValue variable, String expression) throws PyDebuggerException { + //To change body of implemented methods use File | Settings | File Templates. + } } diff --git a/python/src/com/jetbrains/python/console/PythonDebugConsoleCommunication.java b/python/src/com/jetbrains/python/console/PythonDebugConsoleCommunication.java index 95cb6c5887e0..e1722e76c3c9 100644 --- a/python/src/com/jetbrains/python/console/PythonDebugConsoleCommunication.java +++ b/python/src/com/jetbrains/python/console/PythonDebugConsoleCommunication.java @@ -2,8 +2,8 @@ package com.jetbrains.python.console; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Pair; +import com.intellij.util.Function; import com.jetbrains.python.console.pydev.AbstractConsoleCommunication; -import com.jetbrains.python.console.pydev.ICallback; import com.jetbrains.python.console.pydev.InterpreterResponse; import com.jetbrains.python.console.pydev.PydevCompletionVariant; import com.jetbrains.python.debugger.PyDebugProcess; @@ -62,7 +62,7 @@ public class PythonDebugConsoleCommunication extends AbstractConsoleCommunicatio }); } - public void execInterpreter(String s, final ICallback callback) { + public void execInterpreter(String s, final Function callback) { myExpression.append(s); exec(myExpression.toString(), new ProcessDebugger.DebugCallback>() { @Override @@ -72,13 +72,13 @@ public class PythonDebugConsoleCommunication extends AbstractConsoleCommunicatio if (!more) { myExpression.setLength(0); } - callback.call(new InterpreterResponse(more, isWaitingForInput())); + callback.fun(new InterpreterResponse(more, isWaitingForInput())); } @Override public void error(PyDebuggerException exception) { myExpression.setLength(0); - callback.call(new InterpreterResponse(false, isWaitingForInput())); + callback.fun(new InterpreterResponse(false, isWaitingForInput())); } }); }