Blog,

VS Code mit IPython Konsole


Tipps zur Einstellung von VS Code für die Verwendung mit IPython

Ich benutze gerne VS Code für die Software Entwicklung. Ich schätze an VS Code besonders:

Zuvor habe ich für die Python Entwicklung die IDE Spyder verwendet. Diese war in der Winpython Distribution enthalten. Spyder wiederum benutzt als interaktive Konsole IPython. In der Spyder IDE kann man ein Skript, das man im Editor geöffnet hat mit einem Tastendruck (F5) in der IPython Konsole starten. Wenn noch keine Konsole existiert, wird eine automatisch erstellt. Daran hatte ich mich gewöhnt.

Der Umstieg auf VS Code war daher etwas holprig. Ich wollte Winpython weiter nutzen, da es ohne Installation auskommt und eine grosse Anzahl nützlicher Pakete mitbringt. Um Winpython nutzen zu können, war in der VS Code Settings Datei der Eintrag

"python.defaultInterpreterPath":
    "C:\\portable\\WPy64-3720\\python-3.7.2.amd64",

notwendig. Damit wird die Winpython-Distribution der VS Code Python-Extensions bekannt gemacht. Nun war es möglich Python Skripte auszuführen und zu debuggen. Es fehlte aber die interaktive Konsole, mit der man auch nach Programmende oder bei einem Fehler komfortabel weiter arbeiten konnte.

Nach kurzer Suche habe ich die Erweiterung IPython for VS Code gefunden. Damit ist es möglich über einen Befehl direkt eine IPython-Konsole zu starten und das Skript darin auszuführen. Die Erweiterung musste ich allerdings im Source Code anpassen, um die Winpython Distribution nutzen zu können.

Da ich keine vollständige Erweiterung schreiben wollte suchte ich nach einer alternativen Möglichkeit die VS Code Umgebung mit wenig Aufwand anpassen zu können. Die Erweiterung Power Tools ermöglicht genau dies, die Ergänzung von VS Code ohne eine komplette Erweiterung schreiben zu müssen.

So können einfach Schaltflächen hinzugefügt werden:

IPython Schaltflächen

Ich habe mir also die zwei Schaltflächen, Send To IPython und IPython zu VS Code hinzugefügt. Dafür sind folgende Einträge in den VS Code User Settings notwendig:

    "ego.power-tools": {
        "buttons": [
            {
                "text": "IPython",
                "tooltip": "Create shell and start IPython",
                "action": {
                    "type": "script",
                    "script": "ipython.js"
                }
            }
        ],
        "commands": {
            "sendToIPython": {
                "script": "sendToIPython.js",
                "button": {
                    "text": "Send To IPython"
                }
            }
        },

        "user": {
        }
    },

Die beiden Skriptdateien befinden sich in meinem Benutzerverzeichnis im Unterverzeichnis .vscode-powertools und sehen wie folgt aus. Den Pfad zur Kommandozeile der Distribution muss man natürlich anpassen:

ipython.js

exports.execute = async (args) => {
    const vscode = args.require('vscode');

    var ipython_shell = get_ipython_shell(vscode);

    if (ipython_shell==null)
    {
        ipython_shell = vscode.window.createTerminal("IPython")
        setTimeout(() => {
            get_ipython_shell(vscode).sendText("C:\\portable\\WPy64-3720\\scripts\\cmd.bat")
            setTimeout(() => {
                get_ipython_shell(vscode).sendText("ipython")
            }, 100);
        }, 1000);
    }
    ipython_shell.show(false)
};

function get_ipython_shell(vscode)
{
    var ipython_shell = null;
    vscode.window.terminals.forEach(element => {
        if (element.name=="IPython")
        {
            ipython_shell = element
        }
    });
    return ipython_shell
}

sendToIPython.js:

exports.execute = async (args) => {
    const vscode = args.require('vscode');


    var ipython_shell = get_ipython_shell(vscode);
    const editor = vscode.window.activeTextEditor;

    if (editor == undefined)
    {
        vscode.window.showInformationMessage(
            "No active Editor"
        );
        return
    }

    // save current file
    let success = await vscode.commands.executeCommand('workbench.action.files.save');

    const filename = editor.document.fileName;
    var command_zw = null
    var shebang = false
    if (editor.document.lineAt(0).text[0]=="#")
    {
        shebang = 1
    }

    let startLine, endLine;
    if (editor.selection.isEmpty) {
        command_zw = `%run ${filename}`;
    } else {
        if (shebang==1)
        {
            startLine = editor.selection.start.line;
            endLine = editor.selection.end.line;
        }
        else
        {
            startLine = editor.selection.start.line + 1;
            endLine = editor.selection.end.line + 1;
        }
        command_zw = `%load -r ${startLine}-${endLine} ${filename}`;
    }

    var delay = 0;
    const command = command_zw

    if (ipython_shell == null)
    {
        delay = 1300
        ipython_shell = vscode.window.createTerminal("IPython")
        setTimeout(() => {
            get_ipython_shell(vscode).sendText("C:\\portable\\WPy64-3720\\scripts\\cmd.bat")
            setTimeout(() => {
                get_ipython_shell(vscode).sendText("ipython")
            }, 100);
        }, 1000);
    }

    setTimeout(() => {
        ipython_shell.show();
        get_ipython_shell(vscode).sendText(command)
        setTimeout(() => {
            get_ipython_shell(vscode).sendText("")
        }, 100);
    }, delay);

};

function get_ipython_shell(vscode)
{
    var ipython_shell = null;
    vscode.window.terminals.forEach(element => {
        if (element.name=="IPython")
        {
            ipython_shell = element
        }
    });
    return ipython_shell
}

Nun kann ich über den einen Button einfach eine IPython Konsole starten. Der Button Send To IPython erzeugt wenn nicht schon vorhanden ein IPython Konsole und startet Skript aus dem aktuellen Editor Fenster. Genauso wie ich es von Spyder gewohnt war.