init python support

This commit is contained in:
fehrlich
2021-08-18 11:32:21 +02:00
parent 6543180591
commit aa3412e6ac
10 changed files with 349 additions and 7 deletions

7
.gitignore vendored
View File

@@ -80,4 +80,9 @@ typings/
.dynamodb/
dist/
out/
out/
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

View File

@@ -228,6 +228,16 @@ export type PlotlyVisualizationData = {
text?: string | string[];
xaxis?: string;
yaxis?: string;
cells?: {
values?: string[][];
};
header?: {
values?: string[];
};
domain?: {
x?: number[],
y?: number[],
};
x?: (string | number | null)[] | (string | number | null)[][];
y?: (string | number | null)[] | (string | number | null)[][];
z?: (string | number | null)[] | (string | number | null)[][];
@@ -257,7 +267,8 @@ export type PlotlyVisualizationData = {
| "waterfall"
| "funnel"
| "funnelarea"
| "scattermapbox";
| "scattermapbox"
| "table";
mode?:
| "lines"
| "markers"

7
demos/python/Person.py Normal file
View File

@@ -0,0 +1,7 @@
class Person:
def __init__(self, name, parents=None) -> None:
self.name = name
self.parents = [] if parents is None else parents
def addParent(self, parent: "Person"):
self.parents.append(parent)

View File

@@ -0,0 +1,44 @@
from Person import Person
import json
from vscodedebugvisualizer import globalVisualizationFactory
class PersonVisualizer:
def checkType(self, t):
return isinstance(t, Person)
def visualizePerson(self, person: Person, nodes=[], edges=[]):
if person.name in [n["id"] for n in nodes]:
return nodes, edges
nodes.append(
{
"id": person.name,
"label": person.name,
}
)
for p in person.parents:
nodes, edges = self.visualizePerson(p, nodes, edges)
edges.append(
{
"from": p.name,
"to": person.name,
}
)
return nodes, edges
def visualize(self, person: Person):
jsonDict = {
"kind": {"graph": True},
"nodes": [],
"edges": [],
}
self.visualizePerson(person, jsonDict["nodes"], jsonDict["edges"])
return json.dumps(jsonDict)
globalVisualizationFactory.addVisualizer(PersonVisualizer())

123
demos/python/demo.py Normal file
View File

@@ -0,0 +1,123 @@
import numpy as np
# put "x" in the Debug Visualizer and use step by step
# debugging to see the diffrent types of data visualization
x = 5
x = "asdf"
x = 5.5
x = [1, 2, 3, 4, 5, 6, "a", "b"]
x = ["b", "a", "c", "d", "e"]
x.sort()
x = {
"asdf1": "dasdf",
"asdf2": "dasdf",
"asdf3": {"foo": "bar"},
}
x = [1, 2, 3, 4, 5, 6]
# histogram
x = np.concatenate([np.arange(i) for i in range(9)])
x = x.reshape(2, -1)
# one dimension
x = np.arange(100)
x = np.linspace(-np.pi, np.pi, 100)
x = np.sin(x)
# 2 dimension
x = x.reshape(5, 20)
# 2 dimension transpose
x = x.transpose()
x = x.transpose()
# 3 dimensions
x = x.reshape(2, 5, 10)
# 4 dimensions
x = x.reshape(2, 5, 2, 5)
# big number
x = np.empty(2 ** 24)
x[0:1000000] = 1
x[1000000:10000000] = 5
# pyTorch
try:
import torch
x = np.concatenate([np.arange(i) for i in range(9)])
x = x.reshape(2, -1)
x = torch.Tensor(x)
pass
except ImportError:
pass
# tensorflow
try:
import tensorflow as tf
x = np.concatenate([np.arange(i) for i in range(9)])
x = x.reshape(2, -1)
x = tf.convert_to_tensor(x)
pass
except ImportError:
pass
# pandas
try:
import pandas as pd
import plotly.express as px
x = px.data.gapminder().query("year == 2007")
pass
except ImportError:
pass
# custom visualizer defined in ./debugvisualizer.py (this file is included automatically)
from Person import Person
x = Person("Aria")
parent1 = Person("Eduart")
parent2 = Person("Catelyn")
x.addParent(parent1)
x.addParent(parent2)
parent1.addParent(Person("Benjen"))
# direct debug-visualizer json as dict with property "kind"
x = {
"kind": {"dotGraph": True},
"text": '\ndigraph G {\n subgraph cluster_0 {\n style=filled;\n color=lightgrey;\n node [style=filled,color=white];\n a0 -> a1 -> a2 -> a3;\n label = "process #1";\n }\n \n subgraph cluster_1 {\n node [style=filled];\n b0 -> b1 -> b2 -> b3;\n label = "process #2";\n color=blue\n }\n start -> a0;\n start -> b0;\n a1 -> b3;\n b2 -> a3;\n a3 -> a0;\n a3 -> end;\n b3 -> end;\n \n start [shape=Mdiamond];\n end [shape=Msquare];\n}\n',
}
x = {
"kind": {"plotly": True},
"data": [
{
"mode": "lines",
"type": "scatter",
"x": ["A", "B", "C"],
"xaxis": "x",
"y": [4488916, 3918072, 3892124],
"yaxis": "y",
},
{
"cells": {"values": [["A", "B", "C"], [341319, 281489, 294786], [4488916, 3918072, 3892124]]},
"domain": {"x": [0.0, 1.0], "y": [0.0, 0.60]},
"header": {"align": "left", "font": {"size": 10}, "values": ["Date", "Number", "Output"]},
"type": "table",
},
],
"layout": {"xaxis": {"anchor": "y", "domain": [0.0, 1.0]}, "yaxis": {"anchor": "x", "domain": [0.75, 1.0]}},
}
pass

View File

@@ -23,10 +23,9 @@ for i in range(2,100):
# connects the node to a random edge
targetId = str(randint(1, i - 1))
graph["edges"].append({"from": id, "to": targetId})
json_graph = dumps(graph)
print("i is " + str(i))
# try setting a breakpoint right above
# then put json_graph into the visualization console and press enter
# then put graph into the visualization console and press enter
# when you step through the code each time you hit the breakpoint
# the graph should automatically refresh!

View File

@@ -1,5 +1,4 @@
"""Python demo for sorting using VS Code Debug Visualizer."""
import json
def serialize(arr):
@@ -14,7 +13,7 @@ def serialize(arr):
}
],
}
return json.dumps(formatted)
return formatted
arr = [6, 9, 3, 12, 1, 11, 5, 13, 8, 14, 2, 4, 10, 0, 7]

View File

@@ -0,0 +1,151 @@
import {
DataExtractionResult,
DataExtractorId,
GraphNode,
GraphVisualizationData,
} from "@hediet/debug-visualizer-data-extraction";
import { DebugSessionProxy } from "../proxies/DebugSessionProxy";
import {
DebugSessionVisualizationSupport,
VisualizationBackend,
GetVisualizationDataArgs,
VisualizationBackendBase,
} from "./VisualizationBackend";
import { Config } from "../Config";
import { parseEvaluationResultFromGenericDebugAdapter } from "./parseEvaluationResultFromGenericDebugAdapter";
import { FormattedMessage } from "../webviewContract";
import { hotClass, registerUpdateReconciler } from "@hediet/node-reload";
import { DebuggerViewProxy } from "../proxies/DebuggerViewProxy";
registerUpdateReconciler(module);
@hotClass(module)
export class PyEvaluationEngine
implements DebugSessionVisualizationSupport {
constructor(
private readonly debuggerView: DebuggerViewProxy,
private readonly config: Config
) { }
createBackend(
session: DebugSessionProxy
): VisualizationBackend | undefined {
const supportedDebugAdapters = [
"python",
];
if (supportedDebugAdapters.indexOf(session.session.type) !== -1) {
return new PyVisualizationBackend(
session,
this.debuggerView,
this.config
);
}
return undefined;
}
}
export class PyVisualizationBackend extends VisualizationBackendBase {
public readonly expressionLanguageId = "python";
constructor(
debugSession: DebugSessionProxy,
debuggerView: DebuggerViewProxy,
private readonly config: Config
) {
super(debugSession, debuggerView);
}
protected getContext(): "watch" | "repl" {
// we will use "repl" as default so that results are not truncated.
return "repl";
}
public async getVisualizationData({
expression,
preferredExtractorId,
}: GetVisualizationDataArgs): Promise<
| { kind: "data"; result: DataExtractionResult }
| { kind: "error"; message: FormattedMessage }
> {
const frameId = this.debuggerView.getActiveStackFrameId(
this.debugSession
);
const finalExpression = this.getFinalExpression({
expression,
preferredExtractorId,
});
let reply: { result: string; variablesReference: number };
try {
// inject vscodedebugvisualizer for python
await this.debugSession.evaluate({
expression: 'from vscodedebugvisualizer import visualize\ntry:\n import debugvisualizer\nexcept ImportError:\n pass',
frameId,
context: this.getContext(),
});
reply = await this.debugSession.evaluate({
expression: finalExpression,
frameId,
context: this.getContext(),
});
let result = reply.result;
// remove the initial escape by the the debug session e.g. `''{"kind": {"text": true}, "text": "{"asdf1\'"}''`
result = result.replaceAll(/\\'/g, "'");
result = result.replaceAll(/\\'/g, "'");
result = result.replaceAll(/\\\\/g, "\\")
result.substr(1, result.length - 2);
return parseEvaluationResultFromGenericDebugAdapter(
result,
{
debugAdapterType: this.debugSession.session
.configuration.type,
}
);
} catch (error) {
let errorTyped = error as Error;
if (errorTyped.message.includes("ModuleNotFoundError: No module named 'vscodedebugvisualizer'")) {
return {
kind: "error",
message: {
kind: "list",
items: ["Pleas make sure vscodedebugvisualizer is installed: `pip install vscodedebugvisualizer`"],
},
};
}
return {
kind: "error",
message: {
kind: "list",
items: [
"An error occurred while evaluating the expression:",
errorTyped.message,
`Used debug adapter: ${this.debugSession.session.configuration.type}`,
{
kind: "inlineList",
items: [
"Evaluated expression is",
{ kind: "code", content: finalExpression },
],
},
],
},
};
}
}
protected getFinalExpression(args: {
expression: string;
preferredExtractorId: DataExtractorId | undefined;
}): string {
// wrap expression with visualize function
let pythonInject = "";
pythonInject += "visualize(" + args.expression + ")";
return pythonInject;
}
}

View File

@@ -2,5 +2,6 @@ export * from "./VisualizationBackend";
export { ComposedVisualizationSupport } from "./ComposedVisualizationSupport";
export { JsEvaluationEngine } from "./JsVisualizationSupport";
export { PyEvaluationEngine } from "./PyVisualizationSupport";
export { GenericVisualizationSupport } from "./GenericVisualizationSupport";
export { ConfigurableVisualizationSupport } from "./ConfigurableVisualizationSupport";

View File

@@ -21,6 +21,7 @@ import { VisualizationWatchModelImpl } from "./VisualizationWatchModel";
import {
ComposedVisualizationSupport,
JsEvaluationEngine,
PyEvaluationEngine,
GenericVisualizationSupport,
ConfigurableVisualizationSupport,
} from "./VisualizationBackend";
@@ -32,7 +33,7 @@ export function activate(context: ExtensionContext) {
);
}
export function deactivate() {}
export function deactivate() { }
export class Extension {
public readonly dispose = Disposable.fn();
@@ -51,6 +52,7 @@ export class Extension {
this.debuggerView
),
new JsEvaluationEngine(this.debuggerView, this.config),
new PyEvaluationEngine(this.debuggerView, this.config),
new GenericVisualizationSupport(this.debuggerView),
]),
this.debuggerView