Array viewer for console variables (PY-14182).

This commit is contained in:
Dmitry Trofimov
2014-11-06 13:34:52 +01:00
parent fcc06c29fa
commit 51b6a7117c
7 changed files with 147 additions and 123 deletions
+12 -7
View File
@@ -385,16 +385,21 @@ class BaseInterpreterInterface:
return xml
def getArray(self, attr):
def getArray(self, attr, roffset, coffset, rows, cols, format):
xml = "<xml>"
valDict = pydevd_vars.resolveVar(self.getNamespace(), attributes)
if valDict is None:
valDict = {}
array = pydevd_vars.evalInContext(attr, self.getNamespace(), self.getNamespace())
keys = valDict.keys()
xml += pydevd_vars.array_to_xml(array, roffset, coffset, rows, cols, format)
for k in keys:
xml += pydevd_vars.varToXML(valDict[k], to_string(k))
xml += "</xml>"
return xml
def evaluate(self, expression):
xml = "<xml>"
result = pydevd_vars.evalInContext(expression, self.getNamespace(), self.getNamespace())
xml += pydevd_vars.varToXML(result, expression)
xml += "</xml>"
+2
View File
@@ -293,6 +293,8 @@ def start_server(host, port, interpreter):
server.register_function(handshake)
server.register_function(interpreter.connectToDebugger)
server.register_function(interpreter.hello)
server.register_function(interpreter.getArray)
server.register_function(interpreter.evaluate)
# Functions for GUI main loop integration
server.register_function(interpreter.enableGui)
+39 -39
View File
@@ -277,6 +277,43 @@ def customOperation(thread_id, frame_id, scope, attrs, style, code_or_file, oper
traceback.print_exc()
def evalInContext(expression, globals, locals):
result = None
try:
result = eval(expression, globals, locals)
except Exception:
s = StringIO()
traceback.print_exc(file=s)
result = s.getvalue()
try:
try:
etype, value, tb = sys.exc_info()
result = value
finally:
etype = value = tb = None
except:
pass
result = ExceptionOnEvaluate(result)
# Ok, we have the initial error message, but let's see if we're dealing with a name mangling error...
try:
if '__' in expression:
# Try to handle '__' name mangling...
split = expression.split('.')
curr = locals.get(split[0])
for entry in split[1:]:
if entry.startswith('__') and not hasattr(curr, entry):
entry = '_%s%s' % (curr.__class__.__name__, entry)
curr = getattr(curr, entry)
result = curr
except:
pass
return result
def evaluateExpression(thread_id, frame_id, expression, doExec):
'''returns the result of the evaluated expression
@param doExec: determines if we should do an exec or an eval
@@ -285,9 +322,6 @@ def evaluateExpression(thread_id, frame_id, expression, doExec):
if frame is None:
return
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
@@ -296,6 +330,7 @@ def evaluateExpression(thread_id, frame_id, expression, doExec):
updated_globals.update(frame.f_locals) #locals later because it has precedence over the actual globals
try:
expression = str(expression.replace('@LINE@', '\n'))
if doExec:
try:
@@ -312,42 +347,7 @@ def evaluateExpression(thread_id, frame_id, expression, doExec):
return
else:
result = None
try:
result = eval(expression, updated_globals, frame.f_locals)
except Exception:
s = StringIO()
traceback.print_exc(file=s)
result = s.getvalue()
try:
try:
etype, value, tb = sys.exc_info()
result = value
finally:
etype = value = tb = None
except:
pass
result = ExceptionOnEvaluate(result)
# Ok, we have the initial error message, but let's see if we're dealing with a name mangling error...
try:
if '__' in expression:
# Try to handle '__' name mangling...
split = expression.split('.')
curr = frame.f_locals.get(split[0])
for entry in split[1:]:
if entry.startswith('__') and not hasattr(curr, entry):
entry = '_%s%s' % (curr.__class__.__name__, entry)
curr = getattr(curr, entry)
result = curr
except:
pass
return result
return evalInContext(expression, updated_globals, frame.f_locals)
finally:
#Should not be kept alive if an exception happens and this frame is kept in the stack.
del updated_globals
@@ -21,5 +21,5 @@ public interface PyFrameAccessor {
@Nullable
PyReferrersLoader getReferrersLoader();
Object[][] getArrayItems(PyDebugValue var, int colOffset, int rowOffset, int rows, int cols, String format) throws PyDebuggerException;
Object[][] getArrayItems(PyDebugValue var, int rowOffset, int colOffset, int rows, int cols, String format) throws PyDebuggerException;
}
@@ -63,6 +63,8 @@ public class PydevConsoleCommunication extends AbstractConsoleCommunication impl
private static final String CONNECT_TO_DEBUGGER = "connectToDebugger";
private static final String HANDSHAKE = "handshake";
private static final String CLOSE = "close";
private static final String EVALUATE = "evaluate";
private static final String GET_ARRAY = "getArray";
/**
* XML-RPC client for sending messages to the server.
@@ -461,7 +463,21 @@ public class PydevConsoleCommunication extends AbstractConsoleCommunication impl
@Override
public PyDebugValue evaluate(String expression, boolean execute, boolean doTrunc) throws PyDebuggerException {
return null; //To change body of implemented methods use File | Settings | File Templates.
if (myClient != null) {
try {
Object ret = myClient.execute(EVALUATE, new Object[]{expression});
if (ret instanceof String) {
return ProtocolParser.parseValue((String)ret, this);
}
else {
checkError(ret);
}
}
catch (Exception e) {
throw new PyDebuggerException("Evaluate in console failed", e);
}
}
return null;
}
@Nullable
@@ -532,8 +548,23 @@ public class PydevConsoleCommunication extends AbstractConsoleCommunication impl
}
@Override
public Object[][] getArrayItems(PyDebugValue var, int colOffset, int rowOffset, int rows, int cols, String format) {
return new Object[][]{new Object[]{1, 2}, new Object[]{3, 4}};
public Object[][] getArrayItems(PyDebugValue var, int rowOffset, int colOffset, int rows, int cols, String format)
throws PyDebuggerException {
if (myClient != null) {
try {
Object ret = myClient.execute(GET_ARRAY, new Object[]{var.getName(), rowOffset, colOffset, rows, cols, format});
if (ret instanceof String) {
return ProtocolParser.parseArrayValues((String)ret, this);
}
else {
checkError(ret);
}
}
catch (Exception e) {
throw new PyDebuggerException("Evaluate in console failed", e);
}
}
return null;
}
/**
@@ -56,8 +56,8 @@ public class AsyncArrayTableModel extends AbstractTableModel {
@Override
public Object[][] call() throws Exception {
return value.getFrameAccessor()
.getArrayItems(slicedValue, key.first, key.second, Math.min(CHUNK_COL_SIZE, getRowCount() - key.first),
Math.min(CHUNK_ROW_SIZE, getColumnCount() - key.second),
.getArrayItems(slicedValue, key.first, key.second, Math.min(CHUNK_ROW_SIZE, getRowCount() - key.first),
Math.min(CHUNK_COL_SIZE, getColumnCount() - key.second),
myProvider.getFormat());
}
});
@@ -99,10 +99,11 @@ public class AsyncArrayTableModel extends AbstractTableModel {
if (r < chunk.get().length) {
if (c < chunk.get()[r].length) {
return myProvider.correctStringValue((String)chunk.get()[r][c]);
return myProvider.correctStringValue(chunk.get()[r][c]);
}
}
} else {
}
else {
chunk.addListener(new Runnable() {
@Override
public void run() {
@@ -22,11 +22,14 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.RangeMarker;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.util.Consumer;
import com.intellij.util.ui.UIUtil;
import com.intellij.xdebugger.evaluation.XDebuggerEvaluator;
import com.intellij.xdebugger.frame.XValue;
import com.jetbrains.python.debugger.PyDebugValue;
import com.jetbrains.python.debugger.PyDebuggerEvaluator;
import com.jetbrains.python.debugger.PyDebuggerException;
import com.jetbrains.python.debugger.PyFrameAccessor;
import org.jetbrains.annotations.NotNull;
import javax.management.InvalidAttributeValueException;
@@ -197,8 +200,8 @@ public class NumpyArrayTable {
return myValue;
}
public PyDebuggerEvaluator getEvaluator() {
return myEvaluator;
public PyFrameAccessor getEvaluator() {
return myValue.getFrameAccessor();
}
public void init() {
@@ -244,10 +247,10 @@ public class NumpyArrayTable {
}
private void fillColorRange(@NotNull final Runnable returnToMain) {
XDebuggerEvaluator.XEvaluationCallback callback = new XDebuggerEvaluator.XEvaluationCallback() {
Consumer<PyDebugValue> callback = new Consumer<PyDebugValue>() {
@Override
public void evaluated(@NotNull XValue result) {
String rawValue = ((PyDebugValue)result).getValue();
public void consume(@NotNull PyDebugValue result) {
String rawValue = result.getValue();
double min;
double max;
String minValue = rawValue.substring(1, rawValue.indexOf(","));
@@ -271,11 +274,6 @@ public class NumpyArrayTable {
myTableCellRenderer.setMax(max);
returnToMain.run();
}
@Override
public void errorOccurred(@NotNull String errorMessage) {
showError(errorMessage);
}
};
if (getMaxRow(myShape) * getMaxColumn(myShape) > HUGE_ARRAY_SIZE) {
@@ -284,7 +282,13 @@ public class NumpyArrayTable {
}
String evalTypeCommand = "[" + getNodeName() + ".min(), " + getNodeName() + ".max()]";
getEvaluator().evaluate(evalTypeCommand, callback, null);
try {
PyDebugValue value = getEvaluator().evaluate(evalTypeCommand, true, false);
callback.consume(value);
}
catch (PyDebuggerException e) {
showError(e.getMessage());
}
}
public String getDefaultPresentation() {
@@ -341,42 +345,27 @@ public class NumpyArrayTable {
}
private void fillType(@NotNull final Runnable returnToMain) {
XDebuggerEvaluator.XEvaluationCallback callback = new XDebuggerEvaluator.XEvaluationCallback() {
@Override
public void evaluated(@NotNull XValue result) {
setDtypeKind(((PyDebugValue)result).getValue());
returnToMain.run();
}
@Override
public void errorOccurred(@NotNull String errorMessage) {
showError(errorMessage);
}
};
String evalTypeCommand = getNodeName() + ".dtype.kind";
getEvaluator().evaluate(evalTypeCommand, callback, null);
try {
PyDebugValue value = getEvaluator().evaluate(evalTypeCommand, true, false);
setDtypeKind(value.getValue());
returnToMain.run();
}
catch (PyDebuggerException e) {
showError(e.getMessage());
}
}
private void fillShape(@NotNull final Runnable returnToMain) {
XDebuggerEvaluator.XEvaluationCallback callback = new XDebuggerEvaluator.XEvaluationCallback() {
@Override
public void evaluated(@NotNull XValue result) {
try {
setShape(parseShape(((PyDebugValue)result).getValue()));
returnToMain.run();
}
catch (InvalidAttributeValueException e) {
errorOccurred(e.getMessage());
}
}
@Override
public void errorOccurred(@NotNull String errorMessage) {
showError(errorMessage);
}
};
String evalShapeCommand = getEvalShapeCommand(getNodeName());
getEvaluator().evaluate(evalShapeCommand, callback, null);
try {
PyDebugValue value = getEvaluator().evaluate(evalShapeCommand, true, false);
setShape(parseShape(value.getValue()));
returnToMain.run();
}
catch (Exception e) {
showError(e.getMessage());
}
}
private int[] parseShape(String value) throws InvalidAttributeValueException {
@@ -542,14 +531,20 @@ public class NumpyArrayTable {
};
}
public String correctStringValue(@NotNull String value) {
String corrected = value;
if (isNumeric()) {
if (value.startsWith("\'") || value.startsWith("\"")) {
corrected = value.substring(1, value.length() - 1);
public String correctStringValue(@NotNull Object value) {
if (value instanceof String) {
String corrected = (String)value;
if (isNumeric()) {
if (corrected.startsWith("\'") || corrected.startsWith("\"")) {
corrected = corrected.substring(1, corrected.length() - 1);
}
}
return corrected;
}
return corrected;
else if (value instanceof Integer) {
return Integer.toString((Integer)value);
}
return value.toString();
}
public void setDtypeKind(String dtype) {
@@ -611,28 +606,18 @@ public class NumpyArrayTable {
private void doReslice(final String newSlice, int[] shape) {
if (shape == null) {
XDebuggerEvaluator.XEvaluationCallback callback = new XDebuggerEvaluator.XEvaluationCallback() {
@Override
public void evaluated(@NotNull XValue result) {
try {
int[] shape = parseShape(((PyDebugValue)result).getValue());
if (!is2DShape(shape)) {
errorOccurred("Incorrect slice shape " + ((PyDebugValue)result).getValue() + ".");
}
doReslice(newSlice, shape);
}
catch (InvalidAttributeValueException e) {
errorOccurred(e.getMessage());
}
}
@Override
public void errorOccurred(@NotNull String errorMessage) {
showError(errorMessage);
}
};
String evalShapeCommand = getEvalShapeCommand(newSlice);
getEvaluator().evaluate(evalShapeCommand, callback, null);
try {
PyDebugValue result = getEvaluator().evaluate(evalShapeCommand, true, false);
shape = parseShape(((PyDebugValue)result).getValue());
if (!is2DShape(shape)) {
showError("Incorrect slice shape " + ((PyDebugValue)result).getValue() + ".");
}
doReslice(newSlice, shape);
}
catch (Exception e) {
showError(e.getMessage());
}
return;
}