Verwenden von IPython-Notebooks unter Versionskontrolle

569

Was ist eine gute Strategie, um IPython- Notebooks unter Versionskontrolle zu halten?

Das Notebook-Format eignet sich gut für die Versionskontrolle: Wenn man das Notebook und die Ausgänge versionieren möchte, funktioniert dies recht gut. Der Ärger entsteht, wenn man nur die Version der Eingabe steuern möchte, mit Ausnahme der Zellenausgaben (auch "Build-Produkte" genannt), bei denen es sich um große binäre Blobs handeln kann, insbesondere für Filme und Handlungen. Insbesondere versuche ich, einen guten Workflow zu finden, der:

  • ermöglicht mir die Wahl zwischen Einschließen oder Ausschließen von Ausgaben,
  • verhindert, dass ich versehentlich eine Ausgabe festschreibe, wenn ich es nicht will,
  • ermöglicht es mir, die Ausgabe in meiner lokalen Version zu behalten,
  • ermöglicht es mir zu sehen, wann ich Änderungen an den Eingaben mit meinem Versionskontrollsystem habe (dh wenn ich nur die Eingaben versioniere, aber meine lokale Datei Ausgaben hat, möchte ich in der Lage sein zu sehen, ob sich die Eingaben geändert haben (was ein Commit erfordert) ) Bei Verwendung des Versionskontrollstatusbefehls wird immer ein Unterschied registriert, da die lokale Datei Ausgänge hat.)
  • ermöglicht es mir, mein Arbeitsnotizbuch (das die Ausgabe enthält) von einem aktualisierten sauberen Notizbuch zu aktualisieren. (aktualisieren)

Wie bereits erwähnt, ist alles in Ordnung , wenn ich die Ausgaben einbeziehe (was beispielsweise bei Verwendung von nbviewer wünschenswert ist). Das Problem ist, wenn ich die Ausgabe nicht versionieren möchte. Es gibt einige Tools und Skripte zum Entfernen der Ausgabe des Notebooks, aber häufig treten die folgenden Probleme auf:

  1. Ich habe versehentlich eine Version mit der Ausgabe festgeschrieben, wodurch mein Repository verschmutzt wird.
  2. Ich lösche die Ausgabe, um die Versionskontrolle zu verwenden, möchte die Ausgabe jedoch lieber in meiner lokalen Kopie behalten (manchmal dauert die Reproduktion beispielsweise eine Weile).
  3. Einige der Skripte, die die Ausgabe Cell/All Output/Clearentfernen, ändern das Format im Vergleich zur Menüoption geringfügig , wodurch unerwünschte Störungen in den Diffs entstehen. Dies wird durch einige der Antworten gelöst.
  4. Wenn ich Änderungen an einer sauberen Version der Datei abrufe, muss ich eine Möglichkeit finden, diese Änderungen in mein Arbeitsnotizbuch aufzunehmen, ohne alles erneut ausführen zu müssen. (aktualisieren)

Ich habe einige Optionen in Betracht gezogen, die ich unten diskutieren werde, habe aber noch keine gute umfassende Lösung gefunden. Eine vollständige Lösung erfordert möglicherweise einige Änderungen an IPython oder basiert auf einfachen externen Skripten. Ich verwende derzeit Mercurial , möchte aber eine Lösung, die auch mit Git funktioniert : Eine ideale Lösung wäre Agnostic mit Versionskontrolle.

Dieses Problem wurde schon oft diskutiert, aber aus Sicht des Benutzers gibt es keine endgültige oder klare Lösung. Die Antwort auf diese Frage sollte die endgültige Strategie liefern. Es ist in Ordnung, wenn eine aktuelle (sogar Entwicklungs-) Version von IPython oder eine einfach zu installierende Erweiterung erforderlich ist .

Update: Ich habe mit meiner modifizierten Notebook- Version gespielt, die optional .cleanbei jedem Speichern eine Version mit den Vorschlägen von Gregory Crosswhite speichert . Dies erfüllt die meisten meiner Einschränkungen, lässt jedoch Folgendes ungelöst:

  1. Dies ist noch keine Standardlösung (erfordert eine Änderung der Ipython-Quelle. Gibt es eine Möglichkeit, dieses Verhalten mit einer einfachen Erweiterung zu erreichen? Benötigt eine Art On-Save-Hook.
  2. Ein Problem, das ich mit dem aktuellen Workflow habe, ist das Abrufen von Änderungen. Diese werden in die .cleanDatei aufgenommen und müssen dann irgendwie in meine Arbeitsversion integriert werden. (Natürlich kann ich das Notizbuch jederzeit erneut ausführen, aber dies kann schmerzhaft sein, insbesondere wenn einige der Ergebnisse von langen Berechnungen, parallelen Berechnungen usw. abhängen.) Ich habe noch keine gute Idee, wie dies behoben werden kann . Vielleicht funktioniert ein Workflow mit einer Erweiterung wie ipycache , aber das scheint etwas zu kompliziert.

Anmerkungen

Ausgang entfernen (entfernen)

  • Wenn das Notebook läuft, können Sie die Cell/All Output/ClearMenüoption zum Entfernen der Ausgabe verwenden.
  • Es gibt einige Skripte zum Entfernen der Ausgabe, z. B. das Skript nbstripout.py, das die Ausgabe entfernt, jedoch nicht die gleiche Ausgabe wie bei Verwendung der Notebook-Oberfläche erzeugt. Dies wurde schließlich in das Repo von ipython / nbconvert aufgenommen , aber dies wurde geschlossen, da die Änderungen jetzt in ipython / ipython enthalten sind, die entsprechende Funktionalität jedoch noch nicht enthalten zu sein scheint. (Update) That being said, Gregory Crosswhite-Lösung zeigt , dass dies recht einfach zu tun, auch ohne Berufung auf ipython / nbconvertDaher ist dieser Ansatz wahrscheinlich praktikabel, wenn er ordnungsgemäß angeschlossen werden kann. (Das Anschließen an jedes Versionskontrollsystem scheint jedoch keine gute Idee zu sein - dies sollte sich irgendwie in den Notebook-Mechanismus einfügen.)

Newsgroups

Probleme

Anfragen ziehen

mforbes
quelle
Klingt nach einer großartigen Sache, die Sie als Problem auf github.com/ipython/ipython hinzufügen oder eine Pull-Anfrage senden können, die Ihnen dabei hilft, dieses Ziel zu erreichen.
Kyle Kelley
4
Sobald Sie ein funktionierendes Skript zum Entfernen der Ausgabe haben, können Sie einen Git "Clean" -Filter verwenden, um es vor dem Festschreiben automatisch anzuwenden (siehe Clean / Smudge-Filter).
Matthias
1
@foobarbecue Die Frage enthält unbefriedigende Problemumgehungen: Jede hat mindestens eine Einschränkung. Nachdem PR 4175 zusammengeführt wurde, kann wahrscheinlich eine vollständige Lösung formuliert werden, die jedoch noch durchgeführt werden muss. Sobald ich etwas Zeit habe, werde ich es tun (als Antwort), wenn jemand anderes in der Zwischenzeit keine zufriedenstellende Lösung bietet.
Mforbes
1
@saroele Ich habe noch keine empfohlene Lösung gefunden: Ich wollte mich für die --scriptOption entscheiden, aber die wurde entfernt. Ich warte, bis Post-Save-Hooks implementiert sind ( die geplant sind ). An diesem Punkt denke ich, dass ich in der Lage sein werde, eine akzeptable Lösung bereitzustellen, die mehrere der Techniken kombiniert.
Mforbes
1
@mforbes Sieht so aus, als ob PR nur wenige Tage nach Ihrem Kommentar zusammengeführt wurde. Könnten Sie oder jemand, der besser informiert ist als ich, hier eine Antwort posten, die zeigt, wie die neue Funktion verwendet wird?
KobeJohn

Antworten:

124

Hier ist meine Lösung mit Git. Sie können wie gewohnt einfach hinzufügen und festschreiben (und diff): Diese Vorgänge ändern Ihren Arbeitsbaum nicht, und gleichzeitig (erneutes) Ausführen eines Notizbuchs ändert sich Ihr Git-Verlauf nicht.

Obwohl dies wahrscheinlich an andere VCS angepasst werden kann, weiß ich, dass es Ihren Anforderungen nicht entspricht (zumindest der VSC-Agnostizität). Trotzdem ist es perfekt für mich, und obwohl es nichts besonders Geniales ist und viele Leute es wahrscheinlich bereits verwenden, habe ich keine klaren Anweisungen gefunden, wie man es durch Googeln umsetzt. So kann es für andere Menschen nützlich sein.

  1. Speichern Sie eine Datei mit diesem Inhalt irgendwo (für das Folgende nehmen wir an ~/bin/ipynb_output_filter.py)
  2. Mach es ausführbar ( chmod +x ~/bin/ipynb_output_filter.py)
  3. Erstellen Sie die Datei ~/.gitattributesmit dem folgenden Inhalt

    *.ipynb    filter=dropoutput_ipynb
    
  4. Führen Sie die folgenden Befehle aus:

    git config --global core.attributesfile ~/.gitattributes
    git config --global filter.dropoutput_ipynb.clean ~/bin/ipynb_output_filter.py
    git config --global filter.dropoutput_ipynb.smudge cat
    

Erledigt!

Einschränkungen:

  • es funktioniert nur mit git
  • Wenn Sie sich in einem Zweig befinden somebranchund dies tun git checkout otherbranch; git checkout somebranch, erwarten Sie normalerweise, dass der Arbeitsbaum unverändert bleibt. Hier haben Sie stattdessen die Ausgabe und die Zellennummerierung von Notebooks verloren, deren Quelle sich zwischen den beiden Zweigen unterscheidet.
  • Im Allgemeinen ist die Ausgabe überhaupt nicht versioniert, wie bei Gregorys Lösung. Um es nicht jedes Mal wegzuwerfen, wenn Sie etwas mit dem Auschecken tun, kann der Ansatz geändert werden, indem es in separaten Dateien gespeichert wird (beachten Sie jedoch, dass zum Zeitpunkt der Ausführung des obigen Codes die Festschreibungs-ID nicht bekannt ist!). und möglicherweise eine Versionierung (aber beachten Sie, dass dies etwas mehr als a erfordern würde git commit notebook_file.ipynb, obwohl es zumindest git diff notebook_file.ipynbfrei von Base64-Müll bleiben würde ).
  • Das heißt, übrigens, wenn Sie Code abrufen (dh von jemand anderem festgeschrieben, der diesen Ansatz nicht verwendet), der eine Ausgabe enthält, wird die Ausgabe normal ausgecheckt. Nur die lokal produzierte Ausgabe geht verloren.

Meine Lösung spiegelt die Tatsache wider, dass ich persönlich generierte Inhalte nicht gerne versioniert halte. Beachten Sie, dass das Zusammenführen mit der Ausgabe fast garantiert die Ausgabe oder Ihre Produktivität oder beides ungültig macht .

BEARBEITEN:

  • Wenn Sie die Lösung so übernehmen, wie ich es vorgeschlagen habe - das heißt global -, werden Sie Probleme haben, falls Sie für ein Git-Repo die Ausgabe versionieren möchten . Wenn Sie also die Ausgabefilterung für ein bestimmtes Git-Repository deaktivieren möchten , erstellen Sie einfach eine Datei .git / info / attribute mit

    **. ipynb filter =

als Inhalt. Auf die gleiche Weise ist es natürlich möglich, das Gegenteil zu tun: Aktivieren Sie die Filterung nur für ein bestimmtes Repository.

  • Der Code wird jetzt in einem eigenen Git-Repo verwaltet

  • Wenn die obigen Anweisungen zu ImportErrors führen, fügen Sie vor dem Pfad des Skripts "ipython" hinzu:

    git config --global filter.dropoutput_ipynb.clean ipython ~/bin/ipynb_output_filter.py
    

BEARBEITEN : Mai 2016 (aktualisiert im Februar 2017): Es gibt verschiedene Alternativen zu meinem Skript. Der Vollständigkeit halber finden Sie hier eine Liste der mir bekannten: nbstripout ( andere Varianten ), nbstrip , jq .

Pietro Battiston
quelle
2
Wie gehen Sie mit dem Problem um, Änderungen vorzunehmen, die Sie vornehmen? Leben Sie nur damit, dass Sie die gesamte Ausgabe neu generieren müssen? (Ich denke, dies ist eine Manifestation Ihrer zweiten Einschränkung.)
mforbes
1
@ Zhermes: Diese erweiterte Version sollte in Ordnung sein
Pietro Battiston
1
Gibt es eine Möglichkeit, diese Git-Filter-Methode mit einem externen Diff-Tool zu verwenden? Der Filter wird angewendet, wenn ich das normale Befehlszeilen-Tool verwende, aber nicht, wenn ich meld als Diff-Tool verwende. stackoverflow.com/q/30329615/578770
FA
1
Um nicht zu bekommen, musste ImportErrorich das oben Gesagte ändern, um mit ipython zu laufen:git config --global filter.dropoutput_ipynb.clean ipython ~/bin/ipynb_output_filter.py
chris838
1
Tolle Lösung Pietro, danke :) Ich habe in meinem Fall zwei Dinge geändert, als ich Ihr Skript verwendet habe: 1) Ich habe es vorgezogen, den Filter in .gitattributes im Stammverzeichnis des Repos zu deklarieren, im Gegensatz zu ~/.gitattributesanderen Leuten, die dieselben Filter haben wie ich 2 ) Ich habe den regulären Ausdruck als definiert workdir/**/*.ipynb filter=dropoutput_ipynbund die meisten meiner Notizbücher in workdir / => abgelegt. Wenn ich dennoch ein Notizbuch mit der Ausgabe verschieben und das Lesezeichen-Rendern in Github genießen möchte, lege ich es einfach außerhalb dieses Ordners ab.
Svend
63

Wir haben ein Gemeinschaftsprojekt, in dem das Produkt Jupyter Notebooks ist, und wir verwenden seit sechs Monaten einen Ansatz, der hervorragend funktioniert: Wir aktivieren das .pyautomatische Speichern der Dateien und verfolgen sowohl .ipynbDateien als auch .pyDateien.

Auf diese Weise kann jemand, der das neueste Notizbuch anzeigen / herunterladen möchte, dies über github oder nbviewer tun. Wenn jemand sehen möchte, wie sich der Notizbuchcode geändert hat, kann er sich nur die Änderungen an den .pyDateien ansehen .

Bei JupyterNotebook-Servern kann dies durch Hinzufügen der Zeilen erreicht werden

import os
from subprocess import check_call

def post_save(model, os_path, contents_manager):
    """post-save hook for converting notebooks to .py scripts"""
    if model['type'] != 'notebook':
        return # only do this for notebooks
    d, fname = os.path.split(os_path)
    check_call(['jupyter', 'nbconvert', '--to', 'script', fname], cwd=d)

c.FileContentsManager.post_save_hook = post_save

in die jupyter_notebook_config.pyDatei und starten Sie den Notebook-Server neu.

Falls Sie nicht sicher sind , in welchem Verzeichnis Ihr finden jupyter_notebook_config.pyDatei können Sie geben jupyter --config-dir, und wenn Sie die Datei nicht dort finden, können Sie es durch Eingabe erstellen jupyter notebook --generate-config.

Bei Ipython 3Notebook-Servern kann dies durch Hinzufügen der Zeilen erreicht werden

import os
from subprocess import check_call

def post_save(model, os_path, contents_manager):
    """post-save hook for converting notebooks to .py scripts"""
    if model['type'] != 'notebook':
        return # only do this for notebooks
    d, fname = os.path.split(os_path)
    check_call(['ipython', 'nbconvert', '--to', 'script', fname], cwd=d)

c.FileContentsManager.post_save_hook = post_save

in die ipython_notebook_config.pyDatei und starten Sie den Notebook-Server neu. Diese Zeilen stammen aus einer Antwort von Github, die von @minrk bereitgestellt wurde, und @dror nimmt sie auch in seine SO-Antwort auf.

Bei Ipython 2Notebook-Servern kann dies erreicht werden, indem der Server wie folgt gestartet wird:

ipython notebook --script

oder durch Hinzufügen der Zeile

c.FileNotebookManager.save_script = True

in die ipython_notebook_config.pyDatei und starten Sie den Notebook-Server neu.

Falls Sie nicht sicher sind , in welchem Verzeichnis Ihr finden ipython_notebook_config.pyDatei können Sie geben ipython locate profile default, und wenn Sie die Datei nicht dort finden, können Sie es durch Eingabe erstellen ipython profile create.

Hier ist unser Projekt zu Github, das diesen Ansatz verwendet : und hier ist ein Github-Beispiel für die Untersuchung der letzten Änderungen an einem Notebook .

Wir waren sehr zufrieden damit.

Rich Signell
quelle
1
Vielen Dank für die zusätzlichen Beweise, dass die Verwendung --scriptin der Praxis funktioniert hat. Das Problem dabei ist, dass die tatsächlichen Notebooks sehr groß sein können, wenn Bilder aufbewahrt werden. Eine ideale Lösung auf diesem Weg könnte so etwas wie Git-Annex verwenden , um nur das neueste vollständige Notebook im Auge zu behalten.
Mforbes
In Ipython 3.x --scriptist das veraltet. ipython.org/ipython-doc/3/whatsnew/version3.html
Dror
Vielen Dank an @dror, ich habe meine Antwort aktualisiert, um die ipython 3.x-Lösung von minrk bereitzustellen, wie Sie sie auch hier bereitgestellt haben.
Rich Signell
10
Update: Diese Lösung ist in iPython Version 4 aufgrund von "The Big Split" von Jupyter von iPython defekt. Um diese Lösung auf Version 4 anzupassen, verwenden Sie den Befehl jupyter notebook --generate-config, um eine Konfigurationsdatei zu erstellen. Der Befehl ermittelt jupyter --config-dir, welches Verzeichnis die Konfigurationsdateien enthält. Und das von @Rich angegebene Code-Snippet sollte der genannten Datei hinzugefügt werden jupyter_notebook_config.py. Der Rest funktioniert wie bisher.
Mobius Knödel
2
Zusätzlich zu dem Punkt durch @mobiusdumpling, ersetzen die check_call(['ipython'mit check_call(['jupyter', sonst erhalten Sie eine Warnung erhalten, ist ipython nbconvertveraltet und Sie sollten verwenden jupyter nbconvertstatt. (Jupyter v4.1.0, iPython v4.1.2)
Cutculus
36

Ich habe nbstripoutbasierend auf MinRKs Gist erstellt , das sowohl Git als auch Mercurial unterstützt (dank mforbes). Es soll entweder eigenständig in der Befehlszeile oder als Filter verwendet werden, der einfach über nbstripout install/ im aktuellen Repository ( / ) installiert werden kann nbstripout uninstall.

Erhalten Sie es von PyPI oder einfach

pip install nbstripout
kynan
quelle
Ich überlege mir einen Workflow, bei dem sowohl .ipynb als auch die entsprechende .py automatisch mit den oben beschriebenen Hooks nach dem Speichern erstellt werden. Ich möchte .py für Unterschiede verwenden - wäre nbstripout in der Lage, die .py-Datei aus den Zellenausführungszählern zu löschen (# In [1] geändert in In [*]), damit sie die Unterschiede nicht überladen oder sollte ich ein einfaches Skript dafür erstellen?
Krzysztof Słowiński
1
@ KrzysztofSłowiński Nein, nbstripoutunterstützt diesen Anwendungsfall nicht einfach, da er auf dem JSON-Format des Notebooks basiert. Sie sind wahrscheinlich besser dran, ein Skript zu schreiben, das auf Ihren Anwendungsfall spezialisiert ist.
Kynan
13

Hier ist eine neue Lösung von Cyrille Rossant für IPython 3.0, die weiterhin Markdown-Dateien anstelle von json-basierten ipymd-Dateien enthält:

https://github.com/rossant/ipymd

Spencer Boucher
quelle
Jupyter wird anscheinend noch nicht unterstützt.
K.-Michael Aye
Ich verwende ipymd erfolgreich mit dem neuesten Jupyter. Erhalten Sie ein bestimmtes Problem oder eine Fehlermeldung?
Cyrille Rossant
13

Nachdem ich einige Jahre lang Ausgaben in Notebooks entfernt hatte, habe ich versucht, eine bessere Lösung zu finden. Ich verwende jetzt Jupytext , eine Erweiterung für Jupyter Notebook und Jupyter Lab, die ich entworfen habe.

Jupytext kann Jupyter-Notizbücher in verschiedene Textformate (Skripte, Markdown und R-Markdown) konvertieren. Und umgekehrt. Es bietet auch die Möglichkeit zu paaren ein Notebook zu einem dieser Formate, und automatisch die beiden Darstellungen des Notebooks (eine Synchronisation .ipynbund eine .md/.py/.RDatei).

Lassen Sie mich erklären, wie Jupytext die obigen Fragen beantwortet:

ermöglicht mir die Wahl zwischen Einschließen oder Ausschließen von Ausgaben,

Die .md/.py/.RDatei enthält nur die Eingabezellen. Sie sollten diese Datei immer verfolgen. Versionieren Sie die .ipynbDatei nur, wenn Sie die Ausgaben verfolgen möchten.

verhindert, dass ich versehentlich eine Ausgabe festschreibe, wenn ich es nicht will,

Hinzufügen *.ipynbzu.gitignore

ermöglicht es mir, die Ausgabe in meiner lokalen Version zu behalten,

Die Ausgaben bleiben in der (lokalen) .ipynbDatei erhalten

ermöglicht es mir zu sehen, wann ich Änderungen an den Eingaben mit meinem Versionskontrollsystem habe (dh wenn ich nur die Eingaben versioniere, aber meine lokale Datei Ausgaben hat, möchte ich in der Lage sein zu sehen, ob sich die Eingaben geändert haben (was ein Commit erfordert) ) Bei Verwendung des Versionskontrollstatusbefehls wird immer ein Unterschied registriert, da die lokale Datei Ausgänge hat.)

Der Unterschied in der .py/.Roder .md-Datei ist das, wonach Sie suchen

ermöglicht es mir, mein Arbeitsnotizbuch (das die Ausgabe enthält) von einem aktualisierten sauberen Notizbuch zu aktualisieren. (aktualisieren)

Ziehen Sie die neueste Version der Datei .py/.Roder .mdund aktualisieren Sie Ihr Notizbuch in Jupyter (Strg + R). Sie erhalten die neuesten Eingabezellen aus der Textdatei mit übereinstimmenden Ausgaben aus der .ipynbDatei. Der Kernel ist nicht betroffen, was bedeutet, dass Ihre lokalen Variablen erhalten bleiben - Sie können dort weiterarbeiten, wo Sie ihn verlassen haben.

Was ich an Jupytext liebe, ist, dass das Notizbuch (in Form einer .py/.Roder einer .mdDatei) in Ihrer Lieblings-IDE bearbeitet werden kann. Mit diesem Ansatz wird das Refactoring eines Notebooks einfach. Sobald Sie fertig sind, müssen Sie nur noch das Notizbuch in Jupyter aktualisieren.

Wenn Sie es versuchen möchten: Installieren Sie Jupytext mit pip install jupytextund starten Sie Ihr Jupyter Notebook oder Ihren Lab-Editor neu. Öffnen Sie das Notizbuch, für das Sie die Versionskontrolle durchführen möchten, und koppeln Sie es mit einer Markdown-Datei (oder einem Skript) über das Jupytext-Menü im Jupyter-Notizbuch (oder die Jupytext-Befehle in Jupyter Lab). Speichern Sie Ihr Notizbuch, und Sie erhalten die beiden Dateien: das Original .ipynbsowie die versprochene Textdarstellung des Notizbuchs, die sich perfekt für die Versionskontrolle eignet!

Für diejenigen, die interessiert sein könnten: Jupytext ist auch in der Kommandozeile verfügbar .

Marc Wouts
quelle
13

Update : Jetzt können Sie Jupyter Notebook- Dateien direkt in Visual Studio Code bearbeiten . Sie können das Notizbuch oder die konvertierte Python-Datei bearbeiten.

Ich habe endlich einen produktiven und einfachen Weg gefunden, um Jupyter und Git gut zusammen spielen zu lassen. Ich bin noch in den ersten Schritten, aber ich denke bereits, dass es viel besser ist als alle anderen verschlungenen Lösungen.

Visual Studio Code ist ein cooler und Open Source Code Editor von Microsoft. Es verfügt über eine hervorragende Python-Erweiterung, mit der Sie jetzt ein Jupyter-Notizbuch als Python-Code importieren können . Jetzt können Sie Jupyter-Notizbücher auch direkt bearbeiten .

Nachdem Sie Ihr Notizbuch in eine Python-Datei importiert haben, befinden sich Code und Markdown in einer normalen Python-Datei mit speziellen Markierungen in Kommentaren. Sie können im Bild unten sehen:

VSCode-Editor mit einem in Python konvertierten Notizbuch

Ihre Python-Datei enthält nur den Inhalt der Notebook-Eingabezellen. Die Ausgabe wird in einem geteilten Fenster generiert. Sie haben reinen Code im Notizbuch, der sich nicht ändert, während Sie ihn nur ausführen. Keine vermischte Ausgabe mit Ihrem Code. Kein seltsames JSON-unverständliches Format zur Analyse Ihrer Unterschiede.

Nur reiner Python-Code, mit dem Sie jeden einzelnen Diff leicht identifizieren können.

Ich muss meine .ipynbDateien nicht einmal mehr versionieren. Ich kann eine *.ipynbZeile einfügen .gitignore.

Müssen Sie ein Notizbuch erstellen, um es zu veröffentlichen oder mit jemandem zu teilen? Kein Problem, klicken Sie einfach auf die Schaltfläche Exportieren im interaktiven Python-Fenster

Exportieren einer Python-Datei in das Notebook-Format

Wenn Sie das Notizbuch direkt bearbeiten, wird jetzt ein Symbol angezeigt Convert and save to a python script. Jupyter-Symbole in Visual Studio Code

Hier ein Screenshot eines Notizbuchs in Visual Studio Code:

Notebook in VSCode bearbeiten

Ich benutze es erst seit einem Tag, aber endlich kann ich Jupyter gerne mit Git verwenden.

PS: Die Vervollständigung des VSCode-Codes ist viel besser als Jupyter.

neves
quelle
12

(2017-02)

Strategien

  • on_commit ():
    • Entfernen Sie die Ausgabe> name.ipynb ( nbstripout,)
    • Entfernen Sie die Ausgabe> name.clean.ipynb ( nbstripout,)
    • immer nbconvertzu Python: name.ipynb.py ( nbconvert)
    • immer in markdown konvertieren: name.ipynb.md ( nbconvert, ipymd)
  • vcs.configure ():
    • git difftool, mergetool: nbdiff und nbmerge von nbdime

Werkzeuge

Wes Turner
quelle
11

Die sehr beliebten Antworten für 2016 sind inkonsistente Hacks im Vergleich zu dem besseren Weg, dies 2019 zu tun.

Es gibt mehrere Optionen. Die beste Antwort auf die Frage ist Jupytext.

Jupytext

Fangen Sie den Weg zu Daten Wissenschaft Artikel über Jupytext

Die Funktionsweise der Versionskontrolle besteht darin, dass Sie sowohl die .py- als auch die .ipynb-Datei in die Versionskontrolle einfügen. Schauen Sie sich die .py an, wenn Sie den Eingabedifferenz möchten, und schauen Sie sich die .ipynb an, wenn Sie die zuletzt gerenderte Ausgabe möchten.

Bemerkenswerte Erwähnungen: VS Studio, nbconvert, nbdime, Wasserstoff

Ich denke, mit etwas mehr Arbeit werden VS Studio und / oder Wasserstoff (oder ähnliches) die dominierenden Akteure bei der Lösung dieses Workflows sein.

SwimBikeRun
quelle
9

Stoßen Sie einfach auf "jupytext", der wie eine perfekte Lösung aussieht. Es generiert eine .py-Datei aus dem Notizbuch und hält dann beide synchron. Sie können Eingaben über die .py-Datei versionieren, unterscheiden und zusammenführen, ohne die Ausgaben zu verlieren. Wenn Sie das Notizbuch öffnen, wird die .py für Eingabezellen und die .ipynb für die Ausgabe verwendet. Und wenn Sie die Ausgabe in git aufnehmen möchten, können Sie einfach den ipynb hinzufügen.

https://github.com/mwouts/jupytext

Simon
quelle
9

Da es so viele Strategien und Tools für die Versionskontrolle von Notebooks gibt, habe ich versucht, ein Flussdiagramm zu erstellen, um eine geeignete Strategie auszuwählen (erstellt im April 2019).

Entscheidungsfluss zur Auswahl der Versionskontrollstrategie

nik
quelle
8

Wie bereits erwähnt, --scriptist der in veraltet 3.x. Dieser Ansatz kann durch Anwenden eines Post-Save-Hooks verwendet werden. Fügen Sie insbesondere Folgendes hinzu ipython_notebook_config.py:

import os
from subprocess import check_call

def post_save(model, os_path, contents_manager):
    """post-save hook for converting notebooks to .py scripts"""
    if model['type'] != 'notebook':
        return # only do this for notebooks
    d, fname = os.path.split(os_path)
    check_call(['ipython', 'nbconvert', '--to', 'script', fname], cwd=d)

c.FileContentsManager.post_save_hook = post_save

Der Code stammt aus # 8009 .

Dror
quelle
Vielen Dank, dass Sie die Verwendung eines Post-Save-Hooks demonstriert haben. Wie bereits erwähnt, .pyist es leider problematisch, von der Datei auf ein Notizbuch zurückzukehren, sodass dies leider keine vollständige Lösung ist. (Ich wünschte, es wäre so, weil es sehr schön ist, .pyDateien anstelle von Notizbüchern zu
diffundieren
1
Vielen Dank! Ich verwende jetzt diesen Trick, um das --scriptVerhalten unabhängig von der Versionskontrolle zu reproduzieren . Anfangs hatte ich einige Probleme, also für den Fall, dass ich jemandem etwas Zeit sparen kann: 1) Wenn das ipython_notebook_config.pyim Profilordner fehlt, führen Sie es aus ipython profile create, um es zu generieren. 2) Wenn es so aussieht, als würde der Post-Save-Hook ignoriert, führen Sie ipython mit aus, --debugum das Problem zu diagnostizieren. 3) Wenn das Skript mit einem Fehler fehlschlägt ImportError: No module named mistune- installieren Sie einfach minstue : pip install mistune.
Joe
7

Leider weiß ich nicht viel über Mercurial, aber ich kann Ihnen eine mögliche Lösung geben, die mit Git funktioniert, in der Hoffnung, dass Sie meine Git-Befehle möglicherweise in ihre Mercurial-Entsprechungen übersetzen können.

Im Hintergrund addspeichert der Befehl in Git die Änderungen, die an einer Datei vorgenommen wurden, in einem Staging-Bereich. Sobald Sie dies getan haben, werden alle nachfolgenden Änderungen an der Datei von Git ignoriert, es sei denn, Sie weisen sie an, sie ebenfalls zu inszenieren. Daher entfernt das folgende Skript, das für jede der angegebenen Dateien das gesamte outputsund entfernt prompt_number sections, die entfernte Datei bereitstellt und dann das Original wiederherstellt:

HINWEIS: Wenn Sie beim Ausführen eine Fehlermeldung erhalten ImportError: No module named IPython.nbformat, verwenden Sie ipythonstattdessen das Skript python.

from IPython.nbformat import current
import io
from os import remove, rename
from shutil import copyfile
from subprocess import Popen
from sys import argv

for filename in argv[1:]:
    # Backup the current file
    backup_filename = filename + ".backup"
    copyfile(filename,backup_filename)

    try:
        # Read in the notebook
        with io.open(filename,'r',encoding='utf-8') as f:
            notebook = current.reads(f.read(),format="ipynb")

        # Strip out all of the output and prompt_number sections
        for worksheet in notebook["worksheets"]:
            for cell in worksheet["cells"]:
               cell.outputs = []
               if "prompt_number" in cell:
                    del cell["prompt_number"]

        # Write the stripped file
        with io.open(filename, 'w', encoding='utf-8') as f:
            current.write(notebook,f,format='ipynb')

        # Run git add to stage the non-output changes
        print("git add",filename)
        Popen(["git","add",filename]).wait()

    finally:
        # Restore the original file;  remove is needed in case
        # we are running in windows.
        remove(filename)
        rename(backup_filename,filename)

Sobald das Skript für die Dateien ausgeführt wurde, deren Änderungen Sie festschreiben wollten, führen Sie es einfach aus git commit.

Gregory Crosswhite
quelle
Danke für den Vorschlag. Mercurial hat nicht wirklich einen Staging-Bereich wie git (obwohl man für diesen Zweck Quecksilber-Warteschlangen verwenden könnte). In der Zwischenzeit habe ich versucht, diesen Code einem Save Hook hinzuzufügen, der eine saubere Version mit einer .cleanErweiterung speichert . Leider konnte ich nicht sehen, wie dies zu tun ist, ohne IPython direkt zu ändern (obwohl diese Änderung ziemlich trivial war). Ich werde eine Weile damit spielen und sehen, ob es all meinen Bedürfnissen entspricht.
Mforbes
6

Ich benutze einen sehr pragmatischen Ansatz; die für mehrere Notebooks an mehreren Seiten gut funktionieren. Und es ermöglicht mir sogar, Notebooks zu "übertragen". Es funktioniert sowohl für Windows als auch für Unix / MacOS.
Al dachte, es ist einfach, ist die oben genannten Probleme zu lösen ...

Konzept

Verfolgen Sie grundsätzlich nicht die .ipnyb-Dateien, sondern nur die entsprechenden .py-Dateien.
Wenn Sie den Notebook-Server mit der --scriptOption starten , wird diese Datei automatisch erstellt / gespeichert, wenn das Notebook gespeichert wird.

Diese .pyDateien enthalten alle Eingaben. Nicht-Code wird in Kommentaren gespeichert, ebenso wie die Zellränder. Diese Dateien können gelesen / importiert (und in den Notebook-Server gezogen) werden, um ein Notebook (neu) zu erstellen. Nur die Ausgabe ist weg; bis es erneut ausgeführt wird.

Persönlich verwende ich mercurial , um die .pyDateien in der Version zu verfolgen . und verwenden Sie die normalen (Befehlszeilen-) Befehle, um dies hinzuzufügen und einzuchecken (ect). Die meisten anderen (D) VCS erlauben dies.

Es ist einfach, die Geschichte jetzt zu verfolgen; Die .pysind klein, textuell und einfach zu unterscheiden. Hin und wieder benötigen wir einen Klon (einfach verzweigen; dort einen zweiten Notebook-Server starten) oder eine ältere Version (auschecken und in einen Notebook-Server importieren) usw.

Tipps

  • Fügen Sie * .ipynb zu ' .hgignore ' hinzu, damit Mercurial weiß, dass diese Dateien ignoriert werden können
  • Erstellen Sie ein (Bash-) Skript, um den Server zu starten (mit der --scriptOption) und führen Sie eine Versionsverfolgung durch
  • Beim Speichern eines Notizbuchs wird die .pyDatei zwar gespeichert, aber nicht eingecheckt .
    • Das ist ein Nachteil : Das kann man vergessen
    • Es ist auch eine Funktion : Es ist möglich, ein Notizbuch zu speichern (und später fortzufahren), ohne den Repository-Verlauf zu gruppieren.

Wünscht sich

  • Es wäre schön, eine Schaltfläche zum Einchecken / Hinzufügen / usw. im Notebook-Dashboard zu haben
  • Ein Checkout zu (anhand eines Beispiels) file@date+rev.pysollte hilfreich sein. Es wäre zu viel Arbeit, dies hinzuzufügen. und vielleicht werde ich es einmal tun. Bis jetzt mache ich das einfach von Hand.
Albert
quelle
Wie gelangen Sie von der .pyDatei zurück zu einem Notizbuch? Ich mag diesen Ansatz, aber weil .ipynb-> .py-> .ipynbpotenziell verlustbehaftet ist, habe ich dies nicht ernsthaft in Betracht gezogen.
Mforbes
Das ist ganz einfach: Laden Sie es, indem Sie es beispielsweise auf das Notebook-Dashboard legen. Außer "Ausgabedaten" geht nichts verloren
Albert
Wenn das stimmt, dann denke ich, dass dies nahe an der Idee wäre, aber ich erinnere mich, dass IPython keine Verpflichtung eingegangen ist, Daten beim Übergang von .pyzu .ipynbFormaten vollständig zu erhalten . Hier gibt es ein Problem - vielleicht bildet dies die Grundlage für eine vollständige Lösung.
Mforbes
Ich habe einige Schwierigkeiten beim Konvertieren von .pyDateien in .ipynbDateien. nbconvertscheint dies noch nicht zu unterstützen, und ich habe kein Notebook-Dashboard, da ich es ipython notebookmanuell ausführe . Haben Sie allgemeine Vorschläge zur Implementierung dieser Rückwärtskonvertierung?
Mforbes
Sicherlich ist die .pyUmwandlung in ein Notebook nicht für einen Roundtrip gedacht. Das kann also keine allgemeine Lösung sein, obwohl es schön ist, dass es für Sie funktioniert.
Holdenweb
3

Um das hervorragende Skript von Pietro Battiston weiterzuverfolgen, wenn Sie einen Unicode-Analysefehler wie diesen erhalten:

Traceback (most recent call last):
  File "/Users/kwisatz/bin/ipynb_output_filter.py", line 33, in <module>
write(json_in, sys.stdout, NO_CONVERT)
  File "/Users/kwisatz/anaconda/lib/python2.7/site-packages/IPython/nbformat/__init__.py", line 161, in write
fp.write(s)
UnicodeEncodeError: 'ascii' codec can't encode character u'\u2014' in position 11549: ordinal not in range(128)

Sie können am Anfang des Skripts hinzufügen:

reload(sys)
sys.setdefaultencoding('utf8')
Guillaume Dumas
quelle
3

Ich habe ein Python-Paket erstellt, das dieses Problem löst

https://github.com/brookisme/gitnb

Es bietet eine CLI mit einer von Git inspirierten Syntax zum Verfolgen / Aktualisieren / Diff von Notebooks in Ihrem Git-Repo.

Hier ist ein Beispiel

# add a notebook to be tracked
gitnb add SomeNotebook.ipynb

# check the changes before commiting
gitnb diff SomeNotebook.ipynb

# commit your changes (to your git repo)
gitnb commit -am "I fixed a bug"

Beachten Sie, dass der letzte Schritt, in dem ich "gitnb commit" verwende, das Festschreiben für Ihr Git-Repo ist. Es ist im Wesentlichen ein Wrapper für

# get the latest changes from your python notebooks
gitnb update

# commit your changes ** this time with the native git commit **
git commit -am "I fixed a bug"

Es gibt mehrere weitere Methoden, die so konfiguriert werden können, dass in jeder Phase mehr oder weniger Benutzereingaben erforderlich sind. Dies ist jedoch die allgemeine Idee.

Bach
quelle
3

Nachdem ich mich umgesehen hatte, fand ich endlich diesen relativ einfachen Pre-Save-Hook in den Jupyter-Dokumenten . Die Zellenausgabedaten werden entfernt. Sie müssen es in die jupyter_notebook_config.pyDatei einfügen (Anweisungen siehe unten).

def scrub_output_pre_save(model, **kwargs):
    """scrub output before saving notebooks"""
    # only run on notebooks
    if model['type'] != 'notebook':
        return
    # only run on nbformat v4
    if model['content']['nbformat'] != 4:
        return

    for cell in model['content']['cells']:
        if cell['cell_type'] != 'code':
            continue
        cell['outputs'] = []
        cell['execution_count'] = None
        # Added by binaryfunt:
        if 'collapsed' in cell['metadata']:
            cell['metadata'].pop('collapsed', 0)

c.FileContentsManager.pre_save_hook = scrub_output_pre_save

Aus der Antwort von Rich Signell :

Wenn Sie nicht sicher sind, in welchem ​​Verzeichnis Sie Ihre jupyter_notebook_config.pyDatei finden sollen, können Sie jupyter --config-dir[in Eingabeaufforderung / Terminal] eingeben jupyter notebook --generate-config. Wenn Sie die Datei dort nicht finden, können Sie sie durch Eingabe erstellen .

Binärfunt
quelle
1
Ich möchte darauf hinweisen , dass diese Lösung würde nie speichern alle Ausgänge auf die Festplatte, und ist etwas unabhängig von der Versionskontrolle Problem.
Bdforbes
2

Ich habe getan, was Albert & Rich getan hat - Versions-IPynb-Dateien nicht versionieren (da diese Bilder enthalten können, was unordentlich wird). Führen Sie stattdessen entweder immer Ihre Konfigurationsdatei aus ipython notebook --scriptoder c.FileNotebookManager.save_script = Truefügen .pySie sie ein, sodass beim Speichern Ihres Notebooks immer eine (versionierbare) Datei erstellt wird.

Um Notizbücher neu zu generieren (nachdem ich ein Repo ausgecheckt oder einen Zweig gewechselt habe ), lege ich das Skript py_file_to_notebooks.py in das Verzeichnis, in dem ich meine Notizbücher speichere.

Nachdem Sie ein Repo python py_file_to_notebooks.pyausgecheckt haben , führen Sie es einfach aus , um die ipynb-Dateien zu generieren. Nach dem Wechsel der Verzweigung müssen Sie möglicherweise ausführen python py_file_to_notebooks.py -ov, um die vorhandenen ipynb-Dateien zu überschreiben.

Um auf der sicheren Seite zu sein, ist es gut, auch *.ipynbzu Ihrer .gitignoreDatei hinzuzufügen .

Bearbeiten: Ich mache das nicht mehr, weil (A) Sie Ihre Notizbücher jedes Mal aus Py-Dateien neu generieren müssen, wenn Sie einen Zweig auschecken, und (B) Sie andere Dinge wie Abschriften in Notizbüchern verlieren. Ich entferne stattdessen die Ausgabe von Notebooks mit einem Git-Filter. Eine Diskussion darüber finden Sie hier .

Peter
quelle
Diese Idee hat mir gefallen, aber nach dem Testen stellte ich fest, dass die Konvertierung von .pyDateien zurück in .ipynbproblematisch ist, insbesondere bei Notebooks der Version 4, für die es noch keinen Konverter gibt. Derzeit müsste man den v3-Importer verwenden und dann auf v4 konvertieren, und ich bin etwas besorgt über diese komplizierte Reise. Auch eine .pyDatei ist keine sehr gute Wahl, wenn das Notebook hauptsächlich Julia-Code ist! Schließlich --scriptist veraltet, so dass ich denke, Haken sind der richtige Weg.
Mforbes
Die Git-Filter-Lösung in Ihrem Link ist gut, Sie sollten Ihre Antwort von hier hier kopieren :-)
mcarans
2

Ok, es sieht so aus, als ob die derzeit beste Lösung laut einer Diskussion hier darin besteht, einen Git-Filter zu erstellen, um die Ausgabe von ipynb-Dateien beim Festschreiben automatisch zu entfernen.

Folgendes habe ich getan, um es zum Laufen zu bringen (kopiert aus dieser Diskussion):

Ich verändert nbstripout Datei cfriedline leicht einem informativen Fehler zu geben , wenn Sie nicht die neueste IPython importieren: https://github.com/petered/plato/blob/fb2f4e252f50c79768920d0e47b870a8d799e92b/notebooks/config/strip_notebook_output Und es zu meiner Repo, lasse sag rein./relative/path/to/strip_notebook_output

Außerdem wurde die Datei .gitattributes zum Stammverzeichnis des Repos hinzugefügt, die Folgendes enthält:

*.ipynb filter=stripoutput

Und ein setup_git_filters.shContaining erstellt

git config filter.stripoutput.clean "$(git rev-parse --show-toplevel)/relative/path/to/strip_notebook_output" 
git config filter.stripoutput.smudge cat
git config filter.stripoutput.required true

Und rannte source setup_git_filters.sh. Das schicke $ (git rev-parse ...) ist, den lokalen Pfad Ihres Repos auf jedem (Unix-) Computer zu finden.

Peter
quelle
1

Mit dieser jupyter-Erweiterung können Benutzer jupyter-Notebooks direkt an github senden.

Bitte schauen Sie hier

https://github.com/sat28/githubcommit

saß
quelle
Können Sie erklären, was dies bewirkt? Die Dokumentation ist nicht besonders klar.
Alex Monras
@AlexMonras Dies wird eine Schaltfläche in jupyter Notebook aus direkt hinzufügen , wo Sie Notebooks auf Ihre GitHub Repo mit einer Commit - Nachricht drücken kann
sat
1

Dies ist April-2020 und es gibt viele Strategien und Tools für die Versionskontrolle von Jupyter-Notebooks. Hier ist ein kurzer Überblick über alle Tools, die Sie verwenden können:

  • nbdime - Nizza für das lokale Diff'ing und Zusammenführen von Notebooks

  • nbstripout - Ein Git-Filter zum automatischen Entfernen von Notebook-Ausgaben vor jedem Commit

  • jupytext - Hält eine .py-Begleitdatei mit jedem Notizbuch synchronisiert. Sie schreiben nur .py-Dateien fest

  • nbconvert - Konvertiert Notizbücher in ein Python-Skript oder HTML (oder beides) und schreibt diese alternativen Dateitypen fest

  • ReviewNB - Zeigt den Notebook- Unterschied (zusammen mit der Ausgabe) für alle Commit- oder Pull-Anforderungen auf GitHub an. Man kann auch Kommentare zu Notizbuchzellen schreiben, um Änderungen zu besprechen (Screenshot unten).

Geben Sie hier die Bildbeschreibung ein

Haftungsausschluss: Ich habe ReviewNB erstellt.

Amirathi
quelle
0

Wie wäre es mit der Idee, die im folgenden Beitrag besprochen wurde, in der die Ausgabe des Notebooks aufbewahrt werden soll, mit dem Argument, dass das Generieren möglicherweise lange dauert, und es ist praktisch, da GitHub jetzt Notebooks rendern kann. Es wurden automatisch gespeicherte Hooks zum Exportieren von .py-Dateien hinzugefügt, die für Unterschiede und .html zum Teilen mit Teammitgliedern verwendet werden, die keine Notebooks oder Git verwenden.

https://towardsdatascience.com/version-control-for-jupyter-notebook-3e6cef13392d

Krzysztof Słowiński
quelle